题目地址:https://www.bugku.com/ctfexercise-competition-163.html
main函数打开发现是C++写的,充斥大量无用代码
于是转头执行,发现接收输入后回弹err...
搜索字符串发现有三处引用
分别是两个anti_debug和一个puts_wrong
anti_debug分别通过ptrace和getpid()的方法,不必多说,调试的时候直接绕过即可
puts_wrong则是在一个vtable中,很明显是一个类的成员函数
于是根据vt指针找到sub_5607AA5F4DD0
做了一些初始化以后、包括对input和data的赋值
调用了这个函数
- return (*((unsigned int (__fastcall **)(Class *))obj->this + 13))(obj) == 1;
复制代码 this+13即vt[12],点进去看一下即可发现是main_loop
循环处理code,显然是个VM
此处一共有2个类,根据代码逐步复原结构即可然后处理VM的各个handler - .data.rel.ro:00005607AA7F7A10 vt dq offset plus ; DATA XREF: Imp+16↑o
- .data.rel.ro:00005607AA7F7A18 dq offset sub
- .data.rel.ro:00005607AA7F7A20 dq offset cmp
- .data.rel.ro:00005607AA7F7A28 dq offset jmp_2
- .data.rel.ro:00005607AA7F7A30 dq offset mov
- .data.rel.ro:00005607AA7F7A38 dq offset save_ip
- .data.rel.ro:00005607AA7F7A40 dq offset load_ip
- .data.rel.ro:00005607AA7F7A48 dq offset load_short
- .data.rel.ro:00005607AA7F7A50 dq offset wrong
- .data.rel.ro:00005607AA7F7A58 dq offset load_input
- .data.rel.ro:00005607AA7F7A60 dq offset load_data
- .data.rel.ro:00005607AA7F7A68 dq offset xor
- .data.rel.ro:00005607AA7F7A70 dq offset get_final_flag
- .data.rel.ro:00005607AA7F7A78 dq offset main_loop
复制代码跑一下log可以发现是将输入和一个数异或后与另一个数比较的算法,dump出来发现不可见,于是回头调试发现在接受输入后的几行指令后的sub_5607AA5F4D50中对输入进行了一个前后字符异或的处理
我对模拟器进行了Patch功能-即输入不对时也会继续向后执行,和Dump功能的添加–计算并保存flag - code = [8, 0, 20, 8, 1, 0, 8, 2, 1, 8, 7, 9, 8, 8, 0, 8, 9, 0, 1, 9, 8, 1, 8, 2, 3, 7, 8, 516, 65532, 0, 5, 3, 9, 3, 1, 0, 260, 10, 0, 5, 4, 1, 1, 4, 3, 1, 4, 4, 10, 5, 1, 12, 5, 4, 11, 6, 1, 1, 1, 2, 3, 6, 5, 260, 65525, 0, 516, 1, 0, 255, 0, 0, 9, 0, 0, 255, 0, 0, 0, 0, ]
- # data = [46, 0, 38, 0, 45, 0, 41, 0, 77,0,103, 0, 5, 0, 68, 0, 26, 0, 14,0,127, 0, 127, 0, 125, 0, 101, 0, 119,0,36, 0, 26, 0, 93, 0, 51, 0, 81, 0]
- mem = [0 for i in range(50)]
- input = [0 for i in range(50)]
- dump = ""
- n = 0
- flag = 0
- while (n < 100):
- # patch check
- if (n == 21):
- flag = 1
- # print("Patched:%d"%flag)
- c = code[3 * n] & 0xff
- f = code[3 * n] >> 8
- h1 = code[3 * n + 1]
- h2 = code[3 * n + 2]
- if (f != 0 and f != flag):
- n += 1
- print("pass")
- continue
- if (False):
- pass
- elif (c == 1):
- mem[h1] += mem[h2]
- elif (c == 2):
- mem[h1] -= mem[h2]
- elif (c == 3):
- # dump flag
- if (n == 20):
- dump += chr(mem[4] ^ mem[6])
- print("cmp:%d-%d" % (mem[h1], mem[h2]), end='\t')
- if (mem[h1] != mem[h2]):
- flag = 2
- else:
- flag = 1
- print(flag)
- elif (c == 4):
- n += h1
- n &= 0xff
- print("jmp")
- elif (c == 5):
- mem[h1] = mem[h2]
- elif (c == 6):
- mem[h1] = n
- elif (c == 7):
- n = mem[h1]
- elif (c == 8):
- mem[h1] = h2
- elif (c == 9):
- print("failed")
- break
- elif (c == 10):
- print("Load input[%d] to %d" % (mem[h2], h1))
- mem[h1] = input[mem[h2]]
- elif (c == 11):
- mem[h1] = data[mem[h2] * 2]
- elif (c == 12):
- mem[h1] ^= mem[h2]
- elif (c == 255):
- pass
- else:
- print("Error:%d" % c)
- break
- print("[%d]: %d-%d-%d" % (n, c, h1, h2), end=' ')
- print(mem)
- n += 1
- print(dump)
- input = [(ord(i)) for i in dump]
- for i in range(4):
- for j in range(len(input) - 2, -1, -1):
- input[j + 1] ^= input[j]
- print(input)
- print("".join([chr(i) for i in input]))
复制代码最后flag flag{Y0u_ar3_S0co0L}
|