也是很意思的一道题,这里通过ret far指令在32位程序中途切换执行64位代码,这操作很厉害
Meow way
这个程序就比较神奇了,是个32位程序,无壳,运用了很神奇的反调试手法
看看main函数:
可以看到,这里是通过命令行参数传入flag进行验证的
传入参数是48字节长度,然后往下就是48次函数调用,每次调用都有一个参数是不同的,每次调用的函数也是不同的
最后调用完48个函数之后,将生成的结果与固定的48字节数组进行比对,比对成功就是flag
生成flag思路很简单:找到这些函数的生成逻辑,然后用for循环去爆破这48个字符,因为这48个字符之间彼此独立,所以只需要遍历48*118次即可得到flag
接下来随便点开一个看看,同样的参数,不同的函数,很可能都是相同的函数内容
点开发现这玩意是函数指针变量,还不是真正的函数
交叉引用追一下:
发现了函数指针的赋值,同时也看到了其他函数指针也是这么赋值的,赋值的内容依然是数据段的内容
把数据段的内容转换成代码之后:
可以看到,这里是可执行的代码,这里用了call当前地址这种自定位手段,可能是有花指令之类的干扰,为了知道具体执行内容,直接动态看
但是发现,单步执行到函数里的时候,程序会直接退出,调试器没有接管到任何异常,反而步过直接跳过函数,可以正常执行拿到结果
问题就出在了这里的retf指令上!!
观察一下调用函数的时候的参数:
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位程序进行反汇编:
反汇编成功,是可读可执行的正常程序!
功能是参数里的一个值加上取出一个输入字符,最后再和一个固定值异或,最后保存回输入
随便再看几个其他的函数,发现也都是如此的逻辑,只不过异或值和参数各不相同
逻辑很简单,但是!这有48个不同的异或的固定值!!!总不能手动提取吧,这里可以注意到,这里异或的特征码是80 F1,通过IDA的字节序列搜索功能,可以很快提取出来这48个值
最后再把48个函数调用的参数都提取出来就可以生成flag了
生成结果:hitco{_5T4_1pIE_x6_G1C_m0W
emmm…这显然不对啊!!!
后来去定位缺失的字符对应的函数,发现这48个函数逻辑并不是完全一样的,还有不一样的存在,提取出来用010 editor的反汇编查看:
还有一种是使用减法的!!!
考虑到有些字符是用减法生成的之后,再次爆破生成:
// 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}