/// <summary>Gets an array of module infos for the specified process.</summary> /// <param name="processId">The ID of the process whose modules should be enumerated.</param> /// <returns>The array of modules.</returns> internal static ProcessModuleCollection GetModules(int processId) { var modules = new ProcessModuleCollection(0); // Process from the parsed maps file each entry representing a module foreach (Interop.procfs.ParsedMapsModule entry in Interop.procfs.ParseMapsModules(processId)) { int sizeOfImage = (int)(entry.AddressRange.Value - entry.AddressRange.Key); // A single module may be split across multiple map entries; consolidate based on // the name and address ranges of sequential entries. if (modules.Count > 0) { ProcessModule module = modules[modules.Count - 1]; if (module.FileName == entry.FileName && ((long)module.BaseAddress + module.ModuleMemorySize == entry.AddressRange.Key)) { // Merge this entry with the previous one module.ModuleMemorySize += sizeOfImage; continue; } } // It's not a continuation of a previous entry but a new one: add it. unsafe { modules.Add(new ProcessModule() { FileName = entry.FileName, ModuleName = Path.GetFileName(entry.FileName), BaseAddress = new IntPtr(unchecked ((void *)entry.AddressRange.Key)), ModuleMemorySize = sizeOfImage, EntryPointAddress = IntPtr.Zero // unknown }); } } // Move the main executable module to be the first in the list if it's not already string exePath = Process.GetExePath(processId); for (int i = 0; i < modules.Count; i++) { ProcessModule module = modules[i]; if (module.FileName == exePath) { if (i > 0) { modules.RemoveAt(i); modules.Insert(0, module); } break; } } // Return the set of modules found return(modules); }
/// <summary>Gets an array of module infos for the specified process.</summary> /// <param name="processId">The ID of the process whose modules should be enumerated.</param> /// <returns>The array of modules.</returns> internal static ProcessModuleCollection GetModules(int processId) { var modules = new ProcessModuleCollection(0); // Process from the parsed maps file each entry representing a module foreach (Interop.procfs.ParsedMapsModule entry in Interop.procfs.ParseMapsModules(processId)) { int sizeOfImage = (int)(entry.AddressRange.Value - entry.AddressRange.Key); // A single module may be split across multiple map entries; consolidate based on // the name and address ranges of sequential entries. if (modules.Count > 0) { ProcessModule module = modules[modules.Count - 1]; if (module.FileName == entry.FileName && ((long)module.BaseAddress + module.ModuleMemorySize == entry.AddressRange.Key)) { // Merge this entry with the previous one module.ModuleMemorySize += sizeOfImage; continue; } } // It's not a continuation of a previous entry but a new one: add it. unsafe { modules.Add(new ProcessModule() { FileName = entry.FileName, ModuleName = Path.GetFileName(entry.FileName), BaseAddress = new IntPtr((void*)entry.AddressRange.Key), ModuleMemorySize = sizeOfImage, EntryPointAddress = IntPtr.Zero // unknown }); } } // Return the set of modules found return modules; }
private static ProcessModuleCollection GetModules(int processId, bool firstModuleOnly) { // preserving Everett behavior. if (processId == SystemProcessID || processId == IdleProcessID) { // system process and idle process doesn't have any modules throw new Win32Exception(HResults.E_FAIL, SR.EnumProcessModuleFailed); } SafeProcessHandle processHandle = SafeProcessHandle.InvalidHandle; try { processHandle = ProcessManager.OpenProcess(processId, Interop.Advapi32.ProcessOptions.PROCESS_QUERY_INFORMATION | Interop.Advapi32.ProcessOptions.PROCESS_VM_READ, true); bool succeeded = Interop.Kernel32.EnumProcessModules(processHandle, null, 0, out int needed); // The API we need to use to enumerate process modules differs on two factors: // 1) If our process is running in WOW64. // 2) The bitness of the process we wish to introspect. // // If we are not running in WOW64 or we ARE in WOW64 but want to inspect a 32 bit process // we can call psapi!EnumProcessModules. // // If we are running in WOW64 and we want to inspect the modules of a 64 bit process then // psapi!EnumProcessModules will return false with ERROR_PARTIAL_COPY (299). In this case we can't // do the enumeration at all. So we'll detect this case and bail out. if (!succeeded) { if (!Interop.Kernel32.IsWow64Process(Interop.Kernel32.GetCurrentProcess(), out bool sourceProcessIsWow64)) { throw new Win32Exception(); } if (!Interop.Kernel32.IsWow64Process(processHandle, out bool targetProcessIsWow64)) { throw new Win32Exception(); } if (sourceProcessIsWow64 && !targetProcessIsWow64) { // Wow64 isn't going to allow this to happen, the best we can do is give a descriptive error to the user. throw new Win32Exception(Interop.Errors.ERROR_PARTIAL_COPY, SR.EnumProcessModuleFailedDueToWow); } EnumProcessModulesUntilSuccess(processHandle, null, 0, out needed); } int modulesCount = needed / IntPtr.Size; IntPtr[] moduleHandles = new IntPtr[modulesCount]; while (true) { int size = needed; EnumProcessModulesUntilSuccess(processHandle, moduleHandles, size, out needed); if (size == needed) { break; } if (needed > size && needed / IntPtr.Size > modulesCount) { modulesCount = needed / IntPtr.Size; moduleHandles = new IntPtr[modulesCount]; } } var modules = new ProcessModuleCollection(firstModuleOnly ? 1 : modulesCount); char[] chars = ArrayPool <char> .Shared.Rent(1024); try { for (int i = 0; i < modulesCount; i++) { if (i > 0) { // If the user is only interested in the main module, break now. // This avoid some waste of time. In addition, if the application unloads a DLL // we will not get an exception. if (firstModuleOnly) { break; } } IntPtr moduleHandle = moduleHandles[i]; Interop.Kernel32.NtModuleInfo ntModuleInfo; if (!Interop.Kernel32.GetModuleInformation(processHandle, moduleHandle, out ntModuleInfo)) { HandleLastWin32Error(); continue; } var module = new ProcessModule() { ModuleMemorySize = ntModuleInfo.SizeOfImage, EntryPointAddress = ntModuleInfo.EntryPoint, BaseAddress = ntModuleInfo.BaseOfDll }; int length = Interop.Kernel32.GetModuleBaseName(processHandle, moduleHandle, chars, chars.Length); if (length == 0) { HandleLastWin32Error(); continue; } module.ModuleName = new string(chars, 0, length); length = Interop.Kernel32.GetModuleFileNameEx(processHandle, moduleHandle, chars, chars.Length); if (length == 0) { HandleLastWin32Error(); continue; } module.FileName = (length >= 4 && chars[0] == '\\' && chars[1] == '\\' && chars[2] == '?' && chars[3] == '\\') ? new string(chars, 4, length - 4) : new string(chars, 0, length); modules.Add(module); } } finally { ArrayPool <char> .Shared.Return(chars); } return(modules); } finally { if (!processHandle.IsInvalid) { processHandle.Dispose(); } } }
private static ProcessModuleCollection GetModules(int processId, bool firstModuleOnly) { // preserving Everett behavior. if (processId == SystemProcessID || processId == IdleProcessID) { // system process and idle process doesn't have any modules throw new Win32Exception(Interop.Errors.EFail, SR.EnumProcessModuleFailed); } SafeProcessHandle processHandle = SafeProcessHandle.InvalidHandle; try { processHandle = ProcessManager.OpenProcess(processId, Interop.Advapi32.ProcessOptions.PROCESS_QUERY_INFORMATION | Interop.Advapi32.ProcessOptions.PROCESS_VM_READ, true); IntPtr[] moduleHandles = new IntPtr[64]; GCHandle moduleHandlesArrayHandle = new GCHandle(); int moduleCount = 0; for (;;) { bool enumResult = false; try { moduleHandlesArrayHandle = GCHandle.Alloc(moduleHandles, GCHandleType.Pinned); enumResult = Interop.Kernel32.EnumProcessModules(processHandle, moduleHandlesArrayHandle.AddrOfPinnedObject(), moduleHandles.Length * IntPtr.Size, ref moduleCount); // The API we need to use to enumerate process modules differs on two factors: // 1) If our process is running in WOW64. // 2) The bitness of the process we wish to introspect. // // If we are not running in WOW64 or we ARE in WOW64 but want to inspect a 32 bit process // we can call psapi!EnumProcessModules. // // If we are running in WOW64 and we want to inspect the modules of a 64 bit process then // psapi!EnumProcessModules will return false with ERROR_PARTIAL_COPY (299). In this case we can't // do the enumeration at all. So we'll detect this case and bail out. // // Also, EnumProcessModules is not a reliable method to get the modules for a process. // If OS loader is touching module information, this method might fail and copy part of the data. // This is no easy solution to this problem. The only reliable way to fix this is to // suspend all the threads in target process. Of course we don't want to do this in Process class. // So we just to try avoid the race by calling the same method 50 (an arbitrary number) times. // if (!enumResult) { bool sourceProcessIsWow64 = false; bool targetProcessIsWow64 = false; SafeProcessHandle hCurProcess = SafeProcessHandle.InvalidHandle; try { hCurProcess = ProcessManager.OpenProcess(unchecked ((int)Interop.Kernel32.GetCurrentProcessId()), Interop.Advapi32.ProcessOptions.PROCESS_QUERY_INFORMATION, true); bool wow64Ret; wow64Ret = Interop.Kernel32.IsWow64Process(hCurProcess, ref sourceProcessIsWow64); if (!wow64Ret) { throw new Win32Exception(); } wow64Ret = Interop.Kernel32.IsWow64Process(processHandle, ref targetProcessIsWow64); if (!wow64Ret) { throw new Win32Exception(); } if (sourceProcessIsWow64 && !targetProcessIsWow64) { // Wow64 isn't going to allow this to happen, the best we can do is give a descriptive error to the user. throw new Win32Exception(Interop.Errors.ERROR_PARTIAL_COPY, SR.EnumProcessModuleFailedDueToWow); } } finally { if (hCurProcess != SafeProcessHandle.InvalidHandle) { hCurProcess.Dispose(); } } // If the failure wasn't due to Wow64, try again. for (int i = 0; i < 50; i++) { enumResult = Interop.Kernel32.EnumProcessModules(processHandle, moduleHandlesArrayHandle.AddrOfPinnedObject(), moduleHandles.Length * IntPtr.Size, ref moduleCount); if (enumResult) { break; } Thread.Sleep(1); } } } finally { moduleHandlesArrayHandle.Free(); } if (!enumResult) { throw new Win32Exception(); } moduleCount /= IntPtr.Size; if (moduleCount <= moduleHandles.Length) { break; } moduleHandles = new IntPtr[moduleHandles.Length * 2]; } var modules = new ProcessModuleCollection(firstModuleOnly ? 1 : moduleCount); char[] chars = new char[1024]; for (int i = 0; i < moduleCount; i++) { if (i > 0) { // If the user is only interested in the main module, break now. // This avoid some waste of time. In addition, if the application unloads a DLL // we will not get an exception. if (firstModuleOnly) { break; } } IntPtr moduleHandle = moduleHandles[i]; Interop.Kernel32.NtModuleInfo ntModuleInfo; if (!Interop.Kernel32.GetModuleInformation(processHandle, moduleHandle, out ntModuleInfo)) { HandleError(); continue; } var module = new ProcessModule() { ModuleMemorySize = ntModuleInfo.SizeOfImage, EntryPointAddress = ntModuleInfo.EntryPoint, BaseAddress = ntModuleInfo.BaseOfDll }; int length = Interop.Kernel32.GetModuleBaseName(processHandle, moduleHandle, chars, chars.Length); if (length == 0) { HandleError(); continue; } module.ModuleName = new string(chars, 0, length); length = Interop.Kernel32.GetModuleFileNameEx(processHandle, moduleHandle, chars, chars.Length); if (length == 0) { HandleError(); continue; } module.FileName = (length >= 4 && chars[0] == '\\' && chars[1] == '\\' && chars[2] == '?' && chars[3] == '\\') ? new string(chars, 4, length - 4) : new string(chars, 0, length); modules.Add(module); } return(modules); } finally { if (!processHandle.IsInvalid) { processHandle.Dispose(); } } }
private static ProcessModuleCollection GetModules(int processId, bool firstModuleOnly) { // preserving Everett behavior. if (processId == SystemProcessID || processId == IdleProcessID) { // system process and idle process doesn't have any modules throw new Win32Exception(Interop.Errors.EFail, SR.EnumProcessModuleFailed); } SafeProcessHandle processHandle = SafeProcessHandle.InvalidHandle; try { processHandle = ProcessManager.OpenProcess(processId, Interop.Advapi32.ProcessOptions.PROCESS_QUERY_INFORMATION | Interop.Advapi32.ProcessOptions.PROCESS_VM_READ, true); IntPtr[] moduleHandles = new IntPtr[64]; GCHandle moduleHandlesArrayHandle = new GCHandle(); int moduleCount = 0; for (; ; ) { bool enumResult = false; try { moduleHandlesArrayHandle = GCHandle.Alloc(moduleHandles, GCHandleType.Pinned); enumResult = Interop.Kernel32.EnumProcessModules(processHandle, moduleHandlesArrayHandle.AddrOfPinnedObject(), moduleHandles.Length * IntPtr.Size, ref moduleCount); // The API we need to use to enumerate process modules differs on two factors: // 1) If our process is running in WOW64. // 2) The bitness of the process we wish to introspect. // // If we are not running in WOW64 or we ARE in WOW64 but want to inspect a 32 bit process // we can call psapi!EnumProcessModules. // // If we are running in WOW64 and we want to inspect the modules of a 64 bit process then // psapi!EnumProcessModules will return false with ERROR_PARTIAL_COPY (299). In this case we can't // do the enumeration at all. So we'll detect this case and bail out. // // Also, EnumProcessModules is not a reliable method to get the modules for a process. // If OS loader is touching module information, this method might fail and copy part of the data. // This is no easy solution to this problem. The only reliable way to fix this is to // suspend all the threads in target process. Of course we don't want to do this in Process class. // So we just to try avoid the race by calling the same method 50 (an arbitrary number) times. // if (!enumResult) { bool sourceProcessIsWow64 = false; bool targetProcessIsWow64 = false; SafeProcessHandle hCurProcess = SafeProcessHandle.InvalidHandle; try { hCurProcess = ProcessManager.OpenProcess(unchecked((int)Interop.Kernel32.GetCurrentProcessId()), Interop.Advapi32.ProcessOptions.PROCESS_QUERY_INFORMATION, true); bool wow64Ret; wow64Ret = Interop.Kernel32.IsWow64Process(hCurProcess, ref sourceProcessIsWow64); if (!wow64Ret) { throw new Win32Exception(); } wow64Ret = Interop.Kernel32.IsWow64Process(processHandle, ref targetProcessIsWow64); if (!wow64Ret) { throw new Win32Exception(); } if (sourceProcessIsWow64 && !targetProcessIsWow64) { // Wow64 isn't going to allow this to happen, the best we can do is give a descriptive error to the user. throw new Win32Exception(Interop.Errors.ERROR_PARTIAL_COPY, SR.EnumProcessModuleFailedDueToWow); } } finally { if (hCurProcess != SafeProcessHandle.InvalidHandle) { hCurProcess.Dispose(); } } // If the failure wasn't due to Wow64, try again. for (int i = 0; i < 50; i++) { enumResult = Interop.Kernel32.EnumProcessModules(processHandle, moduleHandlesArrayHandle.AddrOfPinnedObject(), moduleHandles.Length * IntPtr.Size, ref moduleCount); if (enumResult) { break; } Thread.Sleep(1); } } } finally { moduleHandlesArrayHandle.Free(); } if (!enumResult) { throw new Win32Exception(); } moduleCount /= IntPtr.Size; if (moduleCount <= moduleHandles.Length) break; moduleHandles = new IntPtr[moduleHandles.Length * 2]; } var modules = new ProcessModuleCollection(firstModuleOnly ? 1 : moduleCount); char[] chars = new char[1024]; for (int i = 0; i < moduleCount; i++) { if (i > 0) { // If the user is only interested in the main module, break now. // This avoid some waste of time. In addition, if the application unloads a DLL // we will not get an exception. if (firstModuleOnly) { break; } } IntPtr moduleHandle = moduleHandles[i]; Interop.Kernel32.NtModuleInfo ntModuleInfo; if (!Interop.Kernel32.GetModuleInformation(processHandle, moduleHandle, out ntModuleInfo)) { HandleError(); continue; } var module = new ProcessModule() { ModuleMemorySize = ntModuleInfo.SizeOfImage, EntryPointAddress = ntModuleInfo.EntryPoint, BaseAddress = ntModuleInfo.BaseOfDll }; int length = Interop.Kernel32.GetModuleBaseName(processHandle, moduleHandle, chars, chars.Length); if (length == 0) { HandleError(); continue; } module.ModuleName = new string(chars, 0, length); length = Interop.Kernel32.GetModuleFileNameEx(processHandle, moduleHandle, chars, chars.Length); if (length == 0) { HandleError(); continue; } module.FileName = (length >= 4 && chars[0] == '\\' && chars[1] == '\\' && chars[2] == '?' && chars[3] == '\\') ? new string(chars, 4, length - 4) : new string(chars, 0, length); modules.Add(module); } return modules; } finally { #if FEATURE_TRACESWITCH Debug.WriteLineIf(Process._processTracing.TraceVerbose, "Process - CloseHandle(process)"); #endif if (!processHandle.IsInvalid) { processHandle.Dispose(); } } }