逆向攻防世界CTF系列11-maze

迷宫问题:迷宫问题 - CTF Wiki (ctf-wiki.org)

64位无壳

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
__int64 __fastcall main(__int64 a1, char **a2, char **a3){
const char *v3; // rsi
signed __int64 v4; // rbx
signed int v5; // eax
char v6; // bp
char v7; // al
const char *v8; // rdi
__int64 v10; // [rsp+0h] [rbp-28h]

v10 = 0LL;
puts("Input flag:");
scanf("%s", &s1, 0LL);
if (strlen(&s1) != 24 || (v3 = "nctf{", strncmp(&s1, "nctf{", 5uLL)) || *(&byte_6010BF + 24) != 125){
LABEL_22:
puts("Wrong flag!");
exit(-1);
}
v4 = 5LL;
if ( strlen(&s1) - 1 > 5 ) {
while ( 1 ){
v5 = *(&s1 + v4);
v6 = 0;
if ( v5 > 78 ){
v5 = (unsigned __int8)v5;
if ( (unsigned __int8)v5 == 79 ){
v7 = sub_400650((char *)&v10 + 4, v3);
goto LABEL_14;
}
if ( v5 == 111 ){
v7 = sub_400660((char *)&v10 + 4, v3);
goto LABEL_14;
}
}
else{
v5 = (unsigned __int8)v5;
if ( (unsigned __int8)v5 == 46 ){
v7 = sub_400670(&v10, v3);
goto LABEL_14;
}
if ( v5 == 48 ){
v7 = sub_400680(&v10, v3);
LABEL_14:
v6 = v7;
goto LABEL_15;
}
}
LABEL_15:
v3 = (const char *)HIDWORD(v10);
if ( !(unsigned __int8)sub_400690(asc_601060, HIDWORD(v10), (unsigned int)v10) )
goto LABEL_22;
if ( ++v4 >= strlen(&s1) - 1 )
{
if ( v6 )
break;
LABEL_20:
v8 = "Wrong flag!";
goto LABEL_21;
}
}
}
if ( asc_601060[8 * (signed int)v10 + SHIDWORD(v10)] != 35 )
goto LABEL_20;
v8 = "Congratulations!";
LABEL_21:
puts(v8);
return 0LL;
}
  • 开头必须是nctf{,总长24,第25位最后一位是不是”}” 125=’}’

image-20241015160229218

右键char,发现四个字符

这里(_DWORD *)是对v6进行强制类型转化,,然后在提领指针,WORD占2个字节,DWORD占4个字节。

shift+f12找到看看,发现

image-20241015160324553

image-20241015160344056

再看之前那张图,当为’O’时,点进函数看看,

image-20241015160448421

在16位的CPU中,一个字刚好为两个字节,而32位CPU中,一个字是四个字节。若以字为单位,向上还有双字(两个字),四字

解题1

好吧,上面分析的很乱,这里有个坑点就是,看了wp才发现,v10其实是两个变量,我一直做不出来的原因就是不太懂伪代码中的那四个函数,怎么得出的上下左右,明明都是v10,第二就是dword(v10)跟普通的int(v10)有什么区别,第三就是太相信伪代码了,反编译的结果也有可能具有误导性。

这里我ida版本是7.0,我切换8.3的伪代码如下:

image-20241015170215142

这里很清晰的有v9和v10之分

image-20241015170240167

image-20241015170248770

可以得知a3也就是v9是行,asc_601060是迷宫,v10是列,返回去

sub_400670:向上.

sub_400680:向下0

O:向左

o:向右

可以从上面得知一行是8个数据

image-20241015170541181

1
2
3
4
5
6
7
8
  ******
* * *
*** * **
** * **
* *# *
** *** *
** *
********

image-20241015170834250

到达#就通关了

根据前面我们可以得到flag:nctf{o0oo00O000oooo..OO}

解法2

有时我们一下子不能发现伪代码的坑点,因此我们要学会尝试分析汇编语言,这里提供第二种理解方式

即使只有一个变量v10我们仍能分析出,每行拥有8个数据

得到迷宫:

1
2
3
4
5
6
7
8
  ******
* * *
*** * **
** * **
* *# *
** *** *
** *
********

结果又发现了一个新知识,每次反编译的结果好像是不同的

image-20241015172029123

发现和之前的结果不同。

image-20241015172204676

HIWORD是High Word的缩写,作用是取得某个4字节变量(即32位的值)在内存中处于高位的两个字节,即一个word长的数据
LOWORD是Low Word的缩写,作用是取得某个4字节变量(即32位的值)在内存中处于低位的两个字节,即一个word长的数据

发现了HIWORD这个细节,是高字

image-20241015172301750

r14是sub_80和70

r15是sub_60和50

image-20241015172343599

r14是低位,与上对照,R14是行,80和70是行,0,.是操作行的

Oo是操作列的

可以得到结果flag