基于mono.ceil对c#进行注入垃圾代码,混淆代码,IL代码注入

本文介绍了如何使用Mono.Cecil库来加密Unity的C#程序集Assembly_CSharp.dll,并进行代码混淆。通过自定义AssemblyResolver,读取并修改程序集,插入垃圾方法或代码,以增加反编译的难度。同时,文章还展示了如何检查和处理被其他程序集引用的类和方法,确保混淆过程的正确性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前言

        unity的c#层,编译处理的程序集Assembly_CSharp.dll,通过dnspy反编译出来,可以看到自己写的代码,代码也是公司的财产(大雾),但是开发项目过程中,有什么方法加密程序集呢?指令表(Instruction List,简称IL)是为可编程逻辑控制器(PLC)设计的编程语言,是相关的IEC 61131-3标准中支援几种语言之一,是类似组合语言的低阶语言。

        Mono.Ceil 地址Mono.Cecil | Mono

        官方wiki:https://github.com/jbevain/cecil/wiki/HOWTO

        通过AssemblyDefinition下的ReadAssembly 读取程序集,AssemblyDefinition存储着改程序集的参数

ReadAssembly(assemblyPath, readParams); 其中参数readParams是对该程序集交互的方法,最简单的将’True’初始化给ReaderParameters.ReadSymbols对象 或 WriterParameters.WriteSymbols对象

 var readParams = new ReaderParameters();
        CustomResolver customResolver = new CustomResolver();
        customResolver.SetPath(projectDir, configPath);
        readParams.AssemblyResolver = customResolver;
        readParams.ReadWrite = true;
        readParams.ReadSymbols = true;

这里的CustomResolver是我的自定义类,指定你的自己的AssemblyResolver。通过这种方式你可以控制你加载模块和你解析的一些和他的相关的引用的生命周期。

继承自BaseAssemblyResolver,

 添加一该程序集需要的外部引用,我这里是拿依赖unity dll。

 dll.Write(baseDllDir, new WriterParameters { WriteSymbols = true });

dll保存

 assembly.MainModule获取程序集模块,

var typeArr = assembly.MainModule.Types;获取该程序集所有的类模块

一个TypeDefinition列表, foreach (var t in typeArr)遍历

TypeDefinition.name 就是类名,可以混淆,

TypeDefinition.Methods该类所有方法,可以插入垃圾方法或者垃圾代码type.Methods.Insert(index, mymethod);

代码你可以通过IL指令自己写,也可以写一个垃圾方法类,遍历类的时候,把垃圾方法类提取出来成IL指令,再插入方法。

 var mymethod = new MethodDefinition();
        Random random = new Random();
        for (int it = 0; it < 3; it++)
        {
            int JunlMethodIndex = random.Next(variableMap.Count);
            string methodNameSeed = "";
            for (int i = 0; i < 17; i++)
            {
                methodNameSeed += _zimu[random.Next(52)]; //通过索引下标随机
            }
            var typeRef = mythodBodyList[JunlMethodIndex].ReturnType;
            mymethod = new MethodDefinition(methodNameSeed + "12345", MethodAttributes.Public, typeRef);
            mymethod.Body.Instructions.Clear();
            mymethod.Body.Variables.Clear();
            foreach (var il in mythodBodyList[JunlMethodIndex].Body.Instructions)
            {
                var ilProcessor = mythodBodyList[JunlMethodIndex].Body.GetILProcessor();
                if (il.OpCode.Equals(Mono.Cecil.Cil.OpCodes.Add))
                {
                    Instruction ilTemp = ilProcessor.Create(Mono.Cecil.Cil.OpCodes.Sub);
                    mymethod.Body.Instructions.Add(ilTemp);
                    continue;
                }
                if (il.OpCode.Equals(Mono.Cecil.Cil.OpCodes.Sub))
                {
                    Instruction ilTemp = ilProcessor.Create(Mono.Cecil.Cil.OpCodes.Add);
                    mymethod.Body.Instructions.Add(ilTemp);
                    continue;
                }
                if (il.OpCode.Equals(Mono.Cecil.Cil.OpCodes.Mul))
                {
                    Instruction ilTemp = ilProcessor.Create(Mono.Cecil.Cil.OpCodes.Div);
                    mymethod.Body.Instructions.Add(ilTemp);
                    continue;
                }
                if (il.OpCode.Equals(Mono.Cecil.Cil.OpCodes.Div))
                {
                    Instruction ilTemp = ilProcessor.Create(Mono.Cecil.Cil.OpCodes.Mul);
                    mymethod.Body.Instructions.Add(ilTemp);
                    continue;
                }
                if (il.OpCode.Equals(Mono.Cecil.Cil.OpCodes.And))
                {
                    Instruction ilTemp = ilProcessor.Create(Mono.Cecil.Cil.OpCodes.Or);
                    mymethod.Body.Instructions.Add(ilTemp);
                    continue;
                }
                if (il.OpCode.Equals(Mono.Cecil.Cil.OpCodes.Or))
                {
                    Instruction ilTemp = ilProcessor.Create(Mono.Cecil.Cil.OpCodes.And);
                    mymethod.Body.Instructions.Add(ilTemp);
                    continue;
                }
                mymethod.Body.Instructions.Add(il);
            }
            foreach (var il in mythodBodyList[JunlMethodIndex].Body.Variables)
            {
                mymethod.Body.Variables.Add(il);
            }
            foreach (var il in mythodBodyList[JunlMethodIndex].Parameters)
            {
                mymethod.Parameters.Add(il);
            }
            int index = random.Next(type.Methods.Count);
            //Console.WriteLine("mymethod what error :{0}", mymethod.Name);
            type.Methods.Insert(index, mymethod);
        }

 我这里演示一些IL指令写垃圾方法,垃圾类就不演示了。

 同时,还可以检查该类或者方法是否被其他程序集引用,如果引用,则不可以混淆,或者记录下来一起混淆,

查看IL指令,不难发现

这是个单例,后面是参数,

 程序集调用方法,下面是方法体

 

 很清楚,查看所有IL指令表IL指令详细表 - 张龙豪 - 博客园,然后

method.Body.Instructions获取方法体里面所有的IL指令

 if (ilLanguage.ToString().Contains("call"))
                    {
                        if (ilLanguage.Operand.GetType() == (typeof(GenericInstanceMethod)) && ((GenericInstanceMethod)ilLanguage.Operand).DeclaringType.Scope.Name == DllName)
                        {
                            GenericInstanceMethod methodRef = ((GenericInstanceMethod)ilLanguage.Operand);
                            //Console.WriteLine("AssemblyEditorPath class:{0}  ==============ref 程序集:{1}  ====== ref classs:{2} === method:{3}", type, methodRef.DeclaringType.Scope.Name, methodRef.DeclaringType, methodRef.Name);
                            string methodName = methodRef.Name;
                            string className = methodRef.DeclaringType.Name;
                            if (!isRefByOtherDLLMap.ContainsKey(className))
                            {
                                List<string> xx = new List<string>();
                                xx.Add(methodName);
                                isRefByOtherDLLMap.Add(className, xx);
                                continue;
                            }
                            if (isRefByOtherDLLMap[className].IndexOf(methodName) == 0)
                                continue;
                            isRefByOtherDLLMap[className].Add(methodName);

                        }
                        if (ilLanguage.Operand.GetType() == (typeof(MethodReference)) && ((MethodReference)ilLanguage.Operand).DeclaringType.Scope.Name == DllName)
                        {

                            MethodReference methodRef = ((MethodReference)ilLanguage.Operand);
                            string methodName = methodRef.Name;
                            string className = methodRef.DeclaringType.Name;
                            if (!isRefByOtherDLLMap.ContainsKey(className))
                            {
                                List<string> xx = new List<string>();
                                xx.Add(methodName);
                                isRefByOtherDLLMap.Add(className, xx);
                                continue;
                            }
                            if (isRefByOtherDLLMap[className].IndexOf(methodName) == 0)
                                continue;
                            isRefByOtherDLLMap[className].Add(methodName);
                        }
                    }

 查找call指令的语句, 

/Console.WriteLine("AssemblyEditorPath class:{0}  ==============ref 程序集:{1}  ====== ref classs:{2} === method:{3}", type, methodRef.DeclaringType.Scope.Name, methodRef.DeclaringType, methodRef.Name);
methodRef.DeclaringType.Scope.Name 引用程序集名

methodRef.DeclaringType 引用的class名

methodRef.Name 引用的程序名

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值