Ha1cyon-CTF 芜湖 题解
源代码
先上源代码:
#include <stdio.h>
#include <iostream>
#include <vector>
using namespace std;
string oOoOo00[35];
char o0ooOo0oo0O[35][42] = {
{
84, 84, 24, 89, 84, 56, 12, 47, 87, 56, 4, 47, 84, 0, 50, 47,
84, 84, 16, 36, 87, 0, 46, 46, 84, 17, 12, 23, 45, 38, 92, 92,
},
{
84, 19, 8, 48, 84, 19, 8, 48, 84, 16, 8, 9, 84, 86, 46, 42,
84, 45, 16, 38, 84, 86, 16, 12, 84, 0, 87, 0, 45, 46, 92, 92,
},
{
84, 17, 8, 7, 84, 87, 12, 87, 84, 45, 8, 45, 84, 19, 54, 35,
84, 19, 54, 16, 84, 84, 16, 36, 84, 45, 83, 6, 45, 41, 92, 92,
},
{
84, 45, 20, 47, 84, 85, 50, 83, 84, 87, 4, 56, 84, 0, 74, 38,
84, 84, 16, 36, 87, 45, 4, 5, 84, 87, 0, 86, 45, 32, 92, 92,
},
{
84, 19, 8, 17, 84, 3, 16, 12, 84, 19, 0, 40, 84, 0, 50, 25,
84, 84, 16, 36, 84, 84, 87, 18, 87, 59, 4, 81, 45, 41, 92, 92,
},
{
84, 17, 4, 6, 84, 19, 46, 55, 87, 42, 4, 12, 84, 17, 38, 85,
84, 84, 16, 36, 84, 17, 8, 46, 84, 0, 50, 17, 45, 39, 92, 92,
},
{
84, 19, 42, 9, 84, 17, 24, 43, 84, 3, 24, 55, 84, 56, 16, 3,
84, 84, 16, 36, 84, 45, 8, 54, 84, 84, 54, 44, 45, 38, 92, 92,
},
{
84, 19, 42, 9, 84, 17, 24, 43, 87, 40, 50, 0, 84, 56, 83, 22,
84, 84, 16, 36, 84, 56, 54, 43, 84, 3, 12, 81, 45, 37, 92, 92,
},
{
87, 45, 74, 56, 84, 59, 24, 14, 84, 87, 83, 43, 84, 84, 83, 32,
84, 45, 83, 6, 84, 56, 4, 87, 84, 85, 87, 22, 45, 41, 92, 92,
},
{
84, 17, 4, 13, 84, 17, 4, 13, 84, 0, 50, 2, 84, 0,
50, 2, 87, 40, 4, 16, 87, 45, 83, 18, 84, 84, 16, 36,
87, 42, 38, 44, 84, 17, 8, 7, 45, 36, 92, 92,
},
{
84, 56, 8, 22, 84, 0, 50, 36, 87, 56, 38, 20, 84, 19,
20, 9, 84, 56, 8, 19, 84, 45, 16, 87, 84, 84, 16, 36,
87, 40, 46, 44, 84, 3, 83, 25, 45, 38, 92, 92,
},
{
87, 42, 87, 17, 87, 0, 46, 46, 84, 59, 34, 84, 84, 17,
54, 11, 84, 19, 4, 82, 84, 45, 12, 25, 84, 84, 16, 36,
84, 59, 38, 89, 84, 59, 34, 85, 45, 38, 92, 92,
},
{
84, 3, 74, 19, 84, 3, 74, 19, 84, 19,
8, 39, 87, 56, 0, 50, 7, 15, 92, 92,
},
{
87, 59, 83, 59, 87, 59, 83, 59, 84, 85, 54, 15, 84, 45,
16, 20, 84, 56, 87, 7, 84, 17, 83, 13, 84, 84, 16, 36,
87, 40, 4, 16, 84, 3, 4, 25, 45, 45, 92, 92,
},
{
84, 0, 50, 17, 84, 87, 12, 87, 84, 19, 50, 50, 84, 19,
20, 9, 84, 3, 74, 88, 84, 85, 50, 83, 84, 84, 16, 36,
84, 56, 54, 43, 84, 17, 8, 46, 45, 36, 92, 92,
},
{
84, 84, 24, 89, 84, 45, 8, 21, 84, 56, 74, 16, 87, 42,
0, 35, 84, 86, 20, 0, 84, 85, 46, 34, 84, 84, 16, 36,
84, 0, 50, 17, 87, 59, 12, 39, 45, 38, 92, 92,
},
{
84, 56, 0, 47, 87, 0, 46, 4, 87, 42, 38, 44, 40, 54, 92, 92,
},
{
84, 14, 8, 51, 84, 56, 20, 41, 84, 17, 54, 8, 84, 59, 24, 22,
84, 14, 16, 18, 87, 45, 54, 82, 84, 0, 50, 81, 45, 44, 92, 92,
},
{
84, 84, 24, 45, 84, 84, 83, 32, 87, 40, 24, 19, 87, 40, 24, 19,
84, 84, 16, 36, 84, 0, 87, 41, 84, 0, 87, 59, 45, 41, 92, 92,
},
{
84, 0, 50, 0, 84, 3, 34, 51, 84, 17, 24, 16, 84, 84, 74, 13,
84, 84, 16, 36, 84, 17, 8, 7, 84, 84, 34, 37, 45, 43, 92, 92,
},
{
84, 17, 24, 43, 84, 19, 42, 9, 84, 17, 24, 43, 87, 56,
34, 0, 84, 59, 34, 51, 84, 17, 24, 16, 84, 17, 83, 13,
87, 45, 4, 23, 84, 56, 74, 11, 45, 37, 92, 92,
},
{
84, 45, 16, 24, 84, 85, 8, 25, 84, 84, 16, 36,
84, 45, 24, 59, 84, 45, 24, 81, 45, 35, 92, 92,
},
{
87, 42, 87, 17, 84, 14, 8, 51, 84, 45, 20, 18, 84, 45, 8, 32,
87, 45, 54, 82, 84, 85, 42, 84, 84, 85, 4, 37, 45, 38, 92, 92,
},
{
84, 56, 20, 41, 84, 19, 34, 52, 84, 59, 42, 44,
84, 45, 74, 9, 84, 3, 74, 80, 45, 46, 92, 92,
},
{
84, 59, 24, 14, 87, 56, 38, 13, 87, 45, 74, 2, 84, 84,
16, 36, 84, 0, 50, 17, 87, 45, 87, 84, 45, 38, 92, 92,
},
{
87, 59, 46, 83, 84, 19, 42, 27, 87, 45,
87, 84, 84, 86, 24, 56, 45, 41, 92, 92,
},
{
84, 17, 24, 43, 84, 45, 8, 32, 84, 85, 12, 41, 84, 87,
54, 4, 84, 0, 54, 41, 84, 84, 16, 36, 84, 3, 83, 17,
87, 43, 12, 84, 84, 19, 54, 82, 45, 34, 92, 92,
},
{
84, 59, 42, 44, 84, 14, 8, 51, 84, 45, 8, 32, 87, 45,
54, 82, 84, 56, 0, 50, 87, 59, 12, 17, 45, 35, 92, 92,
},
{
87, 0, 46, 4, 84, 59, 34, 51, 84, 56, 74, 12, 84, 45, 8, 32,
84, 45, 8, 16, 84, 45, 8, 54, 84, 84, 54, 44, 45, 34, 92, 92,
},
{
84, 59, 24, 14, 87, 56, 38, 13, 87, 45, 74, 2, 84, 84,
16, 36, 84, 0, 50, 17, 87, 45, 87, 84, 45, 35, 92, 92,
},
{
87, 59, 46, 83, 84, 19, 42, 27, 87, 45,
87, 84, 84, 86, 24, 56, 45, 34, 92, 92,
},
{
84, 17, 24, 43, 84, 45, 8, 32, 84, 85, 12, 41, 84, 87,
54, 4, 84, 0, 54, 41, 84, 84, 16, 36, 84, 3, 83, 17,
87, 43, 12, 84, 84, 19, 54, 82, 45, 35, 92, 92,
},
{
84, 59, 42, 44, 84, 14, 8, 51, 84, 45, 8, 32, 87, 45,
54, 82, 84, 56, 0, 50, 87, 59, 12, 17, 45, 41, 92, 92,
},
{
87, 0, 46, 4, 84, 59, 34, 51, 84, 56, 74, 12, 84, 45, 8, 32,
84, 45, 8, 16, 84, 45, 8, 54, 84, 84, 54, 44, 45, 47, 92, 92,
},
{
2, 82, 55, 22, 59, 57, 40, 6, 3, 54, 39, 15, 0, 54,
44, 6, 5, 83, 88, 24, 3, 38, 51, 74, 7, 6, 92, 92,
},
};
int o000O0ooo0ooOoOo[] = {
32, 32, 32, 32, 32, 32, 32, 32, 32, 40, 40, 40, 20, 40, 40, 40, 16, 32,
32, 32, 40, 24, 32, 24, 28, 20, 40, 28, 32, 28, 20, 40, 28, 32, 28,
};
int o0o0o(int o00ooo000, int o00OoO0O) { return !(o00ooo000 & o00OoO0O); }
int Oo0O(int o00ooo000, int o00OoO0O) {
string o00o0o0oo00ooooo00o0o = "真真假假假假真真, 位运算的世界如此奇妙~";
return o0o0o(o0o0o(o00OoO0O, o0o0o(o00ooo000, o00OoO0O)),
o0o0o(o00ooo000, o0o0o(o00ooo000, o00OoO0O)));
}
typedef unsigned char uchar;
static const std::string o00OoO0O =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
static std::string o0o0OO(const std::string &o00ooO0O) {
std::string o00o0oOOOo;
string o0oo0o0oo00oo0o0 = "俗话说, 最危险的地方就是最安全的地方.";
std::vector<int> o00o0O(256, -1);
for (int o00o0o0o0O = 0; o00o0o0o0O < 64; o00o0o0o0O++)
o00o0O[o00OoO0O[o00o0o0o0O]] = o00o0o0o0O;
int o00oOoO0O = 0, o00OO00ooo0O = -8;
for (uchar o00o0oO0Oo : o00ooO0O) {
if (o00o0O[o00o0oO0Oo] == -1) break;
o00oOoO0O = (o00oOoO0O << 6) + o00o0O[o00o0oO0Oo];
o00OO00ooo0O += 6;
if (o00OO00ooo0O >= 0) {
o00o0oOOOo.push_back(char((o00oOoO0O >> o00OO00ooo0O) & 0xFF));
o00OO00ooo0O -= 8;
}
}
return o00o0oOOOo;
}
void o00oo0o0o0o() {
for (int o00o0o0o0O = 0; o00o0o0o0O < 35; o00o0o0o0O++) {
for (int o00o0o0o00 = 0; o00o0o0o00 < o000O0ooo0ooOoOo[o00o0o0o0O];
o00o0o0o00++) {
char o00o0o0oo = o0ooOo0oo0O[o00o0o0o0O][o00o0o0o00];
char o0oooOO = 0;
for (int o00o0o0o0o = 0; o00o0o0o0o < 8; o00o0o0o0o++) {
o0oooOO <<= 1;
o0oooOO ^= Oo0O((o00o0o0oo >> 8 - o00o0o0o0o - 1) & 1,
('a' >> 8 - o00o0o0o0o - 1) & 1) &
1;
}
oOoOo00[o00o0o0o0O] += o0oooOO;
}
cout << o0o0OO(oOoOo00[o00o0o0o0O]) << endl;
}
cout << endl;
}
int main() { o00oo0o0o0o(); }
这是出题人编写的源代码.
解题思路
这道题我们用IDA打开之后, 可以看见:
main函数里面直接跳转到了这里. 经过查看, 第二层for循环中的判断条件和第一层for循环的i结合起来, 应该是在遍历一个二维数组, 而第二层for中的那个变量数组应该表示二维数组中不同维度的元素的长度. 再往下看, v3就是在提取这个二维数组中的每个元素了. 我们点进这个数组, 可以看到一大片数据.
接下来对v3进行处理, 结果存进v2:
for ( k = 0; k <= 7; ++k )
v2 = Oo0O((v3 >> (7 - k)) & 1, (97 >> (7 - k)) & 1) & 1 ^ 2 * v2;
可以看出这是一个按位操作, 而Oo0O()
函数有点迷惑. 它里面的长这样:
__int64 __fastcall Oo0O(int a1, int a2)
{
int v2; // eax
int v3; // ebx
int v4; // eax
int v5; // eax
_BOOL4 v6; // ebx
char v8; // [rsp+1Fh] [rbp-41h]
char v9; // [rsp+20h] [rbp-40h]
unsigned __int64 v10; // [rsp+48h] [rbp-18h]
v10 = __readfsqword(0x28u);
std::allocator<char>::allocator(&v8);
std::__cxx11::basic_string<char,std::char_traits<char>,std::allocator<char>>::basic_string(&v9, &unk_3010, &v8);
std::allocator<char>::~allocator(&v8);
v2 = o0o0o(a1, a2);
v3 = o0o0o(a1, v2);
v4 = o0o0o(a1, a2);
v5 = o0o0o(a2, v4);
v6 = o0o0o(v5, v3);
std::__cxx11::basic_string<char,std::char_traits<char>,std::allocator<char>>::~basic_string(&v9);
return (unsigned int)v6;
}
其中又涉及到了o0o0o()
函数, 这个函数原型十分简单, 就只有一句话: return (a2 & a1) == 0;
如果选手对数字电路有些许了解的话, 应该很轻松的可以辨认出, 这个函数是与非门(NAND门). 结合hint, 我们可以大致画出Oo0O()
函数的结构:
这个结构走一遍, 实际上就是异或门(xor).
异或大家就很熟悉了. 稍微改一下IDA反编译出来的函数, 我们可以得到一堆Base64字符串.
其实没有学过模电问题也不大, 我们使用gdb, 在o0o0OO()
函数前面下个断点, 就像这样:
然后你就可以看见寄存器指向的运算结果了, 继续跟踪, 我们可以把所有经过运算的字符串全部抓出来, 得到了一堆Base64.
这个时候你把Base64全部拿出去解码, 只能得到和程序运行之后的输出一样的一堆歌词, 并没有flag. 我们观察这些歌词的结尾大部分都是逗号, 然后结合hint的提示, 相同字符经过Base64编码后的结果是相同的, 但是你所抓出来的这一大串base64, 他们的结尾甚至都不相同. ,
经过编码后是LA==
, 但是这些base64结尾不全都是这个. 这个时候你需要对Base64的解码过程有一定的理解, Base64解码过程中会舍弃=
所对应的padding
位, 这也是Base64隐写的原理.
因此我们把那一堆Base64用隐写提取脚本提取一下就可以了.
ICTFE中关于Base64隐写提取的函数如下:
def base64_stego(lines):
alphabet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
flag = ''
temp = 0
digit = 0
for i in lines:
if i[-1] != '=':
continue
elif i[-2] != '=':
digit += 2
temp = (temp << 2) + (alphabet.find(i[-2]) & 0x3)
else:
digit += 4
temp = (temp << 4) + (alphabet.find(i[-3]) & 0xf)
if digit == 8:
digit = 0
flag += chr(temp)
temp = 0
elif digit > 8:
digit = 2
flag += chr(temp >> 2)
temp = temp & 0x3
return flag