首页
社区
课程
招聘
[原创] 记一次so文件动态解密
发表于: 2020-7-8 11:32 22841

[原创] 记一次so文件动态解密

2020-7-8 11:32
22841

整个程序基本上就是一个 动态注册 + so函数加密 的逻辑,中间加了一些parser的东西

主要考察了elf文件结构的一些知识以及在攻防对抗中防止IDA静态分析的姿势

找到flag

360加固,先脱壳,看入口函数MainActivity

具体的逻辑写到so里了,使用IDA打开so文件,先看有没有.init.init_array,发现只有.init_array节,

跟进去一看又是字符串解密函数,解密之后,代码如下(这里我根据解密后的数据进行了重命名)

回过来看JNI_Onload函数,

其实就是将native函数test函数动态注册到ooxx函数,直接看ooxx函数

可以发现除了调用了sub_8930之外,就是一堆垃圾代码,先跟进sub_8930函数

这里我把函数分为三块,先看第一块

经过分析,实际上就是读/proc/self/maps的标准输出,从而获取到对应于libnaitve-lib.so的那一行,然后以-分割字符串,并将分割后的第一段解析为16进制的数,实际上就是获取libnaitve-lib.so的加载基地址。

再看第二块,也就是sub_8B90函数的实现

这个地方你仔细地去分析对比,会发现其实就是一个读so文件的对应于symbol nameooxxsymbol table表项中的valuesize,其实就是读ooxx的函数起始地址以及函数大小。其实也就是一个parser的过程之一

对了,这个函数中的一行,也就是v5 = turn_ooxx(s2);这里调用的turn_ooxx函数中的伪代码直接copy出来跑一跑,就可以得到v5的值。我也没有分析这个过程,直接跑的。。

接着看sub_8930函数的第三块。

经过分析会发现,围绕mprotect函数将这个部分再次分成三块,分别实现功能为

这里第二块中的*i ^= byte_1C180[&i[-v5]];这个部分,再加上byte_1C180实际上在bss段,不想再去分析了,直接动态吧。
这里使用objection在动态运行时dump出对应内存中的数据,

使用010 editor查看对应文件

很明显那就是0-255的字节咯,继续看伪码,会发现实际上这里的&i[-v5]实际上就相当于i-v5,而v5i的初值,那么patch脚本就有了

执行这个脚本之后,查看ooxx函数内容

最终会发现,实际上ooxx就是拿我的输入和kanxuetest进行对比。。验证下

拿到flag

整个程序实际上真正难的地方在于看出parser的过程,不过我猜如果写过parser相信会很容易的看出来,还有
另外,这个程序有点类似于之前寒冰师傅说的在函数执行开始之前对函数内容进行恢复,函数执行结束时再还原回加密状态,再加上插入了一堆MOV R0, R0这种无效代码,让我感觉真像so层的"函数抽取壳"的实现。。神奇的题目,最后,附上附件


[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

最后于 2020-7-8 11:32 被Simp1er编辑 ,原因:
上传的附件:
收藏
免费 12
支持
分享
最新回复 (23)
雪    币: 4883
活跃值: (18890)
能力值: ( LV13,RANK:317 )
在线值:
发帖
回帖
粉丝
2
感谢分享~
2020-7-8 14:18
0
雪    币: 19950
活跃值: (4942)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
感谢楼主分享
2020-7-9 18:37
0
雪    币: 1
活跃值: (500)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
请问这个是2w班的练习题吗?
2020-7-10 10:42
0
雪    币: 241
活跃值: (15)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5
更新搂主分享
2020-7-13 07:33
0
雪    币: 10944
活跃值: (7329)
能力值: ( LV12,RANK:219 )
在线值:
发帖
回帖
粉丝
6
请问脱壳那里 native onCreate是怎么还原的?
2020-7-14 13:23
0
雪    币: 2270
活跃值: (5537)
能力值: ( LV8,RANK:146 )
在线值:
发帖
回帖
粉丝
7
Necopy 请问这个是2w班的练习题吗?
2020-7-14 13:47
0
雪    币: 2270
活跃值: (5537)
能力值: ( LV8,RANK:146 )
在线值:
发帖
回帖
粉丝
8
neilwu 请问脱壳那里 native onCreate是怎么还原的?
不需要还原
2020-7-14 13:47
0
雪    币: 10944
活跃值: (7329)
能力值: ( LV12,RANK:219 )
在线值:
发帖
回帖
粉丝
9

这里是脱壳之后就有的嘛? 请问你用的什么脱壳的?

2020-7-14 14:20
1
雪    币: 2270
活跃值: (5537)
能力值: ( LV8,RANK:146 )
在线值:
发帖
回帖
粉丝
10
neilwu 这里是脱壳之后就有的嘛? 请问你用的什么脱壳的?
对的,FART脱的壳
2020-7-14 14:43
0
雪    币: 196
活跃值: (5906)
能力值: (RANK:10 )
在线值:
发帖
回帖
粉丝
11
不论是dex保护中的函数抽取,还是so中函数的保护,时机都是非常关键的。时机不对,即使是正确的内存地址偏移,dump得到的smali指令流以及汇编代码都可能是不对的,依然是未解密的字节流。这道题是对so中函数的一个保护,在被保护的函数的关键逻辑执行前进行解密,执行结束后会再次对关键逻辑进行加密。因此,正确的时机便是关键逻辑被解密后,抓住这一点便能成功拿到flag
2020-7-14 17:07
1
雪    币:
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
12
大佬 牛i逼
2020-7-29 11:04
0
雪    币:
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
13
牛i逼
2020-11-21 22:10
0
雪    币: 160
活跃值: (86)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
14
牛大佬佩服
2020-11-29 00:00
0
雪    币: 178
活跃值: (1306)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
15
感谢分享
2021-7-23 09:24
0
雪    币: 116
活跃值: (1012)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
16
大佬牛逼
2021-7-27 02:04
0
雪    币: 158
活跃值: (1111)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
17
请问2w班有对该练习题进行讲解吗?
2023-4-1 10:41
0
雪    币: 158
活跃值: (1111)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
18

您好,执行您的patch脚本之后,0x8e00——0x8fd0的汇编全变成MOV             R0, R0,然后反编译后,出现下面的问题,请问您知道原因吗?

2023-4-1 11:34
0
雪    币: 324
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
19
我也是和楼上一样
2023-5-11 16:10
0
雪    币: 2270
活跃值: (5537)
能力值: ( LV8,RANK:146 )
在线值:
发帖
回帖
粉丝
20
Losir 我也是和楼上一样
时间太过久远,我已经忘了 实在抱歉,麻烦自己再研究研究吧,可以先把原来的byte show出来,然后看看执行完函数的byte是什么样,确定下是否函数执行成功了,关注下output窗口是否有错误日志出来吧
2023-5-15 09:28
0
雪    币: 324
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
21
Simp1er 时间太过久远,我已经忘了[em_5] 实在抱歉,麻烦自己再研究研究吧,可以先把原来的byte show出来,然后看看执行完函数的byte是什么样,确定下是否函数执行成功了,关注下output窗口是否有 ...
大佬,感谢回复,你的patch代码有问题,当i=255,取余为0,但实际上应该和0xff亦或,当i=256,取余为1,但实际上应该和0亦或,也就是说,从i=255开始,后面的patch全错了。
2023-5-23 11:57
0
雪    币: 324
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
22
Simp1er 时间太过久远,我已经忘了[em_5] 实在抱歉,麻烦自己再研究研究吧,可以先把原来的byte show出来,然后看看执行完函数的byte是什么样,确定下是否函数执行成功了,关注下output窗口是否有 ...
def patchBytes(addr, length):
    for i in range(length):
        if i < 255:
            byte = get_bytes(addr + i,1)
            byte = ord(byte) ^ (i % 0xff)
            patch_byte(addr + i, byte)
        elif i == 255:
            byte = get_bytes(addr + i,1)
            byte = ord(byte) ^ 0xff
            patch_byte(addr + i, byte)
        else:
            byte = get_bytes(addr + i,1)
            byte = ord(byte) ^ ((i - 1) % 0xff)
            patch_byte(addr + i, byte)

patchBytes(0x8e00, 0x8fd0 - 0x8e00)   修改后的脚本
2023-5-23 12:15
0
雪    币: 324
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
23
教教我吧~ 您好,执行您的patch脚本之后,0x8e00——0x8fd0的汇编全变成MOV &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; & ...
可以看我的回复,patch之后记得保存,然后用ida 重新打开就ok啦。
2023-5-23 12:17
1
雪    币:
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
24

APK样本方便再上传下 不? 可以了 我网络问题一开始显示过期了

最后于 2024-4-19 09:46 被ivy1编辑 ,原因:
2024-4-19 09:45
0
游客
登录 | 注册 方可回帖
返回
//