首页 > 其他分享 >10.2 调试事件获取DLL装载

10.2 调试事件获取DLL装载

时间:2023-10-05 13:06:53浏览次数:37  
标签:10.2 MAX TCHAR DLL 模块 PATH 调试 pszFilename

理解了如何通过调试事件输出当前进程中寄存器信息,那么实现加载DLL模块也会变得很容易实现,加载DLL模块主要使用LOAD_DLL_DEBUG_EVENT这个通知事件,该事件可检测进程加载的模块信息,一旦有新模块被加载或装入那么则会触发一个通知事件,利用该方法并配合磁盘路径获取函数则可很容易的实现进程模块加载的监控。

获取加载的动态链接库DLL的详细信息,具体实现细节如下:

  • 首先,代码通过GetFileSize函数获取目标DLL文件的大小,如果大小为0,则立即退出函数。
  • 然后,代码调用CreateFileMappingMapViewOfFile函数创建了一个内存映射对象,该映射对象可以让代码访问DLL文件的内容。
  • 随后,代码调用GetMappedFileName函数获取该内存映射对象关联的DLL文件的路径,其中需要使用QueryDosDevice查询函数来确认磁盘符号对应的真实文件名称, 如果找到对应的真实文件名称,则可以更新原始路径为真实路径,这里用到了字符串操作函数_tcslen、 _tcsnicmp以及_tcsncpy等。
  • 最后,再调用UnmapViewOfFileCloseHandle函数清理资源,并将相关的信息输出到控制台上,包括基址、名称、大小和路径等信息。

有了这段获取DLL完整路径的程序片段,那么实现这个功能将变得很容易,我们看看一下OnDllLoaded中是如何针对DLL进程处理的,实现代码片段如下所示;

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

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

    // 获取文件大小
    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))
            {
                TCHAR szTemp[4096] = { 0 };

                // 得到当前所有磁盘字符串
                if (GetLogicalDriveStrings(4096 - 1, szTemp))
                {
                    TCHAR szName[MAX_PATH];
                    TCHAR szDrive[3] = TEXT(" :");
                    BOOL bFound = FALSE;
                    TCHAR* p = szTemp;
                    do
                    {
                        *szDrive = *p;
                        if (QueryDosDevice(szDrive, szName, 4096))
                        {
                            UINT uNameLen = _tcslen(szName);
                            if (uNameLen < MAX_PATH)
                            {
                                bFound = _tcsnicmp(pszFilename, szName, uNameLen) == 0;
                                if (bFound)
                                {
                                    TCHAR szTempFile[MAX_PATH];
                                    _stprintf(szTempFile, TEXT("%s%s"), szDrive, pszFilename + uNameLen);
                                    _tcsncpy(pszFilename, szTempFile, MAX_PATH);
                                }
                            }
                        }
                        while (*p++);
                    } while (!bFound && *p);
                }
            }
            bSuccess = TRUE;
            UnmapViewOfFile(pMem);
        }
        CloseHandle(hFileMap);
    }

    printf("基址: 0x%08X \t 相对名称: %-30s \t 大小: %-9d \t 路径: %s \n",
        pDebug->lpBaseOfDll, GetBaseName(pszFilename), dwFileSizeLo, pszFilename);
}

上述程序被运行后,则可输出被加载进程的所有模块信息,其中包括了模块基址,相对名称,模块大小,模块完整路径等,输出效果如下图所示;

本文作者: 王瑞 本文链接: https://www.lyshark.com/post/52d14ea1.html 版权声明: 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!

标签:10.2,MAX,TCHAR,DLL,模块,PATH,调试,pszFilename
From: https://blog.51cto.com/lyshark/7711124

相关文章

  • 10.3 调试事件转存进程内存
    我们继续延申调试事件的话题,实现进程转存功能,进程转储功能是指通过调试API使获得了目标进程控制权的进程,将目标进程的内存中的数据完整地转存到本地磁盘上,对于加壳软件,通常会通过加密、压缩等手段来保护其代码和数据,使其不易被分析。在这种情况下,通过进程转储功能,可以将加壳程序的......
  • 10.2 调试事件获取DLL装载
    理解了如何通过调试事件输出当前进程中寄存器信息,那么实现加载DLL模块也会变得很容易实现,加载DLL模块主要使用LOAD_DLL_DEBUG_EVENT这个通知事件,该事件可检测进程加载的模块信息,一旦有新模块被加载或装入那么则会触发一个通知事件,利用该方法并配合磁盘路径获取函数则可很容易的实......
  • 10.3 调试事件转存进程内存
    我们继续延申调试事件的话题,实现进程转存功能,进程转储功能是指通过调试API使获得了目标进程控制权的进程,将目标进程的内存中的数据完整地转存到本地磁盘上,对于加壳软件,通常会通过加密、压缩等手段来保护其代码和数据,使其不易被分析。在这种情况下,通过进程转储功能,可以将加壳程序的......
  • Delphi dll 传递字符串
    //dllcodeuses//ShareMem,SysUtils,Windows,Math;{$R*.res}functionTestString1(Buffer:PChar):PChar;stdcall;varTmpstr:string;begintryTmpstr:=Buffer;ifTmpstr<>''thenbeginResult:=StrAlloc(Length......
  • 无涯教程-OC - 应用调试
    无涯教程在开发应用程序时可能会犯错误,这可能导致不同类型的错误。为了修复这些错误或错误,无涯教程需要调试应用程序。选择调试器Xcode有两个调试器,即GDB和LLDB调试器,默认情况下,已选择GDB。LLDB是作为LLVM开源编译器项目一部分的调试器,您可以通过“editactiveschemes”选项来......
  • Java新特性中的Preview功能如何运行和调试
    在每个Java新版本发布的特性中,都会包含一些Preview(预览)功能,这些功能主要用来给开发者体验并收集建议。所以,Preview阶段的功能并不是默认开启的。如果想体验某个Java版本中的Preview功能,您还需要做一些设置才能把程序跑起来。下面以IDEA2023.2为例,演示为Java21开启Preview功能......
  • 10.1 调试事件读取寄存器
    当读者需要获取到特定进程内的寄存器信息时,则需要在上述代码中进行完善,首先需要编写CREATE_PROCESS_DEBUG_EVENT事件,程序被首次加载进入内存时会被触发此事件,在该事件内首先我们通过lpStartAddress属性获取到当前程序的入口地址,并通过SuspendThread暂停程序的运行,当被暂停后则我没......
  • 在 WebStorm 里调试 vue3 项目
    官方说明:https://blog.jetbrains.com/webstorm/2018/01/working-with-vue-js-in-webstorm/#:~:text=Wecandebugourapplication,andstartthedebugsession.打开WebStorm编辑器右上角的Configuration的Edit,在URL填入项目的地址并选择想要使用的Brower,点击调试之......
  • 10.0 探索API调试事件原理
    本章笔者将通过Windows平台下自带的调试API接口实现对特定进程的动态转存功能,首先简单介绍一下关于调试事件的相关信息,调试事件的建立需要依赖于DEBUG_EVENT这个特有的数据结构,该结构用于向调试器报告调试事件。当一个程序发生异常事件或者被调试器附加时,就会产生对应的DEBUG_EVENT......
  • 10.0 探索API调试事件原理
    本章笔者将通过Windows平台下自带的调试API接口实现对特定进程的动态转存功能,首先简单介绍一下关于调试事件的相关信息,调试事件的建立需要依赖于DEBUG_EVENT这个特有的数据结构,该结构用于向调试器报告调试事件。当一个程序发生异常事件或者被调试器附加时,就会产生对应的DEBUG_EVEN......