C/C++ 内存转储与获取DLL加载

CREATE_PROCESS_DEBUG_EVENT 创建进程的调试事件。CREATE_PROCESS_DEBUG_INFO结构体描述了该类调试事件的详细信息
OUTPUT_DEBUG_STRING_EVENT 该事件,当被调试进程调用OutputDebugString时就会引发该类调试事件,OUTPUT_DEBUG_STRING_INFO结构体描述了关于该事件的详细信息
LOAD_DLL_DEBUG_EVENT 当DLL被加载时,会调用该回调,LOAD_DLL_DEBUG_INFO结构体描述了它的详细信息,dll的路径被放在了,hfile字段,该字段默认是句柄方式存储的,需要手工转换,

实现简易调试器: 通过调试API实现建议调试器,可以加以改进,变成内存dump工具,等,也可以获取实际OEP作为查壳工具来用。

#include <stdio.h>
#include <Windows.h>
#include <Tlhelp32.h>
#include <imagehlp.h>
#pragma comment (lib, "Dbghelp")

BYTE bCC = '\xCC';

// 这是调试进程第一次被断下后执行操作
void OnException(DEBUG_EVENT *pDebug, BYTE *bCode)
{
    CONTEXT context;
    DWORD dwNum;
    BYTE bTmp;

    HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pDebug->dwProcessId);
    HANDLE hThread = OpenThread(THREAD_ALL_ACCESS, FALSE, pDebug->dwThreadId);

    SuspendThread(hThread);
    // 读取出异常首地址
    ReadProcessMemory(hProcess, pDebug->u.Exception.ExceptionRecord.ExceptionAddress, &bTmp, sizeof(BYTE), &dwNum);

    context.ContextFlags = CONTEXT_FULL;
    GetThreadContext(hThread, &context);

    printf("EAX = %x  EIP = %x \n", context.Eax, context.Eip);
    // 将刚才的CC断点取消,也就是会写原始指令集
    WriteProcessMemory(hProcess, pDebug->u.Exception.ExceptionRecord.ExceptionAddress, bCode, sizeof(BYTE), &dwNum);
    context.Eip--;
    SetThreadContext(hThread, &context);

    printf("EAX = %x  EIP = %x \n", context.Eax, context.Eip);
    printf("入口点: %x \n", pDebug->u.CreateProcessInfo.lpBaseOfImage);

    ResumeThread(hThread);
    CloseHandle(hThread);
    CloseHandle(hProcess);
}

int main(int argc, char * argv[])
{
    STARTUPINFO si = { 0 };
    PROCESS_INFORMATION pi = { 0 };
    DEBUG_EVENT de = { 0 };

    // 创建调试进程
    BOOL bRet = CreateProcess("c://123.exe", 0, 0, 0, FALSE, DEBUG_PROCESS | DEBUG_ONLY_THIS_PROCESS, 0, 0, &si, &pi);

    if (bRet == FALSE)
        return bRet;
    CloseHandle(pi.hThread);
    CloseHandle(pi.hProcess);

    BYTE bCode;
    DWORD dwNum;
    int dwCC_Count = 0;

    // 开始调试循环
    while (WaitForDebugEvent(&de, INFINITE))
    {
        switch (de.dwDebugEventCode)
        {
            // 当进程创建成功后自动执行的部分
            case CREATE_PROCESS_DEBUG_EVENT:
            {
                // 获取入口地址 0x0 可以增加偏移到入口后任意位置
                DWORD dwAddr = 0x0 + (DWORD)de.u.CreateProcessInfo.lpStartAddress;
                // 暂停线程
                SuspendThread(de.u.CreateProcessInfo.hThread);
                // 读取入口地址处的字节码
                ReadProcessMemory(de.u.CreateProcessInfo.hProcess, (const void *)dwAddr, &bCode, sizeof(BYTE), &dwNum);
                // 在入口地址处写入0xCC 即写入INT 3
                WriteProcessMemory(de.u.CreateProcessInfo.hProcess, (void *)dwAddr, &bCC, sizeof(BYTE), &dwNum);
                // 恢复线程
                ResumeThread(de.u.CreateProcessInfo.hThread);
                break;
            }
            // 当进程产生异常时自动执行这里
            case EXCEPTION_DEBUG_EVENT:
            {
                switch (dwCC_Count)
                {
                    // 第0次是系统断点,这里我们直接跳过
                    case 0: 
                        dwCC_Count++; break;
                    // 第一次断点,我们让他执行下面的函数
                    case 1:
                        OnException(&de, &bCode); dwCC_Count++; break;
                }
            }
        }
        ContinueDebugEvent(de.dwProcessId, de.dwThreadId, DBG_CONTINUE);
    }
    system("pause");
    return 0;
}

获取DLL加载情况:

#include <stdio.h>
#include <Windows.h>
#include <tchar.h>
#include <psapi.h>

void OnDllLoaded(const LOAD_DLL_DEBUG_INFO *pDebug)
{
    printf("基址: 0x%-8X --> ", pDebug->lpBaseOfDll);

    BOOL bSuccess = FALSE;
    TCHAR pszFilename[MAX_PATH + 1];
    HANDLE hFileMap;

    // Get the file size.
    DWORD dwFileSizeHi = 0;
    DWORD dwFileSizeLo = GetFileSize(pDebug->hFile, &dwFileSizeHi);

    printf("长度: %9d --> ", dwFileSizeLo);

    if (dwFileSizeLo == 0 && dwFileSizeHi == 0)
    {
        return;
    }
    // 创建内存映射
    hFileMap = CreateFileMapping(pDebug->hFile, 0, PAGE_READONLY, 0, 1, 0);

    if (hFileMap)
    {
        void* pMem = MapViewOfFile(hFileMap, FILE_MAP_READ, 0, 0, 1);
        if (pMem)
        {
            if (GetMappedFileName(GetCurrentProcess(), pMem, pszFilename, MAX_PATH))
            {
                printf("路径: %s \n", pszFilename);
            }
            UnmapViewOfFile(pMem);
        }
        CloseHandle(hFileMap);
    }
}

int main(int argc, char * argv[])
{
    STARTUPINFO si = { 0 };
    PROCESS_INFORMATION pi = { 0 };
    DEBUG_EVENT debug_event = { 0 };

    // 创建调试进程
    BOOL bRet = CreateProcess("C:/Program Files/Tencent/QQ/Bin/QQ.exe", 0, 0, 0, FALSE, DEBUG_PROCESS | DEBUG_ONLY_THIS_PROCESS, 0, 0, &si, &pi);
    CloseHandle(pi.hThread);
    CloseHandle(pi.hProcess);

    // 开始调试循环
    while (WaitForDebugEvent(&debug_event, INFINITE))
    {
        switch (debug_event.dwDebugEventCode)
        {
            // 当DLL加载到进程时自动的执行此处代码
        case LOAD_DLL_DEBUG_EVENT:
            OnDllLoaded(&debug_event.u.LoadDll);
            break;
        }
        ContinueDebugEvent(debug_event.dwProcessId, debug_event.dwThreadId, DBG_CONTINUE);
    }
    return 0;
}

原文链接: https://www.cnblogs.com/LyShark/p/13073701.html

欢迎关注

微信关注下方公众号,第一时间获取干货硬货;公众号内回复【pdf】免费获取数百本计算机经典书籍;

也有高质量的技术群,里面有嵌入式、搜广推等BAT大佬

    C/C++ 内存转储与获取DLL加载

原创文章受到原创版权保护。转载请注明出处:https://www.ccppcoding.com/archives/353947

非原创文章文中已经注明原地址,如有侵权,联系删除

关注公众号【高性能架构探索】,第一时间获取最新文章

转载文章受原作者版权保护。转载请注明原作者出处!

(0)
上一篇 2023年3月2日 上午8:20
下一篇 2023年3月2日 上午8:20

相关推荐