首页
社区
课程
招聘
[原创]2022腾讯游戏安全竞赛安卓客户端决赛writeup
发表于: 2022-4-28 12:05 30109

[原创]2022腾讯游戏安全竞赛安卓客户端决赛writeup

2022-4-28 12:05
30109

外挂进程先通过java层解密出sock001并运行,读取数据到/sdcard/1A.txt文件中,然后外挂进程native层不断读取/sdcard/1A.txt文件中的数据,同时调用java层的绘图函数,实现透视。

在查看外挂apk给的so,发现里面并没有远程读写的代码,怀疑是新起了一个进程,在assert文件夹下发现了可疑的以sock开头的几个文件

image-20220424171236773

用010打开,发现所有文件都是被加密过的,看不出来是什么东西

image-20220424171313317

开始在java层上找解密的地方,java层被混淆的很厉害,最终在MainActivity中找到了解密的地方

image-20220424171504527

这里是对sock1进行解密,跟进去,是非常明显的rc4加密,密钥为gamesec

image-20220424171543856

本地用python对sock1进行解密

解密后,再用010打开,发现是一个安卓上的elf可执行文件

image-20220424171724232

同时这里java层采用shell命令,启动了进程,可以用ps -ef查看启动进程的参数

image-20220424171827520

发现是2236 1080,这两个是我测试手机屏幕的高宽,后面会用到

image-20220425185521112

从函数名都可以知道,外挂的native层主要是读取文件数据,然后调用java层绘图函数画图的,这里并不是重点。

用ida打开后发现区段只有两个,明显是被加壳了

image-20220424172012993

怀疑是upx的壳,用010查看upx的特征,发现被改动了

image-20220424172041349

upx的字符串都被替换成了ue4,同时和正常upx加壳的对比,还删掉了声明,尝试手动修复,修复不了,转而采用动态调试方式找到oep入口,因为有反调试,调试器无法attach,老是报奇怪的错,后面才知道是信号的问题,由于调试过程中,老是会跑飞到linker里面,所以萌生了在底层函数上下断的想法,最直接是在libc_init这个函数下断,然后第三个参数就是main函数。

image-20220424172535760

先单步到这,linker位置,此时libc已加载,再跟到libc中下断

image-20220424172618629

成功断下,r2寄存器里面此时是main函数的地址,在main函数下断,f9,此时是程序真正的入口了,发现里面混淆的非常严重

image-20220424172800636

主要混淆有字符串加密以及控制流平坦化,这里想办法脱壳并且去掉混淆先,方便调试

这里通过010editor发现里面的upx字符串都被改成ue4,然后用upx -d直接不识别为upx,应该是本地被patch修改过了,尝试修复

将所有的出现的ue4!字符串改成upx!,算是最基本的特征了

image-20220425180220663

搜索UE4,发现有四个,其中小写的不用改,将其他改为UPX

image-20220425180500597

这里主要是对比了其他upx加壳后的文件,发现基本都是3个0x00结尾

的,所以这里要删除

从文件尾部继续找倒数第一个和倒数第二个UPX!,距离倒数第一个UPX!的20个字节处,为正确的p_info值,取出并填入距离第一个UPX!字符串8个字节的位置。

取出的值0x0004f9ec

image-20220425181807434

填入的位置

image-20220425182015774

再次用upx -d尝试发现已经能识别出upx了,但是还是报错了

image-20220425182507772

这里通过查看upx源码29cK9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6Y4K9i4c8Z5N6h3u0Q4x3X3g2U0L8$3#2Q4x3V1k6#2M7s2S2Q4x3V1k6#2M7s2S2Q4c8f1k6Q4b7V1y4Q4z5p5y4Q4c8e0c8Q4b7V1u0Q4b7e0g2Q4c8e0g2Q4z5p5k6Q4z5p5q4Q4c8e0S2Q4b7U0m8Q4z5o6y4Q4c8e0S2Q4b7f1k6Q4z5e0g2#2M7s2S2Q4c8e0g2Q4b7f1g2Q4z5e0S2Q4c8e0k6Q4z5e0k6Q4b7U0W2Q4c8e0g2Q4z5p5k6Q4b7f1k6Q4c8e0k6Q4z5o6W2Q4b7e0N6Q4c8e0S2Q4b7e0q4Q4z5p5y4Q4c8e0N6Q4b7e0S2Q4z5p5u0Q4c8e0g2Q4b7V1q4Q4z5p5k6Q4c8f1k6Q4b7V1y4Q4z5p5y4Q4c8e0g2Q4z5p5k6Q4z5e0q4Q4c8e0N6Q4z5p5g2Q4b7U0m8Q4c8e0g2Q4z5f1y4Q4b7e0S2Q4c8e0c8Q4b7U0S2Q4z5o6m8Q4c8e0g2Q4b7e0c8Q4z5o6c8Q4c8e0k6Q4z5e0k6Q4z5o6N6Q4c8e0c8Q4b7V1u0Q4b7U0k6Q4c8e0g2Q4b7e0c8Q4b7U0c8Q4c8e0N6Q4z5f1q4Q4z5o6c8Q4c8e0g2Q4b7f1k6Q4b7U0W2Q4c8e0k6Q4b7f1k6Q4z5e0c8Q4c8e0c8Q4b7U0S2Q4b7f1c8Q4c8f1k6Q4b7V1y4Q4z5p5y4Q4c8e0k6Q4z5o6S2Q4z5e0q4Q4c8e0N6Q4z5f1q4Q4z5o6c8Q4c8e0k6Q4z5e0g2Q4b7U0m8Q4c8e0k6Q4z5p5c8Q4b7f1g2Q4c8e0k6Q4z5e0S2Q4b7f1j5@1i4@1f1@1i4@1t1^5i4@1q4m8x3s2R3H3x3q4!0q4c8W2!0n7b7#2)9^5b7#2!0q4y4W2)9^5z5g2)9^5x3q4!0q4y4q4!0n7b7W2!0m8y4g2!0q4y4W2)9^5b7g2!0m8y4g2!0q4z5g2)9&6y4q4)9&6z5g2!0q4y4q4!0n7b7g2)9^5y4W2!0q4c8W2!0n7b7#2)9^5b7%4g2H3P5q4!0q4y4W2!0n7b7g2)9&6x3q4!0q4y4#2!0m8x3q4)9^5x3g2!0q4c8W2!0n7b7#2)9^5b7#2!0q4y4g2)9&6x3q4)9^5b7#2!0q4y4W2!0m8x3q4!0n7y4#2!0q4y4W2)9^5z5g2!0n7c8g2!0q4y4g2)9^5z5q4!0n7x3q4!0q4y4q4!0n7b7g2)9^5y4W2!0q4z5q4!0n7c8W2)9&6z5g2!0q4y4q4!0n7z5q4!0m8b7g2!0q4z5g2)9^5x3q4!0n7b7W2!0q4z5q4!0n7c8g2)9&6x3b7`.`.

image-20220425182810959

说明需要去填入.ELF, 填入位置参考了其他upx加壳文件,在距离第一个UPX!字符串的第28个字节开始填入

image-20220425183105690

再用upx -d,发现还是报错了,但是报错信息更新了

image-20220425183222394

通过搜索upx源码的字符串,找到这里关键对比逻辑

image-20220425183310336

通过调试upx官方程序,发现这里blocksize一直为0,所以报错

image-20220425183407663

在这里下断,找到了位置了,同时我自己在本地用upx加壳后的程序进行对比,找规律,发现p_info的那个值要和blocksize相同。

image-20220425183600116

image-20220425183748653

心情还是比较激动的,折腾挺久的了

可以看出是release版本的控制流平坦化,为了方便,这里用ida 插件34cK9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6Y4K9i4c8Z5N6h3u0Q4x3X3g2U0L8$3#2Q4x3V1k6G2j5Y4m8G2i4K6u0V1M7s2u0G2K9X3g2U0N6q4)9J5c8X3!0T1M7r3!0Q4x3X3c8H3L8s2g2Y4K9h3&6Q4c8f1k6Q4b7V1y4Q4z5p5y4Q4c8e0k6Q4z5f1c8Q4b7e0g2Q4c8e0g2Q4z5p5g2Q4b7V1u0Q4c8e0k6Q4z5p5g2Q4z5o6W2Q4c8e0k6Q4b7U0N6Q4b7U0N6Q4c8e0k6Q4b7U0N6Q4z5o6k6Q4c8f1k6Q4b7V1y4Q4z5p5y4Q4c8e0c8Q4b7U0S2Q4b7V1u0Q4c8e0g2Q4z5o6N6Q4b7V1c8Q4c8e0k6Q4z5e0g2Q4b7U0m8Q4c8e0g2Q4z5p5g2Q4b7V1u0Q4c8e0W2Q4z5e0W2Q4b7e0c8Q4c8e0k6Q4b7U0N6Q4b7U0N6Q4c8e0k6Q4b7U0N6Q4z5o6k6Q4c8e0g2Q4z5o6W2Q4z5p5c8Q4x3@1p5`.

image-20220424181457174

然后这里用这个插件来去掉,右键在函数主分发块上点击OBPO

image-20220424181601986

点击mark and process function,再连续按两次f5,去除混淆成功

主函数去掉混淆后:

image-20220424181740779

效果非常好,伪代码非常清晰

发现每个函数要用的字符串都被加密起来了,解密逻辑都在函数的开头.

image-20220424201339186

而且执行过后,并没有再次加密,这里可以采用先让外挂正常运行一遍,然后dump下来,再把解密后的字符串patch到之前没有解密字符串的程序中。

image-20220424203443548

image-20220424204515256

image-20220424204935908

在调试过程中,发现sock1将sock002、sock003、sock004、sock005都进行了密钥为TencentGameSecurity的rc4算法解密,并且发现sock001文件中间有空缺,

image-20220425100132263

空缺的位置的似乎就是那几个文件,本地重新分析一个安卓可执行elf文件,对照的分析,得出结论sock002解密后对应的是program table,并在调试中确定了这点

image-20220425104318674

解析sock002(progame table),然后将sock001的要加载的代码加载进内存,然后下一步是通过解密后的sock005进行重定位,解密后的sock005为.rel.plt section

image-20220425112112605

sock003解密后,本地查看发现很明显是动态链接的字符串表

image-20220425105240838

sock004dec 经过对比,发现是动态符号表,几个文件的代表意义都知道了,继续分析,相当于自实现了一个linker,再继续调试时发现pc值跳到了sock001、sock002、sock003、sock004、sock005加载到内存中的区间,说明sock1进程相当于执行了一段这几个文件的shellcode,最终进入了这个外挂的关键函数

image-20220424205744937

这里为了证实这个函数是那几个文件中的,用010去搜机器码的十六进制

image-20220424210021286

是可以搜的,同时内存地址,也是在几个文件加载进内存中的地址区间。

image-20220424210722500

​ 并设置pc值为此内存地址,触发异常,调试器会接受到此异常

image-20220424210842056

​ 如果没有调试器,则信号由先前设置的信号处理函数处理,跟进信号处理函数,会发现同样调用了momove函数,将之前的数据覆盖到断点指令上,程序回归正常。

核心函数位于sock001偏移的0x8490

image-20220425015244260

image-20220425003552530

image-20220425022429959

​ 跟进去分析一下是如何做转换的

image-20220425034106204

发现是将pitch yaw roll,传入函数并转化为matrix矩阵,为了后续的计算。

同时在github上找到类似的三维转换二维的代码50eK9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6Y4K9i4c8Z5N6h3u0Q4x3X3g2U0L8$3#2Q4x3V1k6C8M7o6M7%4y4o6u0Q4x3V1k6b7g2f1u0s2f1r3q4@1j5$3S2W2M7W2)9J5c8X3u0D9L8$3u0Q4x3V1j5J5y4K6j5J5z5r3t1K6k6X3j5#2x3$3f1H3y4K6j5$3k6e0M7H3z5o6c8S2z5o6u0T1x3U0V1K6j5X3t1#2z5r3g2W2y4X3x3@1x3U0k6T1i4K6u0r3c8r3q4W2L8h3!0F1i4K6u0r3K9X3&6A6i4K6u0r3f1$3g2J5N6X3g2J5i4K6u0r3f1%4c8J5N6h3y4@1M7@1y4G2L8h3#2G2L8W2)9J5k6h3R3`.

image-20220425034640328

不过这里计算并没有fov,其他倒是差不多

image-20220425034732985

image-20220425004009517

远程读写的操作都集中在这个getprocessvalue函数(自命名)中

image-20220425114453625

根据不同情况选择用syscall或者process_vm_readv来进行远程读写

第一次参与这个比赛,还是挺多收获的,感谢主办方和出题人了,也希望看wp的师傅们也能有所收获2333。

 
 
 
 
 
 
 
 
# coding=utf-8
 
 
 
DEFAULT_KEY = ""
 
 
def rc4(data, key=DEFAULT_KEY, skip=1024):
    x = 0
    box = range(256)
 
    x = 0
    for i in range(256):
        x = (x + box[i] + ord(key[i % len(key)])) % 256
        tmp = box[i]
        tmp2 = box[x]
        box[i] = box[x]
        box[x] = tmp
 
    x = 0
    y = 0
    out = []
    if skip > 0:
        for i in range(skip):
            x = (x + 1) % 256
            y = (y + box[x]) % 256
            box[x], box[y] = box[y], box[x]
 
    for char in data:
        x = (x + 1) % 256
        y = (y + box[x]) % 256
        box[x], box[y] = box[y], box[x]
        k = box[(box[x] + box[y]) % 256]
        out.append(chr(ord(char) ^ k))
 
    return out
 
 
if __name__ == '__main__':
    # handle input file or stream
    import sys
 
    tt = open("sock1", "rb")
    ww = tt.read()
    decrypt_files=rc4(ww, "gamesec", 0)
    decttt=open("sock1dec","wb")
    decttt.write("".join(decrypt_files))
# coding=utf-8
 
 
 
DEFAULT_KEY = ""
 
 
def rc4(data, key=DEFAULT_KEY, skip=1024):
    x = 0
    box = range(256)
 
    x = 0
    for i in range(256):
        x = (x + box[i] + ord(key[i % len(key)])) % 256
        tmp = box[i]
        tmp2 = box[x]
        box[i] = box[x]
        box[x] = tmp
 
    x = 0
    y = 0
    out = []
    if skip > 0:
        for i in range(skip):

[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

收藏
免费 25
支持
分享
最新回复 (18)
雪    币: 180
活跃值: (3901)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
2
mark
2022-4-28 12:58
0
雪    币: 197
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
3
厉害  长见识了
2022-4-28 13:39
0
雪    币: 409
活跃值: (999)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
4
看不懂系列
2022-4-28 13:54
0
雪    币: 3560
活跃值: (6125)
能力值: ( LV5,RANK:65 )
在线值:
发帖
回帖
粉丝
5
厉害
2022-4-28 15:33
0
雪    币: 2677
活跃值: (5700)
能力值: ( LV10,RANK:177 )
在线值:
发帖
回帖
粉丝
6
smallzhong_ 厉害
感谢大佬肯定
2022-4-28 15:50
0
雪    币: 8611
活跃值: (5261)
能力值: ( LV4,RANK:45 )
在线值:
发帖
回帖
粉丝
7
YK大佬太强了
2022-4-28 16:21
0
雪    币: 135
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
8
呜呜呜,什么时候能有Yenkoc
2022-4-28 20:39
0
雪    币: 32
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
9
复杂到劝退了属于是
2022-5-12 11:44
0
雪    币: 15
活跃值: (337)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
10
YK大佬太强了
2022-5-16 13:06
0
雪    币: 2067
活跃值: (226)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
11
YK大佬tql
2022-5-16 16:01
0
雪    币: 890
活跃值: (681)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
12
怎么判断出是upx的?是熟悉upx的特征吗
2022-5-16 16:06
0
雪    币: 260
活跃值: (446)
能力值: ( LV3,RANK:35 )
在线值:
发帖
回帖
粉丝
13
牛逼牛逼,功底太强了,不管是分析流程还是手脱变种upx,太强了
2022-5-17 12:09
0
雪    币: 16752
活跃值: (7281)
能力值: ( LV13,RANK:923 )
在线值:
发帖
回帖
粉丝
14
upx变种壳从内存dump出来应该也可以看吧
2022-5-17 14:25
0
雪    币: 2677
活跃值: (5700)
能力值: ( LV10,RANK:177 )
在线值:
发帖
回帖
粉丝
15
对的,其实upx特征就那些字符串,然后看区段也可以看出来,以及初赛的壳就是upx,更容易往这方面去想
2022-5-17 16:53
0
雪    币: 566
活跃值: (1191)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
16
感谢分享,TQL
2022-5-19 11:32
0
雪    币: 864
活跃值: (5144)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
17
u秀
2022-8-11 10:16
0
雪    币: 240
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
18
2022-10-25 16:41
0
雪    币: 548
活跃值: (65)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
19
tql
2023-5-23 11:34
0
游客
登录 | 注册 方可回帖
返回