angr 9.2.84__py3-none-win_amd64.whl → 9.2.85__py3-none-win_amd64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of angr might be problematic. Click here for more details.
- angr/__init__.py +1 -1
- angr/analyses/cfg/cfg_base.py +6 -1
- angr/analyses/cfg/cfg_fast.py +32 -10
- angr/analyses/decompiler/clinic.py +204 -4
- angr/analyses/decompiler/condition_processor.py +8 -2
- angr/analyses/decompiler/decompiler.py +19 -17
- angr/analyses/decompiler/goto_manager.py +34 -51
- angr/analyses/decompiler/optimization_passes/__init__.py +5 -5
- angr/analyses/decompiler/optimization_passes/div_simplifier.py +2 -0
- angr/analyses/decompiler/optimization_passes/lowered_switch_simplifier.py +1 -1
- angr/analyses/decompiler/optimization_passes/mod_simplifier.py +2 -0
- angr/analyses/decompiler/optimization_passes/multi_simplifier.py +2 -0
- angr/analyses/decompiler/optimization_passes/optimization_pass.py +131 -3
- angr/analyses/decompiler/optimization_passes/ret_deduplicator.py +3 -3
- angr/analyses/decompiler/optimization_passes/return_duplicator.py +519 -0
- angr/analyses/decompiler/peephole_optimizations/constant_derefs.py +14 -2
- angr/analyses/decompiler/region_identifier.py +8 -2
- angr/analyses/decompiler/region_simplifiers/goto.py +5 -4
- angr/analyses/decompiler/structured_codegen/c.py +33 -1
- angr/analyses/decompiler/structuring/phoenix.py +3 -1
- angr/analyses/decompiler/structuring/structurer_nodes.py +11 -5
- angr/analyses/decompiler/utils.py +50 -0
- angr/analyses/disassembly.py +10 -3
- angr/analyses/propagator/engine_ail.py +125 -0
- angr/analyses/reaching_definitions/engine_ail.py +36 -2
- angr/analyses/reaching_definitions/rd_initializer.py +15 -1
- angr/analyses/reaching_definitions/rd_state.py +9 -4
- angr/analyses/stack_pointer_tracker.py +10 -17
- angr/analyses/variable_recovery/engine_ail.py +27 -1
- angr/angrdb/serializers/loader.py +10 -3
- angr/calling_conventions.py +2 -0
- angr/engines/pcode/behavior.py +7 -2
- angr/engines/pcode/cc.py +1 -0
- angr/engines/pcode/emulate.py +144 -104
- angr/engines/pcode/lifter.py +135 -79
- angr/knowledge_plugins/functions/function_manager.py +5 -3
- angr/knowledge_plugins/propagations/states.py +14 -0
- angr/lib/angr_native.dll +0 -0
- angr/procedures/cgc/deallocate.py +5 -2
- angr/procedures/posix/gethostbyname.py +23 -8
- angr/project.py +4 -0
- angr/simos/__init__.py +2 -0
- angr/simos/simos.py +1 -0
- angr/simos/snimmuc_nxp.py +152 -0
- angr/state_plugins/history.py +3 -1
- angr/utils/graph.py +20 -18
- {angr-9.2.84.dist-info → angr-9.2.85.dist-info}/METADATA +9 -8
- {angr-9.2.84.dist-info → angr-9.2.85.dist-info}/RECORD +57 -55
- tests/analyses/cfg/test_cfg_rust_got_resolution.py +2 -1
- tests/analyses/cfg/test_jumptables.py +2 -1
- tests/analyses/decompiler/test_decompiler.py +130 -103
- tests/engines/pcode/test_emulate.py +607 -0
- tests/serialization/test_db.py +30 -0
- angr/analyses/decompiler/optimization_passes/eager_returns.py +0 -285
- {angr-9.2.84.dist-info → angr-9.2.85.dist-info}/LICENSE +0 -0
- {angr-9.2.84.dist-info → angr-9.2.85.dist-info}/WHEEL +0 -0
- {angr-9.2.84.dist-info → angr-9.2.85.dist-info}/entry_points.txt +0 -0
- {angr-9.2.84.dist-info → angr-9.2.85.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,607 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
import unittest
|
|
3
|
+
import operator
|
|
4
|
+
from dataclasses import dataclass
|
|
5
|
+
from typing import Optional, List
|
|
6
|
+
|
|
7
|
+
import claripy
|
|
8
|
+
|
|
9
|
+
import angr
|
|
10
|
+
from angr.engines.pcode.behavior import BehaviorFactory
|
|
11
|
+
from angr.engines.pcode.emulate import PcodeEmulatorMixin
|
|
12
|
+
from angr.sim_state import SimState
|
|
13
|
+
from angr.engines import SimSuccessors
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
try:
|
|
17
|
+
import pypcode
|
|
18
|
+
from pypcode import OpCode
|
|
19
|
+
except ImportError:
|
|
20
|
+
pypcode = None
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
log = logging.getLogger(__name__)
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
@dataclass(eq=True)
|
|
27
|
+
class MockAddrSpace:
|
|
28
|
+
"""
|
|
29
|
+
Mock AddrSpace
|
|
30
|
+
"""
|
|
31
|
+
|
|
32
|
+
name: str
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
CONST_SPACE = MockAddrSpace("const")
|
|
36
|
+
RAM_SPACE = MockAddrSpace("ram")
|
|
37
|
+
REGISTER_SPACE = MockAddrSpace("register")
|
|
38
|
+
UNIQUE_SPACE = MockAddrSpace("unique")
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
@dataclass(eq=True)
|
|
42
|
+
class MockVarnode:
|
|
43
|
+
"""
|
|
44
|
+
Mock Varnode
|
|
45
|
+
"""
|
|
46
|
+
|
|
47
|
+
space: MockAddrSpace
|
|
48
|
+
offset: int
|
|
49
|
+
size: int
|
|
50
|
+
|
|
51
|
+
register_name: str = "<mock>"
|
|
52
|
+
space_encoded_in_offset: Optional[MockAddrSpace] = None
|
|
53
|
+
|
|
54
|
+
def getRegisterName(self) -> str:
|
|
55
|
+
return self.register_name
|
|
56
|
+
|
|
57
|
+
def getSpaceFromConst(self) -> Optional[MockAddrSpace]:
|
|
58
|
+
return self.space_encoded_in_offset
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
@dataclass(eq=True)
|
|
62
|
+
class MockPcodeOp:
|
|
63
|
+
"""
|
|
64
|
+
Mock P-Code Op
|
|
65
|
+
"""
|
|
66
|
+
|
|
67
|
+
opcode: "OpCode"
|
|
68
|
+
output: Optional[MockVarnode]
|
|
69
|
+
inputs: List[MockVarnode]
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
BEHAVIORS = BehaviorFactory()
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
@dataclass
|
|
76
|
+
class MockIRSB:
|
|
77
|
+
"""
|
|
78
|
+
Mock IRSB
|
|
79
|
+
"""
|
|
80
|
+
|
|
81
|
+
_ops: List[MockPcodeOp]
|
|
82
|
+
addr: int = 0
|
|
83
|
+
behaviors: BehaviorFactory = BEHAVIORS
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
OP = MockPcodeOp
|
|
87
|
+
VN = MockVarnode
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
@unittest.skipUnless(pypcode, "pypcode is not available")
|
|
91
|
+
class TestPcodeEmulatorMixin(unittest.TestCase):
|
|
92
|
+
"""
|
|
93
|
+
Test P-Code engine emulator mixin
|
|
94
|
+
"""
|
|
95
|
+
|
|
96
|
+
@staticmethod
|
|
97
|
+
def _step_irsb(irsb, state=None):
|
|
98
|
+
emulator = PcodeEmulatorMixin()
|
|
99
|
+
# FIMXE: *sigh* it's not so easy to use the mixin in isolation
|
|
100
|
+
|
|
101
|
+
emulator.project = angr.load_shellcode(b"\x90", arch="AMD64")
|
|
102
|
+
if state is None:
|
|
103
|
+
state = SimState(arch="AMD64")
|
|
104
|
+
emulator.state = state
|
|
105
|
+
emulator.state.history.recent_bbl_addrs.append(0)
|
|
106
|
+
emulator.successors = SimSuccessors(0, emulator.state)
|
|
107
|
+
emulator.handle_pcode_block(irsb)
|
|
108
|
+
emulator.successors.processed = True
|
|
109
|
+
return emulator.successors
|
|
110
|
+
|
|
111
|
+
def _test_branch_and_call_common(self, opcode: "OpCode"):
|
|
112
|
+
target_addr = 0x12345678
|
|
113
|
+
successors = self._step_irsb(
|
|
114
|
+
MockIRSB(
|
|
115
|
+
[
|
|
116
|
+
OP(
|
|
117
|
+
OpCode.IMARK,
|
|
118
|
+
None,
|
|
119
|
+
[VN(RAM_SPACE, 0, 1)],
|
|
120
|
+
),
|
|
121
|
+
OP(
|
|
122
|
+
opcode,
|
|
123
|
+
None,
|
|
124
|
+
[VN(RAM_SPACE, target_addr, 1)],
|
|
125
|
+
),
|
|
126
|
+
]
|
|
127
|
+
)
|
|
128
|
+
)
|
|
129
|
+
|
|
130
|
+
assert len(successors.all_successors) == 1
|
|
131
|
+
state = successors.all_successors[0]
|
|
132
|
+
assert state.solver.eval(state.regs.pc == target_addr)
|
|
133
|
+
|
|
134
|
+
def test_branch(self):
|
|
135
|
+
self._test_branch_and_call_common(OpCode.BRANCH)
|
|
136
|
+
|
|
137
|
+
def test_call(self):
|
|
138
|
+
self._test_branch_and_call_common(OpCode.CALL)
|
|
139
|
+
|
|
140
|
+
def _test_branchind_and_callind_common(self, opcode: "OpCode"):
|
|
141
|
+
target_addr = 0x12345678
|
|
142
|
+
target_pointer_addr = 0x100000
|
|
143
|
+
target_pointer_size = 8
|
|
144
|
+
|
|
145
|
+
state = SimState(arch="AMD64")
|
|
146
|
+
state.memory.store(target_pointer_addr, claripy.BVV(target_addr, 8 * target_pointer_size), endness="IEnd_LE")
|
|
147
|
+
|
|
148
|
+
successors = self._step_irsb(
|
|
149
|
+
MockIRSB(
|
|
150
|
+
[
|
|
151
|
+
OP(
|
|
152
|
+
OpCode.IMARK,
|
|
153
|
+
None,
|
|
154
|
+
[VN(RAM_SPACE, 0, 1)],
|
|
155
|
+
),
|
|
156
|
+
OP(
|
|
157
|
+
opcode,
|
|
158
|
+
None,
|
|
159
|
+
[VN(RAM_SPACE, target_pointer_addr, target_pointer_size)],
|
|
160
|
+
),
|
|
161
|
+
]
|
|
162
|
+
),
|
|
163
|
+
state,
|
|
164
|
+
)
|
|
165
|
+
|
|
166
|
+
assert len(successors.all_successors) == 1
|
|
167
|
+
state = successors.all_successors[0]
|
|
168
|
+
assert state.solver.eval(state.regs.pc == target_addr)
|
|
169
|
+
|
|
170
|
+
def test_branchind(self):
|
|
171
|
+
self._test_branchind_and_callind_common(OpCode.BRANCHIND)
|
|
172
|
+
|
|
173
|
+
def test_callind(self):
|
|
174
|
+
self._test_branchind_and_callind_common(OpCode.CALLIND)
|
|
175
|
+
|
|
176
|
+
def _test_cbranch_common(self, cond: claripy.BVV):
|
|
177
|
+
condition_addr = 0x100000
|
|
178
|
+
target_addr = 0x12345678
|
|
179
|
+
fallthru_addr = 1
|
|
180
|
+
|
|
181
|
+
state = SimState(arch="AMD64")
|
|
182
|
+
state.memory.store(condition_addr, cond)
|
|
183
|
+
|
|
184
|
+
successors = self._step_irsb(
|
|
185
|
+
MockIRSB(
|
|
186
|
+
[
|
|
187
|
+
OP(
|
|
188
|
+
OpCode.IMARK,
|
|
189
|
+
None,
|
|
190
|
+
[VN(RAM_SPACE, 0, fallthru_addr)],
|
|
191
|
+
),
|
|
192
|
+
OP(
|
|
193
|
+
OpCode.CBRANCH,
|
|
194
|
+
None,
|
|
195
|
+
[VN(RAM_SPACE, target_addr, 8), VN(RAM_SPACE, condition_addr, 1)],
|
|
196
|
+
),
|
|
197
|
+
]
|
|
198
|
+
),
|
|
199
|
+
state,
|
|
200
|
+
)
|
|
201
|
+
|
|
202
|
+
if cond.concrete:
|
|
203
|
+
if state.solver.eval(cond):
|
|
204
|
+
sat_pc, unsat_pc = target_addr, fallthru_addr
|
|
205
|
+
else:
|
|
206
|
+
sat_pc, unsat_pc = fallthru_addr, target_addr
|
|
207
|
+
|
|
208
|
+
assert len(successors.successors) == 1
|
|
209
|
+
state = successors.successors[0]
|
|
210
|
+
assert state.solver.eval(state.regs.pc == sat_pc)
|
|
211
|
+
|
|
212
|
+
assert len(successors.unsat_successors) == 1
|
|
213
|
+
state = successors.unsat_successors[0]
|
|
214
|
+
assert state.solver.eval(state.regs.pc == unsat_pc)
|
|
215
|
+
else:
|
|
216
|
+
assert len(successors.successors) == 2
|
|
217
|
+
pcs = {state.solver.eval(state.regs.pc) for state in successors.successors}
|
|
218
|
+
assert pcs == {target_addr, fallthru_addr}
|
|
219
|
+
|
|
220
|
+
def test_cbranch_taken(self):
|
|
221
|
+
self._test_cbranch_common(claripy.BVV(1, 8))
|
|
222
|
+
self._test_cbranch_common(claripy.BVV(2, 8))
|
|
223
|
+
|
|
224
|
+
def test_cbranch_not_taken(self):
|
|
225
|
+
self._test_cbranch_common(claripy.BVV(0, 8))
|
|
226
|
+
|
|
227
|
+
def test_cbranch_symbolic(self):
|
|
228
|
+
self._test_cbranch_common(claripy.BVS("condition", 8))
|
|
229
|
+
|
|
230
|
+
def _test_rel_cbranch_common(self, cond: claripy.BVV):
|
|
231
|
+
condition_addr = 0x100000
|
|
232
|
+
start_addr = 0
|
|
233
|
+
target_addr = start_addr
|
|
234
|
+
target_stmt = 1
|
|
235
|
+
instruction_len = 1
|
|
236
|
+
fallthru_addr = start_addr + instruction_len
|
|
237
|
+
cbranch_idx = 2
|
|
238
|
+
|
|
239
|
+
state = SimState(arch="AMD64")
|
|
240
|
+
state.memory.store(condition_addr, cond)
|
|
241
|
+
|
|
242
|
+
successors = self._step_irsb(
|
|
243
|
+
MockIRSB(
|
|
244
|
+
[
|
|
245
|
+
# Op 0
|
|
246
|
+
OP(
|
|
247
|
+
OpCode.IMARK,
|
|
248
|
+
None,
|
|
249
|
+
[VN(RAM_SPACE, start_addr, instruction_len)],
|
|
250
|
+
),
|
|
251
|
+
# Op 1
|
|
252
|
+
OP(
|
|
253
|
+
OpCode.INT_ADD,
|
|
254
|
+
VN(UNIQUE_SPACE, 0, 8),
|
|
255
|
+
[VN(UNIQUE_SPACE, 0, 8), VN(CONST_SPACE, 1, 8)],
|
|
256
|
+
),
|
|
257
|
+
# Op 2
|
|
258
|
+
OP(
|
|
259
|
+
OpCode.CBRANCH,
|
|
260
|
+
None,
|
|
261
|
+
[VN(CONST_SPACE, target_stmt - cbranch_idx, 8), VN(RAM_SPACE, condition_addr, 1)],
|
|
262
|
+
),
|
|
263
|
+
]
|
|
264
|
+
),
|
|
265
|
+
state,
|
|
266
|
+
)
|
|
267
|
+
|
|
268
|
+
if cond.concrete:
|
|
269
|
+
if state.solver.eval(cond):
|
|
270
|
+
sat_pc, unsat_pc = target_addr, fallthru_addr
|
|
271
|
+
sat_stmt, unsat_stmt = target_stmt, 0
|
|
272
|
+
else:
|
|
273
|
+
sat_pc, unsat_pc = fallthru_addr, target_addr
|
|
274
|
+
sat_stmt, unsat_stmt = 0, target_stmt
|
|
275
|
+
|
|
276
|
+
assert len(successors.successors) == 1
|
|
277
|
+
state = successors.successors[0]
|
|
278
|
+
assert state.solver.eval(state.regs.pc == sat_pc)
|
|
279
|
+
assert state.scratch.statement_offset == sat_stmt
|
|
280
|
+
|
|
281
|
+
assert len(successors.unsat_successors) == 1
|
|
282
|
+
state = successors.unsat_successors[0]
|
|
283
|
+
assert state.solver.eval(state.regs.pc == unsat_pc)
|
|
284
|
+
assert state.scratch.statement_offset == unsat_stmt
|
|
285
|
+
|
|
286
|
+
else:
|
|
287
|
+
assert len(successors.successors) == 2
|
|
288
|
+
pcs = {
|
|
289
|
+
(state.solver.eval(state.regs.pc), state.scratch.statement_offset) for state in successors.successors
|
|
290
|
+
}
|
|
291
|
+
assert pcs == {(target_addr, target_stmt), (fallthru_addr, 0)}
|
|
292
|
+
|
|
293
|
+
def test_rel_cbranch_taken(self):
|
|
294
|
+
self._test_rel_cbranch_common(claripy.BVV(1, 8))
|
|
295
|
+
self._test_rel_cbranch_common(claripy.BVV(2, 8))
|
|
296
|
+
|
|
297
|
+
def test_rel_cbranch_not_taken(self):
|
|
298
|
+
self._test_rel_cbranch_common(claripy.BVV(0, 8))
|
|
299
|
+
|
|
300
|
+
def test_rel_cbranch_symbolic(self):
|
|
301
|
+
self._test_cbranch_common(claripy.BVS("condition", 8))
|
|
302
|
+
|
|
303
|
+
def test_load_store(self):
|
|
304
|
+
addr = 0x133700000
|
|
305
|
+
addr2 = 0x999900000
|
|
306
|
+
value = claripy.BVV(0xFEDCBA9876543210, 64)
|
|
307
|
+
state = SimState(arch="AMD64")
|
|
308
|
+
state.memory.store(addr, value)
|
|
309
|
+
state.regs.rax = addr
|
|
310
|
+
|
|
311
|
+
# Load value from RAM[addr] and store it into RAM[addr2]
|
|
312
|
+
|
|
313
|
+
successors = self._step_irsb(
|
|
314
|
+
MockIRSB(
|
|
315
|
+
[
|
|
316
|
+
OP(
|
|
317
|
+
OpCode.IMARK,
|
|
318
|
+
None,
|
|
319
|
+
[VN(RAM_SPACE, 0, 1)],
|
|
320
|
+
),
|
|
321
|
+
OP(
|
|
322
|
+
OpCode.COPY,
|
|
323
|
+
VN(UNIQUE_SPACE, 0, 8),
|
|
324
|
+
[VN(CONST_SPACE, addr, 8)],
|
|
325
|
+
),
|
|
326
|
+
OP(
|
|
327
|
+
OpCode.LOAD,
|
|
328
|
+
VN(UNIQUE_SPACE, 8, 8),
|
|
329
|
+
[VN(CONST_SPACE, 0xCACACACA, 0, space_encoded_in_offset=RAM_SPACE), VN(UNIQUE_SPACE, 0, 8)],
|
|
330
|
+
),
|
|
331
|
+
OP(
|
|
332
|
+
OpCode.COPY,
|
|
333
|
+
VN(UNIQUE_SPACE, 0, 8),
|
|
334
|
+
[VN(CONST_SPACE, addr2, 8)],
|
|
335
|
+
),
|
|
336
|
+
OP(
|
|
337
|
+
OpCode.STORE,
|
|
338
|
+
None,
|
|
339
|
+
[
|
|
340
|
+
VN(CONST_SPACE, 0xCACACACA, 0, space_encoded_in_offset=RAM_SPACE),
|
|
341
|
+
VN(UNIQUE_SPACE, 0, 8),
|
|
342
|
+
VN(UNIQUE_SPACE, 8, 8),
|
|
343
|
+
],
|
|
344
|
+
),
|
|
345
|
+
],
|
|
346
|
+
),
|
|
347
|
+
state,
|
|
348
|
+
)
|
|
349
|
+
|
|
350
|
+
new_state = successors.successors[0]
|
|
351
|
+
assert new_state.solver.is_true(new_state.memory.load(addr2, 8) == value)
|
|
352
|
+
|
|
353
|
+
def _test_single_arith_binary_op(self, opcode: "OpCode"):
|
|
354
|
+
opcode_to_operation = {
|
|
355
|
+
OpCode.BOOL_AND: operator.and_,
|
|
356
|
+
OpCode.BOOL_OR: operator.or_,
|
|
357
|
+
OpCode.BOOL_XOR: operator.xor,
|
|
358
|
+
OpCode.INT_ADD: operator.add,
|
|
359
|
+
OpCode.INT_AND: operator.and_,
|
|
360
|
+
OpCode.INT_DIV: operator.floordiv,
|
|
361
|
+
OpCode.INT_EQUAL: operator.eq,
|
|
362
|
+
OpCode.INT_LEFT: operator.lshift,
|
|
363
|
+
OpCode.INT_LESS: operator.lt,
|
|
364
|
+
OpCode.INT_LESSEQUAL: operator.le,
|
|
365
|
+
OpCode.INT_MULT: operator.mul,
|
|
366
|
+
OpCode.INT_NOTEQUAL: operator.ne,
|
|
367
|
+
OpCode.INT_OR: operator.or_,
|
|
368
|
+
OpCode.INT_REM: operator.mod,
|
|
369
|
+
OpCode.INT_RIGHT: claripy.LShR,
|
|
370
|
+
OpCode.INT_SLESS: claripy.SLT,
|
|
371
|
+
OpCode.INT_SLESSEQUAL: claripy.SLE,
|
|
372
|
+
OpCode.INT_SRIGHT: operator.rshift,
|
|
373
|
+
OpCode.INT_SUB: operator.sub,
|
|
374
|
+
OpCode.INT_XOR: operator.xor,
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
operation = opcode_to_operation.get(opcode)
|
|
378
|
+
assert operation is not None
|
|
379
|
+
|
|
380
|
+
is_boolean = opcode in {OpCode.BOOL_AND, OpCode.BOOL_OR, OpCode.BOOL_XOR}
|
|
381
|
+
is_comparison = opcode in {
|
|
382
|
+
OpCode.INT_EQUAL,
|
|
383
|
+
OpCode.INT_LESS,
|
|
384
|
+
OpCode.INT_LESSEQUAL,
|
|
385
|
+
OpCode.INT_NOTEQUAL,
|
|
386
|
+
OpCode.INT_SLESS,
|
|
387
|
+
OpCode.INT_SLESSEQUAL,
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
operand_size = 1 if is_boolean else 4
|
|
391
|
+
|
|
392
|
+
result_addr = 0x100000
|
|
393
|
+
result_size = 1 if is_comparison else operand_size
|
|
394
|
+
|
|
395
|
+
x_addr, x = 0, claripy.BVS("x", operand_size * 8)
|
|
396
|
+
y_addr, y = operand_size, claripy.BVS("y", operand_size * 8)
|
|
397
|
+
|
|
398
|
+
state = SimState(arch="AMD64", remove_options={"SIMPLIFY_MEMORY_WRITES"})
|
|
399
|
+
state.memory.store(x_addr, x, endness="Iend_LE")
|
|
400
|
+
state.memory.store(y_addr, y, endness="Iend_LE")
|
|
401
|
+
|
|
402
|
+
successors = self._step_irsb(
|
|
403
|
+
MockIRSB(
|
|
404
|
+
[
|
|
405
|
+
OP(
|
|
406
|
+
OpCode.IMARK,
|
|
407
|
+
None,
|
|
408
|
+
[VN(RAM_SPACE, 0, 1)],
|
|
409
|
+
),
|
|
410
|
+
OP(
|
|
411
|
+
opcode,
|
|
412
|
+
VN(RAM_SPACE, result_addr, operand_size),
|
|
413
|
+
[VN(RAM_SPACE, x_addr, operand_size), VN(RAM_SPACE, y_addr, operand_size)],
|
|
414
|
+
),
|
|
415
|
+
]
|
|
416
|
+
),
|
|
417
|
+
state,
|
|
418
|
+
)
|
|
419
|
+
|
|
420
|
+
assert len(successors.all_successors) == 1
|
|
421
|
+
state = successors.all_successors[0]
|
|
422
|
+
assert state.solver.eval(state.regs.pc == 1)
|
|
423
|
+
|
|
424
|
+
result = state.memory.load(result_addr, result_size, endness="Iend_LE")
|
|
425
|
+
|
|
426
|
+
if is_boolean:
|
|
427
|
+
booleanize = angr.engines.pcode.behavior.OpBehavior.booleanize
|
|
428
|
+
expected_result = operation(booleanize(x), booleanize(y)).zero_extend(7)
|
|
429
|
+
elif is_comparison:
|
|
430
|
+
expected_result = claripy.If(operation(x, y), claripy.BVV(1, 1), claripy.BVV(0, 1)).zero_extend(7)
|
|
431
|
+
else:
|
|
432
|
+
expected_result = operation(x, y)
|
|
433
|
+
|
|
434
|
+
assert claripy.backends.z3.is_true(result == expected_result)
|
|
435
|
+
|
|
436
|
+
def test_arith_binary_ops(self):
|
|
437
|
+
for opcode in [
|
|
438
|
+
OpCode.BOOL_AND,
|
|
439
|
+
OpCode.BOOL_OR,
|
|
440
|
+
OpCode.BOOL_XOR,
|
|
441
|
+
OpCode.INT_ADD,
|
|
442
|
+
OpCode.INT_AND,
|
|
443
|
+
OpCode.INT_DIV,
|
|
444
|
+
OpCode.INT_EQUAL,
|
|
445
|
+
OpCode.INT_LEFT,
|
|
446
|
+
OpCode.INT_LESS,
|
|
447
|
+
OpCode.INT_LESSEQUAL,
|
|
448
|
+
OpCode.INT_MULT,
|
|
449
|
+
OpCode.INT_NOTEQUAL,
|
|
450
|
+
OpCode.INT_OR,
|
|
451
|
+
OpCode.INT_REM,
|
|
452
|
+
OpCode.INT_RIGHT,
|
|
453
|
+
# OpCode.INT_SDIV, # FIXME
|
|
454
|
+
OpCode.INT_SLESS,
|
|
455
|
+
OpCode.INT_SLESSEQUAL,
|
|
456
|
+
OpCode.INT_SRIGHT,
|
|
457
|
+
OpCode.INT_SUB,
|
|
458
|
+
OpCode.INT_XOR,
|
|
459
|
+
]:
|
|
460
|
+
with self.subTest(opcode):
|
|
461
|
+
self._test_single_arith_binary_op(opcode)
|
|
462
|
+
|
|
463
|
+
def _test_single_arith_unary_op(self, opcode: "OpCode"):
|
|
464
|
+
opcode_to_operation = {
|
|
465
|
+
OpCode.INT_NEGATE: operator.inv,
|
|
466
|
+
OpCode.INT_2COMP: operator.neg,
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
operation = opcode_to_operation.get(opcode)
|
|
470
|
+
assert operation is not None
|
|
471
|
+
|
|
472
|
+
operand_size = 4
|
|
473
|
+
|
|
474
|
+
result_size = operand_size
|
|
475
|
+
result_addr = 0x100000
|
|
476
|
+
|
|
477
|
+
x_addr, x = 0, claripy.BVS("x", operand_size * 8)
|
|
478
|
+
|
|
479
|
+
state = SimState(arch="AMD64", remove_options={"SIMPLIFY_MEMORY_WRITES"})
|
|
480
|
+
state.memory.store(x_addr, x, endness="Iend_LE")
|
|
481
|
+
|
|
482
|
+
successors = self._step_irsb(
|
|
483
|
+
MockIRSB(
|
|
484
|
+
[
|
|
485
|
+
OP(
|
|
486
|
+
OpCode.IMARK,
|
|
487
|
+
None,
|
|
488
|
+
[VN(RAM_SPACE, 0, 1)],
|
|
489
|
+
),
|
|
490
|
+
OP(
|
|
491
|
+
opcode,
|
|
492
|
+
VN(RAM_SPACE, result_addr, operand_size),
|
|
493
|
+
[VN(RAM_SPACE, x_addr, operand_size)],
|
|
494
|
+
),
|
|
495
|
+
]
|
|
496
|
+
),
|
|
497
|
+
state,
|
|
498
|
+
)
|
|
499
|
+
|
|
500
|
+
assert len(successors.all_successors) == 1
|
|
501
|
+
state = successors.all_successors[0]
|
|
502
|
+
assert state.solver.eval(state.regs.pc == 1)
|
|
503
|
+
|
|
504
|
+
result = state.memory.load(result_addr, result_size, endness="Iend_LE")
|
|
505
|
+
expected_result = operation(x)
|
|
506
|
+
|
|
507
|
+
assert claripy.backends.z3.is_true(result == expected_result)
|
|
508
|
+
|
|
509
|
+
def test_arith_unary_ops(self):
|
|
510
|
+
for opcode in [
|
|
511
|
+
OpCode.INT_NEGATE,
|
|
512
|
+
OpCode.INT_2COMP,
|
|
513
|
+
]:
|
|
514
|
+
with self.subTest(opcode):
|
|
515
|
+
self._test_single_arith_unary_op(opcode)
|
|
516
|
+
|
|
517
|
+
def _test_other_unary_common(self, opcode, input_value, expected_value):
|
|
518
|
+
operand_addr = 0x200000
|
|
519
|
+
operand_size = input_value.size() // 8
|
|
520
|
+
|
|
521
|
+
result_addr = 0x100000
|
|
522
|
+
result_size = expected_value.size() // 8
|
|
523
|
+
|
|
524
|
+
state = SimState(arch="AMD64", remove_options={"SIMPLIFY_MEMORY_WRITES"})
|
|
525
|
+
state.memory.store(operand_addr, input_value, endness="Iend_LE")
|
|
526
|
+
state.memory.store(result_addr, claripy.BVV(b"\xCA" * result_size), endness="Iend_LE")
|
|
527
|
+
|
|
528
|
+
successors = self._step_irsb(
|
|
529
|
+
MockIRSB(
|
|
530
|
+
[
|
|
531
|
+
OP(
|
|
532
|
+
OpCode.IMARK,
|
|
533
|
+
None,
|
|
534
|
+
[VN(RAM_SPACE, 0, 1)],
|
|
535
|
+
),
|
|
536
|
+
OP(
|
|
537
|
+
opcode,
|
|
538
|
+
VN(RAM_SPACE, result_addr, result_size),
|
|
539
|
+
[VN(RAM_SPACE, operand_addr, operand_size)],
|
|
540
|
+
),
|
|
541
|
+
],
|
|
542
|
+
),
|
|
543
|
+
state,
|
|
544
|
+
)
|
|
545
|
+
|
|
546
|
+
assert len(successors.all_successors) == 1
|
|
547
|
+
state = successors.successors[0]
|
|
548
|
+
v = state.memory.load(result_addr, result_size, endness="Iend_LE")
|
|
549
|
+
assert state.solver.eval(v == expected_value)
|
|
550
|
+
|
|
551
|
+
def test_bool_negate(self):
|
|
552
|
+
# FIXME: Should values >1 be considered true? If some op only clears the 0th bit this may be incorrect
|
|
553
|
+
self._test_other_unary_common(OpCode.BOOL_NEGATE, claripy.BVV(0, 8), claripy.BVV(1, 8))
|
|
554
|
+
self._test_other_unary_common(OpCode.BOOL_NEGATE, claripy.BVV(1, 8), claripy.BVV(0, 8))
|
|
555
|
+
self._test_other_unary_common(OpCode.BOOL_NEGATE, claripy.BVV(0xFF, 8), claripy.BVV(0, 8))
|
|
556
|
+
|
|
557
|
+
def test_zext(self):
|
|
558
|
+
self._test_other_unary_common(OpCode.INT_ZEXT, claripy.BVV(0x7234, 16), claripy.BVV(0x7234, 16))
|
|
559
|
+
self._test_other_unary_common(OpCode.INT_ZEXT, claripy.BVV(0x7234, 16), claripy.BVV(0x0000_7234, 32))
|
|
560
|
+
self._test_other_unary_common(OpCode.INT_ZEXT, claripy.BVV(0x8234, 16), claripy.BVV(0x0000_8234, 32))
|
|
561
|
+
|
|
562
|
+
def test_sext(self):
|
|
563
|
+
self._test_other_unary_common(OpCode.INT_SEXT, claripy.BVV(0x7234, 16), claripy.BVV(0x7234, 16))
|
|
564
|
+
self._test_other_unary_common(OpCode.INT_SEXT, claripy.BVV(0x7234, 16), claripy.BVV(0x0000_7234, 32))
|
|
565
|
+
self._test_other_unary_common(OpCode.INT_SEXT, claripy.BVV(0x8234, 16), claripy.BVV(0xFFFF_8234, 32))
|
|
566
|
+
|
|
567
|
+
def test_popcount(self):
|
|
568
|
+
self._test_other_unary_common(OpCode.POPCOUNT, claripy.BVV(0, 32), claripy.BVV(0, 32))
|
|
569
|
+
self._test_other_unary_common(OpCode.POPCOUNT, claripy.BVV(0x12345678, 32), claripy.BVV(13, 32))
|
|
570
|
+
self._test_other_unary_common(OpCode.POPCOUNT, claripy.BVV(0xFFFFFFFF, 32), claripy.BVV(32, 32))
|
|
571
|
+
|
|
572
|
+
# TODO: Add tests for the following ops:
|
|
573
|
+
# * = FIXME
|
|
574
|
+
# ! = Not Implemented
|
|
575
|
+
#
|
|
576
|
+
# ! OpCode.CPOOLREF
|
|
577
|
+
# OpCode.FLOAT_ABS
|
|
578
|
+
# OpCode.FLOAT_ADD
|
|
579
|
+
# OpCode.FLOAT_CEIL
|
|
580
|
+
# OpCode.FLOAT_DIV
|
|
581
|
+
# OpCode.FLOAT_EQUAL
|
|
582
|
+
# OpCode.FLOAT_FLOAT2FLOAT
|
|
583
|
+
# OpCode.FLOAT_FLOOR
|
|
584
|
+
# OpCode.FLOAT_INT2FLOAT
|
|
585
|
+
# OpCode.FLOAT_LESS
|
|
586
|
+
# OpCode.FLOAT_LESSEQUAL
|
|
587
|
+
# OpCode.FLOAT_MULT
|
|
588
|
+
# OpCode.FLOAT_NAN
|
|
589
|
+
# OpCode.FLOAT_NEG
|
|
590
|
+
# OpCode.FLOAT_NOTEQUAL
|
|
591
|
+
# OpCode.FLOAT_ROUND
|
|
592
|
+
# OpCode.FLOAT_SQRT
|
|
593
|
+
# OpCode.FLOAT_SUB
|
|
594
|
+
# OpCode.FLOAT_TRUNC
|
|
595
|
+
# OpCode.INT_CARRY
|
|
596
|
+
# OpCode.INT_SBORROW
|
|
597
|
+
# OpCode.INT_SCARRY
|
|
598
|
+
# * OpCode.INT_SDIV
|
|
599
|
+
# * OpCode.INT_SREM
|
|
600
|
+
# ! OpCode.NEW
|
|
601
|
+
# OpCode.RETURN
|
|
602
|
+
|
|
603
|
+
|
|
604
|
+
if __name__ == "__main__":
|
|
605
|
+
log.setLevel(logging.DEBUG)
|
|
606
|
+
logging.getLogger("angr.engines.pcode").setLevel(logging.DEBUG)
|
|
607
|
+
unittest.main()
|
tests/serialization/test_db.py
CHANGED
|
@@ -4,6 +4,7 @@ __package__ = __package__ or "tests.serialization" # pylint:disable=redefined-b
|
|
|
4
4
|
|
|
5
5
|
import os
|
|
6
6
|
import tempfile
|
|
7
|
+
import shutil
|
|
7
8
|
import unittest
|
|
8
9
|
|
|
9
10
|
import angr
|
|
@@ -162,6 +163,35 @@ class TestDb(unittest.TestCase):
|
|
|
162
163
|
proj1 = AngrDB().load(db_file)
|
|
163
164
|
assert proj1.kb.comments[proj.entry] == "Comment 22222222222222222222222"
|
|
164
165
|
|
|
166
|
+
def test_angrdb_save_without_binary_existence(self):
|
|
167
|
+
bin_path = os.path.join(test_location, "x86_64", "fauxware")
|
|
168
|
+
|
|
169
|
+
with tempfile.TemporaryDirectory() as td:
|
|
170
|
+
db_file = os.path.join(td, "proj.adb")
|
|
171
|
+
|
|
172
|
+
with tempfile.TemporaryDirectory() as td0:
|
|
173
|
+
tmp_path = os.path.join(td0, os.path.basename(bin_path))
|
|
174
|
+
shutil.copy(bin_path, tmp_path)
|
|
175
|
+
proj = angr.Project(tmp_path, auto_load_libs=False)
|
|
176
|
+
|
|
177
|
+
AngrDB(proj).dump(db_file)
|
|
178
|
+
|
|
179
|
+
del proj
|
|
180
|
+
os.remove(tmp_path)
|
|
181
|
+
|
|
182
|
+
# now that the binary file no longer exists, we should be able to open the angr DB and save it without
|
|
183
|
+
# raising exceptions.
|
|
184
|
+
|
|
185
|
+
proj = AngrDB().load(db_file)
|
|
186
|
+
os.remove(db_file)
|
|
187
|
+
|
|
188
|
+
db_file_new = os.path.join(td, "proj_new.adb")
|
|
189
|
+
AngrDB(proj).dump(db_file_new)
|
|
190
|
+
|
|
191
|
+
# we should be able to load it back!
|
|
192
|
+
proj_new = AngrDB().load(db_file_new)
|
|
193
|
+
assert os.path.basename(proj_new.loader.main_object.binary) == "fauxware"
|
|
194
|
+
|
|
165
195
|
|
|
166
196
|
if __name__ == "__main__":
|
|
167
197
|
unittest.main()
|