0

enter image description hereHow to find module base address by name (in another process), in Windows x64?

ProcessModuleCollection finds only: ntdll.dll wow64.dll wow64win.dll wow64cpu.dll

Where can find an example of functions for search module base addess by name (which works in x32 and x64 Windows version)?

  • what's "base address"? – Nikita B Jul 01 '13 at 19:59
  • 1
    You need to make your question more clear. You don't mention that you are trying to inspect a different process. `ProcessModuleCollection` works fine on x64 I expect, but I guess the target process is a 32 bit WOW64 process. Or perhaps the other way around. So, more detail please. Edit the question. Make it clear that you refer to an external process. And tell us about the processes. Are they both 32 bit, or both 64 bit, or mixed. And if mixed, which way round. You'll not be able to readily enumerate 64 bit modules from the 32 bit emulator. – David Heffernan Jul 01 '13 at 20:16
  • You can probably PInvoke `GetModuleHandleW` and obtain an `IntPtr` handle to the module that way. – aevitas Jul 01 '13 at 20:17
  • 1
    @aevitas No. That's for modules in the executing process. Brain wants to do this for modules in a different process. – David Heffernan Jul 01 '13 at 20:20
  • Who can write an example uses of WinAPI for search module handle in a different process ? (for 64 bit with 32 bit Windows? c# ) :) – Brain Overflow Jul 01 '13 at 20:22
  • @DavidHeffernan target:x32 process in x64 windows, I try to find 32-bit modules. – Brain Overflow Jul 01 '13 at 20:24
  • @aevitas Read the documentation: http://msdn.microsoft.com/en-us/library/windows/desktop/ms683199.aspx – David Heffernan Jul 01 '13 at 20:25
  • @BrainOverflow Both are x32 processes? Or is the target process a 64 bit process? – David Heffernan Jul 01 '13 at 20:26
  • @DavidHeffernan You are correct, I handle it differently in my lib after revisiting my code. – aevitas Jul 01 '13 at 20:26
  • @DavidHeffernan. My process x32 (for all cpu), target process x32, target windows x64 and x32 :) – Brain Overflow Jul 01 '13 at 20:34
  • No, if both processes are 32 bit, then `ProcessModuleCollection` gives all the modules. Check again. Also, when you say, it is necessary, be prepared to be disappointed. I'm reasonably sure that it's not simple to enumerate 64 bit process from 32 bit process, and possibly vice versa. – David Heffernan Jul 01 '13 at 20:37
  • Duplicate of http://stackoverflow.com/questions/7987945/retrieving-all-32-bit-process-modules-from-64-bit-application-c – Ben Voigt Jul 01 '13 at 21:15
  • That question didn't answer. And I need WinXP-Win8 x64-x32. – Brain Overflow Jul 02 '13 at 04:32
  • You are adding extra requirements in comments after the question has been asked. How can @BenVoigt read your mind and know that you want to support the very rare XP64? – David Heffernan Jul 02 '13 at 09:51
  • That's the advantage of using DbgHelp instead of PSAPI -- DbgHelp runs on XP. – Ben Voigt Jul 02 '13 at 14:03
  • @Ben But the DbgHelp function doesn't do this job. Your answer at the other question is actually wrong. It gives the same results as tool help api. – David Heffernan Jul 02 '13 at 21:46
  • Oh, nevermind, I didn't read the `EnumProcessModulesEx` windows version documentation closely enough. It should run on XP64 also. – Ben Voigt Jul 02 '13 at 22:12

2 Answers2

3

The ProcessModuleCollection instance returned by calling Process.Modules has the information you need. Provided that both processes have the same bitness. So, if the target process is a 32 bit process, make sure your process is also a 32 bit process. And if the target process is a 64 bit process, then make sure your process is a 64 bit process.

From the output you include in the question it is clear that the scenario that produced that output is:

  1. A 64 bit OS.
  2. Your code executes in a 64 bit process.
  3. The target process is a 32 bit process.

The reason that you only enumerate those handful of modules is (presumably) that they are the 64 bit modules that are included in the 32 bit process running under the WOW64 emulator, together with the executable module.

You might be tempted to think that you can use the Windows API to enumerate modules in a process with a different bitness. But you cannot. Attempts to use CreateToolhelp32Snapshot, Module32First and Module32Next yield the same results as your C# code that uses Process.Modules. And that's not at all surprising really. It makes perfect sense that .net, which is implemented in Win32, would call the native Win32 API that is designed for this task.

Your solution is to make sure that the call to Process.Modules is made from a 32 bit process. You will need to use some helper processes of different bitness if you need to be able to target both 32 and 64 bit processes.

Update

Ben Voigt point me to EnumerateLoadedModules64 from the Debug Help API. I confess to being unaware of this. However, it does appear to have the same bitness limitations as the tool help API.

Finally, there is also EnumProcessModulesEx which can enumerate 32 bit modules from a 64 bit process. If you pass LIST_MODULES_32BIT then you can indeed extract the 32 bit modules loaded into an external 32 bit process, from a calling process that is 64 bit.

David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490
  • [Screenshot](http://screenshot.su/img/9b/ba/d8/9bbad84c157588e904ba1f1984e2b37b.jpg) – Brain Overflow Jul 01 '13 at 20:46
  • It's just the same there. How do you imagine `Process.Modules` is implemented? It's just a bunch of calls to the Windows API. Now, I believe that there are some undocumented APIs that can do the job, but good luck getting that to fly. – David Heffernan Jul 01 '13 at 20:46
  • Yes, your code is 64 bit, and the target process is 32 bit. Just compile your code for 32 bit and it's all good. – David Heffernan Jul 01 '13 at 20:47
  • Maybe createtoolhelp32snapshot and modulefirst...WinAPI ? – Brain Overflow Jul 01 '13 at 20:48
  • This code is compiled for ANY CPU in x32 Windows (Microsoft Visual Studio 2010). – Brain Overflow Jul 01 '13 at 20:49
  • Your process, the one that produced that output, is an x64 process. – David Heffernan Jul 01 '13 at 20:51
  • 1
    I don't think tool help API will do it. I expect that's what the .net code is using. IIRC you need undocumented APIs. It's really not that hard for you to make two processes and use IPC. – David Heffernan Jul 01 '13 at 20:52
  • DavidHefferman, [Compiled exe](http://www.mediafire.com/?v3nkausq86i34nc) and target [Game](http://en.wikipedia.org/wiki/Warcraft_III:_The_Frozen_Throne) – Brain Overflow Jul 01 '13 at 20:54
  • Also, you hardly ever want to build for Any CPU, build for x86 or x64 instead. – aevitas Jul 01 '13 at 20:54
  • 1
    @BrainOverflow Your AnyCPU process is being executed as an x64 process on your 64 bit machine. – David Heffernan Jul 01 '13 at 20:55
  • 1
    Reason you're only seeing this few modules is because your process is running as an x64 process, go into the configuration manager and set your project to build as x86; it'll work fine even under an 64-bit operating system. – aevitas Jul 01 '13 at 20:57
  • No, your scenario is exactly as described in my answer. Tool help API won't help. You need to match 32 bit process to 32 bit target, or 64 bit process to 64 bit target. I've said this many times now. The answer will not change. – David Heffernan Jul 01 '13 at 20:59
  • @BrainOverflow If your Windows is 32 bit, then how on earth are you running a 64 bit process? – aevitas Jul 01 '13 at 21:00
  • @DavidHeffernan My bad, that was supposed to say operating system. Edited it for clarity. Thanks. :) – aevitas Jul 01 '13 at 21:01
  • Umm, final two paragraphs are wrong. Yes, there exist API functions with the same-bitness limitation, but this doesn't prove that no API functions exist without the limitation. ToolHelp was obsoleted long ago, you should instead turn to DbgHelp.dll and `EnumerateLoadedModules64`. Or does DbgHelp only work on a process you're debugging? – Ben Voigt Jul 01 '13 at 21:12
  • @Brain Your needs must be tempered by what is possible. – David Heffernan Jul 01 '13 at 21:19
  • @ben thanks. EnumerateLoadedModules64 must be fine for external processes since it takes a process handle as input. And you are sure it's got no bitness limits? – David Heffernan Jul 01 '13 at 21:20
  • Well, I haven't tested it myself, but there's only one conceivable reason for having `EnumerateLoadedModules64` usable from 32-bit code. OTOH the process handle could be used for selection between multiple debuggees, or there could be security rights/privileges which need to be enabled to use it. So it may not be quite as simple as "p/invoke `EnumerateLoadedModules64`", but this is the key to making it work. – Ben Voigt Jul 01 '13 at 21:23
  • @Ben EnumProcessModulesEx also seems to do the job. – David Heffernan Jul 01 '13 at 21:33
  • @David: I do believe so, as long as you don't need to support XP or Svr2003 64-bit. – Ben Voigt Jul 01 '13 at 22:39
  • @DavidHeffernan, EnumProcessModulesEx doesn't work in Windows XP :( – Brain Overflow Jul 02 '13 at 04:26
  • @BenVoigt `EnumerateLoadedModules64` has the same bitness limitations as tool help API. – David Heffernan Jul 02 '13 at 10:09
2

If you're only going to target 32-bit processes with this code, the following should work just fine for you:

    /// <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;
    }

Where Memory.Process is just a System.Diagnostics.Process object. I'm not sure if it'll work on actual x64 processes, but as long as you're targeting 32bit processes (even on a 64bit platform), this code will obtain the base address of a process' module just fine.

What you have to keep in mind is that whenever you enumerate ProcessModules, you'll only be able to get the models that are in the architecture of the callee (x86 or x64). If you are running an x86 process and you are calling Process.Modules on another process, you'll only see the x86 modules of that process. The same applies to x64. You'll either need to find a way around this or compile your project for both x86 and x64 and use the proper ones for each application.

Edit: I've found the following native code on GameDeception which may be of use to you:

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;
    }
}
aevitas
  • 3,753
  • 2
  • 28
  • 39
  • This is just `ProcessModuleCollection`. Which is exactly what is stated in the question is not providing the necessary information. It's fine for 32 bit to 32 bit, and 64 bit to 64 bit. But not with mixed bitness. Which is clearly what we have here. – David Heffernan Jul 01 '13 at 20:38
  • The target can be not only x32 but also x64(sometimes). Also is necessary for different(external) process. – Brain Overflow Jul 01 '13 at 20:40
  • You'll need to build your project as x86 for 32-bit processes and as x64 for 64-bit processes. There's a way around that by going into the shady world of undocumented API, but believe me, it's easier to just make a build of your program for both platforms, provided you use `IntPtr`, you shouldn't run into too many problems. – aevitas Jul 01 '13 at 20:52
  • @Brain Works just fine here. x86 process, x86 target, x64 OS, Process.Modules gives you what you need. – David Heffernan Jul 01 '13 at 21:32
  • 'unsigned long'...'CreateToolhelp32Snapshot' does not exist in the current context. – Brain Overflow Jul 02 '13 at 04:28
  • I found, [Nativ](http://stackoverflow.com/questions/2237628/c-sharp-process-killing) – Brain Overflow Jul 02 '13 at 04:37
  • 1
    @aevitas My problem with this answer is that the question says that `Process.Modules` does not give the desired output. Then your first revision says "use `Process.Modules`". Then the edit adds text to call tool help API. But since `Process.Modules` is implemented on tool help API the edit just adds a long-winded and error-prone way to get the same results as `Process.Modules`. I'm not saying my answer is perfect (it's very clearly not), just that this answer boils down to: `Process.Modules` doesn't give you what you need, so call `Process.Modules` instead. – David Heffernan Jul 02 '13 at 07:13
  • @DavidHeffernan You are right. I have made an edit to the post to include the reasons as to why he is seeing the results he is seeing and how to fix those. Reason I gave this answer is because `Process.Modules` works fine, as long as you take x64 and x86 into account properly. – aevitas Jul 02 '13 at 09:04
  • You should get rid of the native code. It serves no purpose at all. I would also like to comment that you are essentially repeating what I already said in my answer. Which is fine. – David Heffernan Jul 02 '13 at 09:33