首页
社区
课程
招聘
[原创]android so文件攻防实战-某团libmtguard.so反混淆
2022-3-13 11:59 20949

[原创]android so文件攻防实战-某团libmtguard.so反混淆

2022-3-13 11:59
20949

计划是写一个android中so文件反混淆的系列文章,目前这是第二篇。
第一篇:android so文件攻防实战-百度加固免费版libbaiduprotect.so反混淆
样本在附件。我偷个懒,就不完整分析整个so文件了,只分析一下JNI_OnLoad。打开IDA,JNI_OnLoad长这个样子:

BEQ和BNE是一对条件相反的跳转,这之前计算出接下来指令的地址0x3430赋值给R4,loc_340C处的代码通过POP指令将R4的值给PC,看0x3430处的代码。


接下来的代码很多都是这种动态计算跳转地址的。0x3432处的指令从0x3438中取一个dword给R0,跳到0x3440然后再跳到0x407C。0x3444处开始不是指令而是一个跳转表,索引就是R0,值就是接下来指令地址的偏移,0x407C开始的代码就是取这个偏移。所以我们可以写一个脚本patch,计算出偏移,在0x3434处就直接跳过去。

同时还会有一些跳转到0x4094的指令,像上面这样0x3464跳到0x4094之后会返回到0x346C,从0x3462到0x346C这些指令我都直接patch成NOP了。
修复脚本:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
import keystone
from capstone import *
import idc
import ida_bytes
import subprocess
 
arch = keystone.KS_ARCH_ARM
mode = keystone.KS_MODE_THUMB
ks = keystone.Ks(arch, mode)
md = Cs(CS_ARCH_ARM, CS_MODE_THUMB)
 
def is_BLX_sub407C(ea):
    ldr_addr = ea
    ldr_flags = idc.get_full_flags(ldr_addr)
    if not idc.is_code(ldr_flags):
        return False
 
    if idc.print_insn_mnem(ldr_addr) != 'BLX':
        return False
 
    if idc.print_operand(ldr_addr, 0) != 'sub_407C':
        return False
 
    return True
 
def is_BLX_sub4094(ea):
    ldr_addr = ea
    ldr_flags = idc.get_full_flags(ldr_addr)
    if not idc.is_code(ldr_flags):
        return False
 
    if idc.print_insn_mnem(ldr_addr) != 'BLX':
        return False
 
    if idc.print_operand(ldr_addr, 0) != 'sub_4094':
        return False
 
    if idc.print_insn_mnem(ldr_addr - 2) != 'PUSH':
        return False
 
    if idc.print_insn_mnem(ldr_addr + 8) != 'POP':
        return False
 
    return True
 
def func_patch():
 
    ins_addr = idc.next_head(0)
    while ins_addr != idc.BADADDR:
 
         if is_BLX_sub407C(ins_addr):
            for i in CodeRefsTo(ins_addr, False):
                if idc.get_wide_word(i + 4) == 18112:
                    index = idc.get_wide_word(i + 6)
                    patch_qword(i + 6, 0x46C046C0)
                    idc.create_insn(i + 6)
                else:
                    index = idc.get_wide_word(i + 4)
                    patch_qword(i + 4, 0x46C046C0)
                    idc.create_insn(i + 4)
                print("i:" + hex(i))
                index = index * 4 + ins_addr + 4
                offset = ida_bytes.get_dword(index)
                target = ins_addr + 0x4 + offset
                command = "BL " + hex(target)
                print("command:" + command)
                pi = subprocess.Popen(['D:\\keystone-0.9.2-win64\\kstool.exe', 'thumb', command, \
                hex(i)], shell=True, stdout=subprocess.PIPE)
                output = pi.stdout.read()
                ins = str(output[-15:-4])[2:-1]
                ins = ins.split(" ")
                ins = "0x" + ins[3] + ins[2] + ins[1] + ins[0]
                print("ins:" + ins)
                patch_dword(i, int(ins, 16))
 
         if is_BLX_sub4094(ins_addr):
            patch_dword(ins_addr - 2, 0xbf00)
            patch_dword(ins_addr, 0xbf00)
            patch_dword(ins_addr + 2, 0xbf00)
            patch_dword(ins_addr + 4, 0xbf00)
            patch_dword(ins_addr + 6, 0xbf00)
            patch_dword(ins_addr + 8, 0xbf00)
 
         ins_addr = idc.next_head(ins_addr)
 
func_patch()

修复结束之后跟踪指令,0x3434处的代码跳到了0x345A,0x345A处的代码主要逻辑是在0x34C6跳到0x34EC通过0x34EC动态计算地址跳到了0x3520,0x3524处的代码跳到了0x365C,0x366E处的代码跳到了0x35A8,0x35A8是JNI_OnLoad的主要逻辑。

如上图所示,0x35A8基本就干了两件事:FindClass(com/meituan/android/common/mtguard/NBridge)和RegisterNatives(com/meituan/android/common/mtguard/NBridge, main, 1)。

sub_3680里面调用sub_36B4通过异或解密了一些字符串,上图我已经把解密之后的结果patch进去了。
当然用unidbg是可以直接跑JNI_OnLoad的:

不过这个系列文章主要是想讨论一下so混淆和反混淆,有精力的话还可以对这个so进行完整分析,混淆应该没有啥新的了。


[培训]二进制漏洞攻防(第3期);满10人开班;模糊测试与工具使用二次开发;网络协议漏洞挖掘;Linux内核漏洞挖掘与利用;AOSP漏洞挖掘与利用;代码审计。

上传的附件:
收藏
点赞6
打赏
分享
最新回复 (5)
雪    币: 624
活跃值: (501)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
风中的承诺 2022-3-13 18:21
2
0
沙发
雪    币: 34
活跃值: (617)
能力值: ( LV3,RANK:24 )
在线值:
发帖
回帖
粉丝
WeiFire 2022-3-16 17:09
3
0
牛啊
雪    币: 365
活跃值: (480)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
cjja爱之恋 2022-3-16 17:12
4
0
这个so是哪个版本的
雪    币: 2710
活跃值: (1651)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
乐活 2022-3-22 14:45
5
0

学习了

最后于 2022-3-22 15:13 被乐活编辑 ,原因:
雪    币: 5005
活跃值: (3756)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
mb_rjdrqvpa 2022-4-3 21:24
6
0

loc_340C处的代码通过POP指令将R4的值给PC

我不知道哪里搞错了,楼主能否帮忙看下?感激

游客
登录 | 注册 方可回帖
返回