控制流平坦化-[SUCTF2019]hardcpp

64位ELF,IDA打开看到两处控制流平坦化

1

利用deflat.py脚本去除控制流平坦化,在deflat.py所在目录下打开cmd命令行输入

python deflat.py hardCpp 0x4007E0
#“python版本 + 脚本名 + 文件名 + 起始地址”

下载地址:https://github.com/Pure-T/deflat

2

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
105
106
107
108
109
110
111
112
113
114
int __cdecl main(int argc, const char **argv, const char **envp)
{
char v3; // al
char v4; // al
char v5; // al
char v6; // al
char v8; // al
char v9; // al
char v10; // al
char v11; // al
char v12[8]; // [rsp+A0h] [rbp-90h] BYREF
char v13[8]; // [rsp+A8h] [rbp-88h] BYREF
char v14[8]; // [rsp+B0h] [rbp-80h] BYREF
char v15[8]; // [rsp+B8h] [rbp-78h] BYREF
char v16[8]; // [rsp+C0h] [rbp-70h] BYREF
char v17[7]; // [rsp+C8h] [rbp-68h] BYREF
char v18; // [rsp+CFh] [rbp-61h]
int v19; // [rsp+D0h] [rbp-60h]
int v20; // [rsp+D4h] [rbp-5Ch]
int v21; // [rsp+D8h] [rbp-58h]
int v22; // [rsp+DCh] [rbp-54h]
char s; // [rsp+E0h] [rbp-50h] BYREF
char v24[23]; // [rsp+E1h] [rbp-4Fh] BYREF
char v25[8]; // [rsp+F8h] [rbp-38h] BYREF
char v26[8]; // [rsp+100h] [rbp-30h] BYREF
char v27[8]; // [rsp+108h] [rbp-28h] BYREF
char v28[4]; // [rsp+110h] [rbp-20h] BYREF
int v29; // [rsp+114h] [rbp-1Ch]
const char **v30; // [rsp+118h] [rbp-18h]
int v31; // [rsp+120h] [rbp-10h]
int v32; // [rsp+124h] [rbp-Ch]
int v33; // [rsp+128h] [rbp-8h]
bool v34; // [rsp+12Eh] [rbp-2h]

v32 = 0;
v31 = argc;
v30 = argv;
v29 = time(0LL);
puts("func(?)=\"01abfc750a0c942167651c40d088531d\"?");
s = getchar();
fgets(v24, 21, stdin);
v22 = time(0LL);
v21 = v22 - v29; // 0
v33 = v22 - v29; // 0
if ( y >= 10 && (((x - 1) * x) & 1) != 0 )
goto LABEL_13;
while ( 1 )
{
v20 = strlen(&s);
v34 = v20 != 21;
if ( y < 10 || (((x - 1) * x) & 1) == 0 )
break;
LABEL_13:
v20 = strlen(&s);
}
while ( 1 )
{
v19 = 1;
if ( y < 10 || (((x - 1) * x) & 1) == 0 )
break;
v19 = 1;
}
while ( v19 < 21 )
{
if ( y >= 10 && (((x - 1) * x) & 1) != 0 )
{
v18 = v21 ^ *(&s + v19); // v18 = s[v19];
v17[0] = main::$_0::operator()(v27, v18); // v17[0]=v18 = s[v19];后1个字符
v16[0] = main::$_1::operator()(v25, *(&s + v21 + v19 - 1));// v16[0]=v18 = s[v19-1];前1个字符
v8 = main::$_1::operator() const(char)::{lambda(int)#1}::operator()(v16, 7LL);// s[v19-1]%7
v18 = main::$_0::operator() const(char)::{lambda(char)#1}::operator()(v17, v8);// 两个字符相加
v15[0] = main::$_2::operator()(v28, v18); // 相加结果存入v15
v14[0] = main::$_2::operator()(v28, *(&s + v21 + v19 - 1));// 前一个字符存入v14
v9 = main::$_2::operator() const(char)::{lambda(char)#1}::operator()(v14, 18LL);// 前一个字符跟18异或
v13[0] = main::$_3::operator()(v26, v9); // 异或结果存入v13
v10 = main::$_3::operator() const(char)::{lambda(char)#1}::operator()(v13, 3LL);// 再乘3
v12[0] = main::$_0::operator()(v27, v10);
v11 = main::$_0::operator() const(char)::{lambda(char)#1}::operator()(v12, 2LL);// 加上2
v18 = main::$_2::operator() const(char)::{lambda(char)#1}::operator()(v15, v11);// 异或
}
do
{
v18 = v21 ^ *(&s + v19);
v17[0] = main::$_0::operator()(v27, v18);
v16[0] = main::$_1::operator()(v25, *(&s + v21 + v19 - 1));
v3 = main::$_1::operator() const(char)::{lambda(int)#1}::operator()(v16, 7LL);
v18 = main::$_0::operator() const(char)::{lambda(char)#1}::operator()(v17, v3);
v15[0] = main::$_2::operator()(v28, v18);
v14[0] = main::$_2::operator()(v28, *(&s + v21 + v19 - 1));
v4 = main::$_2::operator() const(char)::{lambda(char)#1}::operator()(v14, 18LL);
v13[0] = main::$_3::operator()(v26, v4);
v5 = main::$_3::operator() const(char)::{lambda(char)#1}::operator()(v13, 3LL);
v12[0] = main::$_0::operator()(v27, v5);
v6 = main::$_0::operator() const(char)::{lambda(char)#1}::operator()(v12, 2LL);
v18 = main::$_2::operator() const(char)::{lambda(char)#1}::operator()(v15, v6);
}
while ( enc[v19 - 1] != v18 );
while ( y >= 10 && (((x - 1) * x) & 1) != 0 )
;
++v19;
}
if ( y >= 10 && (((x - 1) * x) & 1) != 0 )
goto LABEL_16;
while ( 1 )
{
puts("You win");
if ( y < 10 || (((x - 1) * x) & 1) == 0 )
break;
LABEL_16:
puts("You win");
}
return 0;
}

分析while当中的几个函数,将s的数据%7再与前一个数据相加,下面前一个字符先与18异或再*3+2,最后再与enc的数据比较

3

递推关系:

  v15=(s[i]+(s[i-1]%7))^((s[i]^18)*3+2)
  //验证
  v15==enc[i]

所以反求 input 的关系式是:

s[i]=(enc[i-1]^((s[i-1]^18)*3+2)&0xff)-(s[i-1]%7)

但是第一个数据找了很久都没有找到,最后看了大佬的wp找到是在最前面的01abfc750a0c942167651c40d088531d是’#’的md5散列,告诉我们第一个字符是#,就离谱

EXP

1
2
3
4
5
6
enc=[0xf3,0x2e,0x18,0x36,0xe1,0x4c,0x22,0xd1,0xf9,0x8c,0x40,0x76,0xf4,0xe,0x0,0x5,0xa3,0x90,0xe,0xa5]
flag='#'
for i in range(0,20):
flag+=chr(((enc[i]^((ord(flag[-1])^18)*3+2))-(ord(flag[-1])%7)) &0xff)
print(flag)