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

如何在Roslyn中从已有Assembly创建CSharpCompilation?.NET6替代方案

解决方案

Roslyn的核心定位是基于源代码的编译工作流,无法直接从已编译的Assembly对象生成可编辑的CSharpCompilation实例,因此不适合你的场景。针对.NET 6+中修改已编译程序集并保存的需求,推荐以下两种可行方案:

一、第三方成熟方案:使用Mono.Cecil

Mono.Cecil是专门用于操作已编译.NET程序集的开源库,API简洁易用,支持修改IL代码、添加/删除成员、加密方法体等操作,完全可以替代原AssemblyBuilder的场景,是当前最便捷的选择。

实现示例

  1. 安装NuGet包:Mono.Cecil
  2. 编写修改逻辑:
private void Protect(FileInfo dllSourceFile, FileInfo targetFile)
{
    // 加载源程序集
    using var assemblyDef = AssemblyDefinition.ReadAssembly(dllSourceFile.FullName);
    
    // 遍历所有模块、类型、方法,修改目标内容
    foreach (var module in assemblyDef.Modules)
    {
        foreach (var type in module.Types)
        {
            // 跳过系统类型与编译器生成类型
            if (type.IsRuntimeSpecialName || type.Namespace.StartsWith("System."))
                continue;
                
            foreach (var method in type.Methods)
            {
                // 跳过无方法体的抽象/接口方法
                if (!method.HasBody || method.IsAbstract)
                    continue;
                    
                // 获取原方法IL字节并加密
                byte[] originalIl = method.Body.GetILAsByteArray();
                byte[] encryptedIl = EncryptIl(originalIl);
                
                // 替换方法体的IL内容
                method.Body.Instructions.Clear();
                method.Body.SetIL(encryptedIl);
                
                // 注意:若加密了IL,需在方法开头插入对应的解密逻辑(否则运行时无法执行)
                // 示例:导入解密方法并插入调用指令
                // var decryptMethod = module.ImportReference(typeof(IlDecryptor).GetMethod("Decrypt"));
                // method.Body.Instructions.Insert(0, Instruction.Create(OpCodes.Ldarg_0));
                // method.Body.Instructions.Insert(1, Instruction.Create(OpCodes.Call, decryptMethod));
            }
        }
    }
    
    // 保存修改后的程序集到目标文件
    assemblyDef.Write(targetFile.FullName);
}

// 自定义IL加密逻辑(替换为你的实际算法)
private byte[] EncryptIl(byte[] ilBytes)
{
    for (int i = 0; i < ilBytes.Length; i++)
    {
        ilBytes[i] = (byte)(ilBytes[i] ^ 0xBB);
    }
    return ilBytes;
}

二、官方底层方案:使用System.Reflection.Metadata

.NET 6+提供了System.Reflection.Metadata和System.Reflection.Metadata.Ecma335 NuGet包,可直接操作程序集的元数据与IL字节,逻辑上接近原AssemblyBuilder的底层实现,但API偏底层,需要熟悉.NET程序集格式。

实现示例

  1. 安装NuGet包:System.Reflection.Metadata、System.Reflection.Metadata.Ecma335
  2. 编写读取、修改、生成程序集的逻辑:
private void Protect(FileInfo dllSourceFile, FileInfo targetFile)
{
    byte[] sourceBytes = File.ReadAllBytes(dllSourceFile.FullName);
    
    // 读取源程序集元数据
    using var sourceStream = new MemoryStream(sourceBytes);
    using var peReader = new PEReader(sourceStream);
    if (!peReader.HasMetadata)
        throw new InvalidOperationException("无效的.NET程序集");
        
    MetadataReader reader = peReader.GetMetadataReader();
    var metadataBuilder = new MetadataBuilder();
    var ilBlobBuilder = new BlobBuilder();
    
    // 遍历并修改方法IL(需手动复制所有元数据,示例仅处理方法)
    foreach (var methodHandle in reader.MethodDefinitions)
    {
        var method = reader.GetMethodDefinition(methodHandle);
        if (!method.ILBody.IsNil)
        {
            // 读取原IL并加密
            var ilReader = reader.GetBlobReader(method.ILBody);
            byte[] originalIl = ilReader.ReadBytes((int)ilReader.RemainingBytes);
            byte[] encryptedIl = EncryptIl(originalIl);
            
            // 将加密后的IL写入新Blob
            int ilOffset = ilBlobBuilder.Count;
            ilBlobBuilder.WriteBytes(encryptedIl);
            BlobHandle newIlHandle = metadataBuilder.GetOrAddBlob(ilBlobBuilder, ilOffset);
            
            // 复制方法定义并替换IL句柄
            metadataBuilder.AddMethodDefinition(
                method.Attributes, method.Name, method.Signature,
                method.ImplAttributes, newIlHandle, method.ParameterList
            );
        }
        else
        {
            // 无IL的方法直接复制
            metadataBuilder.AddMethodDefinition(
                method.Attributes, method.Name, method.Signature,
                method.ImplAttributes, method.ILBody, method.ParameterList
            );
        }
    }
    
    // 生成新PE文件并保存
    using var outputStream = new MemoryStream();
    var peBuilder = new ManagedPEBuilder(
        new PEHeaderBuilder(),
        new MetadataRootBuilder(metadataBuilder),
        new BlobBuilder()
    );
    peBuilder.Serialize(outputStream);
    
    File.WriteAllBytes(targetFile.FullName, outputStream.ToArray());
}

// 自定义IL加密逻辑
private byte[] EncryptIl(byte[] ilBytes)
{
    for (int i = 0; i < ilBytes.Length; i++)
    {
        ilBytes[i] = (byte)(ilBytes[i] ^ 0xAA);
    }
    return ilBytes;
}

关于AssemblyBuilder在.NET 6+的限制

.NET 6+中AssemblyBuilder仍存在,但已移除Save方法,仅支持在内存中生成并加载程序集。若强行使用,需通过反射获取内部PE字节再保存到文件,但这依赖未公开API,稳定性无法保证,不推荐生产环境使用。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.07 21:01:11