如何获取进程启动地址的“名称”,就像Process Explorer中所做的那样?

3

好的,我正在编写一个应用程序,旨在枚举给定进程中的线程,就像Process Explorer一样。我很清楚这可能会因为依赖于“非正式”API(如NtQuerySystemInformation)而在不同的Windows版本之间出现问题,但我完全可以接受。

我已经有了获取给定线程基地址的代码。我现在想把它变成像进程资源管理器那样的东西,也就是“ntdll.dll!EtwDeliverDataBlock+0x453”。我实际上并不需要函数名称或偏移量,只需要模块名称。

我该怎么做?

3个回答

4
如果您只需要模块名称,最简单的方法是使用EnumProcessModules获取所有加载的模块列表,然后在每个模块上使用GetModuleInformationGetModuleInformation返回的其中一项是该模块加载的基地址。从技术上讲,HMODULE本身的整数值与基地址相同,但我觉得这似乎有点脆弱...

然后,只需找到基地址略低于线程当前(或起始)地址的模块即可。

哦,要获取模块的实际名称,可以使用GetModuleBaseName


嗯...这可能行得通。有没有办法可以不必实际打开目标进程的句柄来完成它?(例如,无法对系统进程执行此操作) - Billy ONeal
@Billy:我不确定。我相信Process Explorer实际上使用了内核模式驱动程序来支持其某些功能,所以也许这就是其中之一的情况..? - Dean Harding
通过使用类SystemModuleInformation调用NtQuerySystemInformation来解决这个问题 - 我会回复你我想到的方案。 - Billy ONeal

1
您可以使用 GetModuleHandleEx 函数及 GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS 标识来获取给定地址的模块句柄。之后,您可以使用 GetModuleBaseName 函数获取模块名称。 编辑: 您可能还需要使用 GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT 标识,以避免增加模块的引用计数。

2
GetModuleHandleEx对于远程进程无效。因此,您建议使用UNCHANGED_REFCOUNT标志也是无关紧要的... - wj32

0

您可以使用该代码获取模块句柄(它比GetModuleHandleEx更快),然后调用GetModuleBaseName

HMODULE GetCallingModule( LPCVOID pCaller ) const
{
    HMODULE hModule = NULL;
    MEMORY_BASIC_INFORMATION mbi;
    if ( VirtualQuery(pCaller, &mbi, sizeof(MEMORY_BASIC_INFORMATION)) == sizeof(MEMORY_BASIC_INFORMATION) )
    {
        // the allocation base is the beginning of a PE file 
        hModule = (HMODULE) mbi.AllocationBase;
    }
    return hModule;
}

@KindDragon:要跨进程工作,甚至需要相应的进程句柄才能使用VirtualQueryEx。不过,通过查找您自己进程中静态变量的MEMORY_BASIC_INFORMATION::AllocationBase来获取HINSTANCE hInstance是一个很棒的技巧。但是,只有在避免样板CRT代码等情况下才需要这样做... - 0xC0000022L

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接