cover.png

#Reverse题记
有段时间没有写 CTF Reverse 题目了,在 AI 盛行的时代,手搓题目只能说是自己的兴趣了,在此记录一下以后手搓的 Reverse 题目,作为纪念吧
Attachments_505
找到 main 函数
1 | scanf("%s", Str); |
判断输入字符串是否为 49
此处 v3 和 v10 其实是一个变量,将对应的 Str[i] 减去 48 储存到 box 中,0 ASCII 码值为 48,实则为字符转数字,49长度的字符串转为每9个一行
check1
1 | for ( i = 0; i <= 8; ++i ) |
每一行,需要满足 1-9 的数字都出现一次
check2
1 | for ( i = 0; i <= 8; ++i ) |
同样的,每一列,需要满足 1-9 的数字都出现一次
check3
1 | for ( i = 0; i <= 8; i += 3 ) |
为了检查每个 3x3 的小方格是否包含 1-9 的数字
那么 box 实际为一个满足数独要求的 9x9 的二维数组,输入的字符串长度为 49
实际上可以从 puts_0("Enjoy the beauty of reverse and sudoku!"); 看出这里是数独
最后输出:
1 | for ( k = 0; k < strlen(Str); ++k ) |
magic 数组:
1 | .data:0000000000404080 magic db 6Bh, 2, 66h, 70h, 44h, 69h, 7Eh, 6Eh, 43h, 4Ah, 78h |
64 位,即
1 | 6B 02 66 70 44 69 7E 6E 43 4A 78 4A 6D 60 56 00 51 59 50 43 50 51 6D 74 02 55 50 52 6E 6F 79 40 5D 4B 1E 19 1C 74 03 54 07 4C 52 6A 60 50 58 40 58 0F 00 |
同时可查询到 box 数组默认值
1 | .data:0000000000404020 box db 2 dup(0), 5, 2 dup(0), 4, 3, 6, 5 dup(0), 5, 2 dup(0) |
即
1 | 0 0 5 | 0 0 4 | 3 6 0 |
解数独
1 | 8 2 5 | 9 1 4 | 3 6 7 |
对应应该输入的字符串为:
1 | 8291767138932581849755263447186268341129653538127 |
1 | # ./chall.exe |
1 | moectf{S0_As_I_prAy_Un1imited_B1ade_WOrks---E1m1ya_Shiro} |
Attachments_493
静态链接,C++ 代码编写
1 | std::operator<<<std::char_traits<char>>(&_TMC_END__, "Welcome to MoeCTF 2020!\nPlease input your flag here >>", envp); |
输入了一个长度为 22 的字符串
1 | __int64 __fastcall sub_0() |
进行了多次加密,顺序为
1 | sub_0 -> sub_1 -> sub_2 -> ... ->sub_1996 -> sub_1997 -> sub_1998 -> sub_1999 |
主函数主要是比较输入的字符串的和 key 字符串的每个字符是否相同,key 字符串为:
1 | .data:0000000000074060 key db 2, 0Ah, 6, 16h, 13h, 1Ch, 2, 4Dh, 41h, 28h, 3Dh, 56h |
即
1 | 02 0A 06 16 13 1C 02 4D 41 28 3D 56 52 39 19 70 51 1B 5A 59 7A 22 |
通过动态调试知道第 k 个输入只影响输出 k 和 k-1
我们知道 flag 字符串前面是固定的 meoctf{,所以可以尝试写 gdb_python 脚本爆破
1 | import gdb, string |
上面这个代码的逻辑就是不断尝试调用 sub0 来爆破 flag,如果下一位算出来的答案是 key[j] 那么就说明这个字符是正确的
1 | pwndbg> source solution.py |
得到 flag
1 | moectf{y0u_a2e_G0d~!} |
$ discussion
# Comments