-
Notifications
You must be signed in to change notification settings - Fork 8
/
Copy pathdeflat.py
149 lines (138 loc) · 6.29 KB
/
deflat.py
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
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
from barf.barf import BARF
import angr
import simuvex
import pyvex
import claripy
import struct
def get_retn_predispatcher(cfg):
global main_dispatcher
for block in cfg.basic_blocks:
if len(block.branches) == 0 and block.direct_branch == None:
retn = block.start_address
elif block.direct_branch == main_dispatcher:
pre_dispatcher = block.start_address
return retn, pre_dispatcher
def get_relevant_nop_blocks(cfg):
global pre_dispatcher, prologue, retn
relevant_blocks = []
nop_blocks = []
for block in cfg.basic_blocks:
if block.direct_branch == pre_dispatcher and len(block.instrs) != 1:
relevant_blocks.append(block.start_address)
elif block.start_address != prologue and block.start_address != retn:
nop_blocks.append(block)
return relevant_blocks, nop_blocks
def statement_inspect(state):
global modify_value
expressions = state.scratch.irsb.statements[state.inspect.statement].expressions
if len(expressions) != 0 and isinstance(expressions[0], pyvex.expr.ITE):
state.scratch.temps[expressions[0].cond.tmp] = modify_value
state.inspect._breakpoints['statement'] = []
def symbolic_execution(start_addr, hook_addr=None, modify=None, inspect=False):
global b, relevants, modify_value
if hook_addr != None:
b.hook(hook_addr, retn_procedure, length=5)
if modify != None:
modify_value = modify
state = b.factory.blank_state(addr=start_addr, remove_options={simuvex.o.LAZY_SOLVES})
if inspect:
state.inspect.b('statement', when=simuvex.BP_BEFORE, action=statement_inspect)
p = b.factory.path(state)
succ=p.step()
while succ.successors[0].addr not in relevants:
succ=succ.successors[0].step()
return succ.successors[0].addr
def retn_procedure(state):
global b
ip = state.se.eval(state.regs.ip)
b.unhook(ip)
return
def fill_nop(data, start, end):
global opcode
for i in range(start, end):
data[i] = opcode['nop']
def fill_jmp_offset(data, start, offset):
jmp_offset = struct.pack('<i', offset)
for i in range(4):
data[start + i] = jmp_offset[i]
if __name__ == '__main__':
opcode = {'a':'\x87', 'ae': '\x83', 'b':'\x82', 'be':'\x86', 'c':'\x82', 'e':'\x84', 'z':'\x84', 'g':'\x8F',
'ge':'\x8D', 'l':'\x8C', 'le':'\x8E', 'na':'\x86', 'nae':'\x82', 'nb':'\x83', 'nbe':'\x87', 'nc':'\x83',
'ne':'\x85', 'ng':'\x8E', 'nge':'\x8C', 'nl':'\x8D', 'nle':'\x8F', 'no':'\x81', 'np':'\x8B', 'ns':'\x89',
'nz':'\x85', 'o':'\x80', 'p':'\x8A', 'pe':'\x8A', 'po':'\x8B', 's':'\x88', 'nop':'\x90', 'jmp':'\xE9', 'j':'\x0F'}
filename = '/Users/liumeng/check_passwd_flat'
start = 0x400530
barf = BARF(filename)
base_addr = barf.binary.entry_point >> 12 << 12
b = angr.Project(filename, load_options={'auto_load_libs': False, 'main_opts':{'custom_base_addr': 0}})
cfg = barf.recover_cfg(start)
blocks = cfg.basic_blocks
prologue = start
main_dispatcher = cfg.find_basic_block(prologue).direct_branch
retn, pre_dispatcher = get_retn_predispatcher(cfg)
relevant_blocks, nop_blocks = get_relevant_nop_blocks(cfg)
print '*******************relevant blocks************************'
print 'prologue:%#x' % start
print 'main_dispatcher:%#x' % main_dispatcher
print 'pre_dispatcher:%#x' % pre_dispatcher
print 'retn:%#x' % retn
print 'relevant_blocks:', [hex(addr) for addr in relevant_blocks]
print '*******************symbolic execution*********************'
relevants = relevant_blocks
relevants.append(prologue)
# relevants.append(0x40099b)
relevants_without_retn = list(relevants)
relevants.append(retn)
flow = {}
for parent in relevants:
flow[parent] = []
modify_value = None
patch_instrs = {}
for relevant in relevants_without_retn:
print '-------------------dse %#x---------------------' % relevant
block = cfg.find_basic_block(relevant)
has_branches = False
hook_addr = None
for ins in block.instrs:
if ins.asm_instr.mnemonic.startswith('cmov'):
patch_instrs[relevant] = ins.asm_instr
has_branches = True
elif ins.asm_instr.mnemonic.startswith('call'):
hook_addr = ins.address
if has_branches:
flow[relevant].append(symbolic_execution(relevant, hook_addr, claripy.BVV(1, 1), True))
flow[relevant].append(symbolic_execution(relevant, hook_addr, claripy.BVV(0, 1), True))
else:
flow[relevant].append(symbolic_execution(relevant, hook_addr))
print '************************flow******************************'
# for (k, v) in flow.items():
# print '%#x:' % k, [hex(child) for child in v]
print '************************patch*****************************'
flow.pop(retn)
origin = open(filename, 'rb')
origin_data = list(origin.read())
origin.close()
recovery = open(filename + '.recovered', 'wb')
for nop_block in nop_blocks:
fill_nop(origin_data, nop_block.start_address - base_addr, nop_block.end_address - base_addr + 1)
for (parent, childs) in flow.items():
if len(childs) == 1:
last_instr = cfg.find_basic_block(parent).instrs[-1].asm_instr
file_offset = last_instr.address - base_addr
origin_data[file_offset] = opcode['jmp']
file_offset += 1
fill_nop(origin_data, file_offset, file_offset + last_instr.size - 1)
fill_jmp_offset(origin_data, file_offset, childs[0] - last_instr.address - 5)
else:
instr = patch_instrs[parent]
file_offset = instr.address - base_addr
fill_nop(origin_data, file_offset, cfg.find_basic_block(parent).end_address - base_addr + 1)
origin_data[file_offset] = opcode['j']
origin_data[file_offset + 1] = opcode[instr.mnemonic[4:]]
fill_jmp_offset(origin_data, file_offset + 2, childs[0] - instr.address - 6)
file_offset += 6
origin_data[file_offset] = opcode['jmp']
fill_jmp_offset(origin_data, file_offset + 1, childs[1] - (instr.address + 6) - 5)
recovery.write(''.join(origin_data))
recovery.close()
print 'Successful! The recovered file: %s' % (filename + '.recovered')