You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何程序化修改嵌入资源以定制通用.NET可执行文件

嘿,我完全get到你的需求了——打造一个能通过程序自动修改嵌入资源来定制的通用.NET可执行文件,不管是直接改编译好的exe,还是借助中间语言(IL)来操作,对吧?下面我给你拆解具体的实现方案和可运行的代码示例:

方案1:直接修改已编译的.NET可执行文件(推荐)

这是最贴合你需求的方案,无需原项目代码,直接操作已编译的程序集。我们用Mono.Cecil这个成熟的库来实现,它能轻松读取、修改和保存.NET程序集的资源。

依赖准备

先给你的修改工具项目安装Mono.Cecil NuGet包,它是处理已编译程序集的标配工具。

原程序示例(需要被定制的exe)

先写一个简单的目标程序,它会读取嵌入的资源并输出,作为我们的定制对象:

namespace MyProgram
{
    public class Program
    {
        public static void Main(string[] args)
        {
            // 读取嵌入的定制资源(注意资源名称要和嵌入时的完全一致)
            using var resourceStream = typeof(Program).Assembly.GetManifestResourceStream("MyProgram.CustomResource.txt");
            if (resourceStream == null)
            {
                Console.WriteLine("未找到定制资源");
                return;
            }

            using var reader = new StreamReader(resourceStream);
            var customContent = reader.ReadToEnd();
            Console.WriteLine("定制内容:");
            Console.WriteLine(customContent);
        }
    }
}

注意:把你的资源文件(比如CustomResource.txt)的生成操作设置为嵌入的资源,这样编译后就会被打包进exe里。

资源修改工具代码

下面是自动修改资源的工具代码,它可以加载目标exe,替换或添加嵌入资源:

using Mono.Cecil;
using System.Linq;
using System.IO;

namespace ResourceModifier
{
    class Program
    {
        static void Main(string[] args)
        {
            // 配置参数
            var targetExePath = "MyProgram.exe"; // 要修改的目标exe路径
            var newResourceContent = "这是程序自动修改后的定制内容!"; // 新的资源内容
            var resourceName = "MyProgram.CustomResource.txt"; // 资源名称(必须和原程序一致)

            // 加载目标程序集
            var assemblyDefinition = AssemblyDefinition.ReadAssembly(targetExePath);

            // 查找并替换现有资源
            var existingResource = assemblyDefinition.MainModule.Resources
                .FirstOrDefault(r => r.Name == resourceName) as EmbeddedResource;
            
            if (existingResource != null)
            {
                assemblyDefinition.MainModule.Resources.Remove(existingResource);
            }

            // 添加新的嵌入资源
            var newResourceBytes = System.Text.Encoding.UTF8.GetBytes(newResourceContent);
            assemblyDefinition.MainModule.Resources.Add(
                new EmbeddedResource(resourceName, ManifestResourceAttributes.Private, newResourceBytes)
            );

            // 保存修改后的程序集(这里保存为新文件,避免覆盖原文件)
            var outputPath = Path.ChangeExtension(targetExePath, "_modified.exe");
            assemblyDefinition.Write(outputPath);
            
            Console.WriteLine($"资源修改完成!已保存到:{outputPath}");
        }
    }
}
方案2:借助IL中间表示生成可定制程序集

如果需要预先创建一个可定制的程序模板,也可以用System.Reflection.Emit直接生成IL代码和嵌入资源,后续同样可以用上面的工具修改:

using System.Reflection;
using System.Reflection.Emit;
using System.IO;

namespace DynamicAssemblyGenerator
{
    class Program
    {
        static void Main(string[] args)
        {
            // 定义程序集信息
            var assemblyName = new AssemblyName("CustomizableProgram");
            var assemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Save);
            var moduleBuilder = assemblyBuilder.DefineDynamicModule(assemblyName.Name, "CustomizableProgram.exe");

            // 定义Program类
            var typeBuilder = moduleBuilder.DefineType("CustomizableProgram.Program", TypeAttributes.Public | TypeAttributes.Class);

            // 定义Main方法的IL代码
            var methodBuilder = typeBuilder.DefineMethod("Main", MethodAttributes.Public | MethodAttributes.Static, typeof(void), new[] { typeof(string[]) });
            var il = methodBuilder.GetILGenerator();

            // IL逻辑:读取嵌入资源并输出
            il.DeclareLocal(typeof(Stream));
            il.DeclareLocal(typeof(string));

            // 获取当前程序集并加载资源
            il.Emit(OpCodes.Ldtoken, typeof(Program));
            il.Emit(OpCodes.Call, typeof(Type).GetMethod("GetTypeFromHandle"));
            il.Emit(OpCodes.Callvirt, typeof(Type).GetMethod("get_Assembly"));
            il.Emit(OpCodes.Ldstr, "CustomizableProgram.CustomResource.txt");
            il.Emit(OpCodes.Callvirt, typeof(Assembly).GetMethod("GetManifestResourceStream", new[] { typeof(string) }));
            il.Emit(OpCodes.Stloc_0);

            // 检查资源是否为空
            var resourceExists = il.DefineLabel();
            il.Emit(OpCodes.Ldloc_0);
            il.Emit(OpCodes.Brtrue_S, resourceExists);
            il.Emit(OpCodes.Ldstr, "未找到定制资源");
            il.Emit(OpCodes.Call, typeof(Console).GetMethod("WriteLine", new[] { typeof(string) }));
            il.Emit(OpCodes.Ret);

            il.MarkLabel(resourceExists);
            // 读取资源内容并输出
            il.Emit(OpCodes.Ldloc_0);
            il.Emit(OpCodes.Newobj, typeof(StreamReader).GetConstructor(new[] { typeof(Stream) }));
            il.Emit(OpCodes.Callvirt, typeof(StreamReader).GetMethod("ReadToEnd"));
            il.Emit(OpCodes.Stloc_1);
            il.Emit(OpCodes.Ldstr, "定制内容:");
            il.Emit(OpCodes.Call, typeof(Console).GetMethod("WriteLine", new[] { typeof(string) }));
            il.Emit(OpCodes.Ldloc_1);
            il.Emit(OpCodes.Call, typeof(Console).GetMethod("WriteLine", new[] { typeof(string) }));
            il.Emit(OpCodes.Ret);

            // 完成类型定义
            typeBuilder.CreateType();

            // 添加初始嵌入资源
            var initialContent = "初始定制内容";
            var resourceBytes = System.Text.Encoding.UTF8.GetBytes(initialContent);
            assemblyBuilder.DefineManifestResource("CustomizableProgram.CustomResource.txt", resourceBytes, ResourceAttributes.Private);

            // 保存程序集
            assemblyBuilder.Save("CustomizableProgram.exe");
            Console.WriteLine("可定制程序集生成完成!");
        }
    }
}
关键注意事项
  • 资源名称匹配:修改工具中的资源名称必须和原程序中读取的完全一致,包括命名空间前缀(比如MyProgram.CustomResource.txt,命名空间是原程序的根命名空间)。
  • 强签名程序集:如果目标exe是强签名的,修改后需要重新签名才能运行,可以在assemblyDefinition.Write时传入签名参数(比如new WriterParameters { StrongNameKeyPair = new StrongNameKeyPair(File.OpenRead("key.snk")) })。
  • 跨版本支持:Mono.Cecil支持.NET Framework、.NET Core和.NET 5+的程序集,只需安装对应版本的NuGet包即可。

内容的提问来源于stack exchange,提问作者millinon

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.22 09:52:12