首页
社区
课程
招聘
[原创] 2024腾讯游戏安全大赛-安卓赛道决赛VM分析与还原
发表于: 2024-4-22 10:09 33233

[原创] 2024腾讯游戏安全大赛-安卓赛道决赛VM分析与还原

2024-4-22 10:09
33233

使用模拟器打开游戏,发现进入不了猜测是检测,使用syscall hook 获取全部系统调用,发现使用 prctl和seccomp 后程序卡死 。
图片描述
[Handler_Syscall__NR_seccomp] __NR_seccomp(0x1, 0x1, 0xbc9bac30) libUE4.so+0x46D293B
图片描述
Hook调用seccomp将prog数据获取下来,分析发现进行系统调用号拦截0x129 __NR_recvmsg杀死线程,将prog->len 设置为0游戏正常运行。

26秒后游戏调用access进行环境检测,环境异常游戏闪退。
图片描述
这里捕获到access两个返回地址:
1.libUE4.so+0x46D1FE5
2.libUE4.so+0x46D2093
可能是不同的检测。
分析libUE4.so+0x46D1FE5,我给检测函数命名为access_check_risk_46d1f8c,调用来源于libUE4.so+0x46d1be4。
使用Syscall(0x21) access检测是否存在异常文件。
图片描述
分析函数sub_46d1be4

图片描述
还原代码

图片描述
分析地址0x046d1ef4向内存中libUE4.so + 4FA9950地址写入0, 0x77073096,根据这个判断是crc_buf。

图片描述
这段代码从_FINI_1到_FINI_1+0x36cc964正好是对应着.text段开始和结束,返回的crc值存入data_4fa9d50 = crc,结果判断 if (crc == 0xd18b51ab) 。

图片描述

图片描述
这里可以看得出来是去遍历/proc/self/task/全部线程

以上检测函数如果有返回1 则会调用memclr让程序闪退。
图片描述

将正常游戏.text拷贝到自己申请的内存中,创建一个maps文件,内容写入刚刚创建的地址十六进制加上libUE4.so让检测识别我们拷贝正常游戏.text的地址为crc目标地址,在通过hook系统fopen函数对打开/proc/self/maps文件重定向到自己的maps。

游戏检测调用的并svc而是libc中的syscall函数,因此可以在这个地方进行syscal拦截,判断__number == 0x21 这直接将access的path路径改成空这样就绕过检测了。
图片描述

hook fopen函数判断path是否包含/proc/self/task,将path重定向
hook syscall函数判断__number == 0x21,将path重定向

可以直接修改过滤器的字节码将00000006 00000000 (RET_KILL_THREAD) 修改为 00000006 7FFF0000 (RET_ALLOW),或者使用hook syscall 拦截__number == 0x17F。
图片描述

可以发现很多字符串会被解密到.bss段这也就意味着没有crc,观察被加密的字符串结尾都是以00 01结尾,没错01就代表这个字符串被解密了,这里就可以修改字符串实现绕过检测,当然在真正的tersafe中字符串会被二次检测。
图片描述

图片描述

图片描述
图片描述
初始化寄存器0~17赋值=0

图片描述
图片描述

图片描述
ctx + 3C 获取pc寄存器地址,取指令后bswap,opcode >> 27执行对应handler。(因为取指令的肯定是PC寄存器啊)

其实一开始我挺蒙的,直到我看到这个get_bit函数,一切都合情合理了在去年比赛的时候用到的是Arm64虚拟机,Arm64解析里面使用各种asm_ubfx无符号位域提取,解析指令需要的位域,今年则是Arm虚拟机。
具体查看:[原创]2023腾讯游戏安全大赛-安卓赛道决赛"TVM"分析与还原
图片描述
图片描述
图片描述

比如我现在要还原handler:6,opcode:30020000
[SP, 4] = get(opcode, 0x16, 0x1B); // = 00000000
图片描述
[SP, 8] = get(opcode, 0x11, 0x16); // = 00000001
图片描述
R0 = get(opcode, 0x0C, 0x11); // = 00000000
图片描述
将输入寄存器1值和输入寄存器2值进行ROR然后写入输出寄存器,这就是指令解析过程。
Handler6实现为 ROR,当然这里只有一种情况,有些指令内部又有多种情况。
图片描述
接着解析剩余的Handler也是成功扣了一天一夜。
图片描述
图片描述

将虚拟机的字节码Dump下来这里我用的Dowrd Hex,我称它为vm_shellcode
图片描述
开始调用解析函数,从vm_shellcode的0x7FC地方开始解析(当然你想解析哪里都行)
图片描述
图片描述
解析出来Arm汇编,在通过 ARM to HEX网站把汇编转换成十六进制字节码。
图片描述
图片描述
然后将ARM to HEX生成的字节码替换vm_shellcode
图片描述
将文件写出vm_to_asm.img

vm_to_asm.img拖入ida pro
图片描述

FindCrypt3插件查找到AES_Rijndael_rcon算法。
图片描述
将函数对应名称补齐,发现没有uint8_t* iv且多次使用inv,函数为aes ECB Decrypt算法。
图片描述
完整还原后发现有几处变化,aesKey.dK 变成了aesKey.eK、invShiftRows 和 invSubBytes 顺序颠倒、invMixColumns 被替换成了 mixColumns与addRoundKey顺序颠倒。

将解密算法用游戏同样的方式修改,在游戏内输入32个1,验证一下解密数据相同。
图片描述
将加密算法用游戏同样的方式修改。
图片描述
图片描述
将login验证结果(不懂请返回分析游戏登录部分)进行加密,游戏内输入加密结果登录成功。
登录密码:dde8cdf098e8434b93f04f86085a88f9

图片描述

图片描述

图片描述

图片描述

图片描述

图片描述

图片描述

图片描述
图片描述

调试移动屏幕时触发写入ControlRotation
调试移动屏幕时触发写入ControlRotation
DobbyInstrument((void*)(UE4 + 0x3622218), ControlRotationSet);
图片描述
实现自瞄的逻辑
图片描述

最后附上易语言vm_to_asm.e
编程也就图一乐收收心找个电子厂上班了

sock_filter[0] { code: 0x20, jt: 0x0, jf: 0x0, k: 0x0 } LD W ASB
sock_filter[1] { code: 0x15, jt: 0x0, jf: 0x1, k: 0x129 } JEQ(0x129)
sock_filter[2] { code: 0x6, jt: 0x0, jf: 0x0, k: 0x0 } RET_KILL_THREAD
sock_filter[3] { code: 0x6, jt: 0x0, jf: 0x0, k: 0x7fff0000 } RET_ALLOW
sock_filter[0] { code: 0x20, jt: 0x0, jf: 0x0, k: 0x0 } LD W ASB
sock_filter[1] { code: 0x15, jt: 0x0, jf: 0x1, k: 0x129 } JEQ(0x129)
sock_filter[2] { code: 0x6, jt: 0x0, jf: 0x0, k: 0x0 } RET_KILL_THREAD
sock_filter[3] { code: 0x6, jt: 0x0, jf: 0x0, k: 0x7fff0000 } RET_ALLOW
auto f = fopen("/proc/self/maps");
auto base;
while(buf = fgets(f)) {
    if (strstr(buf, "libUE4.so"))
        base = strtoull(buf);
    }
close(f)
return base;
auto f = fopen("/proc/self/maps");
auto base;
while(buf = fgets(f)) {
    if (strstr(buf, "libUE4.so"))
        base = strtoull(buf);
    }
close(f)
return base;
access("/data/local/tmp/frida-server") access("/data/local/tmp/re.frida.server")
access("/data/local/tmp/frida-server") access("/data/local/tmp/re.frida.server")
auto f = fopen("/proc/self/maps", "r");
while (buf = fgets(f)) {
    str = get_str_frida(); // 46D21BB "frida"
    if (strstr(buf, str)) retrun 1;
    str = get_str_gadget(); // "gadget"
    if (strstr(buf, str)) retrun 1;
}
fclose(f);
return 0;
auto f = fopen("/proc/self/maps", "r");
while (buf = fgets(f)) {
    str = get_str_frida(); // 46D21BB "frida"
    if (strstr(buf, str)) retrun 1;
    str = get_str_gadget(); // "gadget"
    if (strstr(buf, str)) retrun 1;
}

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

最后于 2024-4-28 21:35 被a'ゞCicada编辑 ,原因:
上传的附件:
收藏
免费 25
支持
分享
打赏 + 20.00雪花
打赏次数 1 雪花 + 20.00
 
赞赏  王麻子本人   +20.00 2024/04/24 感谢分享~
最新回复 (30)
雪    币: 3004
活跃值: (30866)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
感谢分享
2024-4-22 13:53
1
雪    币: 8
活跃值: (322)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
厉害厉害
2024-4-22 19:02
1
雪    币: 838
活跃值: (3995)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
4
是__NR_seccomp不是__NR_prctl吗
2024-4-23 15:24
0
雪    币: 1620
活跃值: (285)
能力值: ( LV4,RANK:40 )
在线值:
发帖
回帖
粉丝
5
王麻子本人 是__NR_seccomp不是__NR_prctl吗
__NR_seccomp系统调用过去的
046d2932  movw    r0, #0x17f
046d2936  movs    r1, #1
046d2938  blx     r12
2024-4-23 15:52
0
雪    币: 838
活跃值: (3995)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
6
大哥你是怎么实现,优雅的对全部系统调用都hook的
2024-4-23 17:42
0
雪    币: 3222
活跃值: (4922)
能力值: ( LV9,RANK:160 )
在线值:
发帖
回帖
粉丝
7
大佬,怎么用cheat engine 调试apk的?
2024-4-25 17:26
0
雪    币: 838
活跃值: (3995)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
8
乐子人 大佬,怎么用cheat engine 调试apk的?
ce直接启动就行了呀
2024-4-25 19:29
0
雪    币: 1620
活跃值: (285)
能力值: ( LV4,RANK:40 )
在线值:
发帖
回帖
粉丝
9
乐子人 大佬,怎么用cheat engine 调试apk的?
用ceserver,可以调试native,最新7.5版本好些
2024-4-25 20:47
0
雪    币: 2270
活跃值: (5537)
能力值: ( LV8,RANK:146 )
在线值:
发帖
回帖
粉丝
10
nb
2024-4-25 21:20
0
雪    币: 113
活跃值: (628)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
11
厉害
2024-4-26 11:46
0
雪    币: 3222
活跃值: (4922)
能力值: ( LV9,RANK:160 )
在线值:
发帖
回帖
粉丝
12
a'ゞCicada 用ceserver,可以调试native,最新7.5版本好些
谢谢
2024-4-26 14:46
0
雪    币: 4112
活跃值: (5812)
能力值: ( LV8,RANK:120 )
在线值:
发帖
回帖
粉丝
13
你这思路多少有点涉黑
2024-4-28 12:08
1
雪    币:
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
14
恐怖如斯
2024-4-28 18:17
0
雪    币: 18
活跃值: (130)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
15

 。。同学,要低调。这样很容易暴露自己身份的。。

最后于 2024-4-28 19:11 被wx_赛特编辑 ,原因:
2024-4-28 19:09
0
雪    币: 838
活跃值: (3995)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
16
wx_赛特  。。同学,要低调。这样很容易暴露自己身份的。。
 他的身份应该是这个题目出题的
2024-4-29 00:18
0
雪    币: 180
活跃值: (1313)
能力值: ( LV4,RANK:40 )
在线值:
发帖
回帖
粉丝
17
非常好奇,大佬是怎么在模拟器上操作syscall hook的
2024-4-29 11:42
0
雪    币: 1620
活跃值: (285)
能力值: ( LV4,RANK:40 )
在线值:
发帖
回帖
粉丝
18
artake 非常好奇,大佬是怎么在模拟器上操作syscall hook的
某模拟器底层实现是hook libc全部svc到DeviceIoControl,这里不就有很大的操作空间。
2024-4-29 14:09
0
雪    币: 90
活跃值: (556)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
19
大佬有样本么 方便私发下嘛 想学习一下
2024-4-29 14:49
0
雪    币: 1620
活跃值: (285)
能力值: ( LV4,RANK:40 )
在线值:
发帖
回帖
粉丝
20
青蓝梦 大佬有样本么 方便私发下嘛 想学习一下
https://bbs.kanxue.com/thread-281466.htm
2024-4-29 16:04
1
雪    币: 90
活跃值: (556)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
21
大佬是怎么在模拟器上操作syscall hook的   大佬工具可以私发下嘛
2024-4-29 16:14
0
雪    币: 1549
活跃值: (1638)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
22
小婵婵
2024-4-29 22:08
1
雪    币: 1001
活跃值: (653)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
23
妥妥 挂b思路
2024-5-11 10:54
0
雪    币: 0
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
24
将正常游戏.text拷贝到自己申请的内存中,创建一个maps文件,内容写入刚刚创建的地址十六进制加上libUE4.so让检测识别我们拷贝正常游戏.text的地址为crc目标地址,在通过hook系统fopen函数对打开/proc/self/maps文件重定向到自己的maps。

我可以有这个代码吗?
2024-6-7 18:10
0
雪    币: 0
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
25
这里有人用电报吗?
2024-6-7 18:12
0
游客
登录 | 注册 方可回帖
返回
//