如何在运行时将SyncBlockIndex和对象实例类型更改为不兼容?

时间:2014-02-26 07:15:44

标签: c# clr

需要在运行时更改SyncBlockIndex和对象的类型。例如:

class A { ... }
class B { ... }

A a = new A();
B b = (?)a;

我知道这很愚蠢,但我认为这是可能的:)

1 个答案:

答案 0 :(得分:1)

经过一番调查后,我发现了如何更改SyncBlockIndex和EEClass(实际上是对象的类型)运行时。要执行此操作,请将以下列表中的'n'paste复制到新创建的控制台应用程序并在32-bit目标上运行(在64-bit目标UInt32上应更改为UInt64)

专业提示:GCHandle.Alloc().AddrOfPinnedObject()和其他GCHandle方法返回的不是对象的地址,而是其他内容,如“同义词”。

结果:

using System;
using System.Runtime.InteropServices;

namespace ConsoleTest
{
    public static class ObjectGCEx
    {
        public static unsafe ObjContents *GetGCFields(this object obj)
        {
            return (ObjContents*)((new ObjPointer { Object = obj }).Pointer);
        }

        /// <summary>
        /// Gets private GC object's fields SyncBlockIndex and EEClass struct pointer
        /// </summary>
        public static unsafe void GetGCFields(this object obj, out UInt32 syncBlockIndex, out UInt32 eeClass)
        {
            var contents = (ObjContents*)((new ObjPointer { Object = obj }).Pointer);
            syncBlockIndex = contents->syncBlockIndex;
            eeClass = contents->eeClass;
        }


        /// <summary>
        /// Gets private GC object's fields SyncBlockIndex and EEClass struct pointer
        /// </summary>
        public static unsafe UInt32 GetSyncBlockIndex(this object obj)
        {
            var contents = (ObjContents*)((new ObjPointer { Object = obj }).Pointer);
            return contents->syncBlockIndex;
        }

        /// <summary>
        /// Gets private GC object's fields SyncBlockIndex and EEClass struct pointer
        /// </summary>
        public static unsafe UInt32 GetEEClass(this object obj)
        {
            var contents = (ObjContents*)((new ObjPointer { Object = obj }).Pointer);
            return contents->eeClass;
        }

        /// <summary>
        /// Sets private GC object's field SyncBlockIndex, which is actually index in private GC table.
        /// </summary>
        /// <param name="obj">Object with SyncBlockIndex to be changed</param>
        /// <param name="syncBlockIndex">New value of SyncBlockIndex</param>
        public static unsafe void SetSyncBlockIndex(this object obj, UInt32 syncBlockIndex)
        {
            var contents = (ObjContents*)((new ObjPointer { Object = obj }).Pointer);
            contents->syncBlockIndex = syncBlockIndex;
        }

        /// <summary>
        /// Sets private GC object's field EEClass, which is actually describes current class pointer
        /// </summary>
        /// <param name="obj">Object with SyncBlockIndex to be changed</param>
        /// <param name="syncBlockIndex">New value of SyncBlockIndex</param>
        public static unsafe void SetEEClass(this object obj, UInt32 eeClass)
        {
            var contents = (ObjContents*)((new ObjPointer { Object = obj }).Pointer);
            contents->eeClass = eeClass;
        }
    }

    [StructLayout(LayoutKind.Explicit)]
    public struct ObjPointer
    {
        [FieldOffset(0)]
        internal object Object;

        [FieldOffset(4)]
        internal uint _pointer;

        internal unsafe uint Pointer
        {
            get {
                fixed(uint *pp = &_pointer)
                {
                    return *(uint *)((uint)pp - sizeof(uint)) - sizeof(uint);
                }
            }
        }
    }

    [StructLayout(LayoutKind.Explicit)]
    public struct ObjContents
    {
        [FieldOffset(0)]
        public UInt32 syncBlockIndex;

        [FieldOffset(4)]
        public UInt32 eeClass;

        [FieldOffset(8)]
        public byte fieldsStart;
    }

    public class MainClass      
    {
        public class Person
        {
            public int x = 123;

            public override string ToString()
            {
                return "From Person";
            }
        }

        public class Customer
        {
            public override string ToString()
            {
                return "From Customer";
            }
        }

        public unsafe static void Main(string[] args)
        {
            var first = new Person();
            var second = new Customer();

            unsafe
            {
                Console.WriteLine("type of first: {0}, ToString(): {1}", first.GetType().Name, first);

                first.SetEEClass(second.GetEEClass());

                Console.WriteLine("type of first: {0}, ToString(): {1}", first.GetType().Name, first);
            }

            Console.ReadKey();
        }
    }
}

产地:

type of first: Person, ToString(): From Person
type of first: Customer, ToString(): From Customer

对于同一个对象。此代码不受GC集合保护。

单声道相关

单声道内存不同。它从对象的开始(不是来自.Net Framework的-1字)开始,而SyncBlockIndex是第二个位置,而不是第一个位置。并且SyncBlockInex不是索引,而是指向同步结构的指针。

在GitHub上作为库发布

https://github.com/mumusan/dotnetex