2025腾讯游戏安全竞赛 PC客户端安全 初赛WP

admin 2025年4月10日00:00:39评论10 views字数 6375阅读21分15秒阅读模式
作者坛账号:Tkazer

2025 腾讯游戏安全技术竞赛 PC客户端安全 初赛WP

前言

这也是本菜鸡第一次参加该比赛,之前是有看过前几年比赛的WP,感觉难度不小,这次来尝试一下,由于是纯CTF类型,做起来还算顺手,不过也是遇到不少问题。经过半天的奋战最后还是解了出来,综合体验下来收获还是不少的。

R3分析

将ACEFirstRound.exe放入IDA分析,在main函数可以看到一个虚表,根据里面各个函数内容,将每个虚表函数都重新命名为对应功能。

发现是运行了ACEDriver驱动,与r3程序之间进行通信。

2025腾讯游戏安全竞赛 PC客户端安全 初赛WP

2025腾讯游戏安全竞赛 PC客户端安全 初赛WP

尝试动调发现没办法,发现程序退出,根据CheckRemoteDebuggerPresent的交叉引用发现一个反调试函数。

2025腾讯游戏安全竞赛 PC客户端安全 初赛WP

找该函数的交叉调用,发现是这边启了一个线程来启动反调试。

2025腾讯游戏安全竞赛 PC客户端安全 初赛WP

在该函数这边进行条件断点,修改rip,让代码直接执行到函数结束处,跳过中间反调试相关代码,即可绕过反调试。

2025腾讯游戏安全竞赛 PC客户端安全 初赛WP

动调分析,然后这边输入flag要求是以"ACE_"开头,然后去掉前面这四个字符,首先进行Base58加密,然后再将数据倒转。这边Base58是变表,和标准不一样,提取得:abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ123456789

2025腾讯游戏安全竞赛 PC客户端安全 初赛WP

与"sxx"进行循环xor。

2025腾讯游戏安全竞赛 PC客户端安全 初赛WP

最后通信发送到ACEDriver,命令码是0x154004。

2025腾讯游戏安全竞赛 PC客户端安全 初赛WP

2025腾讯游戏安全竞赛 PC客户端安全 初赛WP

至此R3层分析完毕。

R0分析

IDA载入ACEDriver.sys,发现有几个消息的Callback,但是跳转过来发现有混淆和花指令。

2025腾讯游戏安全竞赛 PC客户端安全 初赛WP

2025腾讯游戏安全竞赛 PC客户端安全 初赛WP

该驱动的混淆和花指令都是一个类型的,花指令是最基础的。

以下图为例子:

对41e9按u再跳过e9字节按c还原,即可pass花指令。

2025腾讯游戏安全竞赛 PC客户端安全 初赛WP

然后截图处是一块,将地址计算完进行jmp,计算出来实际就是jmp到下面pop处,说明这一段是无用的,可以直接将push到pop全部nop即可。其他地方都和这地方混淆差不多类型,都直接跳过花指令后nop即可。

2025腾讯游戏安全竞赛 PC客户端安全 初赛WP

2025腾讯游戏安全竞赛 PC客户端安全 初赛WP

但有一种比较特殊,并不是跳转到下面邻近代码处,而是jmp到其他代码处,观察push和底下pop寄存器是否一致就可以判断是哪一种类型,该种就得手动计算地址然后写jmp。

手动去除大部分混淆后,就可以看到几个回调的里面代码,MessageNotifyCallback里面的代码如下:

2025腾讯游戏安全竞赛 PC客户端安全 初赛WP

进入几层call就可以看到这边就是判断命令码执行,下面就是接收R3发送来的密文数据。

2025腾讯游戏安全竞赛 PC客户端安全 初赛WP

进入call发现就是关键处,unk_140004064那边就是flag密文,使用的是tea加密,key是['A','C','E','6'],然后边加密边判断密文是否相等。

2025腾讯游戏安全竞赛 PC客户端安全 初赛WP

2025腾讯游戏安全竞赛 PC客户端安全 初赛WP

查看tea函数的交叉调用,发现有其他地方有出现。

2025腾讯游戏安全竞赛 PC客户端安全 初赛WP

在第四个call处,发现一个函数传入了tea加密的函数地址,然后进行了一系列变换,应该是对tea函数本体进行了修改。

2025腾讯游戏安全竞赛 PC客户端安全 初赛WP

将该函数代码和相关数据进行提取,对tea函数字节进行本地模拟操作。

 复制代码 隐藏代码// tea函数原字节unsignedchar tea[149] = {0x480x8B0xC40x480x890x580x080x480x890x680x100x480x890x700x180x48,0x890x780x200x410x550x4C0x8B0xEA0x8B0x1A0x450x330xDB0x8B0x7A0x04,0x4C0x8B0xC10x8B0x720x080x8B0x6A0x0C0x440x8B0x090x410x8D0x530x20,0x440x8B0x510x040x410x8B0xCA0x450x8D0x9B0xB90x790x370x9E0xC10xE9,0x050x410x8B0xC20x030xCF0xC10xE00x040x030xC30x330xC80x430x8D0x04,0x130x330xC80x440x030xC90x410x8B0xC90x410x8B0xC10xC10xE90x050xC1,0xE00x040x030xCD0x030xC60x330xC80x430x8D0x040x0B0x330xC80x440x03,0xD10x480x830xEA0x010x750xBD0x410x5D0x480x8B0x5C0x240x080x480x8B,0x6C0x240x100x480x8B0x740x240x180x480x8B0x7C0x240x200x450x890x08,0x450x890x500x040xC3};unsignedchar P_0[0x1000]{};unsignedchar xmmword_140004000[16] = {0x580x410x8B0xC90x410x8B0xC10xC10xE00x040xC10xE90x050x330xC80x41};unsignedchar xmmword_140004010[16] = {0x8B0xC30x480xC10xE80x0B0x410x030xC90x830xE00x030x410x8B0x440x85};unsignedchar xmmword_140004020[16] = {0x000x410x030xC30x330xC80x440x030xD10x480x830xEA0x010x480xB80x00};unsignedchar xmmword_140004030[16] = {0x000x000x000x000x000x000x000x480xB90x000x000x000x000x000x000x00};unsignedchar dword_140004040[4] = {0x000x750x020xFF};unsignedchar word_140004044[2] = {0xE00xFF};unsignedchar byte_140004046[2] = {0xE10x00};unsignedchar qword_140004048[8] = {0x500x480xB80x000x000x000x000x00};unsignedchar dword_140004050[4] = {0x000x000x000xFF};unsignedchar byte_140004054[1] = {0xE0};DWORD64 qword_1400041E0 = 0;DWORD dword_1400041E8 = 0;BYTE byte_1400041EC = 0;// 对tea函数修改的函数void __fastcall sub_14000A35B(__int64 a1){int n64; // ebxchar* v3; // rdxint i; // ecxunsigned __int64 v5; // raxchar* v6; // rdxint j; // ecxunsigned __int64 v8; // raxchar* v9; // rdxunsigned __int64* v10; // rcxunsigned __int64 v11; // r8unsigned __int64 v12; // raxunsigned __int8 CurrentIrql; // dlunsigned __int64 v14; // rcxunsigned __int64 v15; // raxunsigned __int64 v16; // rax    n64 = 0;    v3 = (char*)&xmmword_140004020 + 15;for (i = 0; i < 64; i += 8)    {        v5 = (unsigned __int64)(a1 + 119) >> i;        *v3++ = v5;    }    v6 = (char*)&xmmword_140004030 + 9;for (j = 0; j < 64; j += 8)    {        v8 = (unsigned __int64)(a1 + 52) >> j;        *v6++ = v8;    }    v9 = (char*)&qword_140004048 + 3;    v10 = (unsignedlonglong*)P_0;memcpy(P_0, xmmword_140004000, 16);memcpy(P_0 + 16, xmmword_140004010, 16);memcpy(P_0 + 16 * 2, xmmword_140004020, 16);memcpy(P_0 + 16 * 3, xmmword_140004030, 16);    *((DWORD*)P_0 + 16) = *(DWORD*)dword_140004040;    *((WORD*)P_0 + 34) = *(WORD*)word_140004044;    *((BYTE*)P_0 + 70) = *(BYTE*)byte_140004046;    v11 = (unsigned __int64)P_0;do    {        v12 = v11 >> n64;        n64 += 8;        *v9++ = v12;    } while (n64 < 64);    qword_1400041E0 = *(DWORD64*)(a1 + 86);    dword_1400041E8 = *(DWORD*)(a1 + 94);    byte_1400041EC = *(BYTE*)(a1 + 98);    *(DWORD64*)(a1 + 86) = *(DWORD64*)qword_140004048;    *(DWORD*)(a1 + 94) = *(DWORD*)dword_140004050;    *(BYTE*)(a1 + 98) = *(BYTE*)byte_140004054;}intmain(){// 修改tea加密函数代码字节sub_14000A35B((longlong)tea);system("pause");return0;}

编译使用IDA动调,并按c分析tea数组处的代码,发现分成了三块,手动将三块合并到一块代码,并修复部分跳转的地址,即可得到完整的代码。

2025腾讯游戏安全竞赛 PC客户端安全 初赛WP

2025腾讯游戏安全竞赛 PC客户端安全 初赛WP

2025腾讯游戏安全竞赛 PC客户端安全 初赛WP

合并完的代码如下:

2025腾讯游戏安全竞赛 PC客户端安全 初赛WP

反编译得到修改后的魔改tea加密

2025腾讯游戏安全竞赛 PC客户端安全 初赛WP

即可编写得到对应的解密代码:

 复制代码 隐藏代码voidtea_decrypt(unsignedint* Input, int* Key){unsignedint v6 = Input[0];unsignedint v8 = Input[1];unsignedint sum = 0;// sum从32开始    sum = (-0x61C88647) * 32;for (int i = 0; i < 32; i++)     {        v8 -= (sum + Key[(sum >> 11) & 3]) ^ (v6 + ((v6 << 4) ^ (v6 >> 5)));        v6 -= (sum + v8) ^ (Key[0] + (v8 << 4)) ^ (Key[1] + (v8 >> 5));        sum += 0x61C88647;    }    Input[0] = v6;    Input[1] = v8;}

进行对unk_140004064密文解密即可,不过注意一点,这边是从-1处开始判断,也就是unk_140004064-4处开始是密文。

2025腾讯游戏安全竞赛 PC客户端安全 初赛WP

提取出来就是42的DWORD数据,和上面的判断数值对应上了。

2025腾讯游戏安全竞赛 PC客户端安全 初赛WP

解密

 复制代码 隐藏代码#include<iostream>#include<Windows.h>// 魔改tea解密函数voidtea_decrypt(unsignedint *Input, int *Key){unsignedint v6 = Input[0];unsignedint v8 = Input[1];unsignedint sum = 0;    sum = (-0x61C88647) * 32;for (int i = 0; i < 32; i++)    {        v8 -= (sum + Key[(sum >> 11) & 3]) ^ (v6 + ((v6 << 4) ^ (v6 >> 5)));        v6 -= (sum + v8) ^ (Key[0] + (v8 << 4)) ^ (Key[1] + (v8 >> 5));        sum += 0x61C88647;    }    Input[0] = v6;    Input[1] = v8;}// flag密文unsignedint enc[42] = {0x0EC367B80xC9DA90440xDA6C2DEB0x88DDC9C30x32A015750x231DD0B40x4B9E8A740xD75D3E74,0xEAAB87120xE704E8880xE01A31AC0xECAE205C0xA7BE74670x0C6252A30x1AEFEC4E0xC40DED44,0xC3C842CC0xDE4A0C0E0x7C24F3FC0x8FB8D0010x11153E6E0x530ED15C0xF42148110xBEB517E0,0x63F916340x4D96F8A50xFE23EAC80x2C607ADF0xCC43D85C0xFF186C5B0x8763E1A50x9187BD58,0x87D1069B0xD7878D7B0x836E6B680x55A0C63F0xD979FDB30x3E524DEE0x7AB35C820xA2F4DA8D,0x1708BA4C0x710653E6};// tea解密keyint key[4]{'A''C''E''6'};intmain(){// 42个数据,2个2个进行tea解密for (int i = 0; i < 42; i += 2)    {tea_decrypt((unsignedint *)((DWORD64)enc + i * 4), key);    }// 输出42个解密后数据for (int i = 0; i < 42; i++)printf("%X ", enc[i]);return0;}

Out

33 28 13 0 2D 16 40 41 13 2A 12 4F 45 4B 1F 14 39 49 3B 34 3A 26 3B 19 24 2B 22 5 4C E 0 4C 3B 4 2B 1D 5 39 16 22 3D B

CyberChef

xor('sxx') -> Reverse -> Base58 Decode(换表)

2025腾讯游戏安全竞赛 PC客户端安全 初赛WP

密文:We1C0me!T0Z0Z5GamESecur1t9*CTf

Flag

flag{ACE_We1C0me!T0Z0Z5GamESecur1t9*CTf}

原文始发于微信公众号(吾爱破解论坛):2025腾讯游戏安全竞赛 PC客户端安全 初赛WP

免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉。
  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2025年4月10日00:00:39
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   2025腾讯游戏安全竞赛 PC客户端安全 初赛WPhttps://cn-sec.com/archives/3910026.html
                  免责声明:文章中涉及的程序(方法)可能带有攻击性,仅供安全研究与教学之用,读者将其信息做其他用途,由读者承担全部法律及连带责任,本站不承担任何法律及连带责任;如有问题可邮件联系(建议使用企业邮箱或有效邮箱,避免邮件被拦截,联系方式见首页),望知悉.

发表评论

匿名网友 填写信息