首页
社区
课程
招聘
[原创]2023腾讯游戏安全大赛-安卓赛道决赛"TVM"分析与还原
2023-9-24 20:36 10646

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

2023-9-24 20:36
10646

1.前言

  论坛里已经有很多人发过关于"2023腾讯游戏安全大赛-安卓赛道决赛"的文章了我就不多介绍,本人有幸参加过这次比赛,很可惜的是我PC和安卓两个赛道都参加了时间不够,最近有时间了花了两天重新看了一下题目,发现这个"tvm"还是比较简单的给大家分析还原一下。

  在阅读本文之前,建议先对虚拟机(VM)的执行流程有一定的了解。这样能更好地理解本文所讨论的内容。

2.TVM

  虚拟机流程

  进入虚拟机

  a64.dat不懂的可以看一下juice4fun(a64.dat)里面主要包含了arm64虚拟化指令("tvm"shellcode)。

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);
    // vm_Start(ctx, step)
    sub_98e50(ctx + 0x10, 0x249f0); 
    return 0;
}

  上面是虚拟机初始化代码,通过sub_9570函数初始化虚拟机环境得到vContext(包含虚拟寄存器、虚拟化指令、handler表、跳转表、调用表...),调用sub_98e50开始执行虚拟机。

  vContext结构如下

struct vContext {
 uint64_t x[29]; // 0x00 ~ 0xE0
 uint64_t fp;  // + 0xE8
 uint64_t lr; // + 0xF0
 uint64_t xzr; // +0xF8
 uint64_t sp; // + 0x100
 uint64_t pc; // + 0x108
 ...
}

  handler分发

  对于确认sub_98e50是vm_start的问题,可以根据上面的流程图进行分析。在反汇编中,可以观察到这里进行了表查找调用,也就是Handler的分发过程。

  sub_98e50(vm_start)还原大致内容

uint64_t sub_98e50(uint64_t ctx, uint64_t step) {
    // 0x00098e90 获取 opcode_tab 
    int64_t opcode_tab = 
    // 000996ec 获取 handler_tab
    int64_t handler_tab = 
    // ctx + 0x00 X0
    // ctx + 0x08 X1
    // ctx + 0x10 X2 ... 以此类推 上面有vContext结构
    // 0x00098ea4 获取 pc 寄存器
    uint64_t* pc = (uint64_t*)(ctx + 0x108); 
    while(1) {
        // 0x00099354 虚拟机状态置 1
        *(uint32_t*)((char*)ctx + 0x120) = 1; 
        
        uint64_t i = (*pc >> 2);
        
        // 取出 handler = *(handler_tab+i*8);
        uint64_t handler = *(uint64_t*)(handler_tab + (i << 3)); 
        
        // 取出 opcode = *(opcode_tab+i*4);
        uint32_t opcode = *(uint32_t*)(opcode_tab + (i << 2)); 
        
        // 0x00099368 Handler 分发
        uintptr_t result = (funCall(handler))(opcode, ctx);  
        if (!result) 
            break;
        *pc += 4;
    }
    return 0;
}

  导出所有handler和对应虚拟化指令

+ 0x00
[vm] fun: 0xE2DB4 , opcode: 0xF01E0FF3
[vm] fun: 0xE227C , opcode: 0x95417BFD
[vm] fun: 0xCF004 , opcode: 0xD30043FD
[vm] fun: 0xE1148 , opcode: 0x092003F3
[vm] fun: 0xD0A88 , opcode: 0x05000000
[vm] fun: 0xCF004 , opcode: 0xB200E000
[vm] fun: 0xD2AD0 , opcode: 0x64000000
[vm] fun: 0xE1148 , opcode: 0x761303E1
[vm] fun: 0xD2AD0 , opcode: 0xF8000000
[vm] fun: 0xD6158 , opcode: 0xBD417BFD
[vm] fun: 0xE1148 , opcode: 0x673303E0
[vm] fun: 0xD6E00 , opcode: 0xC04207F3
[vm] fun: 0xD1CC0 , opcode: 0x14123456
+ 0x48
[vm] fun: 0xE6BF4 , opcode: 0xC38043FF
[vm] fun: 0xD0A88 , opcode: 0x91000009
[vm] fun: 0xE1148 , opcode: 0x541F03E8
[vm] fun: 0xCF004 , opcode: 0xCB856129
[vm] fun: 0xCF004 , opcode: 0xFD0033EA
[vm] fun: 0xE3E18 , opcode: 0x75C03BFF
[vm] fun: 0xE4C50 , opcode: 0xFD401BFF
[vm] fun: 0xE9564 , opcode: 0x18137C0C
[vm] fun: 0xE0BE8 , opcode: 0x1E1C03EB
[vm] fun: 0xE1148 , opcode: 0x6F00158C
[vm] fun: 0xE0BE8 , opcode: 0x7A9F03ED
[vm] fun: 0xDF75C , opcode: 0x31CB7D8E
[vm] fun: 0xD8B64 , opcode: 0x424D6D2F
[vm] fun: 0xD5A78 , opcode: 0x750B01CE
[vm] fun: 0xD0B2C , opcode: 0x3F001DD0
[vm] fun: 0xE9564 , opcode: 0x6F9E7610
[vm] fun: 0xD2420 , opcode: 0x63861DD0
[vm] fun: 0xCFAC4 , opcode: 0x601001EE
[vm] fun: 0xE8054 , opcode: 0x8F0001BF
[vm] fun: 0xE4980 , opcode: 0xFDAD694E
[vm] fun: 0xE6BF4 , opcode: 0xE88005AD
[vm] fun: 0xE6BF4 , opcode: 0x1D00216B
[vm] fun: 0xD1AE8 , opcode: 0xAEFFFEBC
[vm] fun: 0xE1148 , opcode: 0xD53F03EB
[vm] fun: 0xD8B64 , opcode: 0x77EB6D4C
[vm] fun: 0xD8B64 , opcode: 0x400B6D2D
[vm] fun: 0xE9564 , opcode: 0x75857D8E
[vm] fun: 0xD2420 , opcode: 0x3D1D1D8E
[vm] fun: 0xD5A78 , opcode: 0x2E2D01CC
[vm] fun: 0xE4980 , opcode: 0xC8AB694C
[vm] fun: 0xCF004 , opcode: 0xFA80056B
[vm] fun: 0xE8054 , opcode: 0xBF000D7F
[vm] fun: 0xD1AE8 , opcode: 0x1FFFFF11
[vm] fun: 0xD7F4C , opcode: 0xDD003BEB
[vm] fun: 0xCF004 , opcode: 0x1E01D56B
[vm] fun: 0xE3E18 , opcode: 0xBDC03BEB
[vm] fun: 0xD7F4C , opcode: 0x558037EB
[vm] fun: 0xD5518 , opcode: 0x719F196B
[vm] fun: 0xE3E18 , opcode: 0x418037EB
[vm] fun: 0xD6E00 , opcode: 0xB9400FEC
[vm] fun: 0xE0BE8 , opcode: 0x7A9D03EB
[vm] fun: 0xCF004 , opcode: 0x3F03058D
[vm] fun: 0xE3E18 , opcode: 0xFDC033ED
[vm] fun: 0xE9564 , opcode: 0x60907D8D
[vm] fun: 0xE9564 , opcode: 0x18105D8C
[vm] fun: 0xE9564 , opcode: 0x1E1F798C
[vm] fun: 0xD2420 , opcode: 0x57871DAC
[vm] fun: 0xD5518 , opcode: 0x759F018C
[vm] fun: 0xE3E18 , opcode: 0x55803BEC
[vm] fun: 0xE9564 , opcode: 0x71901D80
[vm] fun: 0xE0BE8 , opcode: 0x340003EC
[vm] fun: 0xD8B64 , opcode: 0x16EC654D
[vm] fun: 0xE8054 , opcode: 0xBF00019F
[vm] fun: 0xE9564 , opcode: 0x6F877DAE
[vm] fun: 0xD2420 , opcode: 0x639F1DAE
[vm] fun: 0xD5A78 , opcode: 0x610C01CD
[vm] fun: 0xE4980 , opcode: 0x02EC6D4D
[vm] fun: 0xD0B2C , opcode: 0x3D001DAD
[vm] fun: 0xDF458 , opcode: 0x48EB35AD
[vm] fun: 0xE6BF4 , opcode: 0x9D00058C
[vm] fun: 0xCFAC4 , opcode: 0x572001A0
[vm] fun: 0xE6BF4 , opcode: 0x5E80216B
[vm] fun: 0xD1AE8 , opcode: 0x3FFFFEAC
[vm] fun: 0xCF004 , opcode: 0x61800508
[vm] fun: 0xE8054 , opcode: 0x5804011F
[vm] fun: 0xD1AE8 , opcode: 0xBCFFF8C1
[vm] fun: 0xCF004 , opcode: 0xF58043FF
[vm] fun: 0xE1468 , opcode: 0xEAC73BD4

  tvmAsm to Asm

  这里拿个比较简单的举例 ADRP [vm] fun: 0xD0A88, opcode: 05000000 

  对arm汇编熟悉的人那么不难看出来,这个handler内部解析opcode执行对应操作,实际上就对应一条arm64指令。我的还原方法是通过观察arm64-v8a解析opcode的方式,与反汇编操作进行对比,以判断是否相符。

  把sub_D0A88代码还原出来和arm64(ADRP)编码对比一样,由此判定该方法为ADRP。

void sub_D0A88(uint64_t opcode, uint64_t ctx) {
    // integer d = UInt(Rd);
    uint32_t Rd = opcode & 0x1f;
    
    // imm = SignExtend(immhi:immlo:Zeros(12), 64);
    uint64_t imm = (0x3fff & ((opcode >> 0x11) & 0x3000)) | ((0x3ffff & (opcode >> 5)) << 0xe);
    
    uint64_t PC = *(uint64_t*)(ctx + 0x108);
    // bits(64) base = PC[]; base<11:0> = Zeros(12);
    uint64_t base = (PC & 0xfffffffffffff000);
    
    // 写回寄存器 X[d] = base + imm
    *(uint64_t*)(ctx + (Rd << 3)) = base + imm;
}

  还原例子

  这里我进行了对sec2023决赛题目的还原操作。左边是我所还原"tvm"的arm64汇编代码,右边是|_|sher大佬的解题算法。可以发现它们在大体上非常相似。虽然我只花了一两天的时间来完成这个工作,但是已经有了一个相当不错的结果。

3.总结

  编程也就图一乐收收心找个电子厂上班了


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

最后于 2023-9-26 14:52 被a'ゞCicada编辑 ,原因:
收藏
点赞8
打赏
分享
最新回复 (8)
雪    币: 20
活跃值: (75)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
wx_赛特 2023-9-24 22:15
2
0
雪    币: 2192
活跃值: (3492)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
R0g 2 2023-9-24 22:54
3
0
怎么没看到易语言,,易语言写的脱壳机来?
雪    币: 1461
活跃值: (35)
能力值: ( LV4,RANK:40 )
在线值:
发帖
回帖
粉丝
a'ゞCicada 1 2023-9-24 23:02
4
0
wx_赛特 [em_86]
雪    币: 1461
活跃值: (35)
能力值: ( LV4,RANK:40 )
在线值:
发帖
回帖
粉丝
a'ゞCicada 1 2023-9-24 23:02
5
0
R0g 怎么没看到易语言,,易语言写的脱壳机来?
代码都是一键生成的,不用写啊
雪    币: 19299
活跃值: (28938)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
秋狝 2023-9-24 23:23
6
1

感谢分享

最后于 2023-9-24 23:24 被秋狝编辑 ,原因:
雪    币: 2149
活跃值: (433)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
呆萌的小白 2023-9-25 15:59
7
0
虽然看不懂,但是大佬出品肯定精品
雪    币: 8
活跃值: (277)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
wuxin159 2023-10-17 13:53
8
0
感谢分享,大佬
雪    币: 999
活跃值: (768)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
正己 2023-10-17 18:23
9
0
小婵婵牛逼
游客
登录 | 注册 方可回帖
返回