首页
社区
课程
招聘
[原创]某笔记app深度混淆魔改md5逆向思路
发表于: 4天前 795

[原创]某笔记app深度混淆魔改md5逆向思路

4天前
795

看标题大家都知道是哪个软件了,由于特殊原因,本文作为发布各平台的免费文章因为传播性会更广 所以不会去写那么直白的,而且本文也重点讲其中最核心的魔改md5算法的逆向思路,文中会附带我自己开发的逆向工具使用;会的朋友可以选择跳过本文了,当然你也可以看看我的分析方法,估计和你的会不太一样

这里的样本是9.24.0,是最新版;不过初步看和其他版本差不多,除非使用太老的版本的话好像说没有魔改md5,这个我不是很清楚了,没有验证。

我希望通过这个文章能够给大家讲明白魔改md5的一种通用打法吧,因为这个案例魔改点位非常的多,而且还经过了定制化的ollvm,以前的方法基本都失效了,基本上也别指望ida了,老老实实看trace了,但是看trace还不让你省心,因为存在一个hmac,这会导致交叉多轮md5。。。 这时候你跟trace一定要跟紧了。

首先抓包看一下,看一下ua如果有什么okhttp那么大概率是okhttp框架,如果是http协议也可以默认大概率是;如果抓不到或者是其他情况就需要小心,其他协议或者其他框架了;

那okhttp又怎么hook呢?这里需要知道一些开发知识,首先,这个header参数是很多请求都有的,那么他大概了不会针对某一个请求来添加header参数,而是用一套可以复用的逻辑来添加header;

这在okhttp中就是典型的拦截器了,举一个生活化的案例,处理污水,污水流经某一个管道,你加了点试剂让他沉淀,这样流经的所有污水都会被处理;这在okhttp框架中就是拦截器机制,这个机制太常见了,常见到你在很多开源工具都能看见;

本质:统一处理链(Interceptor Pipeline)

那我们怎么定位他某一个拦截器添加了header呢?你得先 hook 到他添加了哪些拦截器,然后在去 hook 这些拦截器的实际拦截函数,然后进入和退出的时候打印一下header,也可以做个diff对比,这样你可以知道 拦截器1加了shie** ,拦截器2加了x-mini-sig;

效果图如下:image-20260407160259079

在native层,这个可以用unidbg来补,主要难点就是okhttp框架的一堆东西,这个可以在unidbg的pom.xml中引入okhttp框架,往上文章太多了;

image-20260407160415912

而这个案例呢,要用unidbg补的话你最好是利用jnitrace看日志然后补,不会补可以看网上文章,或者直接丢给ai来补;最后补出来会在某个jni日志看到shie** ;这个过程需要一定的耐心

image-20260407160442275

这里我就省略了前期的部分字节的逆向过程了,主要就是16+83 字节,后面83字节是什么rc4得到的;然后83字节中又有好几部分,其中最后一部分是16字节,是魔改md5

image-20260407160546462

初始变量改了, 不过只是部分交换;但是要怎么确保用的是对的??

image-20260407160801502

64轮的函数由于恶心的ollvm导致完全展开,ida是真的基本看不了一点;

image-20260407160742055

T表全换:可以从trace中定位偏移规律,然后找到存在ida中的位置,然后写ida脚本 dump出来,也可以找trace规律写正则脚本提取

T表轮间乱序:但T表dump出来的还不行,中间md5的64轮 某些轮次(比如39和40)之间还有交换,所以你会看到T表乱飞的情况,要同步改

image-20260407160818095

这个乱飞的过程实际上是很恶心的;如果你只是简单交换T表是不行的,因为他的abcd也有不同, 所以有的时候要用展开的md5写法才行

整个md5涉及的所有变量都是一个地址,不管是abcd还是f,还是中间变量,全是查表+偏移的,基本上用不了;类似什么v1+496 v+520这种,然后还不是所有的都是查表+偏移,而且偏移是在移动的,有点类似与滑动窗口的样子?? 具体看前面的图

然后为了计算一次hash 会md5 多个64字节的情况,这一点你需要计算出80后面的长度位然后计算字节来判断;但是你还得知道多轮md5到底是怎么做的;

我们可以利用一些规律,比如第一次的md5和第二次的md5在 64轮的第一轮的T表都是一样的,然后作为锚点,借机找到明文加载的pc地址,然后写批量脚本提取每一轮md5的明文;

image-20260407160916255

但是这里还会出现某一轮特殊的情况;其实原因是因为他是多次md5交叉的情况,你在trace中会看见5次md5,那么哪几次是连续的??要怎么根据trace日志还原呢?

还有就是怎么识别出hmac吧。虽然其实你知不知道hmac都不影响算法还原,因为可以视作两轮hash和两个salt;但是如果知道的话,你在逆向的过程肯定是能省一定时间的,而且写还原算法会简洁一点

image-20260407161004702

✔ 静态分析基本失效✔ 必须依赖 trace✔ 需自动化辅助

首先必须trace;

下面的讲解如果看不懂的话,建议关注我的同名b站账号,我今天会出一期进行讲解,会比文章详细得多,因为文字有的时候描述不清楚;

下面我画个图,圈一下涉及到的初始abcd

image-20260407161112417

第一轮参与: 第一处是参与64大轮的第一小轮,但是你怎么保证你的a不会看错d?b和c不会看错?如果是b的话都好说,应该还有其他特征

最终累加:第二处是末尾的和算法出来的abcd相加,这一点是非常有用的,下面给两个trace日志

比如我这里的是 ef29bddaca2a67b2dcff858ad588a2b6,那么根据端序还有md5特点,我知道 dabd29ef 是a,而且这个a应该是两个值加出来的,所以汇编中用正则来搜肯定是 add.*=>.*=0xdabd29efimage-20260407161345374接下来要进行候选判断 :搜出来了0x9bccab01和0x3ef07eee就可以思考谁是原始的a,谁是64轮的a了?这时候如果我们找到了4个初始的abcd,那么这两个中间肯定有一个是,哪个是,哪个就是初始a,另一个是64轮算出来的a;3. 那么这时候就取决于你知道的条件了,因为要根据这个算法的魔改程度来判断;

image-20260407161602173

突破点:

接下来就可以重点突破这几个地方;这里假设他都魔改了,那么我们先突破一波明文

方法:

扫描 0x80 padding

定位写入点image-20260407161643078![image-20image-20260407170048664

比如这个app的案例,这里就是hmac所以有两次hash,全被我逮到了;

换别的大厂看看; jd/ks

image-20260407161831568

image-20260407161925759

这里是适配使用了md结构的hash,包括md家族和sha家族的hash;还有别的扫描方案,其实我感觉大家都会写代码,直接让ai给你写一个就完事了,不过需要加过滤条件才能稳定,不然的话可能2000-3000条日志,这种就失去了意义了;所以如果需要的朋友进我星球自取吧,一是我能赚点米,二是我后面也还有更新,为了这东西单独发篇文章说明更新了什么没啥意义。

这样我们就可以知道他在哪写入0x80了,我们可以根据pc和lr地址跳过去分析了;这时候你就可以找到他魔改md5的函数入口,可以hook拿到输入和输出

MD5 特征:必有 0x80, 除非他魔改掉这个字节

通过前面的明文,还有a,那么我们就差f_old和T了,这时候你只需要知道谁是参与&、^、| 算出来的谁就是f_old,谁是固定ldr出来的,谁大概率是T;

比如我们前面不是搜到了 [libxyass.so 0x12000000+0x84010] 0x12084010: "add w8, w11, w8" ; w11=0x9bccab01 w8=0x3ef07eee => w8=0xdabd29ef

然后这里的0x9bccab01 和 0x3ef07eee 肯定有一个是b,然后我们直接往上翻这几个东西

image-20260407162249479

结果在这里就翻到了第一个值是经过ror得到的,那不就是f么,所以0x3ef07eee 是b

所以0x9bccab01 是被0xb025f196左移得到的,那0xb025f196是f,f = f_old + a + T +M[g]

然后你的a,M都可以知道了,那么T不就确定了?

这时候你就知道T了,然后你如果知道了第二轮的T。第三轮的T,那你可以利用ldr的规律找到他们的加载偏移,从而找到最开始的点位,直接dump。64个T出来;

这时候还能推出b来:你可以借助第一轮的abcd得到f_old,也可以通过&^|排查出来, 还知道T, M还知道左移,你可以算出第一轮新的b

md5的64大轮本质就是生成了64个新b

把md5函数打开,然后每一轮输出下图这样的日志,那么你就可以根据这里的b去trace中搜,如果搜到了,大概率那一轮及以前算的没问题,这时候如果错了,可以利用二分法来定位哪个b算错了,这时候可以排查出到底是哪一轮及以前开始出问题了。这个过程中可以关注f函数是否魔改? 左移量是否魔改? T表是否魔改?明文块是否交叉?这个案例中,除了f函数没有魔改意外,其余全部都会出现。。。所以你一定要会这个逐步定位错误点的问题。

image-20260407163032183

公式可以看上图

新b = 上一轮的旧b + f被左移后的值

这里是算出一个f然后和上一轮的b相加得到新的b,那么你如果知道了上一轮的b,你是不是可以根据add.*上一轮的b 然后搜到下一轮的b的生成点位?比如上一轮的b是0x7e9b89fb 那你就可以写正则:add.*0x7e9b89fb.*=>.*

image-20260407163125504

这里为啥会有两个,因为abcd在64轮中 会有轮转,可能在某一轮就变成了a然后和某个值add了得到了f,这里简单排除一下就知道了,肯定是最早的。

然后你就知道下一轮的b是0x7fb057bc或者0x77ec1bb1; 这时候你可以排除一下,可以根据pc地址跳过去看看谁可疑? 还可以根据这两个值得生成,比如第一个值"add w8, w8, w6" ; w8=0x114cdc1 w6=0x7e9b89fb => w8=0x7fb057bc那么我可以搜0x114cdc1是不是经过了左移得到的:

image-20260407163302279

比如这个图,就很明显了对吧。那么你就从第一轮一直可疑延续到64轮结束,这个过程会很累,有没有什么办法批量?

在这里实际上不是很好搞;但是还是值得的,因为我64轮主要逆向的是20轮左右,其他的都是写脚本dump出来的常量然后再改的;比如你发现左移的汇编大部分都是如下:image-20260407163302279

那么你就可以根据f要准备左移得到新的f,这个新的f会和上一轮的b相加,对吧,那你可以利用这个过程,写正则脚本,然后提取出相似的汇编块,注意这几句汇编可能中间是有其他汇编的,所以你写的模式最好是智能一点:


传播安全知识、拓宽行业人脉——看雪讲师团队等你加入!

收藏
免费 23
支持
分享
最新回复 (8)
雪    币: 11134
活跃值: (9088)
能力值: ( LV12,RANK:250 )
在线值:
发帖
回帖
粉丝
2
严肃学习
4天前
0
雪    币: 35
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
3
666
4天前
0
雪    币: 124
活跃值: (1480)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
严肃学习
4天前
0
雪    币: 7
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
5
感谢分享
4天前
0
雪    币: 0
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
6
严肃学习
3天前
0
雪    币: 104
活跃值: (8162)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
7
tql
3天前
0
雪    币: 1930
活跃值: (2605)
能力值: ( LV4,RANK:40 )
在线值:
发帖
回帖
粉丝
8
已严肃学习
2天前
0
雪    币: 441
活跃值: (690)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
9
1
2天前
0
游客
登录 | 注册 方可回帖
返回