免责声明

本文撰写目的为分享技术, 仅供学习和研究目的, 不分享破解软件

如果喜欢某个软件, 请购买正版

遇事不决Die (雾

先把目标扔进 DetectItEasy 里查一下 看看什么成分

image-20240426191345880

.Net 4.0的DLL, ConfuserEx混淆

Confuser作为一个经典开源混淆, 各种修改变种花里胡哨, 比较难找到能够完全通杀的反混淆工具

首先拿去跑一遍UnconfuserEx清一清再拖进dotpeek里看, 根据api文档, 找到对应的controller看看反混淆效果怎么样

image-20240426191423502

似乎仍然有混淆没解开, 看看这几个StaticMethod

处理字符串加密

image-20240426191513893

一眼比较简单的字符串池类加密, 同时把 intbyte[] 也塞到池里一起混着存了, 根据参数传的key从池中取对应位置然后解密

修改UnconfuserEx的源代码, 增加一个transformer来处理掉它

大致处理流程如下

  1. 使用 Assembly.LoadFile 加载目标DLL
  2. 直接逐个扫描method body, 收集所有的key和对应的解密函数
  3. 挨个 Module.ResolveMethod 然后 MethodBase.Invoke 拿到解密函数返回的结果
  4. 将解密后的字符串替换回原位置

虽然这样并不优雅, 但对各类算法变异通杀效果好, 至于安全性…拽进Windows Sandbox跑 (点头

对这类字符串加密算法的改进可以考虑往上爬调用栈, 确保是来自于预期的地方的call

或者干脆把采用调用来源的某些特征作为解密密钥, 可以有效防止咱这样的直接call解密

当然…你跟踪调用栈…咱也可以模拟调用栈

所以, 有效, 但有那么一点点

image-20240426191820431

进行一个反混淆的跑, 将反混淆后的DLL再次反编译, 字符串已解密

还有一大堆奇奇怪怪的StaticMethod, 现在来处理掉它们

处理 InvokeProxy 混淆

image-20240426192037719

在反编译的代码中可以看到大量的这类函数及其调用, 特征鲜明的InvokeProxy类混淆

此类混淆的目的是掩盖调用目标, 将一目了然的调用转换为乱七八糟不知道在call什么的调用, 干扰逆向者理解代码

image-20240426192235627

IL码可以看到较为明显的特征, 即 使用ldarg将所有参数逐个压栈后执行实际操作, 再ret回去

同样修改UnconfuserEx的源代码, 增加一个transformer对此类混淆进行处理

大致反混淆流程如下:

  1. 根据特征识别代理函数
  2. 取出 ldarg后的第一条指令, 即执行的实际操作
  3. 扫描所有method, 寻找call代理函数的位置
  4. 把实际操作的指令替换回被代理的原位置

至少来个乱序压栈再重新摆正吧 (碎碎念

image-20240426192413635

再次进行一个反混淆的跑, 反编译可见代码逻辑已经很清晰了

开始分析

首先跟踪到Field4.GetMachineCode()IAuthorizeHelper.GetMachineCode()

查找Implementation定位到AuthorizeHelper.GetMachineCode()

image-20240426192611845

CpuId加密, Encrypt是简单的des算法, 没什么看头, 对 GetMachineCode 查找引用

image-20240426192641850

发现了似乎是判断激活的关键函数

image-20240426192651811

向下翻找变量 machineCode 的引用

image-20240426192708192

似乎和sqlite扯上了一点关系, 先暂时不管这数据库哪来的, 看看旁边的关键代码

  1. RSA解密密钥
  2. 从第八位开始截断, 将后面的字符串与 machineCode 匹配
  3. 前8位以 yyyyMMdd 形式, 猜测是授权到期日期

好的, 我们获得了注册码的编码结构信息

继续跟进 RSADecrypt 函数, 根据调用找到初始化密钥的位置

image-20240426193015224

Field1 是以xml形式编码的RSA密钥

并未发现其他引用这个Field的位置, 只传给了 RSADecrypt 函数

Take over the world!

我们已经获得了注册码的编码结构信息, 即 yyyyMMdd机器码

那么, 非对称加密的破解方案非常简单, 直接替换公钥再Keygen一把梭

首先自己生成一份公私钥, 按照同样的编码方式编写Keygen程序用来生成授权

由于目标程序被混淆保护, 直接进行修改比较复杂, 且容易一头撞到保护壳的反篡改校验上

更加优雅的采用Hook方案将破解注入到目标程序中

  1. 新建.Net DLL项目
  2. 添加 Lib.Harmony Hook框架
  3. 劫持AuthorizeHelper.RSADecrypt , 下 Prefix Hook
  4. 篡改第一个参数, 即RSA的密钥, 将我们生成的公钥换进去
  5. 编译之, 破解补丁get

IIS的部署方式, 需要想办法将补丁DLL注入进去, 虽然这样并不优雅(?, 不过以简单粗暴的方式解决问题

  1. 找一个没有上保护的依赖DLL
  2. dnSpy加载修改
  3. 随便找一个一定会在校验授权前先被调用的class
  4. .cctor() 函数, 即class的static initializer中插入代码

image-20240426193438395

启动IIS服务, 观察日志确定DLL注入成功, 获取机器码, 填入keygen, 生成授权, 导入

激活成功

一个彩蛋

写完破解补丁并测试成功后, 突然发现…..

image-20240426193950068

作者把私钥也放在了 Field1 的xml里面

特喵这辈子第一次见到基于非对称加密的授权方案这么做的