Last updated on 2022年6月18日
初步分析
这是一个运行在x86 Windows上的可执行文件,无壳。
我们运行一下观察它的功能:
它读取一行输入然后判断。
逆向分析
我们在IDA打开它,查看反编译的代码:
主流程
它读取输入到input
字符串,然后在sub_411578
进行预处理,最后在check
进行检查对比。
sub_411578
我们看到,它将输入字符串末尾补符号-
,使得字符串的长度为3的整数倍。但是这里的反编译其实是不完整的,我们需要在汇编代码中去花指令从而看到完整的流程。
这里我们可以发现,后面还对输入进行循环做了一个处理,但是sub_411546
和sub_4113A2
中的
hEvent
和hHandle
事件我们还不知道是什么,因此这里我们先去看其他处理的部分。
sub_4112AD
这里没什么好说的,就是比较并输出。有一个这里IDA默认的std::ostream::operator<<
只有一个参数,我们要将它修改为两个参数的(第二个参数是输出格式参数),否则这里反编译会是下面的样子:
TLS
我们注意到在段表中有一个.tls
段,我们基本可以预料是使用tls
的回调函数做了一些操作:
不知道tls的可以参考这一篇文章:TLS回调函数
在函数列表中搜索TLS
,可以看到如下这么几个函数:
其中,带_0
后缀的是对应回调函数的调用函数。
TlsCallback_0_0
sub_411212
和sub_4111AE
就是进程开始前执行的内容(DLL_PROCESS_ATTACH
)。
sub_411212
这个函数有花指令,去花之后代码如下:
它使用CheckRemoteDebuggerPresent
检查是否有调试器,若有则对table
进行干扰操作。
sub_4111AE
这个函数同样有花指令,去花之后如下:
这段代码是一段SMC
,它在进程的段表中查找一个叫.cyzcc
的段,然后对段内容异或操作解密。
我们使用IDAPython脚本对.cyzcc
段进行patch:
from ida_bytes import get_byte, patch_byte
addr = 0x41E000
end = 0x41F200
x = 'D0g3'
for i in range(end - addr):
b = get_byte(addr + i)
bb = b ^ ord(x[i%4])
patch_byte(addr + i, bb)
print("Done")
TlsCallback_1_0
这里我们看到了需要的hHandle
和hEvent
事件信号,但这里只是创建,并不能满足前面循环处理的需求。
TlsCallback_2_0
这个回调函数创建了两个子线程StartAddress
和sub_41109B
StartAddress
这个线程是对table
进行解密,然后接收hHandle
信号,还有一部分处理被花指令隐藏了,去花之后如下:
它有一个循环,接收hHandle
信号和触发hEvent
信号,刚好和之前的sub_411578对应起来。这里的处理相当于把table
当作环形的,然后每次移动指针位置。
flag代码
#include
unsigned char table[128] = {
0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
0x20, 0x21, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C,
0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14,
0x15, 0x16, 0x17, 0x18, 0x19, 0xFA, 0xFB, 0xFC,
0xFD, 0xFE, 0xFF, 0x00, 0xB6, 0xB7, 0xB8, 0xB9,
0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF, 0xB1, 0xB5};
char dest[] = {
0x23, 0x7A, 0x3D, 0x60, 0x34, 0x07, 0x11, 0x36,
0x2C, 0x05, 0x0C, 0x20, 0x0B, 0x22, 0x3F, 0x6F,
0x16, 0x00, 0x37, 0x0D, 0x36, 0x0F, 0x1E, 0x20,
0x37, 0x14, 0x02, 0x09, 0x02, 0x0F, 0x1B, 0x39,
0x00};
char fake_flag[] = "D0g3{cyzcc_have_ten_girlfriends}";
char input[64];
unsigned char* table_ptr;
void decode_table()
{
for (int i = 0; i < 64; ++i)
{
if (i >= 26)
{
if (i >= 45)
table[i] += 122;
else
table[i] += 90;
}
else
{
table[i] += 57;
}
}
}
void get_dest()
{
for (int i = 0; i < 32; ++i)
dest[i] ^= fake_flag[i];
}
int indexof(char ch)
{
for (int i = 0; i < 64; ++i)
if (table_ptr[i] == ch)
return i;
return -1;
}
int main()
{
decode_table();
get_dest();
table_ptr = table;
for (int i = 0; i < 8; ++i)
{
table_ptr[64] = table_ptr[0];
table_ptr++;
int a = indexof(dest[i * 4]);
int b = indexof(dest[i * 4 + 1]);
int c = indexof(dest[i * 4 + 2]);
int d = indexof(dest[i * 4 + 3]);
input[i * 3 + 0] = (a << 2) & 0xC0 | (c << 2) & 0x30 | (d >> 2) & 0xC | b & 0x3;
input[i * 3 + 1] = (b << 2) & 0xC0 | (a << 2) & 0x30 | (d >> 0) & 0xC | c & 0x3;
input[i * 3 + 2] = (c << 2) & 0xC0 | (b << 2) & 0x30 | (d << 2) & 0xC | a & 0x3;
}
puts(input);
}
flag
d0g3{d0g3_1sA_b1gf4mily}