1.前言
论坛里已经有很多人发过关于”2023腾讯游戏安全大赛-安卓赛道决赛“的文章了我就不多介绍,本人有幸参加过这次比赛,很可惜的是我PC和安卓两个赛道都参加了时间不够,最近有时间了花了两天重新看了一下题目,发现这个”tvm“还是比较简单的,给大家分析还原一下。
2.TVM
虚拟机流程
进入虚拟机
a64.dat 不懂的可以看一下-> 里面主要包含了arm64的shellcode。通过sub_9570(); 函数后会得到一个vm虚拟机Context。然后调用sub_98e50(); 开始执行虚拟机
uint32_t sub_99ef4(uint32_t arg1) {
char var_80[0x10] = "builtin";
char var_90[0x10] = "vm_main.img";
char PK[0x10] = "PK";
char var_d8[0x10] = "";
char var_e0[0x10] = "";
uintptr_t ctx = sub_95970(var_d8, var_80, var_90, PK, 0x409, var_e0);
sub_98e50(ctx + 0x10, 0x249f0); // vm_Start(ctx, step)
return 0;
}
handler分发
sub_98e50 是 vm_start 怎么确认的?根据上面的流程图,不难发现这里在查表调用,也就是Handler分发。
uint64_t sub_98e50(uint64_t ctx, uint64_t step) {
int64_t opcode_tab = // 0x00098e90 获取 opcode_tab
int64_t handler_tab = // 000996ec 获取 handler_tab
// ctx + 0x00 X0
// ctx + 0x08 X1
// ctx + 0x10 X2 ... 以此类推
void* pc = ((char*)ctx + 0x108); // 0x00098ea4 获取 pc 寄存器
while(1) {
*(uint32_t*)((char*)ctx + 0x120) = 1; // 0x00099354 虚拟机异常状态置 1
uint64_t i = (pc >> 2);
uint64_t handler = *(uint64_t*)(handler_tab + (i << 3)); // 每一个地址是 0x08 大小
uint32_t opcode = *(uint32_t*)(opcode_tab + (i << 2)); // 每一个opcode是 0x04 大小
uintptr_t result = (funCall(handler))(opcode, ctx); // 0x00099368 查表调用
if (!result) break;
pc += 4;
*((char*)ctx + 0x108) = pc;
}
return 0;
}
导出所有handler和对应opcode
tvmAsm to Asm
拿个比较简单的举例 ADRP
[vm] fun: 0xD0A88, opcode: 05000000 , 不懂的看这里->
对arm汇编熟悉的人,那么不难看出来,这个handler内部解析opcode,执行对应的操作,实际上就对应一条arm64指令。还原很简单,对比一下arm64-v8a手册他们是怎么解析opcode的,对应到反汇编上很快就能还原,就拿上面说的试试就能知道。
还原例子
这里就拿大佬的做一下对比吧,大致识别的都差不多。毕竟才写了一两天不够完善。
总结
编程也就图一乐收收心找个电子厂上班了
更多【2023腾讯游戏安全大赛-安卓赛道决赛"TVM“分析与还原】相关视频教程:www.yxfzedu.com