给手里的一个 Windows 桌面工具做保护、签名、打包,本来想着一个下午能搞定,结果从下午弄到后半夜。趁还记得,把踩的坑按顺序记一下,同样在做 .NET 保护的可以少走点弯路。
工具是「七亿批量远程管理工具」,WinForms 写的,目标框架 net10.0-windows,干的活是远程桌面 / SSH / SFTP / RDP 一站式管理。
先说我选的方案:防反编译、防抄代码,用 .NET Reactor 加壳;防「未知发布者」、防篡改,用 OV 代码签名证书;最后发给客户,用 Inno Setup 做安装包。听着挺顺,做起来全是坑。
坑 1:.NET 5+ 的 exe,根本不是程序本体
第一个报错就很劝退:
RDPManager.exe is not a valid .NET file!原因:.NET Core / .NET 5+ 编译出来的 .exe,只是一层原生启动器(apphost),真正的托管代码在同名的 .dll 里。加壳工具打开 exe 一看是个原生二进制,自然不认。
所以记一条:要给 .NET 5+ 的程序加壳,保护的是那个 .dll,不是 .exe。
坑 2:加壳和「单文件」天生打架
一开始图省事,想用 dotnet publish -p:PublishSingleFile=true 打成单文件,结果加了壳还是那句 not a valid .NET file。
单文件是把所有托管程序集塞进一个原生壳里,加壳工具根本读不出来,压缩过的更读不出来。想在加壳之前打单文件,这条路走不通。要么保护 dll(多文件),要么保护完再用别的打包器去封(那是另一回事,见坑 6)。
不过多文件也没那么可怕,框架依赖版也就十几个文件。
坑 3:混淆之后,JSON 解析全挂了
这个最阴。加壳完,程序看着一切正常,唯独「流量监控」那个界面——左边日志里数据明明来了,右边图表一直显示「等待数据」。
查了半天才明白。代码里大概是这样:
private class AgentResponse {
public List<InterfaceData> interfaces { get; set; }
public string time { get; set; }
}
// ...
var data = JsonSerializer.Deserialize<AgentResponse>(json, opt);System.Text.Json 是靠属性名去匹配 JSON 的 key 的。混淆器把私有类的属性名全改成了乱码,interfaces 对不上,反序列化拿到 null,图表自然没数据。
修法是给属性钉死 JSON 名:
[System.Text.Json.Serialization.JsonPropertyName("interfaces")]
public List<InterfaceData> interfaces { get; set; }只要数据类是 private,混淆 + System.Text.Json 就几乎必踩这个坑。以后新增 JSON 数据类,要么加 [JsonPropertyName],要么干脆设成 public。
坑 4:签名顺序错了,签了也白签
签名本身不难,难在顺序:
- 混淆会大改二进制,所以必须「先混淆、后签名」,反了直接作废;
- 改一行代码、重跑一次混淆,签名就没了,必须重签;
- 主程序的 exe 和安装包(setup.exe)都要签,少签一个,用户下载时照样弹「未知发布者」;
- 签名一定要带时间戳(
/tr+/td SHA256),不然证书一过期,你发出去的老版本签名也跟着失效。
另外一个小坑:signtool 不是系统自带的,得装 Windows SDK 里的 Signing Tools,或者用 VS 的「开发者命令提示符」。
坑 5:Inno Setup 的「语言」,其实有两个
做安装包时想让界面变中文,找了个 ChineseSimplified.isl 丢进 Languages\,结果在设置里怎么也找不到中文选项。
后来才搞明白:Languages\*.isl 是给「你做出来的安装包」用的语言,也就是客户安装时看到的那个向导。它不会把 Inno Setup 编辑器本身变中文——编辑器界面官方只有英/德/日/捷/荷几种,7 版还明确写了不接受额外语言。所以编辑器就老实看英文吧,反正也就点一个 Build。你要的中文,是在装出来的那个安装包上,那才是给客户看的。
坑 6:交付形态选哪个
最后一道选择题:
- 自包含 + 安装包:文件多(运行时几百个,被安装包藏起来),客户不用自己装 .NET,最省心;
- 框架依赖的绿色版:文件少,十几个,客户要自己装运行时,轻、免安装、删文件夹即卸;
- 打包器封成单 exe:就一个文件,看你封的哪版,但极易招杀软误报,慎用。
我最后是主体发绿色版 zip,解压即用、不写注册表;另外配一个安装包,给想要「一个文件」的客户。
注意:想搞「单文件」的话,别用加壳工具直接处理单文件(见坑 2),只能保护完再用打包器封;而打包器封出来的 exe 是杀软误报重灾区,发之前一定丢 VirusTotal 实测过再发。
从「加壳报错」到「混淆搞挂 JSON」再到「编辑器没中文」,一天下来最大的感受是:加壳保护不是点一下按钮就完事,它对代码里那些「依赖名字」的东西——反射、JSON 序列化、资源名——特别敏感。
所以加壳之后,SSH、网络解析、序列化这些「靠名字」的功能,一定要逐项回归测试,别只看「主界面能打开」就发。保护做完也不代表万事大吉,签名、打包、杀软复查,一环扣一环,又给自己上了一课。
工具在这:rdp.7ehl.com,远程桌面 / SSH / SFTP / FTP 一站式管理,有需要可以看看。
评论