본문 바로가기
알고리즘

윈도우 디버그 API를 사용하여 로깅하기

by 코딩스미스 2025. 3. 20.

DLL

void ProcessDebugEvent( DEBUG_EVENT& debugEvent) 
{
    switch (debugEvent.dwDebugEventCode) {
    case OUTPUT_DEBUG_STRING_EVENT: {
        OUTPUT_DEBUG_STRING_INFO& info = debugEvent.u.DebugString;
        char buffer[1024] = { 0 };

        // 디버그 메시지를 읽기 위해 ReadProcessMemory 사용
        if (info.fUnicode) {
            // 유니코드 문자열 처리
            WCHAR wBuffer[512] = { 0 };
            SIZE_T bytesRead;
            ReadProcessMemory(
                OpenProcess(PROCESS_VM_READ, FALSE, debugEvent.dwProcessId),
                info.lpDebugStringData,
                wBuffer,
                info.nDebugStringLength,
                &bytesRead);
            wprintf(L"[Debug] %s\n", wBuffer);
        }
        else {
            // ANSI 문자열 처리
            SIZE_T bytesRead;
            ReadProcessMemory(
                OpenProcess(PROCESS_VM_READ, FALSE, debugEvent.dwProcessId),
                info.lpDebugStringData,
                buffer,
                info.nDebugStringLength,
                &bytesRead);
            printf("[Debug] %s\n", buffer);
        }
        break;
    }
    default:
        break;
    }
}

void RunServer()
{
    LPCSTR slotName = "\\\\.\\mailslot\\SampleMailslot";

    // 메일 슬롯 생성
    HANDLE hMailslot = CreateMailslotA(
        slotName,        // 슬롯 이름
        0,               // 최대 메시지 크기 (0: 무제한)
        MAILSLOT_WAIT_FOREVER,  // 시간 초과 (무한 대기)
        NULL             // 보안 속성
    );

    if (hMailslot == INVALID_HANDLE_VALUE) {
        std::cerr << "메일 슬롯 생성 실패: " << GetLastError() << std::endl;
        return;
    }

    std::cout << "메일 슬롯이 생성되었습니다: " << slotName << std::endl;

    CreateThread(NULL, 0, DebugThread, NULL, 0, NULL);

    char buffer[256];
    DWORD bytesRead;

    while (true) {
        DWORD nextSize, messageCount;

        // 슬롯에 메시지가 있는지 확인
        if (!GetMailslotInfo(hMailslot, NULL, &nextSize, &messageCount, NULL)) {
            std::cerr << "메일 슬롯 정보 조회 실패: " << GetLastError() << std::endl;
            break;
        }

        if (messageCount > 0 && nextSize != MAILSLOT_NO_MESSAGE) {
            // 메시지 읽기
            if (ReadFile(hMailslot, buffer, sizeof(buffer), &bytesRead, NULL)) {
                buffer[bytesRead] = '\0';
                DWORD processID = atoi(buffer);
                gProcessIDs.push(processID);
                std::cout << "받은 메시지: " << buffer << std::endl;
            }
            else {
                std::cerr << "메일 슬롯 읽기 실패: " << GetLastError() << std::endl;
            }
        }

        Sleep(1000); // CPU 사용률을 낮추기 위해 대기
    }

    CloseHandle(hMailslot);
    return;
}
void SendProcessID(DWORD processID)
{
    LPCSTR slotName = "\\\\.\\mailslot\\SampleMailslot";

    // 메일 슬롯에 연결
    HANDLE hFile = CreateFileA(
        slotName,            // 대상 메일 슬롯
        GENERIC_WRITE,       // 쓰기 권한
        FILE_SHARE_READ,     // 공유 모드
        NULL,                // 보안 속성
        OPEN_EXISTING,       // 기존 객체 열기
        FILE_ATTRIBUTE_NORMAL,
        NULL
    );


    if (hFile == INVALID_HANDLE_VALUE) {
        std::cerr << "메일 슬롯 연결 실패: " << GetLastError() << std::endl;
        return;
    }

    std::cout << "메일 슬롯에 연결되었습니다." << std::endl;

    // 메시지 전송
    char message[64];// = "Hello, Mailslot!";
    sprintf_s(message, 64, "%d", processID);
    DWORD bytesWritten;

    if (WriteFile(hFile, message, strlen(message), &bytesWritten, NULL)) {
        std::cout << "메시지 전송 완료: " << message << std::endl;
    }
    else {
        std::cerr << "메시지 전송 실패: " << GetLastError() << std::endl;
    }

    CloseHandle(hFile);
    return;
}

DWORD WINAPI DebugThread(LPVOID lpParam) {
    DEBUG_EVENT debugEvent;
    while (1) {
        while (!gProcessIDs.empty())
        {
            DWORD processID = gProcessIDs.front();
            gProcessIDs.pop();
            if (!DebugActiveProcess(processID)) {
                printf("DebugActiveProcess failed: %d\n", GetLastError());
                return 1;
            }
        }
        while (TRUE) {
            if (WaitForDebugEvent(&debugEvent, 1000)) {
                ProcessDebugEvent(debugEvent);
                ContinueDebugEvent(debugEvent.dwProcessId, debugEvent.dwThreadId, DBG_CONTINUE);
            }
            else {
                break;
            }
        }
        
    }
    return 0;
}

 

Log Host App

RunServer();

 

Log Tester App


DWORD WINAPI DebugThread(LPVOID lpParam) {
    DWORD pid = GetCurrentProcessId();
    DWORD tid = GetCurrentThreadId();
    std::string str;
    DWORD i = 0;
    while (i<1000) {
        str = string_format("[PID:%d TID:%d] %d", pid, tid, i);
        OutputDebugStringA(str.c_str());
        i++;
    }
    return 0;
}


int main()
{
    std::cout << "Test Start" << std::endl;
    DWORD id = GetCurrentProcessId();
    HANDLE thread[2];
    SendProcessID(id);
    Sleep(2000);

    OutputDebugStringA("Test Start");
    for (int i = 0;i < 2;i++) {
        thread[i] = CreateThread(NULL, 0, DebugThread, NULL, 0, NULL);
    }
    WaitForMultipleObjects(2, thread, TRUE, INFINITE);

    OutputDebugStringA("Test End");

    try
    {
        
        //CauseError();
        //OkB();
    }
    catch (const std::exception& ex)
    {
        std::cerr << "Exception caught! Printing stack trace:" << std::endl;
        std::cerr << "예외 발생: " << ex.what() << std::endl;
    }
    std::cout << "Test End" << std::endl;
    return 0;
}