HNCTF 2022 WEEK3mazes

runwu2204 Lv6

脚本参考美团CTF: 100mazes - Pandaos’s blog (panda0s.top)

主要函数

image-20230718102654109

此处的地址offset是物理地址,也就是文件内数据的地址,不是ida反编译中的地址

用010editor查看其物理地址为0x810

image-20230718103649242

通过第一个迷宫函数sub_140001460的地址(0x140001460)与入口点的虚拟地址(0x140001410)相减获取与0x810的相对地址

再将相对地址与实际的入口地址相加获取第一个迷宫函数物理地址

1
2
In [2]: hex(0x140001460-0x140001410+0x810)
Out[2]: '0x860'#物理地址

可以通过capstone反汇编器读取文件进行依次读取迷宫map1,读取的反汇编代码是带制表符\t的所以也需要带上

通过调试发现:

\tmov\tdword ptr [rsp 是对map1,和起点的值进行赋值,每次读取rsp后面的值即可

\tmov\teax, dword ptr [rip 是对方向(wdsa对应的方向字母如第一个函数中是3tkA)进行赋值

\tlea\trcx, [rip 是对map2进行赋值,直接读取后面跟的地址中625个字符即可

此处相对地址有点难以换算,我直接用的是他们之间的地址规律

每个迷宫函数相差

image-20230718105137152

1
2
In [3]: 0x140003F20-0x140001460
Out[3]: 10944

每个map2相差

image-20230718105224111image-20230718105231120

1
2
In [4]: 0x140A859E0-0x140A85010
Out[4]: 2512

搜索第一个迷宫函数中map2的物理地址,之后再每个函数+2512即可

image-20230718105402620

exp:

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
from capstone import Cs
from capstone import *
import struct

def decode(offset,tmp):
data_bin = open(r'E:\QQsavefile\MobileFile\mazes.exe', 'rb').read()#exe路径
data = data_bin[offset: offset+10921]#每个函数长度为10921
md = Cs(CS_ARCH_X86, CS_MODE_64)
inscnt = 0
inscnt2 = 0
map1 = []
map2 = []
map3 = []
for i in md.disasm(data, offset):
ins = "0x%x:\t%s\t%s" % (i.address, i.mnemonic, i.op_str)
if '\tmov\tdword ptr [rsp' in ins or '\tmov\teax, dword ptr [rip' in ins:
if inscnt < 625:#先读625个迷宫字符,作为map1
map1.append(int(i.op_str.split(', ')[1], 16))
inscnt += 1
elif inscnt2 < 2:#625个字符读满后再遇到'\tmov\tdword ptr [rsp'就是赋值迷宫起始点的地址
map3.append(int(i.op_str.split(', ')[1], 16))
inscnt2 += 1
elif inscnt<629:#最后遇到'\tmov\teax, dword ptr [rip',就对方向赋值
off1 =i.address+int(i.op_str.split(', ')[1].split('+')[1].replace(']',''),16)
map1_data = data_bin[0xa76098+tmp*5: 0xa76098+4+tmp*5 ] #方向数组存在规律,每个值相差5
map1=map1+(list(map1_data))
inscnt+=4
if '\tlea\trcx, [rip' in ins:#遇到这个字符串对map2进行赋值
map2_data = data_bin[tmp*2512+0xa82610: tmp*2512+0xa82610+ 4 * 625]#map2存在规律每个相差2512
for i in range(625):
map2.append(struct.unpack("I", map2_data[i * 4: i * 4 + 4])[0])#将4字节解包为unsigned int型

data = []
for i in range(625):
data.append(map1[i] ^ map2[i])#dword_140A85010[25 * v629 + *(_DWORD *)&v628[5]] ^ v630[25 * v629 + *(_DWORD *)&v628[5]]) != 214原函数的map是经过异或加密的,异或回去获取原始的地图
return data, bytearray(map1[-4:]), map3#返回原始地图,方向数组,起点


def checkValid(map, x, y):
if x < 0 or y < 0 or x > 24 or y > 24:
return False
return map[y * 25 + x] == 0xd6


def solve(map, startX, startY, direct, path):#此处不用dfs搜索,因为路径都是单一的每次只要找到了下一次的路径就往路径列表内增加对应的值
map[startY * 25 + startX] = ord('*')
if len(path) == 15:
return True, path

all_dir = []
if checkValid(map, startX - 1, startY):
all_dir.append((startX-1, startY, direct[0]))
if checkValid(map, startX+ 1, startY ):
all_dir.append((startX+ 1, startY , direct[1]))
if checkValid(map, startX , startY- 1):
all_dir.append((startX , startY- 1, direct[2]))
if checkValid(map, startX, startY + 1):
all_dir.append((startX, startY+1, direct[3]))

for dir in all_dir:
result = solve(map, dir[0], dir[1], direct, path + dir[2])
if result[0] == True:
return result
return False, ''

def printMap(map1):
for i in range(25):
line = ''
for j in range(25):
line += chr(map1[i * 25 + j])
print(line)

total = ''
tmp=0
for i in range(0,10933056+10944,10944):#每个迷宫函数的地址进行遍历
map1, dirs, target = decode(i+0x860,tmp)
tmp+=1
total +=solve(map1, target[1], target[0], dirs.decode('utf-8'), '')[1]


import hashlib
mm = hashlib.md5(total.encode('utf-8')).hexdigest()
print(len(total))
print('nssctf{%s}' %mm)

  • 标题: HNCTF 2022 WEEK3mazes
  • 作者: runwu2204
  • 创建于 : 2023-07-18 10:10:12
  • 更新于 : 2023-07-18 11:16:25
  • 链接: https://runwu2204.github.io/2023/07/18/CTF WP/Re/HNCTF 2022 WEEK3mazes/
  • 版权声明: 本文章采用 CC BY-NC-SA 4.0 进行许可。
评论
目录
HNCTF 2022 WEEK3mazes