Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Proposal - Changes to the way Windows process modules are found #28563

Open
ghost opened this issue Jan 30, 2019 · 0 comments
Open

Proposal - Changes to the way Windows process modules are found #28563

ghost opened this issue Jan 30, 2019 · 0 comments

Comments

@ghost
Copy link

ghost commented Jan 30, 2019

There's currently an issue with the way Windows process modules are found where If you attempt to get the modules loaded into an x86 process from an x64 program you are only presented with Ntdll.dll + the Wow64 dll's, which aren't the only modules loaded.

The current method that is being used is EnumProcessModules from psapi.dll - Whilst I don't know what this function is doing internally I'm guessing it's only querying the x64 PEB (if the process is running under Wow64) and therefore only returning the x64 dll's that are loaded in the process.

Something like this could be used to get a full list of modules (both x86 and x64) loaded in a process which you get then use the BaseAddress / ModuleHandle to get the rest of the information you need like is done in the ProcessManger.Win32 class.

[DllImport("kernel32.dll", SetLastError = true)]
internal static extern IntPtr CreateToolhelp32Snapshot(SnapshotFlags flags, uint processId);

[DllImport("kernel32.dll", SetLastError = true)]
internal static extern bool Module32First(IntPtr snapshotHandle, IntPtr moduleEntry);
        
[DllImport("kernel32.dll", SetLastError = true)]
internal static extern bool Module32Next(IntPtr snapshotHandle, IntPtr moduleEntry);

[Flags]
internal enum SnapshotFlags
{
    Module = 0x08,
    Module32 = 0x010
}

[StructLayout(LayoutKind.Sequential)]
internal struct ModuleEntry
{
    internal uint Size;

    private readonly uint ModuleId;
    private readonly uint ProcessId;

    private readonly uint UnusedValue1;
    private readonly uint UnusedValue2;

    internal IntPtr BaseAddress;

    private readonly uint BaseSize;

    private readonly IntPtr ModuleHandle;
            
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 256)]
    internal readonly string Module;
            
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]
    internal readonly string ExePath;
}

internal static IntPtr StructureToPointer<TStructure>(TStructure structure)
{
    var structureSize = Marshal.SizeOf(typeof(TStructure));

    // Allocate memory to store the structure
            
    var pointer = Marshal.AllocHGlobal(structureSize);
            
    // Store the structure in the allocated memory
            
    Marshal.StructureToPtr(structure, pointer, true);

    return pointer;
}

internal static TStructure PointerToStructure<TStructure>(IntPtr address)
{
    // Read the structure from memory at the address
            
    var structure = (TStructure) Marshal.PtrToStructure(address, typeof(TStructure));

    return structure;
} 

internal static IEnumerable<ModuleEntry> GetProcessModules(int processId)
{
    var processModules = new List<ModuleEntry>();
            
    // Create a tool help snapshot
            
    var snapshotHandle = Native.CreateToolhelp32Snapshot(SnapshotFlags.Module | SnapshotFlags.Module32, (uint) processId);
            
    // Initialize a module entry struct
            
    var moduleEntrySize = Marshal.SizeOf(typeof(ModuleEntry));
            
    var moduleEntry = new ModuleEntry { Size = (uint) moduleEntrySize};
            
    // Store the module entry struct in a buffer
            
    var moduleEntryBuffer = StructureToPointer(moduleEntry);
            
    // Get the first module of the process and store it in the buffer
            
    if (!Module32First(snapshotHandle, moduleEntryBuffer))
    {
        return processModules;
    }
            
    // Get the first module entry structure from the buffer
            
    moduleEntry = PointerToStructure<ModuleEntry>(moduleEntryBuffer);
            
    processModules.Add(moduleEntry);
            
    // Get the rest of the modules in the process
            
    while (Module32Next(snapshotHandle, moduleEntryBuffer))
    {
        // Get the module entry structure from the buffer
                
        moduleEntry = PointerToStructure<ModuleEntry>(moduleEntryBuffer);
                
        processModules.Add(moduleEntry);
    }
            
    return processModules;
}

Another option could be to get an instance of the PEB / PEB's (if the process is runnning under Wow64) and then loop through the LdrDataTable entries if Snapshots were not the best option.

@msftgits msftgits transferred this issue from dotnet/corefx Feb 1, 2020
@msftgits msftgits added this to the Future milestone Feb 1, 2020
@maryamariyan maryamariyan added the untriaged New issue has not been triaged by the area owner label Feb 23, 2020
@adamsitnik adamsitnik removed the untriaged New issue has not been triaged by the area owner label Jul 6, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants