使用PInvoke调用ReadProcessMemory读取PEB时出现“无效句柄”错误
问题:通过PInvoke读取进程PEB的ImageBaseAddress时ReadProcessMemory返回无效句柄
我在C#中通过PInvoke调用Win32 API创建进程后,尝试读取该进程PEB中的ImageBaseAddress值,但ReadProcessMemory调用返回false执行失败。最初未能正确获取Win32错误信息,修正后得知错误为无效句柄。
代码实现
using System.ComponentModel; using System.Runtime.InteropServices; using System; namespace ReadProcess { class Program { [StructLayout(LayoutKind.Sequential)] internal struct PROCESS_INFORMATION { public IntPtr hProcess; public IntPtr hThread; public int dwProcessId; public int dwThreadId; } [StructLayout(LayoutKind.Sequential)] internal struct STARTUPINFO { uint cb; IntPtr lpReserved; IntPtr lpDesktop; IntPtr lpTitle; uint dwX; uint dwY; uint dwXSize; uint dwYSize; uint dwXCountChars; uint dwYCountChars; uint dwFillAttributes; uint dwFlags; ushort wShowWindow; ushort cbReserved; IntPtr lpReserved2; IntPtr hStdInput; IntPtr hStdOutput; IntPtr hStdErr; } [StructLayout(LayoutKind.Sequential)] internal struct PROCESS_BASIC_INFORMATION { public IntPtr ExitStatus; public IntPtr PebAddress; public IntPtr AffinityMask; public IntPtr BasePriority; public IntPtr UniquePID; public IntPtr InheritedFromUniqueProcessId; } [DllImport("kernel32.dll", SetLastError = true)] static extern bool ReadProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, [Out] byte[] lpBuffer, int dwSize, out IntPtr lpNumberOfBytesRead); [DllImport("ntdll.dll", SetLastError = true)] static extern int NtQueryInformationProcess(IntPtr processHandle, int processInformationClass, IntPtr processInformation, uint processInformationLength, IntPtr returnLength); [DllImport("kernel32.dll")] static extern bool CloseHandle(IntPtr hProcess); [DllImport("kernel32.dll", SetLastError = true)] static extern bool CreateProcess(IntPtr lpApplicationName, string lpCommandLine, IntPtr lpProcAttribs, IntPtr lpThreadAttribs, bool bInheritHandles, uint dwCreateFlags, IntPtr lpEnvironment, IntPtr lpCurrentDir, [In] ref STARTUPINFO lpStartinfo, out PROCESS_INFORMATION lpProcInformation); public static IntPtr GetPEBAddress(IntPtr hProcess) { //Allocate memory for a new PROCESS_BASIC_INFORMATION structure IntPtr pbi = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(PROCESS_BASIC_INFORMATION))); //Allocate memory for a long IntPtr outLong = Marshal.AllocHGlobal(sizeof(long)); IntPtr outPtr = IntPtr.Zero; int queryStatus = 0; //Store API call success in a boolean queryStatus = NtQueryInformationProcess(hProcess, 0, pbi, (uint)Marshal.SizeOf(typeof(PROCESS_BASIC_INFORMATION)), outLong); //Close handle and free allocated memory CloseHandle(hProcess); Marshal.FreeHGlobal(outLong); //STATUS_SUCCESS = 0, so if API call was successful querySuccess should contain 0 ergo we reverse the check. if (queryStatus == 0) outPtr = Marshal.PtrToStructure<PROCESS_BASIC_INFORMATION>(pbi).PebAddress; //Free allocated space Marshal.FreeHGlobal(pbi); //Return pointer to PEB base address return outPtr; } static void Main(string[] args) { STARTUPINFO startInfo = new STARTUPINFO(); PROCESS_INFORMATION procInfo = new PROCESS_INFORMATION(); CreateProcess((IntPtr)0, "notepad", (IntPtr)0, (IntPtr)0, false, 0x00000004, (IntPtr)0, (IntPtr)0, ref startInfo, out procInfo); byte[] ImageBaseAddress = new byte[IntPtr.Size]; IntPtr lpNumberOfBytesRead; IntPtr pPEB = GetPEBAddress(procInfo.hProcess); ReadProcessMemory(procInfo.hProcess, pPEB + 16, ImageBaseAddress, 8, out lpNumberOfBytesRead); string errorMessage = new Win32Exception(Marshal.GetLastWin32Error()).Message; Console.WriteLine("File handle: 0x{0:X16}", procInfo.hProcess); Console.WriteLine("PEB base address: 0x{0:X16}", pPEB); Console.WriteLine("Last Win32 Error: {0}", errorMessage); } } }
相关截图
- 截图1:程序输出与WinDBG附加到记事本进程后执行
!peb命令的输出对比 - 截图2:Visual Studio调试器截图,断点在
ReadProcessMemory调用后的Console.WriteLine处,显示PEB基地址识别正确
内容的提问来源于stack exchange,提问作者redpanda2236
相关产品推荐
相关产品推荐

