Youngter-drive(BUUCTF)
传送门:https://buuoj.cn/challenges#Youngter-drive
PEID 查壳,发现有 UPX 壳,脱壳,载入 IDA
查看主函数
sub_4110FF 则如下
分析一下主函数,可以看到是多线程运行,CreateThread 函数起到创建新线程,调用函数执行用,值得注意的是这里使用了两次 CreateThread,创建线程 A/B,两个线程交替执行
先看第一个线程 h0bject,它会执行 StartAddress 函数
继续查看 sub_41112C 函数
看一眼第二个线程
结合起来看一下,第一个线程中的函数 sub_41112C 传入 sub_411940 的值也就是 dword_418008(a2),查看 dword_418008
0x1D 是 29,说明计数从 29 开始,线程循环每执行一次减一,减到 0 为止,但要注意并不是计数值每减一都会调用一次这个函数
前面说过,两个线程是交替执行的,StartAddress 会调用这个函数,然后计数值减一,但如图第二个线程中的函数 sub_41119F 不会调用 sub_41112C 这个函数,而是直接把计数值减一。这就意味着输入的 flag 里只有一半的字符会通过 sub_41112C 被变换,其余的一半不会变
看一下 sub_411940 里的操作
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 > 'z') && (v3 < 'A' || v3 > 'Z') )
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;
}
先判断了下字符是不是字母再变换,是大写字母就替换成 off_418000[0][ * (_BYTE *)(a2 + a1) - 38],是小写字母就替换成 off_418000[0][ *(_BYTE *)(a2 + a1) - 96],其中 off_418000[0] 的内容是 QWERTYUIOPASDFGHJKLZXCVBNMqwertyuiopasdfghjklzxcvbnm
接下来回到主函数看待最后有个 sub_411190,打开瞧瞧
把变换后的字符串每一位和 off_418004 比较,全部相同就回显 flag,off_418004 的内容是 TOiZiZtOrYaToUwPnToBsOaOapsyS
至此,程序就大体分析完了,但是还不太清楚两个线程到底是哪个先进行,姑且都试一试,发现是奇数位加密偶数位不变,所以对应写出 exp:
#include <bits/stdc++.h>
using namespace std;
char str1[] = "TOiZiZtOrYaToUwPnToBsOaOapsyS";
char str2[] = "QWERTYUIOPASDFGHJKLZXCVBNMqwertyuiopasdfghjklzxcvbnm";
int main() {
for (int i = 0; i < 29; i++) {
if (i % 2 == 0) {
cout << str1[i];
continue;
}
int cnt = 0;
while (str1[i] != str2[cnt]) cnt++;
if (str1[i] >= 'A' && str1[i] <= 'Z') cout << (char)(cnt + 96);
else cout << (char)(cnt + 38);
}
return 0;
}
解得前29位是 ThisisthreadofwindowshahaIsES
按理说这题应当是多解,最后一位填啥都可以,但是出题人设计的是 E,buu上也只有 E 才通过
flag{ThisisthreadofwindowshahaIsESE}