如何获取托管类的原始内存指针?

如何在C#中找到指向托管类的原始指针,希望它是内存中的原始大小? 显然,CLR不允许这样做 – 更确切地说,严格禁止,因为管理类的非托管表示永远不应该出于稳定性和安全性原因而被处理 – 所以我正在寻找一个黑客。 我不是在寻找序列化 – 我确实需要托管类的转储,因为它在原始内存中表示。

更准确地说,我在下面的例子中寻找类似函数getObjectPtr东西:

 IntPtr getObjectPtr(Object managedClass) {...} void main() { var test=new TestClass(); IntPtr* ptr_to_test=getObjectPtr(test); Console.WriteLine(ptr_to_test.ToString()); } 

提前致谢!

编辑:我终于找到了自己的解决方案,并且当回来发布它作为答案时,对于已经发布的答案很快就完全感到惊讶…感谢大家! 这非常快,完全出乎意料。

最接近我的解决方案是@thehennyy的一个,但是我没有发布它,因为@Chino提出了更好的一个(抱歉我一开始就把它弄错了,我只是忘了再次取消引用指针)。 它不需要代码不安全,而且要求GC更容忍:

 class Program { // Here is the function in case anyone needs it. // Note, though, it does not preserve the handle while you work with // pointer, so it is less reliable than the code in Main(): static IntPtr getPointerToObject(Object unmanagedObject) { GCHandle gcHandle = GCHandle.Alloc(unmanagedObject, GCHandleType.WeakTrackResurrection); IntPtr thePointer = Marshal.ReadIntPtr(GCHandle.ToIntPtr(gcHandle)); gcHandle.Free(); return thePointer; } class TestClass { uint a = 0xDEADBEEF; } static void Main(string[] args) { byte[] cls = new byte[16]; var test = new TestClass(); GCHandle gcHandle = GCHandle.Alloc(test, GCHandleType.WeakTrackResurrection); IntPtr thePointer = Marshal.ReadIntPtr(GCHandle.ToIntPtr(gcHandle)); Marshal.Copy(thePointer, cls, 0, 16); //Dump first 16 bytes... Console.WriteLine(BitConverter.ToString(BitConverter.GetBytes(thePointer.ToInt32()))); Console.WriteLine(BitConverter.ToString(cls)); Console.ReadLine(); gcHandle.Free(); } } /* Example output (yours should be different): 40-23-CA-02 4C-38-04-01-EF-BE-AD-DE-00-00-00-80-B4-21-50-73 That field's value is "EF-BE-AD-DE", 0xDEADBEEF as it is stored in memory. Yay, we found it! */ 

Hovewer,现在我有点无能为力。 根据这篇文章,类中的前2个地址应该是指向SyncBlock和RTTI结构的指针,因此第一个字段的地址必须偏移2个字[32位系统中的8个字节,64位系统中的16个字节]从最开始。 我的是64位; 但是,正如您在输出中看到的那样,很明显第一个字段与对象地址的原始偏移量仅为4个字节,这没有任何意义。

我已将此问作为一个单独的问题 。 也许我应该将此问作为一个单独的问题,但我的解决方案可能存在错误。

嘿这就是你想要的吗?:

 GCHandle gcHandle = GCHandle.Alloc(yourObject,GCHandleType.WeakTrackResurrection); IntPtr thePointer = GCHandle.ToIntPtr(gcHandle); 

您可以编写一个泄漏对象地址的小型IL函数。

 var o = new object(); var d = new DynamicMethod("GetPtr", typeof(IntPtr), new Type[] {typeof(object)}, Assembly.GetExecutingAssembly().ManifestModule); var il = d.GetILGenerator(); il.Emit(OpCodes.Ldarg_0); il.Emit(OpCodes.Ret); var address = (IntPtr)d.Invoke(null, new object[] {o}); Console.WriteLine(address); 

来源是: IllidanS4 / SharpUtils / UnsafeTools.cs