📄 mdx86.c
字号:
_asm {
mov eax, lpv
mov dr0, eax
mov eax, lpvZero
mov dr1, eax
mov eax, dr7
and eax, dwMask
or eax, dwFlags
mov dr7, eax
}
pOwnerProc = pCurProc;
KCALLPROFOFF(73);
return 1;
}
KCALLPROFOFF(73);
}
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
void
ExceptionDispatch(
PCONTEXT pctx
)
{
PTHREAD pth;
PEXCINFO pexi;
int id;
ULONG info = 0;
PEXCARGS pea;
EXCEPTION_RECORD er;
DWORD dwThrdInfo = KTHRDINFO (pCurThread); // need to save it since it might get changed during exception handling
BOOL fInKMode;
pth = pCurThread;
pexi = (PEXCINFO)pth->pcstkTop;
DEBUGMSG(ZONE_SEH, (TEXT("ExceptionDispatch: pexi=%8.8lx Eip=%8.8lx id=%x\r\n"),
pexi, pexi->oldEip, pexi->id));
// Update CONTEXT with infomation saved in the EXCINFO structure
pctx->Eip = pexi->oldEip;
pctx->Esp = (DWORD)pctx + sizeof(CONTEXT);
SetContextMode(pctx, (((PCALLSTACK)pexi)->dwPrcInfo & CST_MODE_FROM_USER)? USER_MODE : KERNEL_MODE);
memset(&er, 0, sizeof(er));
er.ExceptionAddress = (PVOID)pctx->Eip;
// Check for RaiseException call versus a CPU detected exception.
// RaiseException just becomes a call to CaptureContext as a KPSL.
// HandleExcepion sets the LSB of the callstack linkage but ObjectCall
// does not.
if (!(pexi->linkage & 1)) {
NK_PCR *pcr = (NK_PCR *)((char *)pth->tlsPtr - offsetof(NK_PCR, tls));
// Fill in exception record information from the parameters passed to
// the RaiseException call.
// Restore exception list linkage.
DEBUGCHK(pcr->ExceptionList == -2);
pcr->ExceptionList = ((PCALLSTACK)pexi)->extra;
pea = (PEXCARGS)(pctx->Esp + 4);
id = -1;
pctx->Esp += 4; // Remove return address from the stack
DEBUGMSG(ZONE_SEH, (TEXT("Raising exception %x flags=%x args=%d pexi=%8.8lx\r\n"),
pea->dwExceptionCode, pea->dwExceptionFlags, pea->cArguments, pexi));
er.ExceptionCode = pea->dwExceptionCode;
er.ExceptionFlags = pea->dwExceptionFlags;
if (pea->lpArguments && pea->cArguments) {
if (pea->cArguments > EXCEPTION_MAXIMUM_PARAMETERS) {
er.ExceptionCode = STATUS_INVALID_PARAMETER;
er.ExceptionFlags = EXCEPTION_NONCONTINUABLE;
} else {
memcpy(er.ExceptionInformation, pea->lpArguments,
pea->cArguments*sizeof(DWORD));
er.NumberParameters = pea->cArguments;
}
}
} else {
// CPU detected exception. Extract some additional information about
// the cause of the exception from the EXCINFO (CALLSTACK) structure.
id = pexi->id;
info = pexi->info;
pctx->EFlags |= pexi->oldTFlag << 8;
pctx->Esp += pexi->lowSp + sizeof(CALLSTACK);
if ((id == 14) && AutoCommit(info)) {
pth->pcstkTop = (PCALLSTACK)(pexi->linkage & ~1);
goto continueExecution;
}
// Construct an EXCEPTION_RECORD from the EXCINFO structure
er.ExceptionInformation[1] = info;
switch (id) {
case 14: // Page fault
er.ExceptionInformation[0] = (pexi->error >> 1) & 1;
goto accessError;
case 13: // General Protection Fault
er.ExceptionInformation[0] = 1; accessError:
fInKMode = (GetContextMode(pctx) == KERNEL_MODE);
// er.ExceptionInformation[0] == read or write (1 for write)
if (!InSysCall ()
&& (!(info & 0x80000000) || fInKMode)
// writing to shared section require KMode access
&& (!IsInSharedSection(info) || !er.ExceptionInformation[0] || fInKMode)
&& ProcessPageFault(er.ExceptionInformation[0], info)) {
pth->pcstkTop = (PCALLSTACK)(pexi->linkage & ~1);
goto continueExecution;
}
er.ExceptionCode = STATUS_ACCESS_VIOLATION;
er.NumberParameters = 2;
break;
case 3: // Breakpoint
er.ExceptionInformation[0] = 1; // DEBUGBREAK_STOP_BREAKPOINT
er.ExceptionCode = STATUS_BREAKPOINT;
break;
case 2: // Stop thread breakpoint
er.ExceptionInformation[0] = 3; // DEBUG_THREAD_SWITCH_BREAKPOINT
er.ExceptionCode = STATUS_BREAKPOINT;
break;
case 1: // Breakpoint
er.ExceptionInformation[0] = 0;
er.ExceptionCode = STATUS_SINGLE_STEP;
// If you are using the SetCPUHardware watch function you will probably
// want to uncomment the following lines so that it will clear the register
// automatically on exception
/*
if(!SetCPUHardwareWatch(0, (DWORD)-1)) {
pth->pcstkTop = (PCALLSTACK)(pexi->linkage & ~1);
goto continueExecution;
}
*/
break;
case 0: // Divide by zero
er.ExceptionInformation[0] = 0;
er.ExceptionCode = STATUS_INTEGER_DIVIDE_BY_ZERO;
break;
case 6: // Reserved instruction
er.ExceptionCode = STATUS_ILLEGAL_INSTRUCTION;
break;
case 16: {
if (pexi->error & 0x01)
er.ExceptionCode = STATUS_FLOAT_INVALID_OPERATION;
else if (pexi->error & 0x4)
er.ExceptionCode = STATUS_FLOAT_DIVIDE_BY_ZERO;
else if (pexi->error & 0x8)
er.ExceptionCode = STATUS_FLOAT_OVERFLOW;
else if (pexi->error & 0x10)
er.ExceptionCode = STATUS_FLOAT_UNDERFLOW;
else if (pexi->error & 0x20)
er.ExceptionCode = STATUS_FLOAT_INEXACT_RESULT;
else
er.ExceptionCode = STATUS_FLOAT_DENORMAL_OPERAND;
break;
}
case 0xFF: // Stack overflow
er.ExceptionCode = STATUS_STACK_OVERFLOW;
er.ExceptionFlags = EXCEPTION_NONCONTINUABLE;
break;
}
}
if (id != 1 && id != 3 && !IsNoFaultMsgSet ()) {
// if we faulted in DllMain doing PROCESS_ATTACH, the process name will
// be pointing to other process's (the creator) address space. Make sure
// we don't fault on displaying process name.
LPWSTR pProcName = pCurProc->lpszProcName? pCurProc->lpszProcName : L"";
LPCWSTR pszNamePC;
DWORD dwOfstPC = pctx->Eip;
pszNamePC = FindModuleNameAndOffset (dwOfstPC, &dwOfstPC);
if (!((DWORD) pProcName & 0x80000000)
&& (((DWORD) pProcName >> VA_SECTION) != (DWORD) (pCurProc->procnum+1)))
pProcName = L"";
NKDbgPrintfW(L"Exception %03x Thread=%8.8lx Proc=%8.8lx '%s'\r\n",
id, pth, hCurProc, pProcName);
NKDbgPrintfW(L"AKY=%8.8lx PC=%8.8lx(%s+0x%8.8lx) ESP=%8.8lx EA=%8.8lx\r\n",
pCurThread->aky, pctx->Eip, pszNamePC, dwOfstPC, pctx->Esp, info);
if (IsNoFaultSet ()) {
NKDbgPrintfW(L"TLSKERN_NOFAULT set... bypassing kernel debugger.\r\n");
}
}
// Invoke the kernel debugger to attempt to debug the exception before
// letting the program resolve the condition via SEH.
pth->pcstkTop = (PCALLSTACK)(pexi->linkage & ~1);
if (!(pexi->linkage & 1) && IsValidKPtr (pexi)) {
// from RaiseException, free the callstack structure
FreeMem (pexi, HEAP_CALLSTACK);
}
if (!UserDbgTrap(&er, pctx, FALSE) && (IsNoFaultSet () || !HDException(&er, pctx, FALSE))) {
BOOL bHandled = FALSE;
// don't pass a break point exception to NKDispatchException
if ((er.ExceptionCode != STATUS_BREAKPOINT) && (er.ExceptionCode != STATUS_SINGLE_STEP)) {
// to prevent recursive exception due to user messed-up TLS
KTHRDINFO (pth) &= ~UTLS_INKMODE;
bHandled = NKDispatchException(pth, &er, pctx);
}
if (!bHandled && !UserDbgTrap(&er, pctx, TRUE) && !HDException(&er, pctx, TRUE)) {
if (er.ExceptionCode == STATUS_BREAKPOINT) {
if (!pvHDNotifyExdi || pctx->Eip < (DWORD)pvHDNotifyExdi || pctx->Eip > ((DWORD)pvHDNotifyExdi + HD_NOTIFY_MARGIN))
RETAILMSG(1, (TEXT("DEBUG_BREAK @%8.8lx Ignored.\r\n"), pctx->Eip));
if (*(uchar*)pctx->Eip == 0xCC)
++pctx->Eip;
else if (*(uchar*)pctx->Eip == 0xCD)
pctx->Eip += 2;
} else {
// Unhandled exception, terminate the process.
RETAILMSG(1, (TEXT("\r\nUnhandled exception %8.8lx:\r\n"),
er.ExceptionCode));
if (InSysCall()) {
DumpFrame(pth, pctx, id, 0);
lpNKHaltSystem ();
FakeNKHaltSystem ();
} else {
if (!GET_DEAD(pth)) {
PCALLSTACK pcstk = pth->pcstkTop;
while (pcstk && !pcstk->akyLast) {
pth->pcstkTop = (PCALLSTACK) ((DWORD) pcstk->pcstkNext & ~1);
if (IsValidKPtr (pcstk)) {
FreeMem (pcstk, HEAP_CALLSTACK);
}
pcstk = pth->pcstkTop;
}
DEBUGCHK (!pcstk); // should this happen, we have a fault in callback that wasn't handled
// by PSL
// clean up all the temporary callstack
if (er.ExceptionCode == STATUS_STACK_OVERFLOW) {
// stack overflow, not much we can do. Make sure we have enough room to run
// pExcpExitThread
// randomly picked a valid SP
pctx->Esp = (DWORD) pth->tlsPtr - SECURESTK_RESERVE - (PAGE_SIZE >> 1);
}
SET_DEAD(pth);
//pth->tlsSecure[TLSSLOT_KERNEL] |= TLSKERN_TRYINGTODIE;
pctx->Eip = (ULONG)pExcpExitThread;
// pctx->Esp -= 12; // room for the faked call
((ulong*)pctx->Esp)[1] = er.ExceptionCode; // argument, exception code
((PVOID*)pctx->Esp)[2] = er.ExceptionAddress; // argument, exception address
RETAILMSG(1, (TEXT("Terminating thread %8.8lx\r\n"), pth));
} else {
DumpFrame(pth, pctx, id, 0);
RETAILMSG(1, (TEXT("Can't terminate thread %8.8lx, sleeping forever\r\n"), pth));
SurrenderCritSecs();
Sleep(INFINITE);
DEBUGCHK(0); // should never get here
}
}
}
}
}
if (id == 14)
GuardCommit(info);
continueExecution:
// restore ThrdInfo
KTHRDINFO (pth) = dwThrdInfo;
// If returning from handling a stack overflow, reset the thread's stack overflow
// flag. It would be good to free the tail of the stack at this time
// so that the thread will stack fault again if the stack gets too big. But we
// are currently using that stack page.
if (id == 0xFF)
CLEAR_STACKFAULT(pth);
if (GET_DYING(pth) && !GET_DEAD(pth) && (pCurProc == pth->pOwnerProc)) {
SET_DEAD(pth);
CLEAR_USERBLOCK(pth);
CLEAR_DEBUGWAIT(pth);
pctx->Eip = (ULONG)pExcpExitThread;
((ulong*)pctx->Esp)[1] = er.ExceptionCode; // argument, exception code
((PVOID*)pctx->Esp)[2] = er.ExceptionAddress; // argument, exception address
}
}
//------------------------------------------------------------------------------
// Capture processor state into a full CONTEXT structure for debugging
// and exception handling.
//
// (eax) = ptr to EXCINFO structure
//------------------------------------------------------------------------------
Naked
CaptureContext(void)
{
__asm {
push ss
push esp // will be repaired by ExceptionDispatch
pushfd
push cs
push eax // Eip filled in by ExceptionDispatch
push ebp
push eax
push ecx
push edx
push ebx
push esi
push edi
push ds
push es
push fs
push gs
mov ecx, KGDT_R3_DATA
mov ds, cx
mov es, cx
cld
sub esp, size FLOATING_SAVE_AREA
push 0 // dr7
push 0 // dr6
push 0 // dr3
push 0 // dr2
push 0 // dr1
push 0 // dr0
push CONTEXT_FULL
mov ebx, esp // (ebx) = ptr to context structure
push ebx // (arg0) = ptr to CONTEXT
call ExceptionDispatch
// Reload processor state from possibly edited
lea esp, [ebx].SegGs
pop gs
pop fs
pop es
pop ds
pop edi
pop esi
pop ebx
pop edx
pop ecx
mov ax, cs // (ax) = current code selector
xor eax, [esp+12] // (ax) = CS ^ target selector
and eax, 0000fffcH // (eax) = selector bits that differ
jz short no_ring_switch
pop eax
pop ebp
iretd
// Restore frame without a ring switch. Special care must be taken here because
// we need to restore Esp but an IRETD without a ring switch will not restore
// the SS:ESP. Since we are returning the same ring, all that needs to be restored
// are Esp and Eip. This is done by copying the new Eip and new Ebp values onto the
// new stack, switching to the new stack and then restoring Ebp and returning.
// The return must be via an IRETD so that single stepping works correctly.
//
// At this point the stack frame is:
// 24 ss
// 20 esp
// 16 flags
// 12 cs
// 08 eip
// 04 ebp
// 00 eax
// ---------< esp points here
no_ring_switch:
mov ebp, [esp+20] // (ebp) = new stack pointer
mov eax, [esp+16] // (eax) = new EFlags
mov [ebp-4], eax // may overwrite SS value
mov eax, [esp+8] // (eax) = new eip
mov [ebp-12], eax // may overwrite EFlags value
mov eax, [esp+4] // (eax) = new ebp
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -