使用我的自定义WINAPI调试器启动应用程序时,不断抛出异常

时间:2019-01-18 02:13:17

标签: c++ debugging winapi

我正在尝试在Visual Studio 2017中使用C ++创建自己的自定义调试器。测试一些控制台应用程序就可以了。但是,当我用它启动记事本时,在我点击File-> Open对话框并进入输出这两个异常代码的恒定循环并且打开对话框没有打开的情况下,这是恒定不变的:

Exception: 3221356611
Exception: 998

在WinDbg下启动相同的进程时,不会发生这些异常。 该代码被编译为x86,并在Windows 10 1803内部版本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 个答案:

答案 0 :(得分:1)

  • 32213566110xC0020043-RPC_NT_INTERNAL_ERROR
  • 998这是0x3e6-ERROR_NOACCESS对内存的无效访问 位置

您始终无条件返回DBG_CONTINUE的主要错误。但是在EXCEPTION_DEBUG_EVENT上,您只有在处理异常的情况下才返回此代码。否则(如果dwFirstChance == TRUE是第一次机会例外),则必须返回DBG_EXCEPTION_NOT_HANDLED。如果返回DBG_CONTINUE-程序开始从当前上下文继续执行。如果您返回DBG_EXCEPTION_NOT_HANDLED-KiUserExceptionDispatcher将在目标进程中调用,目标进程将调用RtlDispatchException,在此处将称为异常处理程序。了解更多-Structured Exception Handling

但是因为您从不返回DBG_EXCEPTION_NOT_HANDLED-从未调用过程序异常处理程序。根据您的2个例外代码,即使发生这种情况也很容易找到: enter image description here

RpcpRaiseException被调用,内部调用RaiseException(ERROR_NOACCESS..),因此您可以查看998异常。如果您在此处返回DBG_EXCEPTION_NOT_HANDLED-应用程序将自行处理此异常,并且永远不会从RaiseException调用中返回。上下文将切换到__except{}块。但是由于您返回了DBG_CONTINUE-RaiseException返回控件并调用了RpcReportFatalError,因此内部调用RaiseException(RPC_NT_INTERNAL_ERROR..)可以使您查看3221356611 (0xC0020043)

您未关闭hFile上的LOAD_DLL_DEBUG_EVENT的下一个错误-调试器完成此文件后,应使用CloseHandle函数关闭句柄。 CREATE_PROCESS_DEBUG_EVENT

上的错误

这也是您开始调试过程时遇到的错误-一定不要使用CREATE_SUSPENDED标志,一定不能使用DebugActiveProcessResumeThread。您只需要设置DEBUG_PROCESSDEBUG_ONLY_THIS_PROCESS以及全部。不需要处于挂起状态的创建过程,并且在这里主要不调用DebugActiveProcess。此api调用设计不良,它在目标进程中创建了其他线程。比如说xp在这个阶段完全是致命的。