selph
selph
Published on 2022-11-28 / 456 Visits
0
0

HITCON CTF 2022 Writeup Re-meow way

也是很意思的一道题,这里通过ret far指令在32位程序中途切换执行64位代码,这操作很厉害

Meow way

这个程序就比较神奇了,是个32位程序,无壳,运用了很神奇的反调试手法

看看main函数:

image

可以看到,这里是通过命令行参数传入flag进行验证的

传入参数是48字节长度,然后往下就是48次函数调用,每次调用都有一个参数是不同的,每次调用的函数也是不同的

image

最后调用完48个函数之后,将生成的结果与固定的48字节数组进行比对,比对成功就是flag

生成flag思路很简单:找到这些函数的生成逻辑,然后用for循环去爆破这48个字符,因为这48个字符之间彼此独立,所以只需要遍历48*118次即可得到flag

接下来随便点开一个看看,同样的参数,不同的函数,很可能都是相同的函数内容

点开发现这玩意是函数指针变量,还不是真正的函数

image

交叉引用追一下:

image

发现了函数指针的赋值,同时也看到了其他函数指针也是这么赋值的,赋值的内容依然是数据段的内容

把数据段的内容转换成代码之后:

image

可以看到,这里是可执行的代码,这里用了call当前地址这种自定位手段,可能是有花指令之类的干扰,为了知道具体执行内容,直接动态看

但是发现,单步执行到函数里的时候,程序会直接退出,调试器没有接管到任何异常,反而步过直接跳过函数,可以正常执行拿到结果

问题就出在了这里的retf指令上!!

观察一下调用函数的时候的参数:

image

8个参数,如果把2个看成一个的话:

00D3FE6C  00EA6199  "hitcon{AAAAAAAABBBBBBBBCCCCCCCCDDDDDDDDEEEEEEEE}"
00D3FE70  00000000  

00D3FE74  00EA6199  "hitcon{AAAAAAAABBBBBBBBCCCCCCCCDDDDDDDDEEEEEEEE}"
00D3FE78  00000000  

00D3FE7C  000000C4  
00D3FE80  00000000  

00D3FE84  00D3FEA4  
00D3FE88  00000000  

这里就是64位程序的栈参数的形式啊!!!

ret far远跳转会修改段寄存器,这里push了0x33,也就是意味着cs段寄存器会修改为0x33

这个cs段不是32位程序使用的0x23,而是64位程序所使用的0x33

这里的操作应该是强行把接下来执行的内容切换成x64位来执行,然后最后再次通过同样的手段切换回来

把这段程序单独截出来,拖入IDA当64位程序进行反汇编:

image

反汇编成功,是可读可执行的正常程序!

功能是参数里的一个值加上取出一个输入字符,最后再和一个固定值异或,最后保存回输入

随便再看几个其他的函数,发现也都是如此的逻辑,只不过异或值和参数各不相同

逻辑很简单,但是!这有48个不同的异或的固定值!!!总不能手动提取吧,这里可以注意到,这里异或的特征码是80 F1,通过IDA的字节序列搜索功能,可以很快提取出来这48个值

image

最后再把48个函数调用的参数都提取出来就可以生成flag了

生成结果:hitco{_5T4_1pIE_x6_G1C_m0W

emmm…这显然不对啊!!!

后来去定位缺失的字符对应的函数,发现这48个函数逻辑并不是完全一样的,还有不一样的存在,提取出来用010 editor的反汇编查看:

image

还有一种是使用减法的!!!

考虑到有些字符是用减法生成的之后,再次爆破生成:

// meow_way.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//

#include <iostream>
unsigned char fixnum[] = {
    0xBA,0x2F,0xCD,0xF6,0x9F,0xD0,0x22,0xF7,0xD0,0x1F,0xA8,0x3D,0xC7,0xA5,0x47,0x68,
    0xD7,0x4A,0x96,0x91,0x2E,0x19,0xC5,0xE3,0x88,0xBD,0x4E,0x93,0x13,0xF1,0xCC,0x47,
    0xAB,0xC9,0x48,0x2B,0x9,0x50,0x4F,0xE9,0xC0,0x5E,0xEF,0x8B,0x85,0xCB,0x55,0x70
};

unsigned char params[] = {
    196, 22, 142, 119, 5, 185, 13, 107, 36, 85, 18, 53, 118, 231, 251, 160,
    218, 52, 132, 180, 200, 155, 239, 180, 185, 10, 87, 92, 254, 197, 106, 115,
    73, 189, 17, 214, 143, 107, 10, 151, 171, 78, 237, 254, 151, 249, 152, 101
};

unsigned char key[48] = {
    0x96, 0x50, 0xCF, 0x2C, 0xEB, 0x9B, 0xAA, 0xFB, 0x53, 0xAB, 0x73, 0xDD, 0x6C, 0x9E, 0xDB, 0xBC,
    0xEE, 0xAB, 0x23, 0xD6, 0x16, 0xFD, 0xF1, 0xF0, 0xB9, 0x75, 0xC3, 0x28, 0xA2, 0x74, 0x7D, 0xE3,
    0x27, 0xD5, 0x95, 0x5C, 0xF5, 0x76, 0x75, 0xC9, 0x8C, 0xFB, 0x42, 0x0E, 0xBD, 0x51, 0xA2, 0x98
};
int main()
{
    // 异或数值在偏移57处
    for (int i = 0; i < 48; i++)
    {
        for (unsigned char j = 20; j < 128; j++)
        {
            unsigned char c1 = (params[i] + j) ^ fixnum[i];
            unsigned char c2 = (params[i] - j) ^ fixnum[i];
            if (c1 == key[i] || c2 == key[i]) {
                printf("%c",j);
            }

        }
    }
}

得到flag:hitcon{7U5T_4_S1mpIE_xB6_M@G1C_4_mE0w_W@y}


Comment