重命名DLL时的进程模块列表问题

时间:2014-09-04 09:38:57

标签: c# dll

我正在使用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如何能够正确获取信息,还有其他方法可供使用吗?

2 个答案:

答案 0 :(得分:1)

一种方法是直接从进程内存中读取数据,而不使用枚举模块列表的任何Win32函数:

  1. 使用OpenProcess
  2. 打开流程的句柄
  3. 调用NtQueryInformationProcess获取ProcessBasicInformation信息类型并阅读PebBaseAddress结构的_PROCESS_BASIC_INFORMATION属性(进程环境块地址)
  4. 使用目标进程内存中的ReadProcessMemory读取PE块(阅读ldrData部分)
  5. 浏览内存中已加载模块的列表。有关解释,请参阅http://sandsprite.com/CodeStuff/Understanding_the_Peb_Loader_Data_List.html
  6. 这是获得我所知道的模块列表的最低层次方法,我非常确定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