代码之家  ›  专栏  ›  技术社区  ›  Malcolm McCaffery

使用自定义winapi调试器启动应用程序时不断引发异常

  •  0
  • Malcolm McCaffery  · 技术社区  · 7 年前

    我正在尝试用VisualStudio 2017中的C++来创建自己的自定义调试器。测试一些控制台应用程序是可以的。但是,当我用它启动记事本时,直到我单击“文件”->打开对话框,它进入常量循环,输出这两个异常代码,并且打开对话框不会打开:

    Exception: 3221356611
    Exception: 998
    

    当在windbg下启动相同的进程时,这些异常不会发生。 该代码编译为x86,并在Windows 10 1803 Build 17134.523 x64上启动32位进程。

    有什么可能导致这些的建议吗?

    #include "targetver.h"
    #include <stdio.h>
    #include <tchar.h>
    #include <string>
    #include <iostream>
    #include <map>
    
    std::map < LPVOID, std::wstring > DllNameMap;
    
    int main()
    {
        std::wstring filename(L"c:\\windows\\syswow64\\notepad.exe");
        STARTUPINFO si;
        PROCESS_INFORMATION pi;
    
        ZeroMemory(&si, sizeof(si));
        si.cb = sizeof(si);
        ZeroMemory(&pi, sizeof(pi));
    
        DEBUG_EVENT debugEvent;
    
        // Start the child process. 
        if (!CreateProcess(NULL,   // No module name (use command line)
            (LPWSTR)filename.c_str(),           // Command line
            NULL,               // Process handle not inheritable
            NULL,               // Thread handle not inheritable
            FALSE,              // Set handle inheritance to FALSE
            CREATE_SUSPENDED,   // No creation flags
            NULL,               // Use parent's environment block
            NULL,               // Use parent's starting directory 
            &si,                // Pointer to STARTUPINFO structure
            &pi)                // Pointer to PROCESS_INFORMATION structure
            )
        {
            printf("CreateProcess failed (%d).\n", GetLastError());
            return -1;
        }
    
        if (DebugActiveProcess(pi.dwProcessId))
        {
            ResumeThread(pi.hThread);
    
            std::cout << "Debugger attached!" << std::endl;
            EnterDebugLoop(&debugEvent,pi.hProcess);
        }
        return 0;
    }
    
    void EnterDebugLoop(const LPDEBUG_EVENT DebugEv,HANDLE hProcess)
    {
    
        DWORD dwContinueStatus = DBG_CONTINUE; // exception continuation 
    
        for (;;)
        {
            // Wait for a debugging event to occur. The second parameter indicates
            // that the function does not return until a debugging event occurs. 
    
            WaitForDebugEvent(DebugEv, INFINITE);
    
            // Process the debugging event code. 
    
            switch (DebugEv->dwDebugEventCode)
            {
            case EXCEPTION_DEBUG_EVENT:
                // Process the exception code. When handling 
                // exceptions, remember to set the continuation 
                // status parameter (dwContinueStatus). This value 
                // is used by the ContinueDebugEvent function. 
    
                std::cout << "Exception: " << DebugEv->u.Exception.ExceptionRecord.ExceptionCode << std::endl;
    
                switch (DebugEv->u.Exception.ExceptionRecord.ExceptionCode)
                {
                case EXCEPTION_ACCESS_VIOLATION:
                    std::cout << "ACCESS VIOLATION" << std::endl;
                    // First chance: Pass this on to the system. 
                    // Last chance: Display an appropriate error. 
                    break;
    
                case EXCEPTION_BREAKPOINT:
    
                    std::cout << "BREAKPOINT" << std::endl;
                    // First chance: Display the current 
                    // instruction and register values. 
                    break;
    
                case EXCEPTION_DATATYPE_MISALIGNMENT:
                    std::cout << "DATATYPE MISALIGNMENT" << std::endl;
                    // First chance: Pass this on to the system. 
                    // Last chance: Display an appropriate error. 
                    break;
    
                case EXCEPTION_SINGLE_STEP:
                    std::cout << "SINGLE STEP" << std::endl;
                    // First chance: Update the display of the 
                    // current instruction and register values. 
                    break;
    
                case DBG_CONTROL_C:
                    std::cout << "CTRL+C" << std::endl;
                    // First chance: Pass this on to the system. 
                    // Last chance: Display an appropriate error. 
                    break;
    
                default:
                        // Handle other exceptions. 
                    break;
                }
    
                break;
    
            case CREATE_THREAD_DEBUG_EVENT:
                std::cout << "Create Thread" << std::endl;
                // As needed, examine or change the thread's registers 
                // with the GetThreadContext and SetThreadContext functions; 
                // and suspend and resume thread execution with the 
                // SuspendThread and ResumeThread functions. 
                break;
    
            case CREATE_PROCESS_DEBUG_EVENT:
                std::cout << "Create Process" << std::endl;
                // As needed, examine or change the registers of the
                // process's initial thread with the GetThreadContext and
                // SetThreadContext functions; read from and write to the
                // process's virtual memory with the ReadProcessMemory and
                // WriteProcessMemory functions; and suspend and resume
                // thread execution with the SuspendThread and ResumeThread
                // functions. Be sure to close the handle to the process image
                // file with CloseHandle.
    
                //dwContinueStatus = OnCreateProcessDebugEvent(DebugEv);
                break;
    
            case EXIT_THREAD_DEBUG_EVENT:
                // Display the thread's exit code. 
                std::cout << "Exit Thread Exit Code " << DebugEv->u.ExitThread.dwExitCode << std::endl;
    
    
                //dwContinueStatus = OnExitThreadDebugEvent(DebugEv);
                break;
    
            case EXIT_PROCESS_DEBUG_EVENT:
                // Display the process's exit code. 
                std::cout << "Exit process Exit Code " << DebugEv->u.ExitProcess.dwExitCode << std::endl;
                ///dwContinueStatus = OnExitProcessDebugEvent(DebugEv);
                break;
    
            case LOAD_DLL_DEBUG_EVENT:
            {
                PVOID pDllPath = NULL;
                PUCHAR DllPath[(MAX_PATH + 1) * sizeof(WCHAR)];
                DWORD dwLen = 0;
                ZeroMemory(DllPath, sizeof(DllPath));
    
                if (DebugEv->u.LoadDll.lpImageName == NULL)
                {
                    break;
                }
    
                // read DLL name pointer value
                if (ReadProcessMemory(
                    hProcess,
                    DebugEv->u.LoadDll.lpImageName,
                    &pDllPath, sizeof(PVOID),
                    &dwLen) && pDllPath)
                {
                    dwLen = (DebugEv->u.LoadDll.fUnicode ? MAX_PATH * sizeof(WCHAR) : MAX_PATH);
    
                    // read DLL name
                    if (ReadProcessMemory(
                        hProcess,
                        pDllPath,
                        DllPath, dwLen,
                        &dwLen))
                    {
                        char szDllPath[MAX_PATH], *lpszDllName = NULL;
    
                        if (DebugEv->u.LoadDll.fUnicode)
                        {
                            std::wstring path((wchar_t*)DllPath);
                            DllNameMap.insert(std::make_pair(DebugEv->u.LoadDll.lpBaseOfDll, path));
                            std::wcout << "Image loaded (Unicode): " << path.c_str() << std::endl;
                        }
                        else
                        {
                            // todo: Add to DllNameMAp
                            std::wcout << "Image loaded: " << DllPath << std::endl;
    
                        }
                    }
                    else
                    {
                        std::cout << "Error processing memory : " << GetLastError() << std::endl;
                    }
                }
                else
                {
                    std::wcout << "ERROR reading process memory : " << GetLastError() << std::endl;
                }
            }
                // Read the debugging information included in the newly 
                // loaded DLL. Be sure to close the handle to the loaded DLL 
                // with CloseHandle.
    
                ///dwContinueStatus = OnLoadDllDebugEvent(DebugEv);
                break;
    
            case UNLOAD_DLL_DEBUG_EVENT:
                std::wcout << "Unload DLL: " << DllNameMap[DebugEv->u.UnloadDll.lpBaseOfDll] << std::endl;
                break;
    
            case OUTPUT_DEBUG_STRING_EVENT:
                // Display the output debugging string. 
                std::wcout << "Debug Event" << std::endl;
                if (DebugEv->u.DebugString.fUnicode)
                {
                    std::wcout << (wchar_t)DebugEv->u.DebugString.lpDebugStringData << std::endl;
                }
    
                //dwContinueStatus = OnOutputDebugStringEvent(DebugEv);
                break;
    
            case RIP_EVENT:
                //dwContinueStatus = OnRipEvent(DebugEv);
                break;
            }
    
            // Resume executing the thread that reported the debugging event. 
    
            ContinueDebugEvent(DebugEv->dwProcessId,
                DebugEv->dwThreadId,
                dwContinueStatus);
        }
    }
    
    1 回复  |  直到 7 年前
        1
  •  1
  •   RbMm    7 年前
    • 3221356611 这是 0xC0020043 - RPC_NT_INTERNAL_ERROR
    • 998 这是 0x3e6 - ERROR_NOACCESS ( 对内存的访问无效 位置 )

    您无条件返回的主要错误 DBG_CONTINUE 总是。但关于 EXCEPTION_DEBUG_EVENT 只有在处理异常时才返回此代码。否则(如果 dwFirstChance == TRUE 所以这是第一次机会例外)你必须回来 DBG_EXCEPTION_NOT_HANDLED . 如果你回来 dgg-继续 -程序从当前上下文开始继续执行。如果你回来 dbg_异常未处理 - KiUserExceptionDispatcher 将在目标进程中调用,它调用 RtlDispatchException 以及在何处调用异常处理程序。阅读更多 Structured Exception Handling

    但因为你永远不会回来 dbg_异常未处理 -从未调用程序异常处理程序。通过您的两个例外代码,甚至很容易找到发生这种情况的地方: enter image description here

    这个 RpcpRaiseException 被调用,内部调用 RaiseException(ERROR_NOACCESS..) 所以您查看998个异常。如果你回来 dbg_异常未处理 这里-应用程序自行处理此异常,从不从返回 RaiseException 打电话。上下文将转换为 __except{} 块。但因为你回来了 dgg-继续 - 极端例外 返回控制和 RpcReportFatalError 调用,内部调用 RaiseException(RPC_NT_INTERNAL_ERROR..) 所以你和你的观点 3221356611 (0xC0020043)

    你的下一个错误你没有关闭 hFile LOAD_DLL_DEBUG_EVENT - 当调试器完成此文件时,它应该使用close handle函数关闭句柄。 相同的错误 CREATE_PROCESS_DEBUG_EVENT

    另外,在开始调试过程时出现的错误-不能使用 CREATE_SUSPENDED 标志,不得使用 DebugActiveProcess ResumeThread . 你只需要一套 DEBUG_PROCESS DEBUG_ONLY_THIS_PROCESS 等等。不需要在挂起状态下创建进程,也不需要主不调用 调试指定进程 在这里。这个API调用的设计不好,它在目标进程中创建了额外的线程。比如说XP在这个阶段,这是致命的。