BUUTCTF-RE-Youngter-drive
这道题考察了线程的知识点,刚好之前略有耳闻,今天就来好好分析一下。
首先是查壳为UPX
可,脱去后可以看到程序的逻辑:
程序首先分配了一个共享资源区域,然后分别创建了两个进程,我们看到当dword_418008
小于0时,进入下一个函数,我们猜测,这个dword_418008
也许是共享资源
我们分别查看两个进程的内容:
void __stdcall __noreturn StartAddress_0(int a1)
{
while ( 1 )
{
WaitForSingleObject(hObject, 0xFFFFFFFF);
if ( dword_418008 > -1 )
{
sub_41112C((int)Source, dword_418008);
--dword_418008;
Sleep(0x64u);
}
ReleaseMutex(hObject);
}
}
void __stdcall __noreturn sub_411B10(int a1)
{
while ( 1 )
{
WaitForSingleObject(hObject, 0xFFFFFFFF);
if ( dword_418008 > -1 )
{
Sleep(0x64u);
--dword_418008;
}
ReleaseMutex(hObject);
}
}
可以看到两个进程都对dword_418008
进行了递减操作,但是不同的是第一个线程多了一个操作,我们进入sub_41112C
可以看到,它是一个加密程序
我们大致搞清楚了它的进程操作,我们来看下他的判断和加密过程:
大概就是读入一个你的flag,然后对其进行加密,然后与数据off_418004
进行比较判断
其中通过了sub_41112C
的加密。其加密逻辑如下:
char *__cdecl sub_411940(int a1, int a2)
{
char *result; // eax
char v3; // [esp+D3h] [ebp-5h]
v3 = *(_BYTE *)(a2 + a1);
if ( (v3 < 'a' || v3 > 122) && (v3 < 65 || v3 > 90) )
exit(0);
if ( v3 < 'a' || v3 > 'z' )
{
result = off_418000[0];
*(_BYTE *)(a2 + a1) = off_418000[0][*(char *)(a2 + a1) - 38];
}
else
{
result = off_418000[0];
*(_BYTE *)(a2 + a1) = off_418000[0][*(char *)(a2 + a1) - 96];
}
return result;
}
这里的a1
是我们的flag的首地址,a2
是其偏移量,对应的是dword_418008
的数值。
现在我们对程序的逻辑已经有了认识:
- 首先读取一个输入
- 接着通过进程执行,对我们的输入进行变换
- 变换后的数据进行比较
这里我们需要注意一个特点,我们的进程是交替运行的,所以说,我们的加密操作也不是连续进行的,其只对一般的字符进行了加密。
这里的加密逻辑需要特别说明一下: - 如果字母是大写,则减去38,以0~25映射到
off_418000
中 - 如果字母是小写,则减去96,以26~52映射到
off_418000
中
至此我们可以写出我们的解密程序
key = "QWERTYUIOPASDFGHJKLZXCVBNMqwertyuiopasdfghjklzxcvbnm"
cipher = "TOiZiZtOrYaToUwPnToBsOaOapsyS"
flag = ""
for i in range(len(cipher)):
if i & 1:
if ord(cipher[i]) <= ord('Z'):
flag += chr(key.index(cipher[i])+96)
else:
flag += chr(key.index(cipher[i])+38)
else:
flag+=cipher[i]
print(flag)
得到flag