-
Notifications
You must be signed in to change notification settings - Fork 6
/
Copy pathop_helpers.py
125 lines (95 loc) · 4.59 KB
/
op_helpers.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
from .op_detective import get_last_bb_instr
from collections import namedtuple
from binaryninja import *
OpaquePredicateInfo = namedtuple('OpaquePredicateInfo', 'if_addr bb_edge rules')
def patch_op(patches, total_conds, bv):
"""
Provide another layer of filter for deciding whether the basic block really
contains OP or not
Args:
bv (BinaryView): top-level binary view handler. Lots of
interesting methods can be accessed.
patches: identify_authentic_op function's 'total_patch_locations'.
List of OpaquePredicateInfo, or basic blocks that contains OP
total_conds: find_op function's 'total_conds_seen'. Numbers of
conditional statements seen in binary
Returns: None. Output to log
"""
for patch in patches:
# final filter: check if OP basic block still at beginning of a basic block
# if not, it is not the original OP
if not patch.bb_edge.target.function.get_basic_block_at \
(patch.bb_edge.target.start):
continue
if patch.bb_edge.target.function.get_basic_block_at \
(patch.bb_edge.target.start).start != patch.bb_edge.target.start:
continue
#log_debug('[authentic op]: 0x{0:02X}'.format(patch.bb_edge.target.start))
log_info('0x{0:02X}:{1}'.format(patch.bb_edge.target.start, list(set(patch.rules))))
#log_info('@total_conds:'+str(total_conds))
def identify_authentic_op(total_patch_locations, total_conds, metadata, bv, patch=True):
"""
Future Work.
Args:
bv (BinaryView): top-level binary view handler. Lots of
interesting methods can be accessed.
total_patch_locations: find_op function's 'cur_pass_patch_locations'.
List of OpaquePredicateInfo, or basic blocks that contains OP
total_conds: find_op function's 'total_conds_seen'. Numbers of conditional statements
seen in binary
metadata: an AnalysisMetadata namedtuple object
patch: whether to physically patch (i.e. update CFG to remove OP). Currently unused
Returns:
None.
"""
patch_op(total_patch_locations, total_conds, bv)
def find_op(bv, analyses=list(), metadata=None, status=None):
"""Analysis main().
Retrieve each basic block from binary and pass each to respective basic
block analysis: `bb_analysis`, `bb_mlil_analysis`, and `bb_llil_analysis`.
Args:
bv (BinaryView): top-level binary view handler. Lots of
interesting methods can be accessed.
status (FindOpaqueInBackground): plugin main.
Returns:
None: each analysis will log their respective findings.
"""
cur_pass_patch_locations = list()
seen_bbs = set()
total_conds_seen = 0
for func in bv.functions:
for bb in func.basic_blocks:
# bb does not end with JCC, so ignore
if len(bb.outgoing_edges) != 2:
continue
# evaluate both branches
# (does not differentiate between True/False branch)
# but for our purpose, we don't need to
if bb in seen_bbs:
continue
total_conds_seen += 1
for branch in bb.outgoing_edges:
# bb has multiple incoming edges, so ignore
if len(branch.target.incoming_edges) != 1:
continue
# ignore authentic bb
if branch.target.start in metadata.good_bbs:
continue
# core analysis
alerted_rules_in_bb = list() # reset to empty
last_instr_addr = get_last_bb_instr(bb) # if_addr
for analysis in analyses:
analysis_result = analysis(bv, branch.target,
branch.target.start, metadata)
if analysis_result:
# add list of rules alerted in current basic block
alerted_rules_in_bb.extend(analysis_result)
if alerted_rules_in_bb: # list not empty there are alerted
# rules in current basic block
# format: (OP addr, binja branch object, rule list)
cur_pass_patch_locations.append(
OpaquePredicateInfo(last_instr_addr, branch,
alerted_rules_in_bb)
)
seen_bbs.add(bb)
return (cur_pass_patch_locations, total_conds_seen)