跳到主要内容

集成MSBuild自动构建混淆.NET程序集

将恒盾 C# 混淆加密大师的 CLI 接入 MSBuild,可以在 Release 构建完成后自动保护 DLL 或 EXE。Visual Studio、Rider、dotnet build 和 CI 构建都可以使用同一套配置。

1. 准备 CLI 和配置文件

  1. 安装恒盾 C# 混淆加密大师,在安装目录找到 CLI.exe
  2. 在软件中配置混淆选项,通过“文件 > 导出配置”生成 obfuscation.csop
  3. 将配置文件放在需要保护的 .csproj 同一目录。

导出混淆配置

配置文件中的输入和输出路径可以保留示例值,构建时会通过命令行参数覆盖:

{
"ModulePath": "bin/Release/net8.0/MyApp.dll",
"OutputPath": "bin/Release/net8.0/protected/MyApp.dll",
"AntiILDasm": true,
"StringConfusor": true,
"IntConfusor": true,
"FieldRename": true,
"MethodRename": true,
"ParamRename": true,
"TypeRename": true,
"RenameMode": 1,
"Seed": "my-project-release"
}

实际使用时请保留软件导出的完整配置,不要只使用上面的示例片段。

2. 配置 CLI 路径

不建议把个人电脑上的绝对路径写入项目文件。可以在当前 PowerShell 会话中设置环境变量:

$env:OBFUSCATOR_CLI_PATH = 'C:\Tools\CSharpObfuscator\CLI.exe'

也可以在单次构建时传入路径:

dotnet build -c Release -p:ObfuscatorCliPath='C:\Tools\CSharpObfuscator\CLI.exe'

3. 在 .csproj 中加入构建目标

在项目文件的 </Project> 前加入以下内容:

<PropertyGroup>
<ObfuscatorCliPath Condition="'$(ObfuscatorCliPath)' == ''">$(OBFUSCATOR_CLI_PATH)</ObfuscatorCliPath>
<RunObfuscator Condition="'$(RunObfuscator)' == '' and '$(Configuration)' == 'Release' and '$(ObfuscatorCliPath)' != ''">true</RunObfuscator>
<RunObfuscator Condition="'$(RunObfuscator)' == ''">false</RunObfuscator>
<ObfuscatorConfigPath>$(MSBuildProjectDirectory)\obfuscation.csop</ObfuscatorConfigPath>
</PropertyGroup>

<Target Name="ObfuscateReleaseOutput"
AfterTargets="Build"
Condition="'$(Configuration)' == 'Release' and '$(RunObfuscator)' == 'true'">
<PropertyGroup>
<ObfuscatedOutputDir Condition="'$(ObfuscatedOutputDir)' == ''">$(TargetDir)protected\</ObfuscatedOutputDir>
<ObfuscatedOutputPath Condition="'$(ObfuscatedOutputPath)' == ''">$(ObfuscatedOutputDir)$(TargetFileName)</ObfuscatedOutputPath>
</PropertyGroup>

<Error Condition="'$(ObfuscatorCliPath)' == ''"
Text="RunObfuscator=true, but ObfuscatorCliPath or OBFUSCATOR_CLI_PATH is not configured." />
<Error Condition="!Exists('$(ObfuscatorCliPath)')"
Text="Obfuscator CLI was not found: $(ObfuscatorCliPath)" />
<Error Condition="!Exists('$(ObfuscatorConfigPath)')"
Text="Obfuscator config was not found: $(ObfuscatorConfigPath)" />

<RemoveDir Directories="$(ObfuscatedOutputDir)" />
<MakeDir Directories="$(ObfuscatedOutputDir)" />
<ItemGroup>
<ObfuscatorCompanionFile Include="$(TargetDir)**\*"
Exclude="$(ObfuscatedOutputDir)**\*;$(TargetPath)" />
</ItemGroup>
<Copy SourceFiles="@(ObfuscatorCompanionFile)"
DestinationFiles="@(ObfuscatorCompanionFile->'$(ObfuscatedOutputDir)%(RecursiveDir)%(Filename)%(Extension)')"
SkipUnchangedFiles="true" />

<Message Importance="high" Text="Obfuscating $(TargetPath)" />
<Exec Command="&quot;$(ObfuscatorCliPath)&quot; obf --config &quot;$(ObfuscatorConfigPath)&quot; --input &quot;$(TargetPath)&quot; --output &quot;$(ObfuscatedOutputPath)&quot;" />
<Error Condition="!Exists('$(ObfuscatedOutputPath)')"
Text="Obfuscator did not create the expected output: $(ObfuscatedOutputPath)" />
<Message Importance="high" Text="Protected output: $(ObfuscatedOutputDir)" />
</Target>

这个目标会:

  • 只在 Release 配置且已找到 CLI 时执行。
  • 保留原始构建目录,不覆盖原始程序集。
  • 将依赖 DLL、.deps.json.runtimeconfig.json 复制到 protected 目录。
  • 在 CLI 返回错误或没有生成目标文件时使构建失败。

4. 执行构建

执行 Release 构建:

dotnet build -c Release

生成目录示例:

bin/Release/net8.0/
├─ MyApp.dll
├─ MyApp.deps.json
├─ MyApp.runtimeconfig.json
└─ protected/
├─ MyApp.dll
├─ MyApp.deps.json
└─ MyApp.runtimeconfig.json

发布时使用 protected 目录中的文件。Debug 构建默认不会执行混淆;如需临时跳过 Release 混淆,可以执行:

dotnet build -c Release -p:RunObfuscator=false

构建日志中出现以下信息,表示目标已执行:

Obfuscating ...\bin\Release\net8.0\MyApp.dll
Protected output: ...\bin\Release\net8.0\protected\

5. 在 CI 中使用

CI 中先设置 CLI 路径,再执行相同的构建命令:

$env:OBFUSCATOR_CLI_PATH = "$env:OBFUSCATOR_HOME\CLI.exe"
dotnet restore
dotnet build -c Release --no-restore

上传制品前,可以检查受保护的程序集是否存在:

$protectedFile = '.\bin\Release\net8.0\protected\MyApp.dll'
if (-not (Test-Path $protectedFile)) {
throw "未生成混淆后的程序集: $protectedFile"
}

注意事项

  • WPF、WinForms、类库和 ASP.NET Core 项目都可以使用 $(TargetPath) 保护主程序集。
  • 使用反射、依赖注入扫描、JSON 序列化、XAML 绑定、插件加载或 P/Invoke 时,重命名可能影响运行,请配置忽略列表并回归测试。
  • dotnet publish 会重新整理 publish 目录。普通发布应在发布完成后再处理主程序集,不要直接把未经检查的 publish 目录作为最终制品。
  • 启用 PublishSingleFile 时,应将发布得到的单文件 EXE 作为 CLI 输入,并单独验证混淆后的程序。

完整示例项目:GitHub csharp-obfuscator-cli-integration