简介:ConfuserEx是一款由Yair Dolev开发并维护的开源.NET混淆加壳工具,主要面向需要保护商业软件、安全敏感项目或核心算法的.NET开发者,能有效提升程序集抗反编译与防篡改能力。整个zip压缩包共包含27个文件,整体大小约5.28MB,其中既有ConfuserEx主程序及命令行工具(exe),也有Confuser.Core、Confuser.Protections、Confuser.Renamer等核心与扩展库(dll),还附带了pdb调试符号、xml配置说明和运行配置文件,可支撑GUI与命令行两种使用方式,便于按需选择。目前已有377人学习下载,适合具有一定.NET基础、希望系统掌握混淆保护技术的开发者参考。配套资料围绕ConfuserEx的五大功能展开——代码混淆、反调试、反静态分析、资源保护、插件系统,并详细解析了解析、保护、混淆、输出四个工作阶段;读者可以据此了解如何通过XML配置自定义混淆规则,并复现针对典型.NET程序集的实际保护流程,为自身项目增加一层可落地的安全防护。
1. 为什么 .NET 程序集防破解绕不开 ConfuserEx
.NET 程序只要发布成 DLL/EXE,就等于把源码半公开在用户手里——ILSpy、dnSpy 这类工具点一下就能把方法体还原成可读 C#,连注释都带出来。ConfuserEx 是社区里流传最广的开源混淆框架,一个 zip 解压就能用,GUI 和命令行都有,专门解决“程序集裸奔”的问题。它能做符号重命名、控制流搅乱、字符串加密、反调试和防篡改,把静态可读性打掉,同时给动态分析制造障碍。这篇文章写给独立开发者、发闭源组件的团队,以及被逆向搞到头大的朋友,目标是看完就能跑通,并把坑摸清。
2. 先搞懂 ConfuserEx 在保护什么:混淆原理与选型理由
开讲前先把话说清楚:混淆不是加密。加密的目的是“不让你看”,混淆的目的是“让你看得懂但很费劲”。托管程序集的 metadata 和 IL 必须保留,因为 CLR 要靠它们运行。所以 ConfuserEx 做的所有事情,都是在合法 IL 的边界内,把可读性降到最低,顺便给动态调试添堵。
2.1 重命名:把符号表变成乱码
在 .NET 里,类名、方法名、字段名、属性名这些符号,默认全躺在 metadata 表里。dnSpy 之所以能还原得那么像源码,靠的就是这些符号。控件名 usernameTextBox 直接暴露业务含义,方法名 CheckLicense() 直接告诉逆向者授权逻辑在哪。
ConfuserEx 的 rename 做的事情很朴素:扫描程序集的 TypeDef、MethodDef、FieldDef、PropertyDef、EventDef,把符号改写成 a、b、c 之类的短名,或者 Unicode 奇怪字符。关键点在于它不只改名字,还要同步修正所有引用位置,包括方法调用、字段访问、泛型参数、自定义特性的反射引用。改不干净就会在运行时抛 MissingMethodException。
这里有个参数必须先搞清楚:renamePublic,GUI 里对应 Rename public symbols 选项,含义是是否重命名 public 符号。默认关闭,以免外部调用方被打断。我一般会分三种场景定策略:
| 场景 | renamePublic | 附加说明 |
|---|---|---|
| 给公司其他项目引用的库 | 关 | 公共类型必须保住,否则整个解决方案编译不过 |
| 独立交付的客户端 exe | 开 | 反正没有外部引用,开了强度立马上一个台阶 |
| 带插件的宿主程序 | 按插件契约定 | 插件接口要除外,用 rule pattern 排除特定命名空间 |
实际操作里还有个容易被忽略的:反射代码。Type.GetType("MyNamespace.MyClass") 这样的写法,重命名后类型名变了,字符串没变,一运行就返回 null。ConfuserEx 会尝试改写能被静态分析的字符串,但动态拼出来的名字改不掉。遇到这种情况,要么在 crproj 里把该类型排除出 rename,要么改用 nameof 并让混淆器重写常量。
2.2 控制流扁平化与字符串加密:让反编译工具失效
控制流混淆是 ConfuserEx 里最“看得见效果”的一项。原本 IL 是顺序执行的:先取参数,再判断,再调用。Ctrl flow 做的事情是把这些基本块打散,插入一个分发器,用一个状态变量决定下一个执行哪个块。反编译出来就是一个 while(true) + switch(state) 的巨型循环,真正的业务逻辑被埋在几百个 case 分支里。
代价是性能和可读性的双重牺牲。性能上,JIT 对这种模式几乎无法做内联和常量传播,原本能优化掉的一些代码会留在原地。如果对性能敏感,可以只对关键模块开启控制流,而不是全量。我在自己的项目里会先把 ctrl flow 的规则范围缩小到授权、加密、网络协议这几个模块,避免整个程序集变慢。
字符串加密(constants)则是把 IL 里的 ldstr 指令替换成对解密函数的调用。比如原来有个 https://api.example.com/v1/login,混淆后你在 IL 里看到的是加密后的字节数组,运行时才解密。这个保护对静态分析打击很大——想直接从二进制里搜 URL 和密钥是搜不到了。
但要注意,constants 的解密函数是 ConfuserEx 自带的,特征是固定的,de4dot 这类工具会专门识别它。所以只依赖字符串加密是不够的,必须和 rename、ctrl flow 叠起来用。这也是 ConfuserEx 支持 preset 组合的原因:要打就打个组合拳。
2.3 反调试、防篡改与防内存转储:从静态保护走向运行时对抗
静态分析防住了,破解者就转向动态分析:跑起来用 dnSpy 附加调试器,或者直接 dump 内存再分析。ConfuserEx 的运行时保护就是针对这个环节的。
anti debug 的原理是检测调试器,既包括 Debugger.IsAttached 这种托管检测,也包括调用 Native API(如 NtQueryInformationProcess 检查进程是否被调试)。检测到调试器就做点恶心人的事,比如直接 Environment.Exit,或者故意抛异常。有些配置还会周期性检查,防止中途下断点。
anti tamper 的常见做法是给程序集生成一个校验壳,对自身文件算哈希。运行前先读一遍自身,哈希不对就拒绝运行,甚至把内存里的关键状态打乱。这一项对“改一个字节绕过授权判断”的手法有效,但副作用是会和某些杀软的主动防御冲突,导致程序被误报或者运行缓慢。
anti dump 是防止内存转储,运行时把敏感数据打乱存放,检测到 dump 动作就清理关键区域。属于小众但实用的补充。单纯用运行时保护的话,静态可读性几乎没变化,所以它们必须和前面的静态混淆一起用。
需要特别提醒:很多保护项对 Server 环境兼容性差。比如在 IIS 里宿主运行的 WCF 服务,加了 anti tamper 可能导致启动失败,因为程序集文件被占用,校验逻辑读不到完整文件内容。类似的还有 ClickOnce 部署和单文件发布(如果底层还是 Framework 的话),这些场景最好只开 rename + constants。
2.4 和其它工具怎么选:Obfuscar、Dotfuscator 对比
做 .NET 混淆不止 ConfuserEx 一个选项。我在选型时一般把方案分成三档。
第一档是 Obfuscar,开源、轻量,但只做重命名,而且重命名质量一般。适合“不想让源码被一眼看懂”的内部工具,或者发布后根本不打算和逆向者较劲的场景。优点是几乎不会跑崩,缺点是脱壳难度几乎为零。
第二档就是 ConfuserEx。免费、GUI 顺手、保护类型覆盖面全,从静态到运行时都有,适合大多数商业闭源交付。缺点也很明显:原版长期没有跟进 .NET Core/5+,另外对强名称、XAML 这类场景需要手工调参。
第三档是商业混淆壳,比如 .NET Reactor、Themida。它们除了混淆 IL,还会做原生层加壳、反调试器、虚拟机保护,强度确实更高,但价格不便宜,杀软误报率也比 ConfuserEx 高——混淆器的行为和恶意软件太像了,很多杀软宁可错杀。
我的建议:如果你做的是 PC 客户端软件,ConfuserEx 是性价比最好的起点。先用它把标准流程跑通,确认强度不够再考虑商业方案。而且混淆防的是那 99% 拿 dnSpy 看两眼就完事的人;遇到真正愿意花几周逆向的人,任何工具都只能拖延时间,不能阻止。
提示:ConfuserEx 原版只支持 .NET Framework 生成的程序集。如果你的目标项目是 .NET Core 3.1 以上或者 .NET 5+,需要去找 ConfuserEx 的分支版本或其他方案,原版跑不了。
3. 用 ConfuserEx GUI 跑通最小混淆:操作步骤与配置落盘
理论再说得好听,不落地都是零。这一章从解压 zip 开始,到生成第一个混淆后的 exe,全程只有三个动作:解压、拖拽、点按钮。然后我们把 GUI 生成的配置拿出来看,再用命令行把它跑进构建流程。
3.1 最小混淆:从解压 zip 到双击 Protect
先准备一个测试程序集。假设你在 Visual Studio 里建了个 WinForms 项目,编译成 Release。然后把 ConfuserEx.zip 解压到固定目录,我一般放 D:\Tools\ConfuserEx,避免中文路径和空格带来的坑。
# PowerShell 解压并确认目录结构 Expand-Archive -Path .\ConfuserEx.zip -DestinationPath D:\Tools\ConfuserEx Get-ChildItem D:\Tools\ConfuserEx解压后目录里应该有 ConfuserEx.exe(GUI)、Confuser.CLI.exe(命令行)、以及一堆 dll。GUI 操作很简单:双击 ConfuserEx.exe,把要混淆的 exe 或 dll 直接拖进左侧窗口。拖进去会看到它自动识别了模块路径,右侧面板出现 Base Directory、Output Directory 等选项。默认 Output Directory 是 .\Confused,建议改成显式目录,比如 D:\Build\Confused。
接下来右键左侧的模块节点,选择 Add Rule。新规则默认位置在模块节点下,双击规则,在右侧 Protection 列表里勾上 rename、ctrl flow、constants 这三项;preset 下拉框可以直接选 Basic 或 Normal。我一般先选 Normal,它包含 rename、constants、ctrl flow,并且用的是保守参数,不易翻车。
最后点工具栏上的 Protect 按钮。几秒钟后去输出目录里看,会多出一个同名的 exe。拿 dnSpy 打开这个 exe,原来叫 Form1 的类变成了 a,按钮点击事件变成 a.a(),方法体里的字符串也看不到了。这就是最小混淆的效果。
如何确认混淆真的生效?有两个快速判断:第一,用 dnSpy 打开混淆后的 exe,看类名是否已经不是源码里的名字;第二,直接在记事本里搜原字符串,比如你的数据库连接串、接口 URL,搜不到就说明 constants 生效了。这个方法最直观,也适合拿来给同事演示混淆价值。
3.2 crproj 项目文件:GUI 只是配置编辑器
ConfuserEx 的 GUI 会把所有配置存成一个 .crproj 文件,默认名字是项目名.crproj。这个文件是 XML,结构非常清晰,手工改它比反复开 GUI 快得多。一个典型的 crproj 长这样:
<?xml version="1.0" encoding="utf-8"?> <project outputDir="D:\Build\Confused" baseDir="D:\MyApp\bin\Release" xmlns="http://confuser.codeplex.com"> <rule pattern="true" preset="none"> <protection id="rename" /> <protection id="constants" /> <protection id="ctrl flow" /> </rule> <module path="MyApp.exe" /> </project>这里几个属性要注意。outputDir 是混淆后的输出路径;baseDir 是程序集的搜索目录,所有相对路径都基于它;rule 标签的 pattern 是匹配规则,pattern="true" 表示匹配所有模块,后面可以接更精细的 pattern 来控制某些命名空间或程序集。protection id 就是保护项,id 要和 ConfuserEx 内置的识别符一致,多一个空格都会报错。
如果某个依赖 dll 也要一起混淆,就在 project 下面多加一个 module 节点。如果依赖程序集不需要混淆,但希望它的公开类型能被主程序正常引用,可以用 probe path 把它作为探测项放进去,ConfuserEx 在混淆主程序时会去解析它,但不输出混淆版本。这个我在多项目解决方案里经常用。处理带依赖的桌面应用时,probe 往往能解决“混淆后引用找不到类型”的问题。
规则顺序也是坑。crproj 里的 rule 是从上往下匹配的,命中一条后不会继续往下走。所以特殊排除要写在前面,通用的放后面。比如先写一条 pattern 指定某个命名空间预设为 none,再写一条 pattern="true" 用 normal,这样大部分程序集用 normal,特殊区域保持原样。
3.3 命令行:把混淆留给 CI 去跑
GUI 适合第一次探索,但每次发版都要人来点按钮,迟早出错。ConfuserEx 的 CLI 用法很简单:
# 用指定的 crproj 执行混淆 Confuser.CLI.exe -n D:\MyApp\MyApp.crproj-n 参数后面跟 crproj 路径,命令行会按配置执行混淆并输出到 outputDir。没有 GUI,没有弹窗,适合接进 Jenkins、GitLab CI 或批处理。如果你维护多个产品,可以写一个脚本循环跑各自的 crproj:
for %%f in (D:\Build\Projects\*.crproj) do ( echo Processing %%f D:\Tools\ConfuserEx\Confuser.CLI.exe -n %%f if errorlevel 1 exit /b 1 )这脚本有个实际好处:混淆过程中某个程序集失败时,错误码不是 0,CI 会直接标红。但要注意,CLI 输出的是控制台日志,没有 GUI 的一步步进度条;日志里出现 ERROR 字样并不一定等于失败,具体要看退出码和生成的文件是否齐全。这里我建议在脚本里加上对输出目录的检查,比如判断 exe 是否生成、文件修改时间是否更新,比读日志可靠得多。
注意:crproj 里的路径如果写的是相对路径,CLI 的当前工作目录会影响解析。最稳妥的做法是把 baseDir 和 outputDir 全写成绝对路径,或者写成相对于 crproj 文件目录的相对路径,并让脚本先 cd 到 crproj 所在目录。
4. 生产级参数:四个保护项的配置与调节
跑通最小混淆之后,难点在于怎么把参数调到“够用且不翻车”。这一章讲我实际项目里用过的四组配置:重命名的排除策略、控制流的强度取舍、字符串加密的边界、强名称重签名。
4.1 renaming 的保留与排除:四个必调参数
renaming 保护在 crproj 里可以带参数。常见做法是给 rule 节点加 argument 子节点,指定选项名和值。我常用的四个如下:
<rule pattern="true" preset="none"> <protection id="rename"> <argument name="renaming" value="enable" /> <argument name="renamePublic" value="false" /> <argument name="reversible" value="false" /> <argument name="exclude" value="MyApp.Plugin.*" /> </protection> </rule>先看 renamePublic,上一章提过,外部契约库必须设为 false。reversible 决定是否可逆重命名:为 true 时会把原始名字用特殊编码藏进元数据,方便以后用映射文件还原堆栈,但代价是反向者可以用工具直接拿到原名表,强度大降。我一般全部设为 false,排错靠保留构建前的 pdb 来做。
exclude 是重命名的排除规则,支持通配符。它解决的是反射和序列化问题。比如你用 Newtonsoft.Json 序列化一个类,类型名被改了没关系,但属性名被改了,JSON 结构就变了,外部对接方直接解析失败。这时候把 DTO 类的命名空间排除掉,属性名就保住了。
excludeRegex 参数更狠,直接按正则排除。比如排除所有以 Config 结尾的类名。这个参数适合老项目里有大量反射调用的情况,但正则有性能开销,项目大了以后混淆时间会明显变长,所以一般只在必要的小范围用。
4.2 ctrl flow 的强度与性能取舍
ctrl flow 保护在 GUI 里看不到太多滑块,它主要通过 rule 的 preset 和本身参数控制。preset 越高,基本块切得越碎,插入的分发器层数越多,反编译观感越差,性能和体积的代价也越大。我在实战里通常用两个档位:普通客户端程序用 preset="normal",核心授权模块用单独一条规则开 maximum。
<rule pattern="true" preset="normal"> <protection id="ctrl flow" /> </rule> <rule pattern="MyApp.Auth.*" preset="maximum"> <protection id="ctrl flow"> <argument name="complexity" value="100" /> </protection> </rule>pattern 规则从上到下匹配,先匹配到的生效。上面配置的意思是:整体用 normal,但 MyApp.Auth 命名空间下用 maximum。maximum 和 normal 的区别简单说就是控制流被搅乱的程度:normal 下 dnSpy 还能勉强看出 if/else 轮廓,maximum 下基本就是一团乱麻。
complexity 参数控制额外引入的混淆循环层数,范围 0 到 100。值调高后,反编译出来会有大量无意义的分支和死代码,但 JIT 也会变慢。我见过有人把 complexity=100 用在 UI 线程上,结果界面卡顿明显。给个经验值:桌面应用大概 30 到 50,纯后端批处理程序可以上 80 以上。
还有一点:泛型和迭代器方法对 ctrl flow 不太友好。yield return 和 async/await 生成的状态机本来结构就复杂,再加控制流搅乱,偶尔会生成运行时才暴露的坏 IL。这类方法要么排除,要么把 preset 降到 basic。
4.3 constants 加密的边界:哪些字符串不能动
constants 保护会加密 IL 里的所有字符串常量,但有两个边界坑得很深。
第一个是反射用的字符串。Type.GetType 的参数、Assembly.Load 的参数,如果被加密后再解密,逻辑上没问题,因为运行时解密后返回值一样。但有些混淆配置会把这些字符串也改掉,导致混淆后行为异常。要排除的话,可以针对特定方法禁用 constants:
<rule pattern="true" preset="normal"> <protection id="constants"> <argument name="exclude" value="MyApp.Helpers::LoadPlugins(System.String)" /> </protection> </rule>第二个是资源文件。WinForms 的 .resx、WPF 的 ResourceDictionary,它们的访问路径也是字符串。ConfuserEx 的常量加密如果处理不当,可能把资源查找字符串改坏,导致运行时找不到图片或控件模板。实际排查过的情况是:图标没了、按钮文字变空白、皮肤加载失败。
我的处理习惯是:WPF 项目先跑一遍 constants 加密,运行一次把所有界面走一遍,没有异样再继续。资源类字符串如果出问题,就把相关方法排除,或者退回只用 rename + ctrl flow。另外,日志模块的字符串一般不建议加密,日志量大,运行时解密开销积少成多,而且日志内容本身没有保密价值。
4.4 强名称重签名与反调试联动
如果你的程序集用了强名称签名,混淆后签名链会断。原因很简单:混淆工具重写了 IL 和 metadata,原来的强名称签名值已经失效。运行时 CLR 做强名称校验会直接拒绝加载,报错信息通常是 Could not load file or assembly 或 Strong name signature could not be verified。
ConfuserEx 的 module 节点上支持指定 snKey 属性,在混淆流程里用同一把私钥重新签名:
<module path="MyApp.exe" snKey="D:\Keys\MyCompany.snk" />如果不想让混淆器管签名,也可以混淆完以后自己用命令行重签。常见做法是:
sn -R MyApp.exe D:\Keys\MyCompany.snk需要注意的是,sn -R 重签的前提是混淆后的程序集还保留着公钥 blob,否则会提示找不到公钥。另外,延迟签名的程序集需要特殊处理,混淆前要用完整签名替换掉延迟签名。这事容易在 CI 上翻车,我一般把密钥路径写进 crproj,让 ConfuserEx 一步做完,省得后续手工操作。
反调试和强名称的联动是另一层:anti debug 开启后,工具连接到进程做 dump 会被干扰。这对调试者也一样,所以发布前一定要自己跑一遍功能回归,别等到客户现场出问题才发现 anti debug 把正常环境也拦截了。强名称程序集如果同时开了 anti tamper,公钥校验和自我哈希会双重执行,启动时间会增加,但没那么夸张,可以接受。
5. ConfuserEx 踩坑清单:现象、原因、解决
这一章集中记录我实际踩过、以及帮别人排查过的坑。每条按“现象 → 原因 → 解决”写,都是真实发生在发布阶段的问题。
5.1 现象:加了混淆程序启动直接崩,事件日志报 MissingMethodException
原因通常有两个。一是重命名把某个反射查找的类型名改掉了,运行时 Type.GetType 返回 null,后续方法调用直接炸;二是 ctrl flow 对泛型方法或迭代器方法处理不全,生成了非法 IL。排查方法:先把保护项逐个关掉,确定是哪一个保护引起崩溃。
解决:如果是反射问题,用上一章说的 exclude 把相关类型排除;如果是 ctrl flow 崩溃,把出问题的类排除掉,或者降低 preset 到 basic。ConfuserEx 对 iterator(yield return)和 async 方法的兼容性比较差,这两种方法建议在规则里排除:
<rule pattern="true" preset="none"> <protection id="ctrl flow"> <argument name="exclude" value="MyApp.Business.*" /> </protection> </rule>5.2 现象:WPF 界面打开后图片丢失、资源字典加载失败,或者控件模板变成空白
原因:XAML 里的资源 URI 是字符串,constants 加密把字符串改了,或者 rename 把资源程序集里的类名改了,导致 Pack URI 无法解析。这是 WPF 项目最容易踩的坑,而且不一定在启动时暴露,可能打开某个窗口才出问题。
解决:把 WPF 相关的程序集单独建一条规则,只开 rename 和 ctrl flow,不开 constants;或者用 exclude 把资源访问方法排除。我处理过一个项目,最后是给整个视图层命名空间单独设了 preset="basic",只保留重命名,控制流和常量加密全部关掉,才在保证混淆强度的前提下让界面恢复。注意 App.xaml 里的 StartupUri 也属于资源引用字符串,最容易中招。
5.3 现象:杀软把混淆后的 exe 直接隔离或删除,客户机器上程序消失
原因:anti tamper 的自我校验逻辑、anti debug 的调试器检测,行为特征和恶意软件启动逻辑高度相似。尤其是 maximum 预设开启 invalid metadata 时,生成的非标准元数据也会触发启发式扫描。Windows Defender 对 anti debug 的敏感度特别高,经常直接删文件。
解决:在混淆配置里关掉 anti debug 和 invalid metadata,保留 rename、ctrl flow、constants,误报率明显下降。如果还是被杀,就要考虑换商业壳或加白名单签名了。对独立分发的小软件,我一般建议发布前把混淆配置调成“纯静态保护”,也就是不开任何运行时保护项,把误报风险压到最低。
5.4 现象:混淆后换了机器运行报错 Could not load file or assembly
原因:多半是混淆后依赖 dll 没有一起输出。ConfuserEx 默认只混淆你在 module 里列出的程序集,依赖项不会被自动处理。如果主程序引用了 Common.dll,而 Common.dll 没被混淆也没被复制到输出目录,换一台机器自然跑不起来。
解决:把要发布的依赖 dll 也加到 crproj 的 module 列表里,或者用 probe 指定依赖路径并在发布脚本里连同输出目录一起拷贝。我更推荐前者:把所有需要混淆的程序集全部枚举进 crproj,保证输出目录是完整的发布集合。同时,混淆后的程序集不要和原始程序集混放在同一个目录,避免 CLR 加载到未混淆的版本。
5.5 现象:加了 constants 后程序集体积膨胀好几倍
原因:constants 会把大量字符串变成字节数组,本身就会膨胀;如果同时开了 invalid metadata,还会生成大量垃圾元数据,体积直线上涨。曾经见过一个 3MB 的程序集混淆后变成 40MB,客户下载体验很差。
解决:放弃 maximum preset,手动挑选保护项。体积敏感的软件,建议只开 rename + ctrl flow;constants 对体积的影响排在第二位,排在 invalid metadata 之后。另外可以把字符串特别多的模块单独排除,比如把日志模块排除在 constants 之外,日志消息通常没敏感信息,不值得加密。发布前看一眼输出目录的文件总大小,和混淆前对比一下,膨胀超过 3 倍就要检查是不是某个保护项开过头了。
6. 验证混淆效果与自动化集成的两个收尾技巧
先给结论:混淆完不验证等于白混淆。最常见的验证方式是拿 de4dot 跑一遍脱壳测试。de4dot 对 ConfuserEx 有专门的检测插件,如果你混淆配置开得太弱,de4dot 能在几秒钟内还原出可读性不错的代码。
# 用 de4dot 尝试脱壳,注意不要真输出,先看检测结果 de4dot.exe --dont-rename D:\Build\Confused\MyApp.exe参数里 --dont-rename 指只检测并尝试还原字符串和控制流,不做符号重命名,这样能看出 ConfuserEx 的哪些保护被破了。如果 de4dot 日志里显示成功重写了大量方法,那说明你的配置还不够;如果它报错或者还原后的代码仍然是乱的,说明当前强度可以接受。我个人的习惯是:发版前把混淆后的 exe 丢给 de4dot 和 dnSpy 各看一遍,能随手还原就回炉加配置。
另一个落地技巧是把混淆结果集成进构建脚本,并且用文件哈希校验发布物。具体做法是每次混淆后记录 SHA256,发版时比对,防止程序集在传输途中被改掉:
Get-FileHash D:\Build\Confused\MyApp.exe -Algorithm SHA256这个习惯救过我一次:曾经因为杀软误删了部分文件,测试环境一直出现奇怪问题,最后比对哈希才发现发给客户的包少了依赖项。现在我的发布流程是:编译 → ConfuserEx 混淆 → de4dot 验证 → 记录哈希 → 打压缩包。每一步都落脚本,不靠人手点 GUI。希望帮到你。
本文还有配套的精品资源,点击获取