TSCTF-J 2019 EasyCPP

TSCTF-J 2019 EasyCPP

准备

在这里插入图片描述
使用64位IDA打开

代码分析

主函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
int __cdecl main(int argc, const char **argv, const char **envp)
{
__int64 v3; // rax
__int64 v4; // rbx
__int64 v5; // rax
bool v6; // bl
__int64 v7; // rax
__int64 v8; // rax
__int64 v9; // rax
__int64 v10; // rax
__int64 v11; // rax
__int64 v12; // rax
char v14[40]; // [rsp+0h] [rbp-140h] BYREF
__int64 v15; // [rsp+28h] [rbp-118h] BYREF
__int64 v16; // [rsp+30h] [rbp-110h] BYREF
int v17; // [rsp+3Ch] [rbp-104h] BYREF
char v18[32]; // [rsp+40h] [rbp-100h] BYREF
char v19[48]; // [rsp+60h] [rbp-E0h] BYREF
char v20[31]; // [rsp+90h] [rbp-B0h] BYREF
char v21; // [rsp+AFh] [rbp-91h] BYREF
char v22[47]; // [rsp+B0h] [rbp-90h] BYREF
char v23; // [rsp+DFh] [rbp-61h] BYREF
char v24[36]; // [rsp+E0h] [rbp-60h] BYREF
unsigned int v25; // [rsp+104h] [rbp-3Ch]
char *v26; // [rsp+108h] [rbp-38h]
int *v27; // [rsp+110h] [rbp-30h]
_DWORD *v28; // [rsp+118h] [rbp-28h]
int *v29; // [rsp+120h] [rbp-20h]
int i; // [rsp+128h] [rbp-18h]
int v31; // [rsp+12Ch] [rbp-14h]

v31 = 0;
std::vector<int>::vector(v20, argv, envp); // 创建int容器
std::vector<bool>::vector(v19); // 创建bool容器
std::allocator<char>::allocator(&v21);
std::__cxx11::basic_string<char,std::char_traits<char>,std::allocator<char>>::basic_string(v18, &unk_500E, &v21);
std::allocator<char>::~allocator(&v21);
v3 = std::operator<<<std::char_traits<char>>(&std::cout, "give me your key!");
std::ostream::operator<<(v3, &std::endl<char,std::char_traits<char>>);
for ( i = 0; i <= 8; ++i ) // 输入8个key
{
std::istream::operator>>(&std::cin, &keys[i]);
std::__cxx11::to_string((std::__cxx11 *)v22, keys[i]);// 将输入的keys转为字符串
std::__cxx11::basic_string<char,std::char_traits<char>,std::allocator<char>>::operator+=(v18, v22);
std::__cxx11::basic_string<char,std::char_traits<char>,std::allocator<char>>::~basic_string(v22);
}
v28 = keys;
v29 = keys;
v27 = (int *)&unk_83E4;
while ( v29 != v27 )
{
v17 = *v29;
std::vector<int>::push_back(v20, &v17); // 将输入压入v20
++v29;
}
v4 = std::vector<int>::end(v20);
v5 = std::vector<int>::begin(v20);
std::for_each<__gnu_cxx::__normal_iterator<int *,std::vector<int>>,main::{lambda(int &)#1}>(v5, v4);// 遍历并执行lamada函数,进入后发现是与1异或
v26 = v20;
v16 = std::vector<int>::begin(v20);
v15 = std::vector<int>::end(v26);
while ( (unsigned __int8)__gnu_cxx::operator!=<int *,std::vector<int>>(&v16, &v15) )
{
v25 = *(_DWORD *)__gnu_cxx::__normal_iterator<int *,std::vector<int>>::operator*(&v16);
std::allocator<char>::allocator(&v23);
std::__cxx11::basic_string<char,std::char_traits<char>,std::allocator<char>>::basic_string(v14, &unk_500E, &v23);// 创建字符串v14
std::allocator<char>::~allocator(&v23);
depart(v25, v14); // 用depart函数加密
{lambda(std::__cxx11::basic_string<char,std::char_traits<char>,std::allocator<char>> &)#1}::operator()(
(__int64)&func,
(__int64)v14);//对字符进行替换
std::__cxx11::basic_string<char,std::char_traits<char>,std::allocator<char>>::basic_string(v24, v14);
v6 = !{lambda(std::__cxx11::basic_string<char,std::char_traits<char>,std::allocator<char>>,int)#2}::operator()(// 比较结果
(__int64)&check,
(__int64)v24,
v31);
std::__cxx11::basic_string<char,std::char_traits<char>,std::allocator<char>>::~basic_string(v24);
if ( v6 )
{
v7 = std::operator<<<std::char_traits<char>>(&std::cout, "Wrong password!");
std::ostream::operator<<(v7, &std::endl<char,std::char_traits<char>>);
system("pause");
exit(0);
}
++v31;
std::__cxx11::basic_string<char,std::char_traits<char>,std::allocator<char>>::~basic_string(v14);
__gnu_cxx::__normal_iterator<int *,std::vector<int>>::operator++(&v16);
}
v8 = std::operator<<<std::char_traits<char>>(&std::cout, "right!");
std::ostream::operator<<(v8, &std::endl<char,std::char_traits<char>>);
v9 = std::operator<<<std::char_traits<char>>(&std::cout, "flag:MRCTF{md5(");// flag使用MD5 32位大写加密
v10 = std::operator<<<char>(v9, v18);
v11 = std::operator<<<std::char_traits<char>>(v10, ")}");
std::ostream::operator<<(v11, &std::endl<char,std::char_traits<char>>);
v12 = std::operator<<<std::char_traits<char>>(
&std::cout,
"md5()->{32/upper case/put the string into the function and transform into md5 hash}");
std::ostream::operator<<(v12, &std::endl<char,std::char_traits<char>>);
system("pause");
std::__cxx11::basic_string<char,std::char_traits<char>,std::allocator<char>>::~basic_string(v18);
std::vector<bool>::~vector(v19);
std::vector<int>::~vector(v20);
return 0;
}

depart函数

这个递归一开始没看懂,看大佬writeup明白是分解质因数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
__int64 __fastcall depart(int a1, __int64 a2)
{
char v3[32]; // [rsp+20h] [rbp-60h] BYREF
char v4[40]; // [rsp+40h] [rbp-40h] BYREF
int i; // [rsp+68h] [rbp-18h]
int v6; // [rsp+6Ch] [rbp-14h]

v6 = a1;
for ( i = 2; std::sqrt<int>((unsigned int)a1) >= (double)i; ++i )
{
if ( !(a1 % i) ) // a1整除i时,继续分解v6/i
{
v6 = i;
depart(a1 / i, a2);
break;
}
}
std::__cxx11::to_string((std::__cxx11 *)v4, v6);
std::operator+<char>(v3, &unk_500C, v4);
std::__cxx11::basic_string<char,std::char_traits<char>,std::allocator<char>>::operator+=(a2, v3);// 质因数最后以字符型存入a2
std::__cxx11::basic_string<char,std::char_traits<char>,std::allocator<char>>::~basic_string(v3);
return std::__cxx11::basic_string<char,std::char_traits<char>,std::allocator<char>>::~basic_string(v4);
}

结果比较函数

1
2
3
4
5
6
7
8
9
_BOOL8 __fastcall {lambda(std::__cxx11::basic_string<char,std::char_traits<char>,std::allocator<char>>,int)#2}::operator()(__int64 a1, __int64 a2, int a3)
{
const char *v3; // rbx
const char *v4; // rax

v3 = (const char *)std::__cxx11::basic_string<char,std::char_traits<char>,std::allocator<char>>::c_str((char *)&ans[abi:cxx11] + 32 * a3);//对比较的字符串进行交叉引用
v4 = (const char *)std::__cxx11::basic_string<char,std::char_traits<char>,std::allocator<char>>::c_str(a2);
return strcmp(v4, v3) == 0;
}

交叉引用后找到用于比较的字符串

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
int __fastcall __static_initialization_and_destruction_0(int a1, int a2)
{
int result; // eax
char v3; // [rsp+17h] [rbp-29h] BYREF
char v4; // [rsp+18h] [rbp-28h] BYREF
char v5; // [rsp+19h] [rbp-27h] BYREF
char v6; // [rsp+1Ah] [rbp-26h] BYREF
char v7; // [rsp+1Bh] [rbp-25h] BYREF
char v8; // [rsp+1Ch] [rbp-24h] BYREF
char v9; // [rsp+1Dh] [rbp-23h] BYREF
char v10; // [rsp+1Eh] [rbp-22h] BYREF
char v11[33]; // [rsp+1Fh] [rbp-21h] BYREF

if ( a1 == 1 && a2 == 0xFFFF )
{
std::ios_base::Init::Init((std::ios_base::Init *)&std::__ioinit);
__cxa_atexit((void (__fastcall *)(void *))&std::ios_base::Init::~Init, &std::__ioinit, &_dso_handle);
std::allocator<char>::allocator(&v3);
std::__cxx11::basic_string<char,std::char_traits<char>,std::allocator<char>>::basic_string(
&ans[abi:cxx11],
"=zqE=z=z=z",
&v3);
std::allocator<char>::~allocator(&v3);
std::allocator<char>::allocator(&v4);
std::__cxx11::basic_string<char,std::char_traits<char>,std::allocator<char>>::basic_string(
(char *)&ans[abi:cxx11] + 32,
"=lzzE",
&v4);
std::allocator<char>::~allocator(&v4);
std::allocator<char>::allocator(&v5);
std::__cxx11::basic_string<char,std::char_traits<char>,std::allocator<char>>::basic_string(
(char *)&ans[abi:cxx11] + 64,
"=ll=T=s=s=E",
&v5);
std::allocator<char>::~allocator(&v5);
std::allocator<char>::allocator(&v6);
std::__cxx11::basic_string<char,std::char_traits<char>,std::allocator<char>>::basic_string(
(char *)&ans[abi:cxx11] + 96,
"=zATT",
&v6);
std::allocator<char>::~allocator(&v6);
std::allocator<char>::allocator(&v7);
std::__cxx11::basic_string<char,std::char_traits<char>,std::allocator<char>>::basic_string(
(char *)&ans[abi:cxx11] + 128,
"=s=s=s=E=E=E",
&v7);
std::allocator<char>::~allocator(&v7);
std::allocator<char>::allocator(&v8);
std::__cxx11::basic_string<char,std::char_traits<char>,std::allocator<char>>::basic_string(
(char *)&ans[abi:cxx11] + 160,
"=EOll=E",
&v8);
std::allocator<char>::~allocator(&v8);
std::allocator<char>::allocator(&v9);
std::__cxx11::basic_string<char,std::char_traits<char>,std::allocator<char>>::basic_string(
(char *)&ans[abi:cxx11] + 192,
"=lE=T=E=E=E",
&v9);
std::allocator<char>::~allocator(&v9);
std::allocator<char>::allocator(&v10);
std::__cxx11::basic_string<char,std::char_traits<char>,std::allocator<char>>::basic_string(
(char *)&ans[abi:cxx11] + 224,
"=EsE=s=z",
&v10);
std::allocator<char>::~allocator(&v10);
std::allocator<char>::allocator(v11);
std::__cxx11::basic_string<char,std::char_traits<char>,std::allocator<char>>::basic_string(
(char *)&ans[abi:cxx11] + 256,
"=AT=lE=ll",
v11);
std::allocator<char>::~allocator(v11);
result = __cxa_atexit(_tcf_0, 0LL, &_dso_handle);
}
return result;
}

解密

解密脚本如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
str=["=zqE=z=z=z","=lzzE","=ll=T=s=s=E","=zATT","=s=s=s=E=E=E","=EOll=E","=lE=T=E=E=E","=EsE=s=z","=AT=lE=ll"]
flag=[]

for i in range(0,9):
str[i] = str[i].replace("O", "0")
str[i] = str[i].replace("l", "1")
str[i] = str[i].replace("z", "2")
str[i] = str[i].replace("E", "3")
str[i] = str[i].replace("A", "4")
str[i] = str[i].replace("s", "5")
str[i] = str[i].replace("G", "6")
str[i] = str[i].replace("T", "7")
str[i] = str[i].replace("B", "8")
str[i] = str[i].replace("q", "9")
str[i] = str[i].replace("=", " ")
str[i] = str[i].split( )
k=1;
for j in str[i]:
k=k*int(j)
print(k^1,end=' ')

在这里插入图片描述