C#将IntPtr转换为int

我正在动态调用Windows API。 我在网上发现了一些可以做到这一点的代码,我对此非常感兴趣。 至少可以说,这个想法本身就很棒。 但是,我似乎无法使其适用于我的代码。 动态调用的参数类型为stringstring int[] ,我想使用API GetThreadContext ,其参数为pInfo.hThredref ctx (如下所示)。

API调用

 GetThreadContext(pInfo.hThread, ref ctx); 

上面的代码将调用GetThreadContext API(假设它在我的项目中声明) – 并且工作得很好。 然而,动态调用的美妙之处在于不需要声明。 所以,我尝试动态调用:

 ctx = new CONTEXT {ContextFlags = 0x10007}; PROCESS_INFORMATION pInfo; CInvokeAPI.Invoke("kernel32","GetThreadContext",pInfo.hThread, ctx); 

这里的问题是我不知道如何将参数ctx作为类型int传递,因为它是一个结构。

请参阅下面的其他代码

  [StructLayout(LayoutKind.Sequential)] struct CONTEXT { public uint ContextFlags; unsafe fixed byte unused[160]; public uint Ebx; public uint Edx; public uint Ecx; public uint Eax; unsafe fixed byte unused2[24]; } [StructLayout(LayoutKind.Sequential)] struct PROCESS_INFORMATION { public IntPtr hProcess; public IntPtr hThread; public int dwProcessId; public int dwThreadId; } 

调用API动态类

 using System; using System.Runtime.InteropServices; using System.Text; /* * Title: CInvokeAPI.cs * Description: Call API by name implementation in purely managed C# (no 'unsafe' mess here). * * Developed by: affixiate * Comments: If you use this code, I require you to give me credits. */ public static class CInvokeAPI { ///  /// Generates a new, non-garbage collectable string in memory. Use this with Unicode "W" API. ///  /// A Unicode string. /// Address of newly allocated string in memory. Remember to free it after use. public static int StringToPtrW(string theString) { return StringToPtr(Encoding.Unicode.GetBytes(theString)); } ///  /// Generates a new, non-garbage collectable string in memory. Use this with ANSI "A" API. ///  /// An ANSII string. /// Address of newly allocated string in memory. Remember to free it after use. public static int StringToPtrA(string theString) { return StringToPtr(Encoding.ASCII.GetBytes(theString)); } ///  /// Internal method used to allocate memory. ///  /// A byte buffer. /// Address of newly allocated memory. Remember to free it after use. private static int StringToPtr(byte[] buf) { return (int)GCHandle.Alloc(buf, GCHandleType.Pinned).AddrOfPinnedObject(); } ///  /// Invokes the specified Windows API. ///  /// Name of the library. /// Name of the function. /// The arguments. /// True if function succeeds, otherwise false. public static bool Invoke(string libraryName, string functionName, params int[] args) { /* Sanity checks. */ IntPtr hLoadLibrary = LoadLibrary(libraryName); if (hLoadLibrary == IntPtr.Zero) return false; IntPtr hGetProcAddress = GetProcAddress(hLoadLibrary, functionName); if (hGetProcAddress == IntPtr.Zero) return false; // Allocates more than enough memory for an stdcall and the parameters of a WinAPI function IntPtr hMemory = VirtualAlloc(IntPtr.Zero, 1024 * 1024, MEM_COMMIT | MEM_RESERVE, MEM_EXECUTE_READWRITE); if (hMemory == IntPtr.Zero) return false; IntPtr hMemoryItr = hMemory; // Prepends the stdcall header signature Marshal.Copy(new byte[] {0x55, 0x89, 0xE5}, 0, hMemoryItr, 0x3); hMemoryItr = (IntPtr)((int)hMemoryItr + 0x3); // Loop through the passed in arguments and place them on the stack in reverse order for (int i = (args.Length - 1); i >= 0; i--) { Marshal.Copy(new byte[] {0x68}, 0, hMemoryItr, 0x1); hMemoryItr = (IntPtr)((int)hMemoryItr + 0x1); Marshal.Copy(BitConverter.GetBytes(args[i]), 0, hMemoryItr, 0x4); hMemoryItr = (IntPtr)((int)hMemoryItr + 0x4); } Marshal.Copy(new byte[] {0xE8}, 0, hMemoryItr, 0x1); hMemoryItr = (IntPtr)((int)hMemoryItr + 0x1); Marshal.Copy(BitConverter.GetBytes((int)hGetProcAddress - (int)hMemoryItr - 0x4), 0, hMemoryItr, 0x4); hMemoryItr = (IntPtr)((int)hMemoryItr + 0x4); // Cleaning up the stack Marshal.Copy(new byte[] {0x5D, 0xC2, 0x4, 0x0 /* <= I made a LOL. */}, 0, hMemoryItr, 0x4); // Don't forget to increment if you are adding more ASM code here: hMemoryItr = (IntPtr)((int)hMemoryItr + 0x4); try { var executeAsm = (RunAsm) Marshal.GetDelegateForFunctionPointer(hMemory, typeof (RunAsm)); executeAsm(); } catch { return false; } // Clean up the memory we allocated to do the dirty work VirtualFree(hMemory, 0, MEM_RELEASE); return true; } // ReSharper disable InconsistentNaming private const uint MEM_RELEASE = 0x8000; private const uint MEM_COMMIT = 0x1000; private const uint MEM_RESERVE = 0x2000; private const uint MEM_EXECUTE_READWRITE = 0x40; // ReSharper restore InconsistentNaming // My own sexy delegate: [UnmanagedFunctionPointer(CallingConvention.StdCall, SetLastError = true)] private delegate void RunAsm(); // WinAPI used: [DllImport("kernel32.dll", SetLastError = true)] private static extern bool VirtualFree(IntPtr lpAddress, UInt32 dwSize, uint dwFreeType); [DllImport("kernel32.dll", SetLastError = true)] private static extern IntPtr VirtualAlloc(IntPtr lpAddress, UInt32 dwSize, uint flAllocationType, uint flProtect); [DllImport("kernel32.dll", SetLastError = true)] private static extern IntPtr LoadLibrary(string lpFileName); [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Ansi)] private static extern IntPtr GetProcAddress(IntPtr hModule, string lpProcName); } 

你能使用IntPtr.ToInt32方法吗? 这应该适用于第一个参数。 虽然不确定结构转换。

也许看看这篇文章 ,了解如何将结构转换为整数的想法。

更新:

在C#中没有直接的C#等价的VarPtr,但我确实找到了这里引用的手册(以及它正在做什么的解释……听起来类似于这篇文章中对VarPtr的解释)。 这是代码的摘录。 它可能对您有用:

 public static int VarPtr(object e) { GCHandle GC = GCHandle.Alloc(e, GCHandleType.Pinned); int gc = GC.AddrOfPinnedObject().ToInt32(); GC.Free(); return gc; } 

注意:此function存在一些潜在的缺陷,如本文所述。