专栏名称: 吾爱破解论坛
吾爱破解论坛致力于软件安全与病毒分析的前沿,丰富的技术版块交相辉映,由无数热衷于软件加密解密及反病毒爱好者共同维护,留给世界一抹值得百年回眸的惊艳,沉淀百年来计算机应用之精华与优雅,任岁月流转,低调而奢华的技术交流与探索却
目录
相关文章推荐
51好读  ›  专栏  ›  吾爱破解论坛

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

吾爱破解论坛  · 公众号  · 互联网安全  · 2025-04-03 09:20

正文

请到「今天看啥」查看全文


作者 坛账号: Tkazer

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

前言

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

R3分析

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

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



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


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


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


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


与"sxx"进行循环xor。


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



至此R3层分析完毕。

R0分析

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



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

以下图为例子:

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


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



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

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


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


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



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


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


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

 复制代码 隐藏代码
// tea函数原字节
unsignedchar tea[149] = {
    0x480x8B 0xC40x480x890x580x080x480x890x680x100x480x890x700x180x48,
    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; // ebx
    char* v3; // rdx
    int i; // ecx
    unsigned __int64 v5; // rax
    char* v6; // rdx
    int j; // ecx
    unsigned __int64 v8; // rax
    char* v9; // rdx
    unsigned __int64* v10; // rcx
    unsigned __int64 v11; // r8
    unsigned __int64 v12; // rax
    unsigned __int8 CurrentIrql; // dl
    unsigned __int64 v14; // rcx
    unsigned __int64 v15; // rax
    unsigned __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;
}

int main()
{
    // 修改tea加密函数代码字节
    sub_14000A35B((longlong)tea);
    system("pause");
    return0;
}

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




合并完的代码如下:


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


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

 复制代码 隐藏代码
void tea_decrypt(unsigned int* 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处开始是密文。


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


解密

 复制代码 隐藏代码
#include 
#include 

// 魔改tea解密函数
void tea_decrypt(unsigned int *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,
    0xEAAB87120xE704E8880xE01A31AC0xECAE205C 0xA7BE74670x0C6252A30x1AEFEC4E0xC40DED44,
    0xC3C842CC0xDE4A0C0E0x7C24F3FC0x8FB8D0010x11153E6E0x530ED15C0xF42148110xBEB517E0,
    0x63F916340x4D96F8A50xFE23EAC80x2C607ADF0xCC43D85C0xFF186C5B0x8763E1A50x9187BD58,
    0x87D1069B0xD7878D7B0x836E6B680x55A0C63F0xD979FDB30x3E524DEE0x7AB35C820xA2F4DA8D,
    0x1708BA4C0x710653E6};

// tea解密key
int key[4]{'A''C''E''6'};

int main()
{
    // 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(换表)


密文: We1C0me!T0Z0Z5GamESecur1t9*CTf

Flag

flag{ACE_We1C0me!T0Z0Z5GamESecur1t9*CTf}


-官方论坛

www.52pojie.cn


👆👆👆

公众号 设置“星标”, 不会错过 新的消息通知
开放注册、精华文章和周边活动 等公告

图片







请到「今天看啥」查看全文