2018护网杯线上 APM233

Author Avatar
kabeor 7月 31, 2019

2018护网杯线上 APM233

MFC42的逆向

一共四层验证,IDA打开后基本全红,直接按P创建函数
花指令格式为jz address+1; jnz address+1;,因此显示出address处的opcode,按D设为数据,address+1处创建函数,平衡栈帧即可

主流程

Check1

第一层与字符串1d2e3c4a比较

Check2

z3直接计算

from z3 import *
from pwn import *

Dr0 = BitVec('Dr0',32)
Dr1 = BitVec('Dr1',32)
Dr2 = BitVec('Dr2',32)
Dr3 = BitVec('Dr3',32)
s = Solver()

s.add(Dr0 <= 0x7FFFFFFF)
s.add(Dr1 <= 0x7FFFFFFF)
s.add(Dr2 <= 0x7FFFFFFF)
s.add(Dr3 <= 0x7FFFFFFF)
s.add(Dr1+Dr0 == 0x899a9d9c)
s.add(Dr2+Dr1 == 0x384989ED)
s.add(Dr3+Dr2 == 0x2B2C85BC)
s.add(Dr0-Dr3 == 0xAFAFDC11)

s.check()

m = s.model()

Dr0 = int('%s'%m[Dr0])
Dr1 = int('%s'%m[Dr1])
Dr2 = int('%s'%m[Dr2])
Dr3 = int('%s'%m[Dr3])

ans = '%s%s%s%s'%(p32(Dr0).encode('hex'),p32(Dr1).encode('hex'),p32(Dr2).encode('hex'),p32(Dr3).encode('hex'))

print(ans)

不知道为什么我这里的数值和别人的不一样,算出来的也不一样。。。正确结果应该是efbe3323adde6666feca1313beba1414

Check3

各种反调试虚拟机检测,未检测到的返回值就是key: 0acb7935481efc12

Check4

要求玩家的位置不能与三个AI重合,玩家每次的可走的步数为1-4,AI的行动路线如下所示
a1 = [4, -1, 6, -1, 3, 2, 4, 1, 3, -1, 5, 1, 2, -1, 5, 1, 3, -2, 7, 0, 2, 3, 5, 0, 5, 0, 5, 2, 1, -2, 6, -1, 3, 3, 4, 0, 5, -1, 6, 0, 4, 0, 7, 0, 5, -2, 7, 2, 2, -1, 6, 2, 2, 1, 5, 0, 2, 0, 3, 0, 4, 0, 6, -1, 5, 0, 5, 3, 0, 5, 3, 2]
a2 = [2, 2, 3, 3, 3, -2, 7, 1, 1, 1, 5, 1, 0, 2, 5, 1, 0, 0, 4, 0, 7, 2, 2, 0, 4, 1, 3, 4, 0, 1, 6, -1, 5, -1, 3, 5, 1, 2, 5, 0, 5, 0, 2, 5, 1, 1, 5, 2, 2, 1, 2, 3, 5, -1, 4, 1, 2, -1, 7, 1, 2, 2, 1, 2, 5, 0, 5, 0, 5, -1, 3, 2]
a3 = [3, -1, 6, -1, 5, 0, 4, 0, 2, 5, 0, 5, 1, -1, 5, 1, 0, 2, 4, 0, 5, 0, 4, 0, 6, -1, 6, 1, 2, 1, 3, 3, 2, 3, 3, 0, 5, -1, 4, 0, 6, 0, 5, 0, 5, 1, 2, 2, 3, 0, 5, 5, 0, 0, 6, 2, -1, 1, 5, 1, 0, 3, 4, -1, 4, 5, 0, 2, 5, 1, 4, 1]
通过上述规则,可以得到玩家的路线为
[1, 4, 1, 3, 1, 4, 1, 2, 2, 3, 2, 1, 1, 4, 1, 1, 1, 4, 1, 4, 2, 3, 1, 4, 1, 4, 2, 1, 1, 4, 1, 3, 2, 3, 2, 3, 1, 4, 1, 4, 1, 4, 2, 3, 1, 4, 2, 2, 1, 4, 3, 2, 1, 4, 1, 1, 1, 4, 1, 2, 2, 3, 1, 4, 2, 3, 2, 3, 2, 3, 2, 3]
玩家的行动由输入b64encode后再将编码后的结果拆为两两一组

脚本

from base64 import b64decode,b64encode

def level4():
a1 = [4, -1, 6, -1, 3, 2, 4, 1, 3, -1, 5, 1, 2, -1, 5, 1, 3, -2, 7, 0, 2, 3, 5, 0, 5, 0, 5, 2, 1, -2, 6, -1, 3, 3, 4, 0, 5, -1, 6, 0, 4, 0, 7, 0, 5, -2, 7, 2, 2, -1, 6, 2, 2, 1, 5, 0, 2, 0, 3, 0, 4, 0, 6, -1, 5, 0, 5, 3, 0, 5, 3, 2]
a2 = [2, 2, 3, 3, 3, -2, 7, 1, 1, 1, 5, 1, 0, 2, 5, 1, 0, 0, 4, 0, 7, 2, 2, 0, 4, 1, 3, 4, 0, 1, 6, -1, 5, -1, 3, 5, 1, 2, 5, 0, 5, 0, 2, 5, 1, 1, 5, 2, 2, 1, 2, 3, 5, -1, 4, 1, 2, -1, 7, 1, 2, 2, 1, 2, 5, 0, 5, 0, 5, -1, 3, 2]
a3 = [3, -1, 6, -1, 5, 0, 4, 0, 2, 5, 0, 5, 1, -1, 5, 1, 0, 2, 4, 0, 5, 0, 4, 0, 6, -1, 6, 1, 2, 1, 3, 3, 2, 3, 3, 0, 5, -1, 4, 0, 6, 0, 5, 0, 5, 1, 2, 2, 3, 0, 5, 5, 0, 0, 6, 2, -1, 1, 5, 1, 0, 3, 4, -1, 4, 5, 0, 2, 5, 1, 4, 1]

pos1 = 0
pos2 = 0
pos3 = 0
pos4 = 0
choice = []
for i in range(len(a1)):
pos1 += a1[i]
pos2 += a2[i]
pos3 += a3[i]
if (pos4 + 4 != pos1) and (pos4 + 4 != pos2) and (pos4 + 4 != pos3):
t = 4
elif (pos4 + 3 != pos1) and (pos4 + 3 != pos2) and (pos4 + 3 != pos3):
t = 3
elif (pos4 + 2 != pos1) and (pos4 + 2 != pos2) and (pos4 + 2 != pos3):
t = 2
else:
t = 1
pos4 += t
choice.append(t-1)

print choice

b64 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'

print choice
ans = ''
for i in xrange(0,len(choice),3):
t = (choice[i]<<4) + (choice[i+1]<<2) + choice[i+2]
print t,
ans+=b64[t]

print

print ans
print b64decode(ans)

# level1 1d2e3c4a
level2() # efbe3323adde6666feca1313beba1414
# level3 0acb7935481efc12
level4() # 21d03c42f365901cff

程序输入有时间限制,可以找到时间call直接jmp,也可以鼠标模拟

鼠标点击模拟脚本

from pymouse import *
import time
m = PyMouse()

k1 = "1d2e3c4a"
key1 = list(k1)
k2 = "efbe3323adde6666feca1313beba1414"
key2 = list(k2)
k3 = "0acb7935481efc12"
key3 = list(k3)
k4 = "21d03c42f365901cff"
key4 = list(k4)

def mnclick(x, y):
for i in range(y):
if(x[i] == '0'): m.click(1075, 418)
elif(x[i] == '1'): m.click(1118, 418)
elif(x[i] == '2'): m.click(1162, 418)
elif(x[i] == '3'): m.click(1205, 418)
elif(x[i] == '4'): m.click(1075, 465)
elif(x[i] == '5'): m.click(1118, 465)
elif(x[i] == '6'): m.click(1162, 465)
elif(x[i] == '7'): m.click(1205, 465)
elif(x[i] == '8'): m.click(1075, 511)
elif(x[i] == '9'): m.click(1118, 511)
elif(x[i] == 'a'): m.click(1162, 511)
elif(x[i] == 'b'): m.click(1205, 511)
elif(x[i] == 'c'): m.click(1075, 558)
elif(x[i] == 'd'): m.click(1118, 558)
elif(x[i] == 'e'): m.click(1162, 558)
elif(x[i] == 'f'): m.click(1205, 558)
time.sleep(1)
m.click(670, 624)

mnclick(key1, 8)
mnclick(key2, 32)
mnclick(key3, 16)
mnclick(key4, 18)

按钮位置是用spy++查看窗口属性看到的

最后 flag{N0t_d1ff1cul7_r1ght?_3d34e}

From https://kabeor.github.io/2018护网杯线上 APM233/ bye

This blog is under a CC BY-NC-SA 4.0 Unported License
本文链接:https://kabeor.github.io/2018护网杯线上 APM233/