使用调试寄存器断点和向量异常处理捕获Stacktraces

时间:2017-02-05 14:12:58

标签: c assembly x86

我一直在研究代码以尝试监视堆栈跟踪,并且有想法尝试使用调试寄存器和向量异常处理(对于x86)。我做了一个示例程序,它将输出访问当前返回地址的地址。如果在调用的函数内发生堆栈跟踪,则此方法有效。如果它没有(注释掉读取返回地址的代码),则在返回指令上触发异常。从这里我的异常处理程序没有被调用,程序抛出另一个异常,然后以stackhash错误终止。有没有办法让它捕获堆栈跟踪如果它发生但是如果没有发生堆栈跟踪也不会在返回时崩溃?

这是我为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;
}

1 个答案:

答案 0 :(得分: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;