使用模拟器打开游戏,发现进入不了猜测是检测,使用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
;
}
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)
最后于 2024-4-28 21:35
被a'ゞCicada编辑
,原因: