2017-02-05 17 views
2

Я работаю над кодом, чтобы попытаться отслеживать трассировку стека и попытался использовать регистры отладки и векторную обработку исключений (для x86). Я сделал пример программы, которая будет выводить адрес любого доступа к текущему адресу возврата. Это работает, если в вызываемой функции встречается трассировка стека. Если это не так (закомментируйте код, который читает обратный адрес), триггеры исключения в команде возврата. Отсюда мой обработчик исключений не вызывается, и программа выдает другое исключение, а затем завершается ошибкой stackhash. Есть ли способ сделать этот захват трассировкой стека, если он встречается, но также не сбой при возврате, если трассировка стека не происходит?Ловушка Stacktraces с отладочным регистром Точки останова и векторная обработка исключений

Вот код моей тестовой программы, написанные для Visual Studio 2012 (C, x86)

#include <Windows.h> 
#include <stdio.h> 

DWORD WINAPI myFunction(void); 
void myFunction2(void); 
DWORD WINAPI ExceptionHandler(EXCEPTION_POINTERS *pExceptionInfo); 

int main() 
{ 
    HANDLE thread = GetCurrentThread(); 
    static CONTEXT context; 

    AddVectoredExceptionHandler(1, (PVECTORED_EXCEPTION_HANDLER)ExceptionHandler); 
    context.ContextFlags = CONTEXT_DEBUG_REGISTERS; 
    GetThreadContext(thread, &context); 
    context.Dr6 = 0; 

    context.Dr7 = 0; 
    context.Dr7 |= (3 << 16); //set bits 16-17 to 1 - break read/write 
    context.Dr7 |= (3 << 18); //set bits 18-19 to 1 - size = 4 
    context.Dr7 |= 0x101; //enable local hardware breakpoint on dr0 
    context.Dr7 |= 1 << 13; 

    _asm { 
     push offset label //push return address 
     lea eax, [esp] 
     mov context.Dr0, esp 
    } 
    SetThreadContext(thread, &context); 
    __asm 
    { 
     jmp myFunction // "call" myFunction 
label: 
    } 

    printf("Return from my function\n"); 
    getchar(); 


    return 0; 
} 


// try windows api stack trace 
DWORD WINAPI myFunction(void) 
{ 
    PVOID out[10]; 
    CaptureStackBackTrace(0, 10, out, 0); 
    return 0; 
} 

// simple pull return address from esp 
void __declspec(naked) myFunction2(void) 
{ 
    __asm{ 
     mov eax, [esp] 
     ret 
    } 
} 


DWORD WINAPI ExceptionHandler(EXCEPTION_POINTERS *pExceptionInfo) 
{ 
    //Handle hwbp 

    if(pExceptionInfo->ExceptionRecord->ExceptionCode==EXCEPTION_SINGLE_STEP && //hardware breakpoints are SINGLE_STEP 
     (pExceptionInfo->ContextRecord->Dr6 & 1)) //check to see that instruction occured on Dr0 
    { 
     pExceptionInfo->ContextRecord->Dr7 &= 0xfffffffe; // disable Dr0 
     printf("Hardware breakpoint triggered at %08Xh\n", pExceptionInfo->ExceptionRecord->ExceptionAddress); 
     return EXCEPTION_CONTINUE_EXECUTION; 
    } 

    printf("Other exception\n"); 
    return EXCEPTION_CONTINUE_SEARCH; 
} 
+0

сначала вы должны установить 'pExceptionInfo-> ContextRecord-> ContextFlags | = CONTEXT_DEBUG_REGISTERS;' в 'ExceptionHandler' без этого все ваши изменения потеряны – RbMm

ответ

0

вам нужен код, как это:

LONG WINAPI ExceptionHandler(PEXCEPTION_POINTERS ExceptionInfo) 
{ 
    PEXCEPTION_RECORD ExceptionRecord = ExceptionInfo->ExceptionRecord; 

    if (ExceptionRecord->ExceptionCode != STATUS_SINGLE_STEP) return EXCEPTION_CONTINUE_SEARCH; 

    CONTEXT* ContextRecord = ExceptionInfo->ContextRecord; 

    if (!_bittest((PLONG)&ContextRecord->Dr6, 3)) 
    { 
     return EXCEPTION_CONTINUE_SEARCH; 
    } 

    ContextRecord->EFlags |= RESUME_FLAG; 
    ContextRecord->Dr7 = 0; 
    ContextRecord->Dr3 = 0; 
    ContextRecord->ContextFlags |= CONTEXT_DEBUG_REGISTERS; 

    return EXCEPTION_CONTINUE_EXECUTION; 
} 

void test() 
{ 
    if (AddVectoredExceptionHandler(TRUE, ExceptionHandler)) 
    { 
     CONTEXT ctx; 
     ctx.ContextFlags = CONTEXT_DEBUG_REGISTERS; 
     ctx.Dr7 = 0xF0000040; 
     ctx.Dr6 = 0; 
     ctx.Dr3 = (ULONG_PTR)_AddressOfReturnAddress(); 

     SetThreadContext(NtCurrentThread(), &ctx); 
    } 
} 

это будет работал на x86 и x64 , вам не нужно использовать встроенный asm. главная ваша ошибка - забудьте ContextRecord->ContextFlags |= CONTEXT_DEBUG_REGISTERS; строка