internal static unsafe bool GetModuleInformation(SafeProcessHandle processHandle, IntPtr moduleHandle, out NtModuleInfo ntModuleInfo) => GetModuleInformation(processHandle, moduleHandle, out ntModuleInfo, sizeof(NtModuleInfo));
public static extern bool GetModuleInformation(SafeProcessHandle processHandle, IntPtr moduleHandle, NtModuleInfo ntModuleInfo, int size);
private static extern bool GetModuleInformation(SafeProcessHandle processHandle, IntPtr moduleHandle, out NtModuleInfo ntModuleInfo, int size);
private static ModuleInfo[] NtGetModuleInfos(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.EFail,SR.GetString(SR.EnumProcessModuleFailed)); //} IntPtr processHandle = IntPtr.Zero; try { // PROCESS_QUERY_INFORMATION | PROCESS_VM_READ processHandle = OpenProcess(ProcessAccess.QueryInformation | ProcessAccess.VMRead, false, processId); IntPtr[] moduleHandles = new IntPtr[64]; GCHandle moduleHandlesArrayHandle = new GCHandle(); int moduleCount = 0; for (;;) { bool enumResult = false; try { moduleHandlesArrayHandle = GCHandle.Alloc(moduleHandles, GCHandleType.Pinned); enumResult = 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 ---- by calling the same method 50 (an arbitary number) times. // if (!enumResult) { bool sourceProcessIsWow64 = false; bool targetProcessIsWow64 = false; if (!IsOSOlderThanXP()) { IntPtr hCurProcess = IntPtr.Zero; try { hCurProcess = OpenProcess(ProcessAccess.QueryInformation, true, GetCurrentProcessId()); bool wow64Ret; wow64Ret = IsWow64Process(hCurProcess, out sourceProcessIsWow64); if (!wow64Ret) { return(null); } wow64Ret = IsWow64Process(processHandle, out targetProcessIsWow64); if (!wow64Ret) { return(null); } 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(299 /* ERROR_PARTIAL_COPY */, // SR.GetString(SR.EnumProcessModuleFailedDueToWow)); return(null); } } finally { if (hCurProcess != IntPtr.Zero) { CloseHandle(hCurProcess); } } } // If the failure wasn't due to Wow64, try again. for (int i = 0; i < 50; i++) { enumResult = EnumProcessModules(processHandle, moduleHandlesArrayHandle.AddrOfPinnedObject(), moduleHandles.Length * IntPtr.Size, ref moduleCount); if (enumResult) { break; } Thread.Sleep(1); } } } finally { moduleHandlesArrayHandle.Free(); } if (!enumResult) { return(null); } moduleCount /= IntPtr.Size; if (moduleCount <= moduleHandles.Length) { break; } moduleHandles = new IntPtr[moduleHandles.Length * 2]; } ArrayList moduleInfos = new ArrayList(); int ret; for (int i = 0; i < moduleCount; i++) { ModuleInfo moduleInfo = new ModuleInfo(); IntPtr moduleHandle = moduleHandles[i]; NtModuleInfo ntModuleInfo = new NtModuleInfo(); if (!GetModuleInformation(processHandle, new HandleRef(null, moduleHandle), ntModuleInfo, Marshal.SizeOf(ntModuleInfo))) { return(null); } moduleInfo.sizeOfImage = ntModuleInfo.SizeOfImage; moduleInfo.entryPoint = ntModuleInfo.EntryPoint; moduleInfo.baseOfDll = ntModuleInfo.BaseOfDll; StringBuilder baseName = new StringBuilder(1024); ret = GetModuleBaseName(processHandle, new HandleRef(null, moduleHandle), baseName, baseName.Capacity * 2); if (ret == 0) { return(null); } ; moduleInfo.baseName = baseName.ToString(); StringBuilder fileName = new StringBuilder(1024); ret = GetModuleFileNameEx(processHandle, new HandleRef(null, moduleHandle), fileName, fileName.Capacity * 2); if (ret == 0) { return(null); } ; moduleInfo.fileName = fileName.ToString(); // smss.exe is started before the win32 subsystem so it get this funny "\systemroot\.." path. // We change this to the actual path by appending "smss.exe" to GetSystemDirectory() if (string.Compare(moduleInfo.fileName, "\\SystemRoot\\System32\\smss.exe", StringComparison.OrdinalIgnoreCase) == 0) { moduleInfo.fileName = Path.Combine(Environment.SystemDirectory, "smss.exe"); } // Avoid returning Unicode-style long string paths. IO methods cannot handle them. if (moduleInfo.fileName != null && moduleInfo.fileName.Length >= 4 && moduleInfo.fileName.StartsWith(@"\\?\", StringComparison.Ordinal)) { moduleInfo.fileName = moduleInfo.fileName.Substring(4); } moduleInfos.Add(moduleInfo); // // 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; } } ModuleInfo[] temp = new ModuleInfo[moduleInfos.Count]; moduleInfos.CopyTo(temp, 0); return(temp); } finally { //Debug.WriteLineIf(Process.processTracing.TraceVerbose, "Process - CloseHandle(process)"); if (processHandle != IntPtr.Zero) { CloseHandle(processHandle); } } }
public static extern bool GetModuleInformation(IntPtr processHandle, HandleRef moduleHandle, NtModuleInfo ntModuleInfo, int size);
internal static bool GetModuleInformation(SafeProcessHandle processHandle, IntPtr moduleHandle, out NtModuleInfo ntModuleInfo) => GetModuleInformation(processHandle, moduleHandle, out ntModuleInfo, NtModuleInfo.s_sizeOf);
public static extern bool GetModuleInformation(Microsoft.Win32.SafeHandles.SafeProcessHandle processHandle, HandleRef moduleHandle, NtModuleInfo ntModuleInfo, int size);