【问题标题】:Find module handle in Windows x64 from external process从外部进程中查找 Windows x64 中的模块句柄
【发布时间】:2013-07-02 18:19:37
【问题描述】:

如何在 Windows x64 中按名称(在另一个进程中)查找模块基地址?

ProcessModuleCollection 仅找到:ntdll.dll wow64.dll wow64win.dll wow64cpu.dll

在哪里可以找到按名称搜索模块基地址的函数示例(适用于 x32 和 x64 Windows 版本)?

【问题讨论】:

  • 什么是“基地址”?
  • 你需要让你的问题更清楚。您没有提到您正在尝试检查不同的过程。 ProcessModuleCollection 在我期望的 x64 上运行良好,但我猜目标进程是 32 位 WOW64 进程。或者也许反过来。所以,请更详细一点。编辑问题。明确指出您指的是外部流程。并告诉我们这些过程。它们都是 32 位的,还是 64 位的,还是混合的。如果是混合的,那就轮到你了。您将无法从 32 位模拟器轻松枚举 64 位模块。
  • 您可以通过 PInvoke GetModuleHandleW 获取模块的 IntPtr 句柄。
  • @aevitas 否。这是针对执行过程中的模块的。 Brain 希望对不同进程中的模块执行此操作。
  • 谁能写一个 WinAPI 在不同进程中用于搜索模块句柄的示例? (对于 32 位 Windows 的 64 位?c#):)

标签: c# 32bit-64bit


【解决方案1】:

调用Process.Modules 返回的ProcessModuleCollection 实例包含您需要的信息。前提是两个进程具有相同的位数。因此,如果目标进程是 32 位进程,请确保您的进程也是 32 位进程。如果目标进程是64位进程,那么请确保你的进程是64位进程。

从您在问题中包含的输出可以清楚地看出,产生该输出的场景是:

  1. 64 位操作系统。
  2. 您的代码在 64 位进程中执行。
  3. 目标进程是 32 位进程。

之所以只列举那少数几个模块,是因为(推测)它们是在 WOW64 模拟器下运行的 32 位进程中包含的 64 位模块,以及可执行模块。

您可能会想,您可以使用 Windows API 来枚举进程中具有不同位数的模块。但你不能。尝试使用 CreateToolhelp32SnapshotModule32FirstModule32Next 会产生与使用 Process.Modules 的 C# 代码相同的结果。这一点也不奇怪。在 Win32 中实现的 .net 将调用为此任务设计的本机 Win32 API,这是完全合理的。

您的解决方案是确保对 Process.Modules 的调用是从 32 位进程发出的。如果您需要同时定位 32 位和 64 位进程,则需要使用一些不同位数的辅助进程。

更新

Ben Voigt 在调试帮助 API 中将我指向 EnumerateLoadedModules64。我承认我不知道这一点。但是,它似乎确实具有与工具帮助 API 相同的位数限制。

最后还有EnumProcessModulesEx,它可以从64位进程中枚举出32位模块。如果您传递LIST_MODULES_32BIT,那么您确实可以从 64 位调用进程中提取加载到外部 32 位进程中的 32 位模块。

【讨论】:

  • 那里也一样。你认为Process.Modules 是如何实现的?这只是对 Windows API 的一堆调用。现在,我相信有一些未记录的 API 可以完成这项工作,但祝你好运。
  • 我认为工具帮助 API 做不到。我希望这就是 .net 代码所使用的。 IIRC,您需要未记录的 API。做两个进程,用IPC,真的没那么难。
  • @BrainOverflow 您的 AnyCPU 进程正在 64 位机器上作为 x64 进程执行。
  • 您只看到这几个模块的原因是因为您的进程作为 x64 进程运行,进入配置管理器并将您的项目设置为 x86;即使在 64 位操作系统下也能正常工作。
【解决方案2】:

如果您只打算使用此代码针对 32 位进程,则以下内容应该适合您:

    /// <summary>
    /// Gets the base address of a process' module with the specified name.
    /// </summary>
    /// <param name="moduleName">Name of the module.</param>
    /// <returns>The module BaseAddress if successful; otherwise, IntPtr.Zero.</returns>
    public IntPtr GetModuleBaseAddress(string moduleName)
    {
        var module = Memory.Process.Modules.Cast<ProcessModule>().FirstOrDefault(m => m.ModuleName == moduleName);

        return module != null ? module.BaseAddress : IntPtr.Zero;
    }

其中 Memory.Process 只是一个 System.Diagnostics.Process 对象。我不确定它是否适用于实际的 x64 进程,但只要您针对 32 位进程(即使在 64 位平台上),此代码就可以很好地获取进程模块的基地址。

您需要记住的是,每当您枚举ProcessModules 时,您将只能获得被调用方架构中的模型(x86 或 x64)。如果您正在运行一个 x86 进程并且在另一个进程上调用 Process.Modules,您将只能看到该进程的 x86 模块。这同样适用于 x64。您要么需要找到解决此问题的方法,要么针对 x86 和 x64 编译您的项目并为每个应用程序使用正确的项目。

编辑:我在GameDeception 上找到了以下本机代码,可能对您有用:

unsigned long ProcessDevice::getModuleAddress(DWORD proc, const char *modname)
{
    HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, proc);

    if( snapshot == INVALID_HANDLE_VALUE )
    {
        return 0;
    }

    MODULEENTRY32 mod;
    mod.dwSize = sizeof(MODULEENTRY32);

    if( Module32First(snapshot, &mod) )
    {
        if( strcmp(mod.szModule, modname) == 0 )
            return (unsigned long)mod.modBaseAddr;

        while( Module32Next(snapshot, &mod) )
        {
            if( strcmp(mod.szModule, modname) == 0 )
                return (unsigned long)mod.modBaseAddr;
        }

        /* Failed to find the module */
        return 0;
    }
    else
    {
        /* Failed to read any module info */
        return 0;
    }
}

【讨论】:

  • 这只是ProcessModuleCollection。问题中所说的正是没有提供必要的信息。 32位到32位,64位到64位都可以。但不是混合位数。这显然是我们所拥有的。
  • 目标不仅可以是 x32,还可以是 x64(有时)。对于不同的(外部)流程也是必需的。
  • 您需要将项目构建为用于 32 位进程的 x86 和用于 64 位进程的 x64。通过进入无证 API 的阴暗世界可以解决这个问题,但相信我,只要您使用 IntPtr,为这两个平台构建您的程序会更容易,您不应该遇到太多问题。
  • @Brain 在这里工作得很好。 x86 进程、x86 目标、x64 操作系统、Process.Modules 为您提供所需的一切。
  • @aevitas 我对这个答案的问题是问题说Process.Modules 没有提供所需的输出。然后你的第一个版本说“使用Process.Modules”。然后编辑添加文本以调用工具帮助 API。但是由于Process.Modules 是在工具帮助API 上实现的,因此编辑只是添加了一种冗长且容易出错的方法来获得与Process.Modules 相同的结果。我并不是说我的答案是完美的(很明显不是),只是这个答案归结为:Process.Modules 无法满足您的需求,因此请致电Process.Modules
猜你喜欢
  • 2013-12-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-11-16
  • 1970-01-01
  • 2014-10-09
  • 1970-01-01
相关资源
最近更新 更多