Youngter-drive(BUUCTF)

传送门:https://buuoj.cn/challenges#Youngter-drive

PEID 查壳,发现有 UPX 壳,脱壳,载入 IDA

Youngter-drive(BUUCTF)

查看主函数

Youngter-drive(BUUCTF)

sub_4110FF 则如下

Youngter-drive(BUUCTF)

分析一下主函数,可以看到是多线程运行,CreateThread 函数起到创建新线程,调用函数执行用,值得注意的是这里使用了两次 CreateThread,创建线程 A/B,两个线程交替执行

先看第一个线程 h0bject,它会执行 StartAddress 函数

Youngter-drive(BUUCTF)

继续查看 sub_41112C 函数

Youngter-drive(BUUCTF)

看一眼第二个线程

Youngter-drive(BUUCTF)

结合起来看一下,第一个线程中的函数 sub_41112C 传入 sub_411940 的值也就是 dword_418008(a2),说明计数从 29 开始,线程循环每执行一次减一,减到 0 为止,但要注意并不是计数值每减一都会调用一次这个函数。前面说过,两个线程是交替执行的,StartAddress 会调用这个函数,然后计数值减一,但如图第二个线程中的函数 sub_41119F 不会调用 sub_41112C 这个函数,而是直接把计数值减一。这就意味着输入的 flag 里只有一半的字符会通过 sub_41112C 被变换,其余的一半不会变。这函数里先判断了下字符是不是字母再变换,大写字母就替换成 off_418000[0][ * (_BYTE *)(a2 + a1) - 38],小写字母就替换成 off_418000[0][ *(_BYTE *)(a2 + a1) - 96],其中 off_418000[0] 的内容是 QWERTYUIOPASDFGHJKLZXCVBNMqwertyuiopasdfghjklzxcvbnm

接下来回到主函数看待最后有个 sub_411190,打开瞧瞧

Youngter-drive(BUUCTF)

把变换后的字符串每一位和 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}

上一篇:简单实现 手写 观察者模式


下一篇:守护进程:每秒生成一个日志文件