-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcfg_generator.py
167 lines (142 loc) · 7.66 KB
/
cfg_generator.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
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
from models.inner_instruction import *
from models.cfg import *
def generate_cfg_block(block, info_provider, class_name, method_name, recursive=False):
cfg_blocks = []
cfg_block = None
wait_for_follow = []
for i in range((len(block.instructions))):
instruction = block.instructions[i]
if cfg_block is None:
cfg_block = CFGBlock(hex(instruction.address))
if len(wait_for_follow) > 0:
for fol_block in wait_for_follow:
# print(fol_block.name, end=' ')
fol_block.goto_block(cfg_block.name)
# print('')
wait_for_follow = []
# 对于调用有 Block 的方法,现在还想不到好的解决办法
if instruction.goto_insns: # 如果有调用函数
basic_info, imp_name = instruction.goto_insns
if basic_info == '$Function': # function
if filter_oc_function(imp_name):
continue
if recursive and basic_info != class_name and imp_name != method_name: # 如果需要更进一步解析(防止递归)
recursive_function = info_provider(basic_info, imp_name)
if recursive_function is not None:
recursive_cfg = generate_cfg(recursive_function, info_provider, True)
# cfg_block.add_node(recursive_cfg)
cfg_block.goto_block(recursive_cfg.entry.name) # 该块进入调用的函数
cfg_blocks.append(cfg_block)
for rec_block in recursive_cfg.all_blocks: # 将深入的函数的块都加到当前 CFG 中
cfg_blocks.append(rec_block)
if rec_block.out:
rec_block.out = False # 对于当前函数来说,这个块不是出口块
wait_for_follow.append(rec_block)
cfg_block = None
# cfg_block.add_node(recursive_cfg)
# cfg_blocks.append(cfg_block)
continue
cfg_node = CFGNode(CFGNodeTypeFunction)
cfg_node.function_name = imp_name
if len(instruction.block_data) > 0:
# 生成 Block 的 CFG
for _, oc_block in instruction.block_data:
oc_block_imp = info_provider('$Block', oc_block)
if oc_block_imp is not None:
oc_block_cfg = generate_cfg(oc_block_imp, info_provider, True)
cfg_node.oc_blocks.append(oc_block_cfg)
else:
if recursive and basic_info != class_name and imp_name != method_name:
# print('find recursive method')
# print(basic_info, imp_name)
recursive_method = info_provider(basic_info, imp_name)
if recursive_method is not None:
# print('find it')
recursive_cfg = generate_cfg(recursive_method, info_provider, True)
cfg_block.goto_block(recursive_cfg.entry.name)
cfg_blocks.append(cfg_block)
for rec_block in recursive_cfg.all_blocks:
# print(rec_block.name, end=' ')
cfg_blocks.append(rec_block)
if rec_block.out:
rec_block.out = False
wait_for_follow.append(rec_block)
# print('')
cfg_block = None
continue
cfg_node = CFGNode(CFGNodeTypeMethod)
cfg_node.class_name = basic_info
cfg_node.method_name = imp_name
if len(instruction.block_data) > 0:
# 生成 Block 的 CFG
for _, oc_block in instruction.block_data:
oc_block_imp = info_provider('$Block', oc_block)
if oc_block_imp is not None:
oc_block_cfg = generate_cfg(oc_block_imp, info_provider, True)
cfg_node.oc_blocks.append(oc_block_cfg)
cfg_block.add_node(cfg_node)
if cfg_block is not None:
cfg_blocks.append(cfg_block)
return cfg_blocks
def generate_cfg(method, info_provider, recursive=False):
# print('Current generate CFG of method: %s in class: %s' % (method.method_name, method.class_name))
wait_blocks_queue = []
cfg_name = method.class_name + ': ' + method.method_name
cfg = CFG(cfg_name)
wait_blocks_queue.append(method.entry_block)
while len(wait_blocks_queue) > 0:
block = wait_blocks_queue[0]
wait_blocks_queue = wait_blocks_queue[1:]
cfg_blocks = generate_cfg_block(block, info_provider, method.class_name,
method.method_name, recursive)
if block.is_return:
cfg_blocks[-1].out = True
for cfg_block in cfg_blocks:
cfg.add_block(cfg_block)
if cfg.entry is None:
cfg.entry = cfg_blocks[0]
if not block.is_return: # 含有 ret 的基本块应该肯定不会有 followed 的块
if block.jump_to_block is not None and block.jump_to_block in method.all_blocks:
cfg_blocks[-1].goto_block(block.jump_to_block)
if (cfg.get_block(block.jump_to_block) is None and
method.all_blocks[block.jump_to_block] not in wait_blocks_queue):
wait_blocks_queue.append(method.all_blocks[block.jump_to_block])
if block.jump_condition and block.next_block is not None:
cfg_blocks[-1].goto_block(block.next_block)
if (cfg.get_block(block.next_block) is None and
method.all_blocks[block.next_block] not in wait_blocks_queue):
wait_blocks_queue.append(method.all_blocks[block.next_block])
return cfg
# for i in range(len(method.instructions)):
# instruction = method.instructions[i]
# if instruction.goto_insns:
# basic_info, imp_name = instruction.goto_insns
# if basic_info == '$Function': # function
# if filter_oc_function(imp_name):
# continue
# if recursive:
# recursive_function = info_provider(basic_info, imp_name)
# if recursive_function is not None:
# recursive_cfg = generate_cfg(recursive_function, info_provider, True)
# for recursive_cfg_node in recursive_cfg.nodes:
# cfg.add_node(recursive_cfg_node)
# continue
# cfg_node = CFGNode(CFGNodeTypeFunction)
# cfg_node.function_name = imp_name
# else: # method
# if recursive:
# recursive_method = info_provider(basic_info, imp_name)
# if recursive_method is not None:
# recursive_cfg = generate_cfg(recursive_method, info_provider, True)
# for recursive_cfg_node in recursive_cfg.nodes:
# cfg.add_node(recursive_cfg_node)
# continue
# cfg_node = CFGNode(CFGNodeTypeMethod)
# cfg_node.class_name = basic_info
# cfg_node.method_name = imp_name
# cfg.add_node(cfg_node)
# return cfg
def filter_oc_function(function):
if function.startswith('_objc_'):
return True
return False