首页 > 其他分享 >Cecil修改UnityDll,不使用反射就能调用internal的函数

Cecil修改UnityDll,不使用反射就能调用internal的函数

时间:2025-01-19 16:23:32浏览次数:1  
标签:assemblyDef UnityDll 程序 private dll internal var new Cecil

简介

在Unity Editor开发过程中,我们会经常使用反射调用一些unity还没开放的接口,比如s_LastControlID, 但每个程序集都写一边反射不免显得有些麻烦。
本篇文章将介绍注入InternalsVisibleToAttribute注解到unity dll的方法,来帮助大家更便捷地调用unity 的内部函数。

思路

InternalsVisibleToAttribute可以为当前程序集添加友元程序集,友元程序集可以调用当前程序集的internal函数。

Cecil可以编辑当前程序集的IL代码和元数据。 那么如果我们在unity dll的元数据中将Assembly-Csharp程序集添加为友元,那么就能实现Assembly-Csharp调用对应unity dll的internal函数。

代码及使用方法

核心类是AssemblyHacker, 通过传入目标程序集的绝对路径和友元程序集的FullName,可以实现添加友元程序集的效果。

    internal class AssemblyHacker
    {

        private string targetAsmFileName;
        private AssemblyDefinition assemblyDef;

        private DefaultAssemblyResolver assemblyResolver;


        //targetAsms是 需要修改的dll绝对路径的集合
        //friedns是友元程序集的FullName
        public static void Hack(ICollection<string> targetAsms, ICollection<string> friends)
        {

            foreach (var targetAsm in targetAsms)
            {
                var hacker = new AssemblyHacker();
                hacker.SetAssembly(targetAsm);

                hacker.Work(friends);

                //dispose Assembly不会清除 resolver里面缓存的 引用Assembly,需要手动清理
                hacker.assemblyResolver.Dispose();
            }
        }

        private void SetAssembly(string assemblyName)
        {
            targetAsmFileName = assemblyName;

            if (assemblyResolver == null)
            {

                assemblyResolver = new DefaultAssemblyResolver();
                var targetDirName = Path.GetDirectoryName(targetAsmFileName);
                var targetDirName2 = Path.GetDirectoryName(targetDirName);
                assemblyResolver.AddSearchDirectory(targetDirName);
                assemblyResolver.AddSearchDirectory(targetDirName2);
            }

            assemblyDef = AssemblyDefinition.ReadAssembly(targetAsmFileName,
                new ReaderParameters { AssemblyResolver = assemblyResolver, ReadWrite = true });


        }


        private void Work(ICollection<string> friends)
        {

            AddFriendForTarget(friends);

        }

        private void AddFriendForTarget(ICollection<string> friends)
        {

            var friendAssemblyList = friends.ToList();

            var assemblyAttrs = assemblyDef.CustomAttributes;

            //如果已经是友元程序集,忽略它。
            foreach (var assemblyAttr in assemblyAttrs)
            {
                if (assemblyAttr.AttributeType.FullName.Equals(typeof(InternalsVisibleToAttribute).FullName))
                {
                    var oldFriendAssembly = assemblyAttr.ConstructorArguments[0].Value.ToString();

                    friendAssemblyList.Remove(oldFriendAssembly);
                }
            }


            //var attrType = GetInternalsVisibleType();
            var attrType = assemblyDef.MainModule.ImportReference(typeof(InternalsVisibleToAttribute));
            var attCtor = attrType.Resolve().Methods.First(x => x.Name == ".ctor" && x.Parameters.Count == 1);

            MethodReference attrCtorMethodRef;
            attrCtorMethodRef = assemblyDef.MainModule.ImportReference(attCtor);


            foreach (var friend in friendAssemblyList)
            {
                var attr = new CustomAttribute(attrCtorMethodRef);
                attr.ConstructorArguments.Add(new CustomAttributeArgument(attrType, friend));

                assemblyAttrs.Add(attr);
            }

            //var newAssemblyFile = targetAsmFileName.Replace(".dll", "New.dll");
            assemblyDef.Write();

            assemblyDef.Dispose();

            //Console.WriteLine("write result to " + newAssemblyFile);

        }

        private TypeReference GetInternalsVisibleType()
        {
            foreach (var attr in assemblyDef.CustomAttributes)
            {
                if (attr.AttributeType.FullName.Equals("System.Runtime.CompilerServices.InternalsVisibleToAttribute"))
                {
                    Console.WriteLine("attrType Asm is " + attr.AttributeType.Module.FileName);
                    return attr.AttributeType;
                }
            }

            throw new Exception("cannot find InternalsVisibleToAttribute Type in assembly Definition");
        }



    }

入口函数

    /// <summary>
    /// 传入的参数是 需要修改的程序集的 文件名
    /// 当前程序会将 对应的程序集
    /// </summary>
    internal class Program
    {
        static void Main(string[] args)
        {
            PrivilegeCheck.Check();


            var lines=File.ReadAllLines("MonoCecilProxy.txt");
            var friendlAsmStrs = lines[0].Trim().Split(' ');

            List<string> targetAsms = new List<string>();
            for (int i = 1; i < lines.Length; i++) 
            { 
                var line = lines[i].Trim();
                if (line.Equals(string.Empty))
                    break;
                targetAsms.Add(lines[i].Trim());
            }

            AssemblyHacker.Hack(targetAsms, friendlAsmStrs);

            Console.WriteLine("finished");

            Console.ReadKey();
        }

    }


Assembly-CSharp 
C:\Program Files\Unity\Hub\Editor\2022.3.32f1\Editor\Data\Managed\UnityEngine\UnityEditor.CoreModule.dll
C:\Program Files\Unity\Hub\Editor\2022.3.32f1\Editor\Data\Managed\UnityEngine\UnityEngine.IMGUIModule.dll

// 这里第一行是需要添加进去的 友元程序集的 名称
// 剩下的几行是需要被修改的程序集的 文件名FullPath 

程序权限

由于unity dll位于C盘,这里我们需要提升程序的权限。

csproj项目文件里添加app.manifest

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net462</TargetFramework>
    <ApplicationManifest>app.manifest</ApplicationManifest>

  </PropertyGroup>
<?xml version="1.0" encoding="utf-8"?>
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1">
  <assemblyIdentity version="1.0.0.0" name="MyApplication.app"/>
  <trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
    <security>
      <requestedPrivileges xmlns="urn:schemas-microsoft-com:asm.v3">

		  <requestedExecutionLevel level="requireAdministrator" uiAccess="false" />

      </requestedPrivileges>
    </security>
  </trustInfo>



</assembly>

标签:assemblyDef,UnityDll,程序,private,dll,internal,var,new,Cecil
From: https://www.cnblogs.com/dewxin/p/18679627

相关文章

  • 《CPython Internals》阅读笔记:p177-p220
    《CPythonInternals》学习第11天,p177-p220总结,总计44页。一、技术总结1.memoryallocationinC(1)staticmemeoryallocationMemoryrequirementsarecalculatedatcompiletimeandallocatedbytheexecutablewhenitstarts.(2)automaticmemeoryallocation......
  • 《CPython Internals》阅读笔记:p152-p176
    《CPythonInternals》学习第10天,p152-p176总结,总计25页。一、技术总结1.addinganitemtoalistmy_list=[]my_list.append(obj)上面的代码涉及两个指令:LOAD_FAST,LIST_APPEND。整章看下来这有这点算是可以记的了,其它的只感觉作者在零零碎碎的罗列内容。二、英语......
  • 《CPython Internals》阅读笔记:p151-p151
    《CPythonInternals》学习第9天,p151-p1510总结,总计1页。一、技术总结无。二、英语总结(生词:1)1.marshal(1)marshalingMarshallingormarshaling(USspelling)istheprocessoftransformingthememoryrepresentationofanobjectintoadataformsuitablefo......
  • 《CPython Internals》阅读笔记:p76-p95
    《CPythonInternals》学习第5天,p76-p95总结,总计20页。一、技术总结无。二、英语总结(生词:1)1.checkvi/vt.toexamsthtoensureitiscorrect,true,oringoodcondition.示例:(1)AfterI'dfinishedthetest,Icheckedmyanswersformistakes.这种用法比......
  • 《CPython Internals》阅读笔记:p43-p60
    《CPythonInternals》学习第3天,p43-p60总结,总计18页。一、技术总结1.编译所需要的packagesudoaptinstall-ybuild-essentiallibssl-devzlib1g-devlibncurses5-dev\libncursesw5-devlibreadline-devlibsqlite3-devlibgdbm-dev\libdb5.3-devlibbz2-devlib......
  • 【ARM】MDK-编译时Linker Error:Internal fault
    【更多软件使用问题请点击亿道电子官方网站】1、文档目标记录问题ARMCLANG:LinkerError:Internalfault:[0xb3b91b:6120001]的解决方案,以及添加原厂对于该问题的说明链接,为同事解决该问题提供参考。2、问题场景客户在编译时linking中出现报错信息.\SPIN32G0601-JXP......
  • 基于Cecil源码的IL练级攻略(2)Metadata存储结构
    目录简介什么是元数据MetadataHeader参考文献简介上文提到CLRRuntimeHeader中包含metadatadirectory,我们可以通过这个字段访问对应的元数据信息。本篇文章会大致介绍一下元数据metadata以及它的存储结构。后续的文章都将基于本篇文章,因此如果有不理解的地方,推荐重新再看一......
  • 基于Cecil源码的IL练级攻略(0)入门
    目录简介公共语言运行时基础(BasicsoftheCommonLanguageRuntime)简介本篇文章希望给读者提供一个关于中间语言(IL,intermediatelanguage)的全局视野,给没接触过的同学补充一些基础知识。公共语言运行时基础(BasicsoftheCommonLanguageRuntime)公共语言运行时是.NET......
  • 基于Cecil源码的IL练级攻略(序)
    目录背景谁应该读本系列文章目录背景在服务端开发或者是客户端开发过程中,会大量应用C#语言,而C#语言又是基于.NET公共语言基础结构(CommonLanguageInfrastructure)。C#编译器(legacy,MonoCompiler,Roslyn)将我们的源码转化为中间语言(IL,intermediatelanguage)。运行时(runt......
  • Win11系统提示找不到Windows.Internal.WaaSMedicDocked.dll文件的解决办法
    在大部分情况下出现我们运行或安装软件,游戏出现提示丢失某些DLL文件或OCX文件的原因可能是原始安装包文件不完整造成,原因可能是某些系统防护软件将重要的DLL文件识别为可疑,阻止并放入了隔离单里,还有一些常见的DLL文件缺少是因为系统没有安装齐全的微软运行库,还有部分情况是因为......