注册

CpuDbg x96

查看: 1927|回复: 0
收起左侧

GetMappedFileName 引发的一系列吊诡问题

[复制链接]
发表于 2022-10-12 19:49:04 | 显示全部楼层 |阅读模式
标题改过一次了, 原标题太长了, 原标题是  "u.LoadDll.hFile 句柄为空引发的模块窗口exe信息为空等系列问题"
后来发现这一系列问题都是 GetMappedFileName 这个函数引起的...
---------------------------------------------------------------------------------------------------


第一次遇到 DebugEvent->u.LoadDll.hFile 句柄为空的情况.
先说说是怎样发现这个问题的.
今天在调试一个64位程序的时候, 下了个INT3断点重启后,发现断点没了.
打开UDD菜单,发现并没有保存当前调试目标的UDD文件.于是调试分析定位到了这个 DebugEvent->u.LoadDll.hFile 为空的原因引发的.


在接收到创建进程事件的时候, 通过 DebugEvent->u.LoadDll.hFile 句柄来获取模块完整路径. 代码如下:


[C++] 纯文本查看 复制代码
DWORD CDebugger::DebugX86_DispatcDebughEvent(const DEBUG_EVENT* lpDebugEvent)
{
        switch (lpDebugEvent->dwDebugEventCode)
        {
                // 异常事件
        case EXCEPTION_DEBUG_EVENT: return DebugX86_Exception(lpDebugEvent);
                // 创建进程事件
        case CREATE_PROCESS_DEBUG_EVENT: return DebugX86_CreateProcess(lpDebugEvent);    // <---------------------通过这个事件来获取模块路径.其中 lpDebugEvent->u.LoadDll.hFile 就是那个句柄
                // 创建线程事件
        case CREATE_THREAD_DEBUG_EVENT: return DebugX86_CreateThread(lpDebugEvent);
                // 退出线程事件
        case EXIT_THREAD_DEBUG_EVENT: return DebugX86_ExitThread(&lpDebugEvent->u.ExitThread);
                // 退出进程事件
        case EXIT_PROCESS_DEBUG_EVENT: return DebugX86_ExitProcess(lpDebugEvent);
                // 加载DLL事件
        case LOAD_DLL_DEBUG_EVENT: return DebugX86_LoadDll(lpDebugEvent);
                // 卸载DLL事件
        case UNLOAD_DLL_DEBUG_EVENT: return DebugX86_UnLoadDll(&lpDebugEvent->u.UnloadDll);
                // 日志输出
        case OUTPUT_DEBUG_STRING_EVENT: return DebugX86_OutputDebugString(&lpDebugEvent->u.DebugString);
                // rip
        case RIP_EVENT: return DebugX86_RipEvent(&lpDebugEvent->u.RipInfo);

        default:LogOutput("未知异常!"); return DBG_CONTINUE;
        }

        return false;
}




在另一篇贴子中 获取UnityPlayer.dll模块路径错误的问题 也是通过这个句柄来获取路径的.

这个问题很吊诡,怎么会为空呢? 第一次遇到这种情况. (也有可能之前也遇到过,只是没有注意到.)
下面是 lpDebugEvent 结构体:


[C++] 纯文本查看 复制代码
    typedef struct _DEBUG_EVENT {
    DWORD dwDebugEventCode;
    DWORD dwProcessId;
    DWORD dwThreadId;
    union {
        EXCEPTION_DEBUG_INFO Exception;
        CREATE_THREAD_DEBUG_INFO CreateThread;
        CREATE_PROCESS_DEBUG_INFO CreateProcessInfo;   // 这个是创建进程的结构体.
        EXIT_THREAD_DEBUG_INFO ExitThread;
        EXIT_PROCESS_DEBUG_INFO ExitProcess;
        LOAD_DLL_DEBUG_INFO LoadDll;                   // 而我在创建进程的事件中, 引用了加载DLL事件的结构体
        UNLOAD_DLL_DEBUG_INFO UnloadDll;
        OUTPUT_DEBUG_STRING_INFO DebugString;
        RIP_INFO RipInfo;
    } u;
} DEBUG_EVENT, *LPDEBUG_EVENT;


当初在写调试器框架的时候,看到有这么个句柄,就直接拿来用了. 不曾想会出现获取不到的情况.
既然这个程序会有这问题,我就又看了看 x64dbg 的模块窗口, 没有问题,可以获取到exe模块信息. 也不晓得x64dbg是怎么实现的,也懒得翻源码了.
又看了 yzdbg, 发现一样的是为空的. 看来yzdbg作者我俩写法应该差不多,都有这情况.


cpudbg模块窗口exe信息为空

cpudbg模块窗口exe信息为空


cpudbg模块窗口exe信息为空

yzdbg模块窗口exe信息为空

yzdbg模块窗口exe信息为空


yzdbg模块窗口exe信息为空

这个获取不到句柄的问题, 会导致UDD保存失败之外, 还会导致模块窗口获取不到主程序.exe的信息.等等.
既然问题找到了,回头空了再来解决吧.
有问题的这个demo我是真想放上来, 奈何服务器小水管,不抗造...

-----------------------------------------------------------
2022.10.13 刚刚我用了一个临时解决方案,
通过进程句柄,调用 GetModuleFileNameEx 获取文件绝对路径, 然后在调用 CreateFile 拿到文件句柄.(没办法,封装的子函数里面太多地方要用到文件句柄)
这一切都正常的, 包括打印的文件路径也是正确的. 我印象中,早期我是用的 GetModuleFileNameEx 来获取文件路径的, 可是后面有遇到获取不到的情况, 才改用 GetMappedFileName 函数来获取.
但没想到的是用 GetMappedFileName 遇到了获取的文件路径不对的情况, 具体的可参考这一篇贴子: 获取UnityPlayer.dll模块路径错误的问题
这篇贴子中遇到的问题: 明明路径是 c:\游戏\UnityPlayer.dll  可通过 GetMappedFileName 得到的路径确是   c:\UnityPlayer.dll
当时这路径都在一个逻辑分区上,所以也没想太多.


可是今天遇到的这个问题. 也是因为  GetMappedFileName 函数引发的.  
本来目标程序是在 D 盘上的  后来我拷到 Z 盘上了. 也就是拷贝到 Z 盘之后, 我才发现 UDD 没有保存. 于是才发现获取不到文件句柄. 然后就是一系列的问题.
原来都是 GetMappedFileName 这个函数造成的.  文件我由D盘拷贝到Z盘,且D盘的文件删除之后,  为什么 GetMappedFileName  获取的还是之前D盘我删掉的路径?


另篇贴子中提到的 GetFinalPathNameByHandle  函数, 没有这类问题, 但这个函数新版本才有, 如果是在xp上运行32位的程序, 就又得专门处理一下. 而且我也不敢保证
这个函数就一定能获取所有的例子路径.


至于 GetMappedFileName  获取之前的路径原因还不清楚, 随便GG了一下, 也没有找到相关的信息. 回头空了再研究吧.

-----------------------------------------------------------
2022.10.13 刚才又看了一下, 不仅仅是 GetMappedFileName 有问题.  应该是从创建进程的时候开始就有问题了.
在创建进程后, WaitForDebugEvent 获取的第一个事件就是 CREATE_PROCESS_DEBUG_EVENT  而这里 DEBUG_EVENT 参数获取的句柄就已经是空的了.
这个问题还没找到原因. 有可能是操作系统的原因? 也有可能是系统的BUG? 搞不清楚, 回头空了再研究研究...
-----------------------------------------------------------
to be continued...


回复

使用道具 举报

游客
回复
您需要登录后才可以回帖 登录 | 注册

QQ|Archiver|手机版| CpuDbg x96

GMT, 2024-12-22 05:31 , Processed in 0.062500 second(s), 21 queries .

Powered by Discuz! X3.4 Licensed

© 2001-2013 Comsenz Inc.

快速回复 返回顶部 返回列表