免责声明
本文撰写目的为分享技术, 仅供学习和研究目的, 不分享破解软件
如果喜欢某个软件, 请购买正版
遇事不决Die (雾
先把目标扔进 DetectItEasy
里查一下 看看什么成分
.Net 4.0的DLL, ConfuserEx混淆
Confuser作为一个经典开源混淆, 各种修改变种花里胡哨, 比较难找到能够完全通杀的反混淆工具
首先拿去跑一遍UnconfuserEx清一清再拖进dotpeek里看, 根据api文档, 找到对应的controller看看反混淆效果怎么样
似乎仍然有混淆没解开, 看看这几个StaticMethod
处理字符串加密
一眼比较简单的字符串池类加密, 同时把 int
和 byte[]
也塞到池里一起混着存了, 根据参数传的key从池中取对应位置然后解密
修改UnconfuserEx的源代码, 增加一个transformer来处理掉它
大致处理流程如下
- 使用
Assembly.LoadFile
加载目标DLL - 直接逐个扫描method body, 收集所有的key和对应的解密函数
- 挨个
Module.ResolveMethod
然后MethodBase.Invoke
拿到解密函数返回的结果 - 将解密后的字符串替换回原位置
虽然这样并不优雅, 但对各类算法变异通杀效果好, 至于安全性…拽进Windows Sandbox跑 (点头
对这类字符串加密算法的改进可以考虑往上爬调用栈, 确保是来自于预期的地方的call
或者干脆把采用调用来源的某些特征作为解密密钥, 可以有效防止咱这样的直接call解密
当然…你跟踪调用栈…咱也可以模拟调用栈
所以,
有效, 但有那么一点点
进行一个反混淆的跑, 将反混淆后的DLL再次反编译, 字符串已解密
还有一大堆奇奇怪怪的StaticMethod, 现在来处理掉它们
处理 InvokeProxy 混淆
在反编译的代码中可以看到大量的这类函数及其调用, 特征鲜明的InvokeProxy类混淆
此类混淆的目的是掩盖调用目标, 将一目了然的调用转换为乱七八糟不知道在call什么的调用, 干扰逆向者理解代码
IL码可以看到较为明显的特征, 即 使用ldarg将所有参数逐个压栈后执行实际操作, 再ret回去
同样修改UnconfuserEx的源代码, 增加一个transformer对此类混淆进行处理
大致反混淆流程如下:
- 根据特征识别代理函数
- 取出
ldarg后的第一条指令
, 即执行的实际操作 - 扫描所有method, 寻找call代理函数的位置
- 把实际操作的指令替换回被代理的原位置
至少来个乱序压栈再重新摆正吧 (碎碎念
再次进行一个反混淆的跑, 反编译可见代码逻辑已经很清晰了
开始分析
首先跟踪到Field4.GetMachineCode()
即IAuthorizeHelper.GetMachineCode()
查找Implementation定位到AuthorizeHelper.GetMachineCode()
CpuId加密, Encrypt是简单的des算法, 没什么看头, 对 GetMachineCode
查找引用
发现了似乎是判断激活的关键函数
向下翻找变量 machineCode
的引用
似乎和sqlite扯上了一点关系, 先暂时不管这数据库哪来的, 看看旁边的关键代码
- RSA解密密钥
- 从第八位开始截断, 将后面的字符串与
machineCode
匹配 - 前8位以
yyyyMMdd
形式, 猜测是授权到期日期
好的, 我们获得了注册码的编码结构信息
继续跟进 RSADecrypt
函数, 根据调用找到初始化密钥的位置
Field1
是以xml形式编码的RSA密钥
并未发现其他引用这个Field的位置, 只传给了 RSADecrypt
函数
Take over the world!
我们已经获得了注册码的编码结构信息, 即 yyyyMMdd机器码
那么, 非对称加密的破解方案非常简单, 直接替换公钥再Keygen一把梭
首先自己生成一份公私钥, 按照同样的编码方式编写Keygen程序用来生成授权
由于目标程序被混淆保护, 直接进行修改比较复杂, 且容易一头撞到保护壳的反篡改校验上
更加优雅的采用Hook方案将破解注入到目标程序中
- 新建.Net DLL项目
- 添加
Lib.Harmony
Hook框架 - 劫持
AuthorizeHelper.RSADecrypt
, 下Prefix
Hook - 篡改第一个参数, 即RSA的密钥, 将我们生成的公钥换进去
- 编译之, 破解补丁get
IIS的部署方式, 需要想办法将补丁DLL注入进去, 虽然这样并不优雅(?, 不过以简单粗暴的方式解决问题
- 找一个没有上保护的依赖DLL
- dnSpy加载修改
- 随便找一个一定会在校验授权前先被调用的class
- 在
.cctor()
函数, 即class的static initializer中插入代码
启动IIS服务, 观察日志确定DLL注入成功, 获取机器码, 填入keygen, 生成授权, 导入
激活成功
一个彩蛋
写完破解补丁并测试成功后, 突然发现…..
作者把私钥也放在了 Field1
的xml里面