C# .NET 4.0 - Determining which modules are loaded in the wow process... menu

User Tag List

Results 1 to 10 of 10
  1. #1
    Tanaris4's Avatar Contributor Authenticator enabled
    Reputation
    148
    Join Date
    Oct 2008
    Posts
    646
    Thanks G/R
    0/0
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)

    C# .NET 4.0 - Determining which modules are loaded in the wow process...

    So for those people using .NET 4.0, is anyone able to successfully traverse through the dlls loaded by wow?

    I've noticed there is a bug in .NET 4.0 (https://connect.microsoft.com/Visual...e-managed-dlls) where you can no longer do this.

    And of course the GetMappedFileName solution suggested only appears to work on windows 7+.

    Has anyone been able to do this? I'm trying to find the base address of all loaded modules and their file name.

    Thanks in advance!
    ~ Tanaris
    https://tanaris4.com

    C# .NET 4.0 - Determining which modules are loaded in the wow process...
  2. #2
    TOM_RUS's Avatar Legendary
    Reputation
    914
    Join Date
    May 2008
    Posts
    699
    Thanks G/R
    0/52
    Trade Feedback
    0 (0%)
    Mentioned
    1 Post(s)
    Tagged
    0 Thread(s)
    Just wondering does Traversing the Module List work? (that's C++, but should not be hard to convert to C#)

  3. #3
    Tanaris4's Avatar Contributor Authenticator enabled
    Reputation
    148
    Join Date
    Oct 2008
    Posts
    646
    Thanks G/R
    0/0
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Originally Posted by TOM_RUS View Post
    Just wondering does Traversing the Module List work? (that's C++, but should not be hard to convert to C#)
    Will try that now, I'm thinking it might be because my app is 64-bit, and wow is running in 32-bit mode.

    Of course when I run my app on 32-bit windows, it's fine. Why can't this just work like on OS X
    https://tanaris4.com

  4. #4
    Tanaris4's Avatar Contributor Authenticator enabled
    Reputation
    148
    Join Date
    Oct 2008
    Posts
    646
    Thanks G/R
    0/0
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Ahh I can use EnumProcessModulesEx function (Windows) (EnumProcessModulesEx ), then specify LIST_MODULES_32BIT
    https://tanaris4.com

  5. #5
    TOM_RUS's Avatar Legendary
    Reputation
    914
    Join Date
    May 2008
    Posts
    699
    Thanks G/R
    0/52
    Trade Feedback
    0 (0%)
    Mentioned
    1 Post(s)
    Tagged
    0 Thread(s)
    Originally Posted by Tanaris4 View Post
    Ahh I can use EnumProcessModulesEx function (Windows) (EnumProcessModulesEx ), then specify LIST_MODULES_32BIT
    Win32 applications that use the EnumProcessModules function will not see all managed modules listed.
    Dunno about EnumProcessModulesEx though.

  6. #6
    _Mike's Avatar Contributor
    Reputation
    310
    Join Date
    Apr 2008
    Posts
    531
    Thanks G/R
    0/2
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    EnumProcessModulesEx won't work. .Net 4 assemblies aren't loaded with LoadLibrary so they won't be in the loader list that psapi enumerates. I think the only solution is to do what that connect link suggests and use GetMappedFileName* or NtQueryVirtualMemory with the section name info class**.

    *) It does work on XP and onwards. Read the Remarks section.
    Programs that must run on earlier versions of Windows as well as Windows 7 and later versions should always call this function as GetMappedFileName. To ensure correct resolution of symbols, add Psapi.lib to the TARGETLIBS macro and compile the program with -DPSAPI_VERSION=1. To use run-time dynamic linking, load Psapi.dll.
    **) For example
    Code:
    struct UNICODE_STRING
    {
       USHORT Length;
       USHORT MaximumLength;
       PWSTR Buffer;
    };
    
    typedef struct
    {
       UNICODE_STRING SectionFileName;
       WCHAR NameBuffer[];
    } *PMEMORY_SECTION_NAME;
    
    std::wstring GetSectionName(void* addr)
    {
       HMODULE ntdll = GetModuleHandle(L"ntdll");   
       typedef NTSTATUS (NTAPI *tNtQueryVirtualMemory)(HANDLE h, PVOID addr, DWORD infoclass, PVOID buffer, SIZE_T size, SIZE_T* outSize);
       auto NtQueryVirtualMemory = reinterpret_cast<tNtQueryVirtualMemory>(GetProcAddress(ntdll, "NtQueryVirtualMemory"));
       if(!NtQueryVirtualMemory)
       {
          throw std::exception();
       }
    
       SIZE_T outSize = 0;
       NTSTATUS status = NtQueryVirtualMemory(INVALID_HANDLE_VALUE, addr, 2 /* MemorySectionName class */, nullptr, 0, &outSize);
       if(status != 0xC0000004 /*STATUS_INFO_LENGTH_MISMATCH*/ || !outSize)
       {
          throw std::exception();
       }
    
       std::auto_ptr<char> buffer(new char[outSize]);
       status = NtQueryVirtualMemory(INVALID_HANDLE_VALUE, addr, 2, buffer.get(), outSize, &outSize);
       if(status != 0)
       {
          throw std::exception();
       }
       PMEMORY_SECTION_NAME section = reinterpret_cast<PMEMORY_SECTION_NAME>(&*buffer);
       return section->NameBuffer;
    }

  7. #7
    Cypher's Avatar Kynox's Sister's Pimp
    Reputation
    1358
    Join Date
    Apr 2006
    Posts
    5,368
    Thanks G/R
    0/6
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Originally Posted by _Mike View Post
    EnumProcessModulesEx won't work. .Net 4 assemblies aren't loaded with LoadLibrary so they won't be in the loader list that psapi enumerates. I think the only solution is to do what that connect link suggests and use GetMappedFileName* or NtQueryVirtualMemory with the section name info class**.

    *) It does work on XP and onwards. Read the Remarks section.


    **) For example
    Code:
    struct UNICODE_STRING
    {
       USHORT Length;
       USHORT MaximumLength;
       PWSTR Buffer;
    };
    
    typedef struct
    {
       UNICODE_STRING SectionFileName;
       WCHAR NameBuffer[];
    } *PMEMORY_SECTION_NAME;
    
    std::wstring GetSectionName(void* addr)
    {
       HMODULE ntdll = GetModuleHandle(L"ntdll");   
       typedef NTSTATUS (NTAPI *tNtQueryVirtualMemory)(HANDLE h, PVOID addr, DWORD infoclass, PVOID buffer, SIZE_T size, SIZE_T* outSize);
       auto NtQueryVirtualMemory = reinterpret_cast<tNtQueryVirtualMemory>(GetProcAddress(ntdll, "NtQueryVirtualMemory"));
       if(!NtQueryVirtualMemory)
       {
          throw std::exception();
       }
    
       SIZE_T outSize = 0;
       NTSTATUS status = NtQueryVirtualMemory(INVALID_HANDLE_VALUE, addr, 2 /* MemorySectionName class */, nullptr, 0, &outSize);
       if(status != 0xC0000004 /*STATUS_INFO_LENGTH_MISMATCH*/ || !outSize)
       {
          throw std::exception();
       }
    
       std::auto_ptr<char> buffer(new char[outSize]);
       status = NtQueryVirtualMemory(INVALID_HANDLE_VALUE, addr, 2, buffer.get(), outSize, &outSize);
       if(status != 0)
       {
          throw std::exception();
       }
       PMEMORY_SECTION_NAME section = reinterpret_cast<PMEMORY_SECTION_NAME>(&*buffer);
       return section->NameBuffer;
    }
    I know it's only POC code, but fyi std::auto_ptr will call 'delete', not 'delete []', meaning that you may be leaking memory. You probably want to use a std::vector instead (or something similar to scoped_array if you really want to avoid a vector for whatever reason).

    Also of note is that auto_ptr is deprecated now anyway (C++11), so for a non-shared owning smart pointer you probably want unique_ptr (if available on your platform). It has working move semantics, unlike auto_ptr's broken faux move semantics.

    Originally Posted by TOM_RUS View Post
    Dunno about EnumProcessModulesEx though.
    From MSDN:
    This function is intended primarily for 64-bit applications. If the function is called by a 32-bit application running under WOW64, the dwFilterFlag option is ignored and the function provides the same results as the EnumProcessModules function.

    Last edited by Cypher; 07-20-2012 at 08:36 PM.

  8. #8
    -Ryuk-'s Avatar Elite User CoreCoins Purchaser Authenticator enabled
    Reputation
    529
    Join Date
    Nov 2009
    Posts
    1,028
    Thanks G/R
    38/51
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    I know you have fixed your issue, but here is what I use:

    Code:
                ToolHelpHandle hModuleSnap = NativeMethods.CreateToolhelp32Snapshot(NativeMethods.SnapshotFlags.Module,                                                                            (uint)Pid);
    
                NativeMethods.MODULEENTRY32 me32 = new NativeMethods.MODULEENTRY32();
                me32.dwSize = (uint)System.Runtime.InteropServices.Marshal.SizeOf(me32);
                IntPtr ourModule = (IntPtr)null;
    
                if (NativeMethods.Module32First(hModuleSnap, ref me32))
                {
                    do
                    {
                         Logging.WriteLineDebug(me32.szModule) 
                    } while (NativeMethods.Module32Next(hModuleSnap, ref me32));
                }
    
    
            [DllImport("kernel32.dll")]
            static public extern bool Module32First(ToolHelpHandle hSnapshot, ref MODULEENTRY32 lpme);
    
    
            [DllImport("kernel32.dll")]
            static public extern bool Module32Next(ToolHelpHandle hSnapshot, ref MODULEENTRY32 lpme);
    
    
            [DllImport("kernel32.dll")]
            static public extern bool Process32First(ToolHelpHandle hSnapshot, ref PROCESSENTRY32 lppe);
    
    
            [DllImport("kernel32.dll")]
            static public extern bool Process32Next(ToolHelpHandle hSnapshot, ref PROCESSENTRY32 lppe);
    
    
            [DllImport("kernel32.dll", SetLastError = true)]
            static public extern ToolHelpHandle CreateToolhelp32Snapshot(SnapshotFlags dwFlags, uint th32ProcessID);
    
    
    
    
            [Flags]
            public enum SnapshotFlags : uint
            {
                HeapList = 0x00000001,
                Process = 0x00000002,
                Thread = 0x00000004,
                Module = 0x00000008,
                Module32 = 0x00000010,
                Inherit = 0x80000000,
                All = 0x0000001F
            }
    
    [StructLayoutAttribute(LayoutKind.Sequential)]
            public struct MODULEENTRY32
            {
                public uint dwSize;
                public uint th32ModuleID;
                public uint th32ProcessID;
                public uint GlblcntUsage;
                public uint ProccntUsage;
                IntPtr modBaseAddr;
                public uint modBaseSize;
                public IntPtr hModule;
                [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
                public string szModule;
                [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]
                public string szExePath;
            };
    |Leacher:11/2009|Donor:02/2010|Established Member:09/2010|Contributor:09/2010|Elite:08/2013|

  9. #9
    _Mike's Avatar Contributor
    Reputation
    310
    Join Date
    Apr 2008
    Posts
    531
    Thanks G/R
    0/2
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Like already mentioned, toolhelp/psapi will not show .net4 assembly dlls.

    Originally Posted by Cypher View Post
    I know it's only POC code, but fyi std::auto_ptr will call 'delete', not 'delete []', meaning that you may be leaking memory. You probably want to use a std::vector instead (or something similar to scoped_array if you really want to avoid a vector for whatever reason).

    Also of note is that auto_ptr is deprecated now anyway (C++11), so for a non-shared owning smart pointer you probably want unique_ptr (if available on your platform). It has working move semantics, unlike auto_ptr's broken faux move semantics.
    Good catch on the delete/delete[] operators. I'm a bit embarrassed I let that one slip by. I've gotten a bit to reliant on MSVC's vendor-specific behaviour where both operators are identical. Not a good thing when posting code publicly. I normally use vectors for dynamic buffers. I can't really remember why I chose auto_ptr for this.
    And thanks for the C++11 info. I haven't had a chance to learn all the new stuff yet.

  10. #10
    Seifer's Avatar Site Donator
    Reputation
    129
    Join Date
    Apr 2007
    Posts
    270
    Thanks G/R
    1/0
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    If you're just after the base address and the file names, you could just use the Process.Modules property of a process and access the BaseAddress and FileName properties of the respective ProcessModule objects.

    Used them a while ago in my DLL injector to check if a certain DLL was already injected, should pretty much beat all the API stuff.

Similar Threads

  1. [Bot] Which bots are working at the moment?
    By pokeaddict in forum Pokemon GO Hacks|Cheats
    Replies: 45
    Last Post: 11-01-2016, 04:39 AM
  2. Replies: 12
    Last Post: 08-02-2016, 03:56 AM
  3. Replies: 7
    Last Post: 09-02-2012, 02:41 AM
  4. Flight Paths - Determining which level flights are available?
    By Tanaris4 in forum WoW Memory Editing
    Replies: 4
    Last Post: 03-04-2012, 11:39 AM
  5. [WoW][3.1.3][mac] Determining which items are in your bags
    By Tanaris4 in forum WoW Memory Editing
    Replies: 7
    Last Post: 06-08-2009, 07:20 AM
All times are GMT -5. The time now is 01:57 AM. Powered by vBulletin® Version 4.2.3
Copyright © 2025 vBulletin Solutions, Inc. All rights reserved. User Alert System provided by Advanced User Tagging (Pro) - vBulletin Mods & Addons Copyright © 2025 DragonByte Technologies Ltd.
Google Authenticator verification provided by Two-Factor Authentication (Free) - vBulletin Mods & Addons Copyright © 2025 DragonByte Technologies Ltd.
Digital Point modules: Sphinx-based search