Dailydave mailing list archives
Re: Tool announce: user mode single stepping
From: "Matt Conover" <mconover () gmail com>
Date: Wed, 29 Nov 2006 17:15:09 -0800
I guess you never heard of tcodetrace... http://72.14.203.104/search?q=cache:gDeAFf4bIJ4J:www.cybertech.net/~sh0ksh0k/projects/tcodetrace There was been a documented included with the code since March 2006 named "Self Single-Stepping.txt" which as title implies, utilizes this exact technique. The source code has also been posted there for a long time.. these are the contents of "Self Single-Stepping.txt": For static code, every instruction between TRAP_STATIC_CODE_START/TRAP_STATIC_CODE_END is trapped For dynamic code, you specify the code address and code size all within TRAP_DYNAMIC_CODE You specify all callback that will be called for each instruction about to be executed. The callback can analyze the instruction and chose one of these options: 1. Execute the instruction (return TRAP_EXECUTE) 2. Stop trapping (return TRAP_STOP) and continue after the trapping code ( e.g., first instruction after TRAP_STATIC_CODE_END/TRAP_DYNAMIC_CODE) 3. Kick in a debugger (return TRAP_DEBUG) by leaving the single-step exception unhandled 4. Skip the instruction (return TRAP_SKIP). 5. Disable trapping and execute until a breakpoint is reached (TRAP_GO) 6. Step over the current instruction (TRAP_STEP_OVER). If the next instruction is a call, for example, it will execute the function and then break after the call completes. 7. Step out of the current function (TRAP_STEP_OUT). Non single-step exceptions are left unhandled so that the program will function as it normally would have The benefit of doing it this is way as opposed to using the native Win32 debugging technique is that: 1. You can load whatever code you want to execute within the current process 2. You don't leave signs the code is being debugged like debugging does Currently it will skip int1/int3/into/popf automatically, but anything more advanced should be done by the user-defined handler. +++ TRAP_SAMPLE.C TRAP_CONTEXT TrapA, TrapB, TrapC, *CurrentTrap; BOOL DumpInstruction(TRAP_CONTEXT *TrapContext, CONTEXT *CPU); DWORD TestFunc(); void TestTrap() { char buf[] = "\xcc\x90\xcc\x90"; CurrentTrap = &TrapA; TRAP_STATIC_CODE_START(TrapA, DumpInstruction) _asm int 3 _asm mov eax, 0x12345678 _asm mov ebx, 0xAABBCCDD TRAP_STATIC_CODE_END(TrapA) printf("\n=== Finished (stepped through %d instructions)\n\n", TrapA.Count); assert(TRAP_COUNT(TrapA) == 3); CurrentTrap = &TrapB; TRAP_STATIC_CODE_START(TrapB, DumpInstruction) _asm call TestFunc TRAP_STATIC_CODE_END(TrapB) assert(TRAP_COUNT(TrapA) == 3); printf("\n=== Finished (stepped through %d instructions)\n\n", TrapB.Count); CurrentTrap = &TrapC; TRAP_DYNAMIC_CODE(TrapC, buf, 4, DumpInstruction) printf("\n=== Finished (stepped through %d instructions)\n\n", TrapC.Count); assert(TRAP_COUNT(TrapC) == 4); } __declspec(naked) DWORD TestFunc() { _asm { mov eax, 0xABABCDCD ret } } BOOL DumpInstruction(TRAP_CONTEXT *TrapContext, CONTEXT *CPU) { DWORD Address = CPU->Eip; BYTE *p = (BYTE *)Address; { // Demonstrate that it isn't detected as a debugger BOOL (*f)(); f = (BOOL (*)())GetProcAddress(GetModuleHandle("kernel32"), "IsDebuggerPresent"); assert(f && !f()); } printf("Executing 0x%08lx", Address); if (!TRAP_IN_RANGE(Address, *CurrentTrap)) printf(" (outside trap range)"); putchar('\n'); return TRAP_CONTINUE; } +++ OUTPUT Executing 0x00418165 Executing 0x00418166 Executing 0x0041816b === Finished (stepped through 3 instructions) Executing 0x0041820f Executing 0x004013ac (outside trap range) Executing 0x004183e0 (outside trap range) Executing 0x004183e5 (outside trap range) === Finished (stepped through 4 instructions) Executing 0x0012feb4 Executing 0x0012feb5 Executing 0x0012feb6 Executing 0x0012feb7 === Finished (stepped through 4 instructions) #include "disasm.h" #define ENABLE_TRAPPING_ON_CONTEXT(c) (c)->EFlags |= EFLAGS_TF #define DISABLE_TRAPPING_ON_CONTEXT(c) (c)->EFlags &= ~EFLAGS_TF #define ENABLE_BREAKPOINTS_ON_CONTEXT(c) \ { \ (c)->EFlags &= ~EFLAGS_RF; \ if ((c)->Dr0) (c)->Dr7 |= (1<<0); \ if ((c)->Dr1) (c)->Dr7 |= (1<<1); \ if ((c)->Dr2) (c)->Dr7 |= (1<<2); \ if ((c)->Dr3) (c)->Dr7 |= (1<<3); \ } #define DISABLE_BREAKPOINTS_ON_CONTEXT(c) \ { \ (c)->EFlags |= EFLAGS_RF; \ (c)->Dr7 &= ~0x0F; \ } #define SET_EFLAGS(flags) \ { \ _asm mov eax, flags \ _asm push eax \ _asm popfd \ } #define ENABLE_TRAPPING() \ { \ _asm pushfd \ _asm pop eax \ _asm or eax, EFLAGS_TF \ _asm push eax \ _asm popfd \ } #define DISABLE_TRAPPING() \ { \ _asm pushfd \ _asm pop eax \ _asm mov ebx, EFLAGS_TF \ _asm not ebx \ _asm and eax, ebx \ _asm push eax \ _asm popfd \ } #define ENABLE_BREAKPOINTS() \ { \ _asm pushfd \ _asm pop eax \ _asm mov ebx, EFLAGS_RF \ _asm not ebx \ _asm and eax, ebx \ _asm push eax \ _asm popfd \ } #define DISABLE_BREAKPOINTS() \ { \ _asm pushfd \ _asm pop eax \ _asm or eax, EFLAGS_RF \ _asm push eax \ _asm popfd \ } // The trap handler must return one of these three values: #define TRAP_CONTINUE 1 // Contiues execution with trapping enabled #define TRAP_STOP 2 // Stop execution of trapping code, continue immediately after all trapping code #define TRAP_DEBUG 3 // Leaves the single step exception unhandled #define TRAP_SKIP 4 // Skips an instruction instruction #define TRAP_STEP_OVER 5 // Runs until the instruction following the current one is reached (used for branches or privileged instructions) #define TRAP_STEP_OUT 6 // Runs until a return instruction is reached #define TRAP_GO 7 // Continues execution with trapping disabled typedef BOOL (*USER_TRAP_HANDLER)(struct _TRAP_CONTEXT *TrapContext, CONTEXT *CPU); #define TRAP_STATIC_CODE_START(TrapId, UserTrapHandler, disasm) \ assert(DISASM_ARCH_TYPE(disasm) == ARCH_X86); \ memset(&TrapId, 0, sizeof(TrapId)); \ TrapId.Disassembler = disasm; \ TrapId.Handler = UserTrapHandler; \ TrapId.CommandFile = stdin; \ CurrentTrap = &TrapId; \ __try \ { \ PEXCEPTION_ROUTINE InternalHandler = NULL; \ _asm { mov eax, fs:[0] } \ _asm { mov eax, [eax+4] } \ _asm { mov InternalHandler, eax } \ assert(!IsBadCodePtr((FARPROC)InternalHandler)); \ TrapId.InternalHandler = InternalHandler; \ goto TrapId##_CodeEnd; \ TrapId##_GetStartAddress: \ TrapId.StartPointer = (DWORD)GetEIP() + 13; \ ENABLE_TRAPPING() \ _asm { nop } #define TRAP_STATIC_CODE_END(TrapId) \ _asm { nop } \ TrapId##_CodeEnd: \ TrapId.EndPointer = (DWORD)GetEIP() - 6; \ goto TrapId##_GetStartAddress; \ HANDLE_TRAP(TrapHandler) #define TRAP_DYNAMIC_CODE(TrapId, Code, CodeSize, UserTrapHandler, disasm) \ assert(DISASM_ARCH_TYPE(disasm) == ARCH_X86); \ memset(&TrapId, 0, sizeof(TrapId)); \ TrapId.Disassembler = disasm; \ TrapId.CommandFile = stdin; \ TrapId.Handler = UserTrapHandler; \ CurrentTrap = &TrapId; \ __try \ { \ PEXCEPTION_ROUTINE InternalHandler = NULL; \ _asm { mov eax, fs:[0] } \ _asm { mov eax, [eax+4] } \ _asm { mov InternalHandler, eax } \ assert(!IsBadCodePtr((FARPROC)InternalHandler)); \ TrapId.InternalHandler = InternalHandler; \ TrapId.StartPointer = (DWORD)Code; \ TrapId.EndPointer = (DWORD)(Code + CodeSize); \ _asm lea ebx, Code \ _asm mov ebx, [ebx] \ _asm pushfd \ _asm pop eax \ _asm or eax, EFLAGS_TRAP \ _asm push eax \ _asm popfd \ _asm jmp ebx \ HANDLE_TRAP(TrapHandler) #define HANDLE_TRAP(a) } __except(a(GetExceptionInformation())) { } #define IS_TRAP(a) ((a)->ExceptionRecord->ExceptionCode == EXCEPTION_SINGLE_STEP) #define IS_BREAKPOINT(a) ((a)->ExceptionRecord->ExceptionCode == EXCEPTION_BREAKPOINT) #define DUMP_TRAP_EXCEPTION(e) \ { \ DWORD e_i = 0; \ printf("Exception code: "); \ switch ((e)->ExceptionCode) \ { \ case EXCEPTION_ACCESS_VIOLATION: printf("access violation\n"); break; \ case EXCEPTION_BREAKPOINT: printf("breakpoint reached\n"); break; \ case EXCEPTION_DATATYPE_MISALIGNMENT: printf("datatype misalignment\n"); break; \ case EXCEPTION_SINGLE_STEP: printf("single step trap\n"); break; \ case DBG_CONTROL_C: printf("Control-C (application break)\n"); break; \ default: printf("unknown exception code = 0x%08lx\n", (e)->ExceptionCode); break; \ } \ if ((e)->ExceptionFlags & EXCEPTION_NONCONTINUABLE) printf("Non-continuable\n"); \ printf("Exception address: 0x%08lx\n", (e)->ExceptionAddress); \ if ((e)->NumberParameters != -1 && !(e)->NumberParameters) \ { \ printf("Exception information:\n"); \ for (e_i = 0; e_i < (e)->NumberParameters; e_i++) printf("\t0x%08lx\n", (e)->ExceptionInformation[e_i]); \ } \ putchar('\n'); \ } #define DUMP_TRAP_CONTEXT(c) \ { \ printf("Registers:\n"); \ printf("EIP: 0x%08lx ESP: 0x%08lx EBP: 0x%08lx EFLAGS: 0x%08lx\n", (c)->Eip, (c)->Esp, (c)->Ebp, (c)->EFlags); \ printf("EAX: 0x%08lx EBX: 0x%08lx ECX: 0x%08lx EDX: 0x%08lx\n", \ (c)->Eax, (c)->Ebx, (c)->Ecx, (c)->Edx); \ printf("ESI: 0x%08lx EDI: 0x%08lx\n", (c)->Esi, (c)->Edi); \ putchar('\n'); \ } #define DUMP_TRAP_INFO(a) \ { \ DUMP_TRAP_EXCEPTION((a)->ExceptionRecord); \ DUMP_TRAP_CONTEXT((a)->ContextRecord); \ } // NOTE: this will of course return false if the to-be-trapped code does a call or jump // to code outside of the trap range #define TRAP_IN_RANGE(eip, TrapId) (eip >= (TrapId).StartPointer && eip < (TrapId).EndPointer) TRAP_CONTEXT *CurrentTrap; int TrapHandler (EXCEPTION_POINTERS *Context); #define RETURN_TRAP_ERROR(c) \ { \ fflush(stdout); fflush(stderr); \ TrapDisableAllBreakpoints(CurrentTrap); \ DISABLE_TRAPPING_ON_CONTEXT(c); \ ENABLE_BREAKPOINTS_ON_CONTEXT(c); \ if (CurrentTrap->PendingBreakpoints) TrapReenableBreakpoints(CurrentTrap); \ (c)->Dr6 = 0; \ CurrentTrap->BreakpointOccurred = FALSE; \ CurrentTrap->MemoryBreakpointAddress = NULL; \ return EXCEPTION_CONTINUE_SEARCH; \ } #define RETURN_TRAP_STOP(c) \ { \ DISABLE_BREAKPOINTS_ON_CONTEXT(c); \ DISABLE_TRAPPING_ON_CONTEXT(c); \ TrapRemoveAllBreakpoints(CurrentTrap); \ (c)->Dr6 = 0; \ CurrentTrap->BreakpointOccurred = FALSE; \ CurrentTrap->MemoryBreakpointAddress = NULL; \ CurrentTrap->LastTrapType = TRAP_STOP; \ return EXCEPTION_EXECUTE_HANDLER; \ } #define RETURN_TRAP_GO(c) \ { \ fflush(stdout); \ memcpy(&CurrentTrap->PreviousContext, (c), sizeof(CONTEXT)); \ DISABLE_TRAPPING_ON_CONTEXT(c); \ ENABLE_BREAKPOINTS_ON_CONTEXT(c); \ if (TRAP_IN_RANGE((c)->Eip, *CurrentTrap)) CurrentTrap->TrapExecuted++; \ CurrentTrap->TotalExecuted++; \ if (CurrentTrap->PendingBreakpoints) TrapReenableBreakpoints(CurrentTrap); \ (c)->Dr6 = 0; \ CurrentTrap->BreakpointOccurred = FALSE; \ CurrentTrap->MemoryBreakpointAddress = NULL; \ CurrentTrap->LastTrapType = TRAP_GO; \ return EXCEPTION_CONTINUE_EXECUTION; \ } #define RETURN_TRAP_CONTINUE(c) \ { \ fflush(stdout); \ memcpy(&CurrentTrap->PreviousContext, (c), sizeof(CONTEXT)); \ ENABLE_TRAPPING_ON_CONTEXT(c); \ ENABLE_BREAKPOINTS_ON_CONTEXT(c); \ (c)->Dr6 = 0; \ CurrentTrap->BreakpointOccurred = FALSE; \ CurrentTrap->MemoryBreakpointAddress = NULL; \ CurrentTrap->LastTrapType = TRAP_CONTINUE; \ return EXCEPTION_CONTINUE_EXECUTION; \ } #define TRAP_HANDLE_BREAKPOINT() \ { \ Breakpoint->CurrentTriggerCount++; \ Breakpoint->TotalTriggerCount++; \ if (!TrapDisableBreakpoint(CurrentTrap, Breakpoint)) { assert(0); goto abort; } \ if (Breakpoint->CurrentTriggerCount >= Breakpoint->Threshold) \ { \ if (Breakpoint->Flags) \ { \ printf("*** Hit "); \ if (Breakpoint->Flags & BREAKPOINT_READ) printf("read/write "); \ else printf("write "); \ printf("memory breakpoint 0x%08lx at 0x%02lX\n", Breakpoint->SavedAddress, CPU->Eip); \ } \ else \ { \ printf("*** Hit code breakpoint at 0x%02lX\n", Breakpoint->SavedAddress); \ assert(Breakpoint->SavedAddress == (BYTE *)CPU->Eip); \ } \ Breakpoint->CurrentTriggerCount = 0; \ if (Breakpoint->RemoveOnTrigger) \ { \ if (!TrapRemoveBreakpoint(CurrentTrap, Breakpoint)) { assert(0); goto abort; } \ } \ else \ { \ Breakpoint->Reenable = TRUE; \ CurrentTrap->PendingBreakpoints = TRUE; \ } \ } \ else \ { \ Breakpoint->Reenable = TRUE; \ CurrentTrap->PendingBreakpoints = TRUE; \ } \ } TRAP_CONTEXT TrapThreads[TRAP_MAX_THREADS]; TRAP_CONTEXT *CurrentTrap, *OriginalTrap; extern BOOL Interactive; int TrapHandler(EXCEPTION_POINTERS *Context) { DWORD i, EIP = Context->ContextRecord->Eip; BYTE *pEIP = (BYTE *)EIP; INSTRUCTION *pInstruction = &CurrentTrap->Disassembler->Instruction; BREAKPOINT *Breakpoint; CONTEXT *CPU, tmpContext; DISABLE_BREAKPOINTS() if (TrapThreads[0].Initialized != TRAP_INITIALIZED) { OriginalTrap = CurrentTrap; // This is the first time TrapHandler has been called, initialize TrapThreads memcpy(&TrapThreads[0], CurrentTrap, sizeof(TRAP_CONTEXT)); CurrentTrap = &TrapThreads[0]; CurrentTrap->Initialized = TRAP_INITIALIZED; CurrentTrap->ID = GetCurrentThreadId(); CurrentTrap->LastTrapType = CurrentTrap->TrapType = TRAP_CONTINUE; } else { CurrentTrap = NULL; for (i = 0; TrapThreads[i].Initialized == TRAP_INITIALIZED; i++) { if (TrapThreads[i].ID == GetCurrentThreadId()) { CurrentTrap = &TrapThreads[i]; break; } } if (!CurrentTrap) { if (i == TRAP_MAX_THREADS) { printf("ERROR: too many threads (%d max)\n", TRAP_MAX_THREADS); fflush(stdout); assert(0); goto abort; } memcpy(&TrapThreads[i], CurrentTrap, sizeof(TRAP_CONTEXT)); CurrentTrap = &TrapThreads[i]; CurrentTrap->Initialized = TRAP_INITIALIZED; CurrentTrap->ID = GetCurrentThreadId(); CurrentTrap->LastTrapType = CurrentTrap->TrapType = TRAP_CONTINUE; printf("*** NEW THREAD %d (%d total threads)\n", CurrentTrap->ID, i+1); } } assert(GetCurrentThreadId() == CurrentTrap->ID); assert(CurrentTrap->LastTrapType == TRAP_CONTINUE || CurrentTrap->LastTrapType == TRAP_GO); CPU = CurrentTrap->CPU = Context->ContextRecord; if (CurrentTrap->PendingBreakpoints && !TrapReenableBreakpoints(CurrentTrap)) { assert(0); goto abort; } // Disable memory breakpoints while in the exception handler memset(&tmpContext, 0, sizeof(CONTEXT)); tmpContext.ContextFlags = CONTEXT_DEBUG_REGISTERS; if (GetThreadContext(GetCurrentThread(), &tmpContext)) { DISABLE_BREAKPOINTS_ON_CONTEXT(&tmpContext); if (!SetThreadContext(GetCurrentThread(), &tmpContext)) assert(0); } else { assert(0); // ignore } if (IS_BREAKPOINT(Context) && !TrapFindBreakpoint(CurrentTrap, pEIP)) { // This breakpoint occurred naturally in the program printf(" *** Hit native code breakpoint at 0x%02lX\n", pEIP); CurrentTrap->BreakpointOccurred = TRUE; CurrentTrap->PredictedStackChange = CurrentTrap->PredictedFlagChanges = 0; CurrentTrap->IgnoreFlagMask = -1; CurrentTrap->PredictedBranch = NULL; if (!CurrentTrap->EmulateResumeFlag) RETURN_TRAP_ERROR(CPU) pEIP++; CPU->Eip++; if (CurrentTrap->LastTrapType == TRAP_CONTINUE) RETURN_TRAP_CONTINUE(CPU) else RETURN_TRAP_GO(CPU) } else if (IS_TRAP(Context) || IS_BREAKPOINT(Context)) { assert(pEIP == (BYTE *)CPU->Eip); Breakpoint = TrapFindBreakpoint(CurrentTrap, pEIP-1); if (Breakpoint) { if (*(pEIP-1) == X86_NOP) { // This is a temporary breakpoint used to skip instructions if (!TrapRemoveBreakpoint(CurrentTrap, Breakpoint)) { assert(0); goto abort; } } Breakpoint = NULL; assert(!CurrentTrap->BreakpointOccurred); } if (CPU->Dr6 & 0x0F) // a memory breakpoint occurred { CurrentTrap->MemoryBreakpointAddress = NULL; switch (CPU->Dr6 & 0x0F) { case (1<<0): CurrentTrap->MemoryBreakpointAddress = (BYTE *)CPU->Dr0; break; case (1<<1): CurrentTrap->MemoryBreakpointAddress = (BYTE *)CPU->Dr1; break; case (1<<2): CurrentTrap->MemoryBreakpointAddress = (BYTE *)CPU->Dr2; break; case (1<<3): CurrentTrap->MemoryBreakpointAddress = (BYTE *)CPU->Dr3; break; default: assert(0); goto abort; // multiple breakpoints occurred at once? } assert(CurrentTrap->MemoryBreakpointAddress); Breakpoint = TrapFindBreakpoint(CurrentTrap, CurrentTrap->MemoryBreakpointAddress); Breakpoint = NULL; if (!Breakpoint) { printf("*** Hit native memory breakpoint at instruction before 0x%02lX\n", pEIP); assert(0); // this shouldn't happen very often -- anti-debugging trick? CurrentTrap->BreakpointOccurred = TRUE; CurrentTrap->PredictedStackChange = CurrentTrap->PredictedFlagChanges = 0; CurrentTrap->IgnoreFlagMask = -1; CurrentTrap->PredictedBranch = NULL; // EFLAGS.RF flag has no effect on memory breakpoints, so pass it to the program if (CurrentTrap->LastTrapType != TRAP_CONTINUE) RETURN_TRAP_GO(CPU) // The current mode is TRAP_CONTINUE, so just continue as if nothing happened } else { TRAP_HANDLE_BREAKPOINT(); Breakpoint = NULL; } } Breakpoint = TrapFindBreakpoint(CurrentTrap, pEIP); if (Breakpoint && !Breakpoint->Disabled) { // A breakpoint at the current instruction assert(Breakpoint->SavedAddress == (BYTE *)CPU->Eip); TRAP_HANDLE_BREAKPOINT(); Breakpoint = NULL; } if (EIP != (DWORD)CurrentTrap->EndPointer) { TrapGetFPU(CurrentTrap); switch (CurrentTrap->Handler(CurrentTrap, CPU)) { case TRAP_DEBUG: RETURN_TRAP_ERROR(CPU) assert(0); case TRAP_STOP: goto stop; case TRAP_CONTINUE: CurrentTrap->TotalExecuted++; if (TRAP_IN_RANGE(EIP, *CurrentTrap)) CurrentTrap->TrapExecuted++; RETURN_TRAP_CONTINUE(CPU) assert(0); case TRAP_SKIP: assert(pEIP == (BYTE *)EIP); if (pInstruction->Address != pEIP) { pInstruction = GetInstruction(CurrentTrap->Disassembler, EIP, (BYTE *)EIP, 0); if (!pInstruction) { assert(0); goto abort; } } CurrentTrap->TotalSkipped++; if (TRAP_IN_RANGE(EIP, *CurrentTrap)) CurrentTrap->TrapSkipped++; CPU->Eip += pInstruction->Length - 1; pEIP += pInstruction->Length - 1; if (!TrapAddBreakpoint(CurrentTrap, pEIP, X86_NOP, 1, TRUE)) { assert(0); goto abort; } RETURN_TRAP_CONTINUE(CPU) assert(0); case TRAP_STEP_OVER: pEIP += pInstruction->Length; if (!TrapAddBreakpoint(CurrentTrap, pEIP, X86_BREAK, 1, TRUE)) { assert(0); goto abort; } RETURN_TRAP_GO(CPU) assert(0); case TRAP_STEP_OUT: if (IsBadCodePtr((FARPROC)CurrentTrap->ReturnAddress)) { printf("ERROR: invalid return address 0x%02lX\n", CurrentTrap->ReturnAddress); assert(0); goto abort; } printf("*** Setting break point on return address 0x%02lX\n", CurrentTrap->ReturnAddress); if (!TrapAddBreakpoint(CurrentTrap, CurrentTrap->ReturnAddress, X86_BREAK, 1, TRUE)) { assert(0); goto abort; } RETURN_TRAP_GO(CPU) assert(0); case TRAP_GO: // Run through trap code, but with trapping disable printf("context emuate %d\n", CurrentTrap->EmulateResumeFlag); RETURN_TRAP_GO(CPU) assert(0); default: assert(0); goto abort; } } else { printf("\nReached last instruction at 0x%02lX\n", EIP); stop: assert(!OriginalTrap->TotalExecuted && !OriginalTrap->TotalSkipped); for (i = 0; TrapThreads[i].Initialized == TRAP_INITIALIZED; i++) { OriginalTrap->TotalExecuted += TrapThreads[i].TotalExecuted; OriginalTrap->TotalSkipped += TrapThreads[i].TotalSkipped; OriginalTrap->TrapExecuted += TrapThreads[i].TrapExecuted; OriginalTrap->TrapSkipped += TrapThreads[i].TrapSkipped; } RETURN_TRAP_STOP(CPU) } assert(0); // shouldn't be reached } abort: DUMP_TRAP_INFO(Context); RETURN_TRAP_ERROR(CPU) }
_______________________________________________ Dailydave mailing list Dailydave () lists immunitysec com http://lists.immunitysec.com/mailman/listinfo/dailydave
Current thread:
- Tool announce: user mode single stepping Rafal_Wojtczuk (Nov 29)
- Re: Tool announce: user mode single stepping Jared DeMott (Nov 29)
- Re: Tool announce: user mode single stepping Dave Korn (Nov 29)
- Re: Tool announce: user mode single stepping Thomas Ptacek (Nov 29)
- Re: Tool announce: user mode single stepping Matt Conover (Nov 29)
- Re: Tool announce: user mode single stepping Thomas Ptacek (Nov 29)
- <Possible follow-ups>
- Re: Tool announce: user mode single stepping Rafal_Wojtczuk (Nov 30)
- Re: Tool announce: user mode single stepping Matt Conover (Nov 30)