如何直接修改.net pe文件中的某个方法的IL字节码,不需要重新编译

浮思梧桐 2020-03-29 11:45:53
这个可以通过CFF explorer实现,但是如何通过编程的方式来修改呢
...全文
158 2 打赏 收藏 转发到动态 举报
写回复
用AI写文章
2 条回复
切换为时间正序
请发表友善的回复…
发表回复
bbwolf 2021-01-12
  • 打赏
  • 举报
回复
我猜你是需要根据某些数据动态处理代码里的值,有两个方案: 一、代码需要动态值的地方通过检查一个文件来处理,这个文件可以用动态生成,也可以做加密。 二、动态生成dll

public static string DoWebService(string url, string commandname, object[] args, string bindingname, string ns, string parmnames, bool returnxml, bool useaction)
        {
            string rt = "";

            AssemblyBuilder AB = AppDomain.CurrentDomain.DefineDynamicAssembly(new AssemblyName("WebService"), AssemblyBuilderAccess.RunAndSave);
            TypeBuilder T = AB.DefineDynamicModule("WebService", "WebService.dll")
                       .DefineType("Nordasoft.WebService", TypeAttributes.Public, typeof(System.Web.Services.Protocols.SoapHttpClientProtocol));

            T.SetCustomAttribute(
                    new CustomAttributeBuilder(
                        typeof(WebServiceBindingAttribute).GetConstructor(new Type[] { typeof(string), typeof(string) }),
                        new object[] { bindingname, ns }));

            List<Type> TS = new List<Type>();
            string[] pns = parmnames.Split(",".ToCharArray());
            for (int i = 0; i < args.Length; i++)
            {
                if (pns[i].StartsWith("#"))
                {
                    TS.Add(args[i].GetType().MakeByRefType());
                }
                else
                {
                    TS.Add(args[i].GetType());
                }

            }
            Type[] PTS = TS.ToArray();

            MethodBuilder MB = T.DefineMethod(commandname, MethodAttributes.Public, typeof(string), PTS);
            string actions = "";
            if (useaction)
            {
                actions = ns + commandname;
            }
            MB.SetCustomAttribute(
                new CustomAttributeBuilder(
                    typeof(SoapDocumentMethodAttribute).GetConstructor(new Type[] { typeof(string) }),
                    new object[] { actions }));

            ParameterBuilder pb;
            int outstart = PTS.Length;
            if (PTS.Length > 0)
            {
                for (int pi = 1; pi <= PTS.Length; pi++)
                {
                    if (pns[pi - 1].StartsWith("#"))
                    {
                        if (outstart == PTS.Length) outstart = pi - 1;
                        pb = MB.DefineParameter(pi, ParameterAttributes.Out, pns[pi - 1].Substring(1));

                    }
                    else
                    {
                        pb = MB.DefineParameter(pi, ParameterAttributes.None, pns[pi - 1]);
                    }
                }
            }

            if (returnxml)
            {
                pb = MB.DefineParameter(0, ParameterAttributes.None, null);
                pb.SetCustomAttribute(
                    new CustomAttributeBuilder(
                        typeof(System.Xml.Serialization.XmlElementAttribute).GetConstructor(new Type[] { typeof(string) }),
                        new object[] { "return" },
                        new PropertyInfo[] { typeof(System.Xml.Serialization.XmlElementAttribute).GetProperty("Form"), },
                        new object[] { System.Xml.Schema.XmlSchemaForm.Unqualified }
                        )
                    );
            }
            ILGenerator ig = MB.GetILGenerator();
            //声明命令名字符串
            ig.DeclareLocal(typeof(string));
            //声明命令参数数组
            ig.DeclareLocal(typeof(object[]));

            ig.DeclareLocal(typeof(object[]));

            //加载参数0到堆栈[0]==参数0表示当前方法
            ig.Emit(OpCodes.Ldarg_0);
            //加载字符串到堆栈[1]
            ig.Emit(OpCodes.Ldstr, commandname);
            //把参数数量加到堆栈[2]
            ig.Emit(OpCodes.Ldc_I4, outstart);
            //用堆栈[2]的数字生成object数组并放如堆栈[2]
            ig.Emit(OpCodes.Newarr, typeof(object));
            //把堆栈[2]的数组付给参数[1]==声明的数组
            ig.Emit(OpCodes.Stloc_1);
            //将数组放回堆栈[2]
            ig.Emit(OpCodes.Ldloc_1);

            //循环将参数放到数组对应的位置
            for (int pi = 0; pi < outstart; pi++)
            {
                //将参数序号加到堆栈
                ig.Emit(OpCodes.Ldc_I4, pi);
                //将参数[序号+1]位置的数据加到堆栈
                ig.Emit(OpCodes.Ldarg, pi + 1);
                //将[序号+1]对应的数据替换到声明数组[序号]位置
                ig.Emit(OpCodes.Stelem_Ref);
                //将参数1入栈
                ig.Emit(OpCodes.Ldloc_1);
            }
            //调用基类型Invoke方法
            MethodInfo cm = T.BaseType.GetMethod("Invoke", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public | BindingFlags.DeclaredOnly);
            ig.Emit(OpCodes.Call, cm);
            ig.Emit(OpCodes.Stloc_2);
            //若out参数数量>0 循环处理返回的对象列表中的值给out参数地址
            if (outstart < PTS.Length)
            {
                for (int i = 1; i < PTS.Length - outstart + 1; i++)
                {
                    //将参数加载到堆栈
                    ig.Emit(OpCodes.Ldarg, outstart + i);
                    //加载返回值
                    ig.Emit(OpCodes.Ldloc_2);
                    //将返回值的索引加载到堆栈
                    ig.Emit(OpCodes.Ldc_I4, i);
                    //将索引楚的数据地址加载到堆栈
                    ig.Emit(OpCodes.Ldelem_Ref);
                    //转换类型为字符串
                    ig.Emit(OpCodes.Castclass, typeof(string));
                    //将转换过的字符串地址放入参数位置
                    ig.Emit(OpCodes.Stind_Ref);
                }

            }

            ig.Emit(OpCodes.Ldloc_2);
            //加载返回值索引0
            ig.Emit(OpCodes.Ldc_I4_0);
            //引用返回值索引0处的数据
            ig.Emit(OpCodes.Ldelem_Ref);
            //转换为字符串
            ig.Emit(OpCodes.Castclass, typeof(string));
            //将字符串加载到局部变量0
            ig.Emit(OpCodes.Stloc_0);
            //将变量0入栈
            ig.Emit(OpCodes.Ldloc_0);
            //返回
            ig.Emit(OpCodes.Ret);

            Type O = T.CreateType();

            ConstructorInfo ci = O.GetConstructor(Type.EmptyTypes);
            object s = ci.Invoke(new object[] { });
            PropertyInfo piurl = O.GetProperty("Url");
            piurl.SetValue(s, url, null);
            MethodInfo mi = O.GetMethod(commandname);
            object rtobj = mi.Invoke(s, args);
            rt = rtobj.ToString();
            s = null;
            return rt;
        }
动态生成webservice的soap调用的方案可以参考一下,这里可以做一个判断比如通过文件是否存在来判断dll是否生成,然后用反射调用,没有生成用这个生成以后调用AB.Save方法可以保存到本地
github_36000833 2020-03-29
  • 打赏
  • 举报
回复
知道要改哪里改成什么,就简单了。比如把a.exe偏移量12345的字节改为0x88,C#代码为:
using (var fs = File.Open("a.exe", FileMode.Open))
{
    fs.Position = 12345;
    fs.WriteByte(0x88);
}
改很简单,值一块钱。 知道改哪里,值一万块。

17,740

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 .NET Framework
社区管理员
  • .NET Framework社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧