考点:

控制流平坦化

反编译main函数

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
int __cdecl main(int argc, const char **argv, const char **envp)
{
signed int v3; // eax
unsigned int v4; // ST38_4
__int64 v5; // ST30_8
signed int v7; // [rsp+2Ch] [rbp-54h]
char v8; // [rsp+40h] [rbp-40h]
int v9; // [rsp+78h] [rbp-8h]
int v10; // [rsp+7Ch] [rbp-4h]

v9 = 0;
printf("input your flag:", argv, envp);
gets(&v8); // 输入
v10 = general_inspection((int (*)[9])sudoku);
v7 = -1804515313;
while ( 1 )
{
while ( 1 )
{
while ( v7 == -2071121728 )
{
v4 = blank_num((int (*)[9])sudoku);
v5 = mem_alloc(v4);
trace(sudoku, v5, v4);
check((int (*)[9])sudoku);
check1(&v8); // 加密
check3(&v8); // 加密 调用了check2()
v9 = 0;
v7 = -303742386;
}
if ( v7 != -1804515313 )
break;
v3 = -2071121728;
if ( v10 )
v3 = 664169471;
v7 = v3;
}
if ( v7 == -303742386 )
break;
if ( v7 == 664169471 )
{
printf("error");
check((int (*)[9])sudoku);
v9 = 0;
v7 = -303742386;
}
}
return v9;
}

python代码还原逻辑:

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
def check2():
v16 = []
for i in range(len(flag)):
v16.append(flag[v15] -48 )
#这个位置其实是数字得char和int转化
for i in range(9):
for j in range(9):
if dog3[9 * i + j] == 0:
dog3[9 *i + i] = v16[v13]
v13 += 1
#这里形成一个数独游戏得填入
for i in range(9):
for j in range(9):
if dog3[9 * i + j] != sudoku[9 * i + j]:
# 关键比较
print("!!!")

def check1():
v12 = len(flag)>>1
for i in range(len(flag)>>1):
(flag[i],flag[v12+1]) = (flag[v12+1],flag[i])
#前后两部分互换
for i in range(0,len(flag),2):
(flag[i],flag[i+1]) = (flag[i+1],flag[i])
#两位之间互换
for i in range(len(flag)):
flag[i] = ((flag[i]&0xf3)|(~flag[i]&0xc)) - 20

# 转自 https://blog.csdn.net/wlz_lc_4/article/details/103466957

解题的关键就是找到原来的数独,和填好的数独,提取填好的数字,然后做check1中的逆向操作就可以得到flag

最终是比较dog3和sudoku里的值,dog3是已知部分填充部分,sudoku需要动态调试得知填入的值

1
2
3
4
5
6
7
8
9
10
11
12
.data:0000000000604300                 public D0g3
.data:0000000000604300 ; _DWORD D0g3[81]
.data:0000000000604300 D0g3 dd 1, 0, 5, 3, 2, 7, 2 dup(0), 2 dup(8), 0, 9, 0, 5, 2 dup(0)
.data:0000000000604300 ; DATA XREF: check2(char *)+462↑o
.data:0000000000604300 ; check2(char *):loc_402F53↑o ...
.data:0000000000604300 dd 2, 2 dup(0), 7, 2 dup(0), 1, 0, 5, 0, 3, 4, 9, 0, 1
.data:0000000000604300 dd 2 dup(0), 3, 3 dup(0), 1, 2 dup(0), 7, 0, 9, 0, 6, 7
.data:0000000000604300 dd 0, 3, 2, 9, 0, 4, 8, 2 dup(0), 6, 0, 5, 4, 0, 8, 0
.data:0000000000604300 dd 9, 2 dup(0), 4, 2 dup(0), 1, 0, 3, 2 dup(0), 2, 1, 0
.data:0000000000604300 dd 3, 0, 7, 0, 4
.data:0000000000604300 _data ends
.data:0000000000604300

逆向脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
sudoku = [1, 4, 5, 3, 2, 7, 6, 9, 8, 8, 3, 9, 6, 5, 4, 1, 2, 7, 6, 7, 2, 8, 1, 9, 5, 4, 3, 4, 9, 6, 1, 8, 5, 3, 7, 2, 2, 1, 8, 4, 7, 3, 9, 5, 6, 7, 5, 3, 2, 9, 6, 4, 8, 1, 3, 6, 7, 5, 4, 2, 8, 1, 9, 9, 8, 4, 7, 6, 1, 2, 3, 5, 5, 2, 1, 9, 3, 8, 7, 6, 4]
dog3 = [1, 0, 5, 3, 2, 7, 0, 0, 8, 8, 0, 9, 0, 5, 0, 0, 2, 0, 0, 7, 0, 0, 1, 0, 5, 0, 3, 4, 9, 0, 1, 0, 0, 3, 0, 0, 0, 1, 0, 0, 7, 0, 9, 0, 6, 7, 0, 3, 2, 9, 0, 4, 8, 0, 0, 6, 0, 5, 4, 0, 8, 0, 9, 0, 0, 4, 0, 0, 1, 0, 3, 0, 0, 2, 1, 0, 3, 0, 7, 0, 4]
flag = []
for i in range(81):
if sudoku[i] != dog3[i]:
tmp = ord(str(sudoku[i])) + 20
flag.append( tmp&0xf3 | ~tmp&0xc )
print(flag)
for i in range(0,40,2):
(flag[i], flag[i+1]) = (flag[i+1], flag[i]) #两位操作
for i in range(20):
(flag[i],flag[i+20]) = (flag[i+20], flag[i])
for i in range(40):
print(chr(flag[i]),end='')

# 转自 https://www.cnblogs.com/jentleTao/p/12666415.html

flag{KDEEIFGKIJ@AFGEJAEF@FDKADFGIJFA@FDE@JG@J}