10.2 调试事件获取DLL装载

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

理解了如何通过调试事件输出当前进程中寄存器信息,那么实现加载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 许可协议。转载请注明出处!

目录
相关文章
|
数据建模 C++ 容器
调试实战 —— dll 加载失败之全局变量初始化篇
调试实战 —— dll 加载失败之全局变量初始化篇
|
3月前
|
安全 数据处理 C++
LabVIEW调用外部DLL(动态链接库)
LabVIEW调用外部DLL(动态链接库)
19 0
|
3月前
|
数据采集 安全 测试技术
LabVIEW调用DLL时需注意的问题
LabVIEW调用DLL时需注意的问题
32 0
IIS加载uslresol.dll模块失败导致应用程序启动异常
IIS加载uslresol.dll模块失败导致应用程序启动异常
|
Java 编译器 C++
JNI编程怎么跟踪调试dll?
本文主要讲解一下在jni开发中,如何调试C/C++编写的DLL模块。
437 0
JNI编程怎么跟踪调试dll?
|
Windows
模块 DLL usrresol.dll 未能加载
IIS应用程序池自动关闭,模块DLL C:\windows\system32\inetsrv\urlresol.dll 未能加载
556 0
模块 DLL usrresol.dll 未能加载
|
C++ Windows
windbg调试实例(4)--句柄泄露[转]
同事介绍了一篇调试句柄泄露的blog文章,今天有空看了一下,这家伙用视频的方式录下整个调试的过程,学习一目了然,真是有心。鉴于学习的过程总结一下能加深记忆,所以我这里做个记录,感兴趣的朋友可以看这里:http://blogs.msdn.com/ntdebugging/archive/2007/09/14/talkbackvideo-understanding-handle-leaks-and-how-to-use-htrace-to-find-them.aspx     如果你不喜欢英文,那就可以看下面我蹩脚的解释了。
1311 0
|
C++ Windows
windbg调试实例(4)--句柄泄露
同事介绍了一篇调试句柄泄露的blog文章,今天有空看了一下,这家伙用视频的方式录下整个调试的过程,学习一目了然,真是有心。鉴于学习的过程总结一下能加深记忆,所以我这里做个记录,感兴趣的朋友可以看这里:http://blogs.msdn.com/ntdebugging/archive/2007/09/14/talkbackvideo-understanding-handle-leaks-and-how-to-use-htrace-to-find-them.aspx     如果你不喜欢英文,那就可以看下面我蹩脚的解释了。
885 0