XMAN2018排位赛_Dragon_Quest

[XMAN2018排位赛]Dragon Quest

64位ida打开

image-20230426222920909

当函数start_quest返回值为0x1337时输出flag

塞了不少混淆

image-20230426223036156

可以看出表达式恒为0,存在大量不透明谓词

idapython

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
from ida_bytes import get_bytes, patch_bytes


def compare1(buff, addr):
enc = [0x8B, 0x04, 0x25, 0xE0, 0x03, 0x61, 0x00, 0x8B] # mov eax, x25
eax = [0xB8, 0x00]
for i in range(8):
if buff[i] != enc[i]:
return 0
tmp = addr + 25
patch_bytes(tmp, bytes(eax))


def compare2(buff, addr):
enc = [0x8B, 0x0C, 0x25, 0xE0, 0x03, 0x61, 0x00, 0x8B] # mov ecx, x25
ecx = [0xB9, 0x00, 0x00, 0x00, 0x00, 0x90]
for i in range(8):
if buff[i] != enc[i]:
return 0
tmp = addr + 25
patch_bytes(tmp, bytes(ecx))


def compare3(buff, addr):
enc = [0x44, 0x8B, 0x0C, 0x25, 0xE0, 0x03, 0x61, 0x00, 0x44] # mov r9d, x25
r9d = [0x41, 0xB9, 0x00, 0x00, 0x00, 0x00, 0x90]
for i in range(len(enc)):
if buff[i] != enc[i]:
return 0
tmp = addr + 29
patch_bytes(tmp, bytes(r9d))


if __name__ == '__main__':
start_addr = 0x00404350
end_addr = 0x00404AD5

for i in range(start_addr, end_addr, 1):
buf = get_bytes(i, 9)
compare1(buf, i)
compare2(buf, i)
compare3(buf, i)

更好的版本 (pizza yyds)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import ida_xref
import ida_idaapi
from ida_bytes import get_bytes, patch_bytes

def do_patch(ea):
if(get_bytes(ea, 1) == b"\x8B"): # mov eax-edi, dword
reg = (ord(get_bytes(ea + 1, 1)) & 0b00111000) >> 3
patch_bytes(ea, (0xB8 + reg).to_bytes(1,'little') + b'\x00\x00\x00\x00\x90\x90')
elif(get_bytes(ea, 2) == b"\x44\x8B"): # mov r8d-r15d, dword
reg = (ord(get_bytes(ea + 2, 1)) & 0b00111000) >> 3
patch_bytes(ea + 1, (0xB8 + reg).to_bytes(1,'little') + b'\x00\x00\x00\x00\x90\x90')
else:
print('error')

for addr in range(0x0000000000610318, 0x00000000006105AC, 4):
ref = ida_xref.get_first_dref_to(addr)
print(hex(addr).center(20,'-'))
while(ref != ida_idaapi.BADADDR):
do_patch(ref)
print('patch at ' + hex(ref))
ref = ida_xref.get_next_dref_to(addr, ref)
print('-' * 20)

去除混淆后,返回值由函数sanitize_input生成,该函数同样是加了不透明谓词

image-20230427002501982

去除后进行分析

image-20230427002713826

即v11等于0

image-20230427002839812

求和的值要求与之前压入hero数组的值相同

写脚本

1
2
3
4
5
6
7
8
# 补全初始状态为0
vec = [0, 0x0064, 0x00D6, 0x010A, 0x0171, 0x01A1, 0x020F, 0x026E, 0x02DD, 0x034F,
0x03AE, 0x041E, 0x0452, 0x04C6, 0x0538, 0x05A1, 0x0604, 0x0635, 0x0696,
0x0704, 0x0763, 0x07CC, 0x0840, 0x0875, 0x08D4, 0x0920, 0x096C, 0x09C2,
0x0A0F]

for i in range(1, len(vec)):
print(chr(vec[i] - vec[i-1]), end="")

flag{dr4g0n_or_p4tric1an_it5_LLVM}