我正在使用CreateToolhelp32Snaphot方法列出特定进程中加载的所有模块,但我只是注意到,如果重命名加载的DLL,它仍然使用初始名称列出(可能是加载DLL时的名称)处理)。这是一个已知的问题吗?
MODULEENTRY32 modEntry = new MODULEENTRY32();
modEntry.dwSize = (UInt32)Marshal.SizeOf(typeof(MODULEENTRY32));
handleToSnapshot = CreateToolhelp32Snapshot((uint)SnapshotFlags.Module | (uint)SnapshotFlags.Module32, procId);
if (Module32First(handleToSnapshot, ref modEntry))
{
do
{
Console.WriteLine(modEntry.szExePath);
}
while (Module32Next(handleToSnapshot, ref modEntry));
}
我也尝试过使用EnumProcessModulesEx + GetModuleFileNameEx,我也得到了相同的结果。我想知道Process Explorer如何能够正确获取信息,还有其他方法可供使用吗?
答案 0 :(得分:1)
一种方法是直接从进程内存中读取数据,而不使用枚举模块列表的任何Win32函数:
OpenProcess
NtQueryInformationProcess
获取ProcessBasicInformation
信息类型并阅读PebBaseAddress
结构的_PROCESS_BASIC_INFORMATION
属性(进程环境块地址)ReadProcessMemory
读取PE块(阅读ldrData
部分)这是获得我所知道的模块列表的最低层次方法,我非常确定Process Explorer可以做类似的事情。
但是请注意,编写此代码确实很痛苦,因为您必须处理64位问题:要使用的不同内存地址,WOW64 stuff等等。最后但同样重要的是:当您使用C#时,祝您获得所有(有时未记录的)结构/函数的正确P / Invoke签名,祝你好运:)
编辑: 如下面的评论中所述,这是获取进程加载的模块列表的另一种低级方法。但我不确定这会提供您重命名模块时所描述的行为。
我建议你深入研究the source code of Process Hacker这是一个非常类似于Process Explorer的开源项目。我测试了PH,它与你描述的行为相同。注意:这只是C代码,而不是C#。查看KProcessHacker
目录,它是执行所有操作的驱动程序的代码。
答案 1 :(得分:0)
在NTFS中,文件名是存储在主文件表中的元数据变量。 MFT还包含一个文件ID。当您更改文件名时,它不会更改文件ID。标识符唯一地标识文件。
文件的打开句柄不是通过文件名而是通过此唯一标识符来跟踪的。
ProcessHacker,Process Explorer和其他工具将使用NtQueryInformationFile枚举器从内核中使用FILE_INTERNAL_INFORMATION
此结构包含成员变量IndexNumber
,这是唯一的文件标识符。
如果要执行相同的操作,则需要进入内核并执行相同的操作:
找到进程加载的模块,获取文件句柄,使用该句柄通过NtQueryInformationFile获取IndexNumber