如何逐步跟踪程序?

How can I trace a program by step in?

提问人:Leo Galante 提问时间:7/28/2023 最后编辑:Leo Galante 更新时间:7/28/2023 访问量:97

问:

主要问题:

我正在尝试编写自己的跟踪器,但我找不到任何关于如何跟踪程序本身的材料, MSDN 中没有关于EXCEPTION_SINGLE_STEP以及如何调用它的信息。同样,据我了解,我 需要以某种方式打电话给EXCEPTION_SINGLE_STEP,但如何?在第一个EXCEPTION_BREAKPOINT异常之后,我的应用程序 只是开始并继续,直到执行其任何操作。如果我只是在每条指令之前放置一个断点,然后删除它, 那么我会不断产生EXCEPTION_BREAKPOINT,而不是EXCEPTION_SINGLE_STEP,

1)调试循环环节

我的代码:

BOOL TraceProcess(PEInformation& PEInformation)
{
    DEBUG_EVENT debugEvent; Regs Regs;

    bool IsRunning = true;     
    CONTEXT Context{}; Context.ContextFlags = CONTEXT_ALL;
    HANDLE hThread;
    while (IsRunning)
    {
        if (!WaitForDebugEvent(&debugEvent, INFINITE))
        {
            // Error handling
            DebugActiveProcessStop(PEInformation.processInfo.dwProcessId);
            return FALSE;
        } 

        // Process the debug event based on its type
        switch (debugEvent.dwDebugEventCode)
        {
        case EXCEPTION_DEBUG_EVENT:
            switch (debugEvent.u.Exception.ExceptionRecord.ExceptionCode)
            {
            case EXCEPTION_BREAKPOINT:
                hThread = OpenThread(THREAD_ALL_ACCESS, FALSE, debugEvent.dwThreadId);
                if (!GetThreadContext(hThread, &Context))
                {
                    std::cerr << "GetThreadContext failed: " << GetLastError() << std::endl;
                    break;
                }

                std::cout << "rip: " << std::hex << Context.Rip << std::endl;
                break;
            case EXCEPTION_SINGLE_STEP:
                hThread = OpenThread(THREAD_ALL_ACCESS, FALSE, debugEvent.dwThreadId);
                if (!GetThreadContext(hThread, &Context))
                {
                    std::cerr << "GetThreadContext failed: " << GetLastError() << std::endl;
                    break;
                }

                std::cout << "rip: " << std::hex << Context.Rip << std::endl;
                break;
            }
            break;

        case CREATE_THREAD_DEBUG_EVENT:
            // Handle newly created threads
            // Process debugEvent.u.CreateThread for detailed information
            break;

        case CREATE_PROCESS_DEBUG_EVENT:
            // Handle newly created processes (main thread)
            // Process debugEvent.u.CreateProcessInfo for detailed information
            break;

        case EXIT_THREAD_DEBUG_EVENT:
            // Handle thread exit
            // Process debugEvent.u.ExitThread for detailed information
            break;

        case EXIT_PROCESS_DEBUG_EVENT:
            // Handle process exit
            // Process debugEvent.u.ExitProcess for detailed information
            DebugActiveProcessStop(PEInformation.processInfo.dwProcessId);
            return TRUE;

        case LOAD_DLL_DEBUG_EVENT:
            // Handle DLL loading
            // Process debugEvent.u.LoadDll for detailed information
            break;

        case UNLOAD_DLL_DEBUG_EVENT:
            // Handle DLL unloading
            // Process debugEvent.u.UnloadDll for detailed information
            break;

        case OUTPUT_DEBUG_STRING_EVENT:
            // Handle output of debug strings
            // Process debugEvent.u.DebugString for detailed information
            break;
            // Handle other debug events as needed

        }

        // Continue execution of the traced process
        ContinueDebugEvent(debugEvent.dwProcessId, debugEvent.dwThreadId, DBG_CONTINUE);
    }

    return true;
}
C++ 异常 调试 winapi 逆向工程

评论

1赞 RbMm 7/28/2023
EXCEPTION_SINGLE_STEP在 2 种情况下:1.) 如果 EFlags (0x100) 2.) ,则设置 TF你 ser DRx bp
1赞 Wyck 7/28/2023
在 x86 上,当程序生成 INT 3 时,会在调试器中获取EXCEPTION_BREAKPOINT。当程序生成 INT 1 时,您将在调试器中获取EXCEPTION_SINGLE_STEP。INT 1 是通过在处理器上设置 Trap Flag 来生成的,该标志在每条指令后执行 INT 1,允许调试器四处窥探并可能恢复执行,直到它达到与源语言中的高级语句匹配的点,以便单步执行或单步执行行为,如编译器和加载器生成的调试符号所估计的那样。

答:

1赞 Leo Galante 7/28/2023 #1

评论中的人是很棒的人)谢谢@Wyck和@RbMm

溶液

BOOL TraceProcess()
{
    DEBUG_EVENT debugEvent;

    bool IsRunning = true;     
    CONTEXT Context{}; Context.ContextFlags = CONTEXT_ALL;
    while (IsRunning)
    {
        if (!WaitForDebugEvent(&debugEvent, INFINITE))
        {
            // Error handling
            DebugActiveProcessStop(debugEvent.dwProcessId);
            return FALSE;
        } 

        HANDLE hThread = OpenThread(THREAD_ALL_ACCESS, FALSE, debugEvent.dwThreadId);
        if (!hThread) { std::cerr << "hThread is NULL" << std::endl; return false; }

        // Process the debug event based on its type
        switch (debugEvent.dwDebugEventCode)
        {
        case EXCEPTION_DEBUG_EVENT:
            switch (debugEvent.u.Exception.ExceptionRecord.ExceptionCode)
            {
            case EXCEPTION_BREAKPOINT:
                if (!GetThreadContext(hThread, &Context))
                {
                    std::cerr << "GetThreadContext failed: " << GetLastError() << std::endl;
                    break;
                }

                Context.EFlags |= 0x100;

                if (!SetThreadContext(hThread, &Context))
                {
                    std::cerr << "SetThreadContext failed: " << GetLastError() << std::endl;
                    break;
                }

                std::cout << "rip: " << std::hex << Context.Rip << std::endl;
                CloseHandle(hThread);
                break;
            case EXCEPTION_SINGLE_STEP:
                if (!GetThreadContext(hThread, &Context))
                {
                    std::cerr << "GetThreadContext failed: " << GetLastError() << std::endl;
                    break;
                }
                std::bitset<32> flags(Context.EFlags);

                if (!flags[8])
                {
                    Context.EFlags |= 0x100;
                    if (!SetThreadContext(hThread, &Context))
                    {
                        std::cerr << "SetThreadContext failed: " << GetLastError() << std::endl;
                        break;
                    }
                }
                CloseHandle(hThread);
                break;
            }
            break;

        case CREATE_THREAD_DEBUG_EVENT:
            // Handle newly created threads
            // Process debugEvent.u.CreateThread for detailed information
            break;

        case CREATE_PROCESS_DEBUG_EVENT:
            // Handle newly created processes (main thread)
            // Process debugEvent.u.CreateProcessInfo for detailed information
            break;

        case EXIT_THREAD_DEBUG_EVENT:
            // Handle thread exit
            // Process debugEvent.u.ExitThread for detailed information
            break;

        case EXIT_PROCESS_DEBUG_EVENT:
            // Handle process exit
            // Process debugEvent.u.ExitProcess for detailed information
            DebugActiveProcessStop(debugEvent.dwProcessId);
            return TRUE;

        case LOAD_DLL_DEBUG_EVENT:
            // Handle DLL loading
            // Process debugEvent.u.LoadDll for detailed information
            break;

        case UNLOAD_DLL_DEBUG_EVENT:
            // Handle DLL unloading
            // Process debugEvent.u.UnloadDll for detailed information
            break;

        case OUTPUT_DEBUG_STRING_EVENT:
            // Handle output of debug strings
            // Process debugEvent.u.DebugString for detailed information
            break;
            // Handle other debug events as needed

        }

        // Continue execution of the traced process
        ContinueDebugEvent(debugEvent.dwProcessId, debugEvent.dwThreadId, DBG_CONTINUE);
    }

    return true;
}

评论

0赞 Ben Voigt 7/28/2023
不要用于位操作,你不想要进位。使用按位 OR ( 和复合赋值版本+||=)
0赞 Ben Voigt 7/28/2023
此外,您到处都在泄漏螺纹手柄。打开线程一次,根据需要多次使用句柄,然后调用 。CloseHandle
0赞 Leo Galante 7/28/2023
@BenVoigt 谢谢!据我了解,debugEvent.dwThreadId 具有发生某些事件的 id,因此,它不能只获得一次,因为在应用程序运行期间,在多线程应用程序的情况下,它的“工作”线程可能会发生变化
0赞 500 - Internal Server Error 7/28/2023
狮子座,你是在回复@BenVoigt删除的评论吗?因为他是对的,你需要关闭那些你打开的线程句柄,否则你很快就会用完。--- 好消息是,您首先不需要打开这些句柄:Thread Create 事件为您提供了线程的句柄。您只需要将其存储在某个查找结构中,以便可以从其他调试事件中给出的线程 ID 中找到它。