首页
社区
课程
招聘
[原创]2022腾讯游戏安全竞赛PC赛道初赛writeup
发表于: 2022-4-19 08:49 11775

[原创]2022腾讯游戏安全竞赛PC赛道初赛writeup

2022-4-19 08:49
11775

打开程序,发现程序开启了ASLR。于是先使用cffexplorer将ASLR关闭,便于之后的调试。

发现程序在绘制一次图案后便不再绘制了。怀疑代码只会运行一次。将程序拖入IDA进行分析。

打开IDA,首先进入winmain,看到消息的处理逻辑中。对于没有消息时,会调用 sub_1400015E0 函数。

image-20220418120735621

将该函数重命名为 dosomething ,进入函数中进行分析。如果当前是第一次进入,则使用 ZwAllocateVirtualMemory 函数申请一块RWX属性的内存,大小为0x2BF9字节。由于页对齐,操作系统会申请一块3个页面大小的内存。

image-20220418120938340

image-20220418121012252

image-20220418123101601

跟进.data这块数据,发现其是一段代码。因此将这块数据命名为shellcodefunc 。可以看到之后对这块shellcode进行了相应参数的填充。

在完成了对shellcode的初始化之后,如果shellcode的内存还存在,则会对shellcode进行调用。这里可以发现,使用了 GetTickCount 函数。如果运行时间超过4000毫秒,就使用ZwFreeVirtualMemory 释放内存。

image-20220418121820315

因此这里直接将140001265位置的jbe改为jmp,实现可以一直显示图像的功能,方便调试。

image-20220418122038316

考虑到在将shellcode复制到申请的内存中之后程序还对其中一些内容进行了修改,因此直接对源程序进行分析不太合适。这里首先对

处下断,得到申请的shellcode的地址,然后待其填充完毕后再将已经填充了相应参数的shellcode从内存中dump下来进行分析。dump下来之后可以看到这是一块0x3000大小的内存。

将dump下来的内存拖入ida进行分析,可以看到其中有三个函数,分别在+0、+420、+650的位置。

image-20220418123408811

而在这三个函数后面,跟随了大段数据。全部dump下来可以看到数据格式如下

image-20220418123500887

每一个数据单元是4个字节,其中存储了一个数字,大多为1~7,但也有一些例外。

在对shellcode的三个函数进行分析之后,发现sub_420中有一个switch-case结构,根据存储的数据的不同进行不同的处理。

image-20220418123655013

可以看到,如果当前数据为5或者6的话,会调用sub_0函数。而调用时的这个参数非常像一个RGBA的数据。

image-20220418123807823

调用时如果数据为5,则使用ebx中的值作为第五个参数,如果为6,则使用edi中的值作为第五个参数。这里跟到前面,把给edi赋值的代码进行patch,将其颜色替换为 ffffff00 ,重新运行程序,可以看到绘制出来的方块颜色与旗子的方块颜色相同。

image-20220418124332867

image-20220418124135157

由此可以推断,当数据为5时,绘制的是旗子的黄色方块,数据为6时,绘制的是右边的的蓝色方块。但不知为何数据为5时黄色的方块没有被正常绘制出来。

实在太菜了,用了很笨的办法来达到目的,我猜正解肯定是修改数据来让方块正确绘制,不过我逆向能力还是不行,逆不出来。。

对switch-case中的算法进行了一段时间的分析,还是没有找到能构造出成功绘制旗子的方法。于是对shellcode中的其他代码进行了探索。由于绘制时要调用sub_0,因此对sub_0中各个call进行了分析,发现在shellcode+31c这个call之前进行对[rcx+xxx]的填充时,内存中的数据很像坐标。

image-20220418130252333

每一次对这里的调用都会让内存中的对应区域多出一块28*4字节大小的数据。数据的格式很有规律,像是x,y,z+rgba的结构。在对其进行进一步的分析之后发现其结构如下

可以看出,a1,a2,a3,a4有点像是正方形的四个顶点。对其中数据进行进一步分析可以证实这一推断。

image-20220418130608423

最后分析得出该结构对应的四个点如下

image-20220418130718703

a1,a2,a3,a4分别为左上、右上、左下、右下四个点。

在对5和6的处理代码单步跟踪计数之后发现,每次绘制时,case 5会进入11次,case 6会进入31次。而且绘制时的顺序是先绘制11个5,然后再绘制31个6。经过对正确图像的查看,可以确定这两个就是点的坐标。因为答案中旗子使用了11个方块,右边的图案使用了31个方块。将其数据dump下来,发现绘制5时的坐标非常奇怪,从-290~100的数据都存在。而绘制6时的坐标则分布非常有规律,坐标点均在0~1之间。使用CE进行进一步分析,发现屏幕中心点为0,向两边延伸,坐标的范围在 -1~1之间。显然,绘制5时的坐标有误,使其无法被正确绘制。

在完成以上分析后,我想到了可以在这里进行hook,让5的数据被正确绘制。这里使用了注入dll的方式。在dll中对 shellcode+0x30e 的位置挂上inlinehook。挂inlinehook的方法如下

首先在 shellcode+30e 的位置进行inlinehook,使用ff25跳转到纯汇编函数 AsmHookHandler

AsmHookHandler 中进行对寄存器的保存,然后跳转到 HookHandler 函数中。在从 HookHandler 中返回后再从栈中恢复寄存器,并执行hook点中原来的指令,然后跳转回到原函数的下一条需要执行的指令。

在HookHandler函数中,首先对最初的11个黄色方块进行绘制。由之前的dump可知在系统缩放为 125% 的情况下右边图案最高点的y坐标为 0.882840 。经过实验,旗子最左边的x坐标应为 -0.9305 。一个方块的宽为 0.064935 ,高为 0.118343 。左右相邻两个格子的间隔为 0.012987 ,上下相邻的两个格子间隔为 0.023669 。经过对旗子的观察可知,旗杆高度为6个格子,在第四个格子高度向右再画三个格子,然后再斜着画上两个格子即可。

为了适配不同的系统缩放,在100%、125%、150%、175%缩放下分别对旗杆左上角位置进行定位。并根据系统缩放调整绘制的格子以及间隔的大小。代码如下,其中 getScreenZoom 为封装的获取系统缩放的函数。

综上, HookHandler 中的代码如下。

最后通过cffexplorer对去掉ASLR、关闭 GetTickCount 检测后的程序进行导入表的注入。让其加载时同时加载 dll3.dll 模块。最终效果如下。

image-20220418133512607

代码已经开源到https://github.com/smallzhong/gslab-2022-competition仓库中,在release https://github.com/smallzhong/gslab-2022-competition/files/8508875/exe%2Bdll.zip中可以下载经过patch的exe和用来注入的dll。

.text:000000014000119F call    memcpy
.text:000000014000119F call    memcpy
typedef struct _v3
{
    float x, y, z;
}v3, * pv3;
 
typedef struct _v4
{
    DWORD r, g, b, a;
}v4, * pv4;
 
typedef struct _Info
{
    v3 a1;
    v4 b1;
 
    v3 a2;
    v4 b2;
 
    v3 a3;
    v4 b3;
 
    v3 a4;
    v4 b4;
} Info, * PInfo;
typedef struct _v3
{
    float x, y, z;
}v3, * pv3;
 
typedef struct _v4
{
    DWORD r, g, b, a;
}v4, * pv4;
 
typedef struct _Info
{
    v3 a1;
    v4 b1;
 
    v3 a2;
    v4 b2;
 
    v3 a3;
    v4 b3;
 
    v3 a4;
    v4 b4;
} Info, * PInfo;
PUCHAR t = (PUCHAR)((*saddr) + 0x30e);
g_origin = (ULONG64)((*saddr) + 0x31c); // 需要跳回的地方
 
char bufcode[] = {
    0xFF, 0x25, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00,
    0x00, 0x00,
    0x00, 0x00,
    0x00, 0x00,
};
 
*(PULONG64)&bufcode[6] = (ULONG64)AsmHookHandler;
 
DWORD old_protect = 0;
VirtualProtect(t, 0x1000, PAGE_EXECUTE_READWRITE, &old_protect);
A("改变内存属性成功");
 
A("AsmHookHandler = %llx\r\n", AsmHookHandler);
memcpy(t, bufcode, sizeof bufcode);
A("memcpy完成");
PUCHAR t = (PUCHAR)((*saddr) + 0x30e);
g_origin = (ULONG64)((*saddr) + 0x31c); // 需要跳回的地方
 
char bufcode[] = {
    0xFF, 0x25, 0x00, 0x00, 0x00, 0x00,
    0x00, 0x00,
    0x00, 0x00,
    0x00, 0x00,
    0x00, 0x00,
};
 
*(PULONG64)&bufcode[6] = (ULONG64)AsmHookHandler;
 
DWORD old_protect = 0;
VirtualProtect(t, 0x1000, PAGE_EXECUTE_READWRITE, &old_protect);
A("改变内存属性成功");
 
A("AsmHookHandler = %llx\r\n", AsmHookHandler);
memcpy(t, bufcode, sizeof bufcode);
A("memcpy完成");
AsmHookHandler proc
    push r15;
    push r14;
    push r13;
    push r12;
    push r11;
    push r10;
    push r9;
    push r8;
    push rdi;
    push rsi;
    push rbp;
    push rsp;
    push rbx;
    push rdx;
    push rcx;
    push rax;
 
    mov rcx,rsp;
    sub rsp,0100h
    call HookHandler
    add rsp,0100h;
 
    pop rax;
    pop rcx;
    pop rdx;
    pop rbx;
    pop rsp;
    pop rbp;
    pop rsi;
    pop rdi;
    pop r8;
    pop r9;
    pop r10;
    pop r11;
    pop r12;
    pop r13;
    pop r14;
    pop r15;
 
    ;原来的操作
     mov     rcx, r14
     mov     rax, [r14]
     mov     rdx, [rsp+304]
    jmp g_origin ;跳回到需要跳到的位置
AsmHookHandler endp
AsmHookHandler proc
    push r15;
    push r14;
    push r13;
    push r12;
    push r11;
    push r10;
    push r9;
    push r8;
    push rdi;
    push rsi;
    push rbp;
    push rsp;
    push rbx;
    push rdx;
    push rcx;
    push rax;
 
    mov rcx,rsp;
    sub rsp,0100h
    call HookHandler
    add rsp,0100h;
 
    pop rax;
    pop rcx;
    pop rdx;
    pop rbx;
    pop rsp;
    pop rbp;
    pop rsi;
    pop rdi;
    pop r8;
    pop r9;
    pop r10;
    pop r11;
    pop r12;
    pop r13;

[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

最后于 2022-5-1 20:48 被kanxue编辑 ,原因:
上传的附件:
收藏
免费 9
支持
分享
最新回复 (4)
雪    币: 2134
活跃值: (3911)
能力值: ( LV4,RANK:55 )
在线值:
发帖
回帖
粉丝
2
太快了
2022-4-19 10:16
0
雪    币: 8745
活跃值: (5673)
能力值: ( LV13,RANK:296 )
在线值:
发帖
回帖
粉丝
3
太快了
2022-4-19 13:12
0
雪    币: 13992
活跃值: (17371)
能力值: ( LV12,RANK:290 )
在线值:
发帖
回帖
粉丝
4
感谢分享
2022-4-19 15:23
0
雪    币: 8416
活跃值: (4991)
能力值: ( LV4,RANK:45 )
在线值:
发帖
回帖
粉丝
5
mark
2022-4-19 18:58
0
游客
登录 | 注册 方可回帖
返回
//