angr 9.2.148__py3-none-manylinux2014_aarch64.whl → 9.2.149__py3-none-manylinux2014_aarch64.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/calling_convention/calling_convention.py +42 -2
- angr/analyses/cfg/cfg_emulated.py +5 -2
- angr/analyses/cfg/cfg_fast.py +48 -46
- angr/analyses/decompiler/ail_simplifier.py +65 -32
- angr/analyses/decompiler/block_simplifier.py +20 -6
- angr/analyses/decompiler/clinic.py +80 -13
- angr/analyses/decompiler/dephication/rewriting_engine.py +24 -2
- angr/analyses/decompiler/optimization_passes/__init__.py +5 -0
- angr/analyses/decompiler/optimization_passes/base_ptr_save_simplifier.py +15 -13
- angr/analyses/decompiler/optimization_passes/determine_load_sizes.py +64 -0
- angr/analyses/decompiler/optimization_passes/eager_std_string_concatenation.py +165 -0
- angr/analyses/decompiler/optimization_passes/engine_base.py +11 -2
- angr/analyses/decompiler/optimization_passes/inlined_string_transformation_simplifier.py +17 -2
- angr/analyses/decompiler/optimization_passes/optimization_pass.py +10 -6
- angr/analyses/decompiler/optimization_passes/win_stack_canary_simplifier.py +99 -30
- angr/analyses/decompiler/peephole_optimizations/__init__.py +6 -0
- angr/analyses/decompiler/peephole_optimizations/base.py +43 -3
- angr/analyses/decompiler/peephole_optimizations/constant_derefs.py +1 -1
- angr/analyses/decompiler/peephole_optimizations/inlined_strcpy.py +3 -0
- angr/analyses/decompiler/peephole_optimizations/inlined_strcpy_consolidation.py +4 -1
- angr/analyses/decompiler/peephole_optimizations/remove_cxx_destructor_calls.py +32 -0
- angr/analyses/decompiler/peephole_optimizations/remove_redundant_bitmasks.py +69 -2
- angr/analyses/decompiler/peephole_optimizations/rewrite_conv_mul.py +40 -0
- angr/analyses/decompiler/peephole_optimizations/rewrite_cxx_operator_calls.py +90 -0
- angr/analyses/decompiler/presets/fast.py +2 -0
- angr/analyses/decompiler/presets/full.py +2 -0
- angr/analyses/decompiler/ssailification/rewriting_engine.py +51 -4
- angr/analyses/decompiler/ssailification/ssailification.py +23 -3
- angr/analyses/decompiler/ssailification/traversal_engine.py +15 -1
- angr/analyses/decompiler/structured_codegen/c.py +141 -10
- angr/analyses/decompiler/utils.py +6 -1
- angr/analyses/s_reaching_definitions/s_rda_view.py +1 -0
- angr/analyses/typehoon/lifter.py +20 -0
- angr/analyses/typehoon/simple_solver.py +42 -9
- angr/analyses/typehoon/translator.py +4 -1
- angr/analyses/typehoon/typeconsts.py +17 -6
- angr/analyses/typehoon/typehoon.py +21 -5
- angr/analyses/variable_recovery/engine_ail.py +44 -5
- angr/analyses/variable_recovery/engine_base.py +35 -12
- angr/analyses/variable_recovery/variable_recovery_fast.py +33 -2
- angr/calling_conventions.py +23 -5
- angr/engines/light/engine.py +7 -0
- angr/knowledge_plugins/functions/function.py +68 -0
- angr/knowledge_plugins/propagations/states.py +5 -2
- angr/knowledge_plugins/variables/variable_manager.py +3 -3
- angr/procedures/definitions/__init__.py +1 -1
- angr/procedures/definitions/types_stl.py +22 -0
- angr/sim_type.py +251 -130
- {angr-9.2.148.dist-info → angr-9.2.149.dist-info}/METADATA +7 -7
- {angr-9.2.148.dist-info → angr-9.2.149.dist-info}/RECORD +55 -49
- {angr-9.2.148.dist-info → angr-9.2.149.dist-info}/WHEEL +1 -1
- {angr-9.2.148.dist-info → angr-9.2.149.dist-info}/licenses/LICENSE +3 -0
- {angr-9.2.148.dist-info → angr-9.2.149.dist-info}/entry_points.txt +0 -0
- {angr-9.2.148.dist-info → angr-9.2.149.dist-info}/top_level.txt +0 -0
angr/__init__.py
CHANGED
|
@@ -13,8 +13,16 @@ import ailment
|
|
|
13
13
|
|
|
14
14
|
from angr.code_location import ExternalCodeLocation
|
|
15
15
|
|
|
16
|
-
from angr.calling_conventions import
|
|
16
|
+
from angr.calling_conventions import (
|
|
17
|
+
SimFunctionArgument,
|
|
18
|
+
SimRegArg,
|
|
19
|
+
SimStackArg,
|
|
20
|
+
SimCC,
|
|
21
|
+
default_cc,
|
|
22
|
+
SimCCMicrosoftThiscall,
|
|
23
|
+
)
|
|
17
24
|
from angr.sim_type import (
|
|
25
|
+
SimTypeCppFunction,
|
|
18
26
|
SimTypeInt,
|
|
19
27
|
SimTypeFunction,
|
|
20
28
|
SimType,
|
|
@@ -24,6 +32,7 @@ from angr.sim_type import (
|
|
|
24
32
|
SimTypeBottom,
|
|
25
33
|
SimTypeFloat,
|
|
26
34
|
SimTypeDouble,
|
|
35
|
+
parse_cpp_file,
|
|
27
36
|
)
|
|
28
37
|
from angr.sim_variable import SimStackVariable, SimRegisterVariable
|
|
29
38
|
from angr.knowledge_plugins.key_definitions.atoms import Register, MemoryLocation, SpOffset
|
|
@@ -153,6 +162,13 @@ class CallingConventionAnalysis(Analysis):
|
|
|
153
162
|
|
|
154
163
|
assert self._function is not None
|
|
155
164
|
|
|
165
|
+
demangled_name = self._function.demangled_name
|
|
166
|
+
if demangled_name != self._function.name:
|
|
167
|
+
r_demangled = self._analyze_demangled_name(demangled_name)
|
|
168
|
+
if r_demangled is not None:
|
|
169
|
+
self.cc, self.prototype, self.prototype_libname = r_demangled
|
|
170
|
+
return
|
|
171
|
+
|
|
156
172
|
if self._function.is_simprocedure:
|
|
157
173
|
hooker = self.project.hooked_by(self._function.addr)
|
|
158
174
|
if isinstance(
|
|
@@ -348,6 +364,30 @@ class CallingConventionAnalysis(Analysis):
|
|
|
348
364
|
|
|
349
365
|
return None
|
|
350
366
|
|
|
367
|
+
def _analyze_demangled_name(self, name: str) -> tuple[SimCC, SimTypeFunction, str | None] | None:
|
|
368
|
+
"""
|
|
369
|
+
Analyze a function with a demangled name. Only C++ names are supported for now.
|
|
370
|
+
|
|
371
|
+
:param name: The demangled name of the function.
|
|
372
|
+
:return: A tuple of the calling convention, the function type, and the library name if available.
|
|
373
|
+
"""
|
|
374
|
+
parsed, _ = parse_cpp_file(name)
|
|
375
|
+
if not parsed or len(parsed) != 1:
|
|
376
|
+
return None
|
|
377
|
+
proto = next(iter(parsed.values()))
|
|
378
|
+
if (
|
|
379
|
+
isinstance(proto, SimTypeCppFunction)
|
|
380
|
+
and self.project.simos.name == "Win32"
|
|
381
|
+
and self.project.arch.name == "X86"
|
|
382
|
+
and proto.convention == "__thiscall"
|
|
383
|
+
):
|
|
384
|
+
cc_cls = SimCCMicrosoftThiscall
|
|
385
|
+
else:
|
|
386
|
+
cc_cls = default_cc(self.project.arch.name, self.project.simos.name)
|
|
387
|
+
assert cc_cls is not None
|
|
388
|
+
cc = cc_cls(self.project.arch)
|
|
389
|
+
return cc, proto, None
|
|
390
|
+
|
|
351
391
|
def _analyze_function(self) -> tuple[SimCC, SimTypeFunction] | None:
|
|
352
392
|
"""
|
|
353
393
|
Go over the variable information in variable manager for this function, and return all uninitialized
|
|
@@ -681,7 +721,7 @@ class CallingConventionAnalysis(Analysis):
|
|
|
681
721
|
# no more arguments
|
|
682
722
|
temp_args.append(None)
|
|
683
723
|
elif isinstance(arg_loc, SimStackArg):
|
|
684
|
-
if arg_loc.stack_offset in defs_by_stack_offset:
|
|
724
|
+
if arg_loc.stack_offset - cc.STACKARG_SP_DIFF in defs_by_stack_offset:
|
|
685
725
|
temp_args.append(arg_loc)
|
|
686
726
|
else:
|
|
687
727
|
# no more arguments
|
|
@@ -2967,10 +2967,13 @@ class CFGEmulated(ForwardAnalysis, CFGBase): # pylint: disable=abstract-method
|
|
|
2967
2967
|
new_state.options.add(o.DO_RET_EMULATION)
|
|
2968
2968
|
# Remove bad constraints
|
|
2969
2969
|
# FIXME: This is so hackish...
|
|
2970
|
-
|
|
2970
|
+
preserved_constraints = [
|
|
2971
2971
|
c for c in new_state.solver.constraints if c.op != "BoolV" or c.args[0] is not False
|
|
2972
2972
|
]
|
|
2973
|
-
new_state.solver._solver.
|
|
2973
|
+
new_solver = new_state.solver._solver.blank_copy()
|
|
2974
|
+
new_solver.add(preserved_constraints)
|
|
2975
|
+
new_state.solver._stored_solver = new_solver
|
|
2976
|
+
|
|
2974
2977
|
# Swap them
|
|
2975
2978
|
saved_state, job.state = job.state, new_state
|
|
2976
2979
|
sim_successors, exception_info, _ = self._get_simsuccessors(addr, job)
|
angr/analyses/cfg/cfg_fast.py
CHANGED
|
@@ -4841,66 +4841,68 @@ class CFGFast(ForwardAnalysis[CFGNode, CFGNode, CFGJob, int], CFGBase): # pylin
|
|
|
4841
4841
|
|
|
4842
4842
|
# determine if the function uses ebp as a general purpose register or not
|
|
4843
4843
|
if addr == func_addr or 0 < addr - func_addr <= 0x20:
|
|
4844
|
-
|
|
4845
|
-
|
|
4846
|
-
|
|
4847
|
-
|
|
4848
|
-
|
|
4849
|
-
and len(insn.operands) == 2
|
|
4850
|
-
and insn.operands[0].type == capstone.x86.X86_OP_REG
|
|
4851
|
-
and insn.operands[1].type == capstone.x86.X86_OP_REG
|
|
4852
|
-
):
|
|
4844
|
+
func = self.kb.functions.get_by_addr(func_addr)
|
|
4845
|
+
if "bp_as_gpr" not in func.info:
|
|
4846
|
+
ebp_as_gpr = True
|
|
4847
|
+
cap = self._lift(addr, size=cfg_node.size).capstone
|
|
4848
|
+
for insn in cap.insns:
|
|
4853
4849
|
if (
|
|
4850
|
+
insn.mnemonic == "mov"
|
|
4851
|
+
and len(insn.operands) == 2
|
|
4852
|
+
and insn.operands[0].type == capstone.x86.X86_OP_REG
|
|
4853
|
+
and insn.operands[1].type == capstone.x86.X86_OP_REG
|
|
4854
|
+
):
|
|
4855
|
+
if (
|
|
4856
|
+
insn.operands[0].reg == capstone.x86.X86_REG_EBP
|
|
4857
|
+
and insn.operands[1].reg == capstone.x86.X86_REG_ESP
|
|
4858
|
+
):
|
|
4859
|
+
ebp_as_gpr = False
|
|
4860
|
+
break
|
|
4861
|
+
elif (
|
|
4862
|
+
insn.mnemonic == "lea"
|
|
4863
|
+
and len(insn.operands) == 2
|
|
4864
|
+
and insn.operands[0].type == capstone.x86.X86_OP_REG
|
|
4865
|
+
and insn.operands[1].type == capstone.x86.X86_OP_MEM
|
|
4866
|
+
) and (
|
|
4854
4867
|
insn.operands[0].reg == capstone.x86.X86_REG_EBP
|
|
4855
|
-
and insn.operands[1].
|
|
4868
|
+
and insn.operands[1].mem.base == capstone.x86.X86_REG_ESP
|
|
4856
4869
|
):
|
|
4857
4870
|
ebp_as_gpr = False
|
|
4858
4871
|
break
|
|
4859
|
-
|
|
4860
|
-
insn.mnemonic == "lea"
|
|
4861
|
-
and len(insn.operands) == 2
|
|
4862
|
-
and insn.operands[0].type == capstone.x86.X86_OP_REG
|
|
4863
|
-
and insn.operands[1].type == capstone.x86.X86_OP_MEM
|
|
4864
|
-
) and (
|
|
4865
|
-
insn.operands[0].reg == capstone.x86.X86_REG_EBP
|
|
4866
|
-
and insn.operands[1].mem.base == capstone.x86.X86_REG_ESP
|
|
4867
|
-
):
|
|
4868
|
-
ebp_as_gpr = False
|
|
4869
|
-
break
|
|
4870
|
-
func = self.kb.functions.get_by_addr(func_addr)
|
|
4871
|
-
func.info["bp_as_gpr"] = ebp_as_gpr
|
|
4872
|
+
func.info["bp_as_gpr"] = ebp_as_gpr
|
|
4872
4873
|
|
|
4873
4874
|
elif self.project.arch.name == "AMD64":
|
|
4874
4875
|
# determine if the function uses rbp as a general purpose register or not
|
|
4875
4876
|
if addr == func_addr or 0 < addr - func_addr <= 0x20:
|
|
4876
|
-
|
|
4877
|
-
|
|
4878
|
-
|
|
4879
|
-
|
|
4880
|
-
|
|
4881
|
-
and len(insn.operands) == 2
|
|
4882
|
-
and insn.operands[0].type == capstone.x86.X86_OP_REG
|
|
4883
|
-
and insn.operands[1].type == capstone.x86.X86_OP_REG
|
|
4884
|
-
):
|
|
4877
|
+
func = self.kb.functions.get_by_addr(func_addr)
|
|
4878
|
+
if "bp_as_gpr" not in func.info:
|
|
4879
|
+
rbp_as_gpr = True
|
|
4880
|
+
cap = self._lift(addr, size=cfg_node.size).capstone
|
|
4881
|
+
for insn in cap.insns:
|
|
4885
4882
|
if (
|
|
4883
|
+
insn.mnemonic == "mov"
|
|
4884
|
+
and len(insn.operands) == 2
|
|
4885
|
+
and insn.operands[0].type == capstone.x86.X86_OP_REG
|
|
4886
|
+
and insn.operands[1].type == capstone.x86.X86_OP_REG
|
|
4887
|
+
):
|
|
4888
|
+
if (
|
|
4889
|
+
insn.operands[0].reg == capstone.x86.X86_REG_RBP
|
|
4890
|
+
and insn.operands[1].reg == capstone.x86.X86_REG_RSP
|
|
4891
|
+
):
|
|
4892
|
+
rbp_as_gpr = False
|
|
4893
|
+
break
|
|
4894
|
+
elif (
|
|
4895
|
+
insn.mnemonic == "lea"
|
|
4896
|
+
and len(insn.operands) == 2
|
|
4897
|
+
and insn.operands[0].type == capstone.x86.X86_OP_REG
|
|
4898
|
+
and insn.operands[1].type == capstone.x86.X86_OP_MEM
|
|
4899
|
+
) and (
|
|
4886
4900
|
insn.operands[0].reg == capstone.x86.X86_REG_RBP
|
|
4887
|
-
and insn.operands[1].
|
|
4901
|
+
and insn.operands[1].mem.base == capstone.x86.X86_REG_RSP
|
|
4888
4902
|
):
|
|
4889
4903
|
rbp_as_gpr = False
|
|
4890
4904
|
break
|
|
4891
|
-
|
|
4892
|
-
insn.mnemonic == "lea"
|
|
4893
|
-
and len(insn.operands) == 2
|
|
4894
|
-
and insn.operands[0].type == capstone.x86.X86_OP_REG
|
|
4895
|
-
and insn.operands[1].type == capstone.x86.X86_OP_MEM
|
|
4896
|
-
) and (
|
|
4897
|
-
insn.operands[0].reg == capstone.x86.X86_REG_RBP
|
|
4898
|
-
and insn.operands[1].mem.base == capstone.x86.X86_REG_RSP
|
|
4899
|
-
):
|
|
4900
|
-
rbp_as_gpr = False
|
|
4901
|
-
break
|
|
4902
|
-
func = self.kb.functions.get_by_addr(func_addr)
|
|
4903
|
-
func.info["bp_as_gpr"] = rbp_as_gpr
|
|
4905
|
+
func.info["bp_as_gpr"] = rbp_as_gpr
|
|
4904
4906
|
|
|
4905
4907
|
def _extract_node_cluster_by_dependency(self, addr, include_successors=False) -> set[int]:
|
|
4906
4908
|
to_remove = {addr}
|
|
@@ -9,7 +9,7 @@ import networkx
|
|
|
9
9
|
|
|
10
10
|
from ailment import AILBlockWalker
|
|
11
11
|
from ailment.block import Block
|
|
12
|
-
from ailment.statement import Statement, Assignment, Store, Call, ConditionalJump, DirtyStatement
|
|
12
|
+
from ailment.statement import Statement, Assignment, Store, Call, ConditionalJump, DirtyStatement, WeakAssignment
|
|
13
13
|
from ailment.expression import (
|
|
14
14
|
Register,
|
|
15
15
|
Convert,
|
|
@@ -247,6 +247,9 @@ class AILSimplifier(Analysis):
|
|
|
247
247
|
):
|
|
248
248
|
codeloc = CodeLocation(block.addr, stmt_idx, block_idx=block.idx, ins_addr=stmt.ins_addr)
|
|
249
249
|
equivalence.add(Equivalence(codeloc, stmt.dst, stmt.src))
|
|
250
|
+
elif isinstance(stmt, WeakAssignment):
|
|
251
|
+
codeloc = CodeLocation(block.addr, stmt_idx, block_idx=block.idx, ins_addr=stmt.ins_addr)
|
|
252
|
+
equivalence.add(Equivalence(codeloc, stmt.dst, stmt.src, is_weakassignment=True))
|
|
250
253
|
elif isinstance(stmt, Call):
|
|
251
254
|
if isinstance(stmt.ret_expr, (VirtualVariable, Load)):
|
|
252
255
|
codeloc = CodeLocation(block.addr, stmt_idx, block_idx=block.idx, ins_addr=stmt.ins_addr)
|
|
@@ -1172,6 +1175,9 @@ class AILSimplifier(Analysis):
|
|
|
1172
1175
|
# register variable = Convert(Call)
|
|
1173
1176
|
call = eq.atom1
|
|
1174
1177
|
# call_addr = call.operand.target.value if isinstance(call.operand.target, Const) else None
|
|
1178
|
+
elif eq.is_weakassignment:
|
|
1179
|
+
# variable =w something else
|
|
1180
|
+
call = eq.atom1
|
|
1175
1181
|
else:
|
|
1176
1182
|
continue
|
|
1177
1183
|
|
|
@@ -1196,6 +1202,9 @@ class AILSimplifier(Analysis):
|
|
|
1196
1202
|
assert the_def.codeloc.stmt_idx is not None
|
|
1197
1203
|
|
|
1198
1204
|
all_uses: set[tuple[Any, CodeLocation]] = rd.get_vvar_uses_with_expr(the_def.atom)
|
|
1205
|
+
if eq.is_weakassignment:
|
|
1206
|
+
# eliminate the "use" at the weak assignment site
|
|
1207
|
+
all_uses = {use for use in all_uses if use[1] != eq.codeloc}
|
|
1199
1208
|
|
|
1200
1209
|
if len(all_uses) != 1:
|
|
1201
1210
|
continue
|
|
@@ -1218,10 +1227,13 @@ class AILSimplifier(Analysis):
|
|
|
1218
1227
|
continue
|
|
1219
1228
|
|
|
1220
1229
|
# check if the use and the definition is within the same supernode
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
|
|
1230
|
+
# also we do not allow any calls between the def site and the use site
|
|
1231
|
+
if not self._loc_within_superblock(
|
|
1232
|
+
addr_and_idx_to_block[(the_def.codeloc.block_addr, the_def.codeloc.block_idx)],
|
|
1233
|
+
u.block_addr,
|
|
1234
|
+
u.block_idx,
|
|
1235
|
+
terminate_with_calls=True,
|
|
1236
|
+
):
|
|
1225
1237
|
continue
|
|
1226
1238
|
|
|
1227
1239
|
# ensure there are no other calls between the def site and the use site.
|
|
@@ -1247,10 +1259,6 @@ class AILSimplifier(Analysis):
|
|
|
1247
1259
|
):
|
|
1248
1260
|
continue
|
|
1249
1261
|
|
|
1250
|
-
# check if there are any calls in between the def site and the use site
|
|
1251
|
-
if self._count_calls_in_supernodeblocks(super_node_blocks, the_def.codeloc, u) > 0:
|
|
1252
|
-
continue
|
|
1253
|
-
|
|
1254
1262
|
# replace all uses
|
|
1255
1263
|
old_block = addr_and_idx_to_block.get((u.block_addr, u.block_idx), None)
|
|
1256
1264
|
if old_block is None:
|
|
@@ -1262,7 +1270,7 @@ class AILSimplifier(Analysis):
|
|
|
1262
1270
|
|
|
1263
1271
|
if isinstance(eq.atom0, VirtualVariable):
|
|
1264
1272
|
src = used_expr
|
|
1265
|
-
dst:
|
|
1273
|
+
dst: Expression = call.copy()
|
|
1266
1274
|
|
|
1267
1275
|
if isinstance(dst, Call) and dst.ret_expr is not None:
|
|
1268
1276
|
dst_bits = dst.ret_expr.bits
|
|
@@ -1272,7 +1280,7 @@ class AILSimplifier(Analysis):
|
|
|
1272
1280
|
dst.fp_ret_expr = None
|
|
1273
1281
|
dst.bits = dst_bits
|
|
1274
1282
|
|
|
1275
|
-
if src.bits != dst.bits:
|
|
1283
|
+
if src.bits != dst.bits and not eq.is_weakassignment:
|
|
1276
1284
|
dst = Convert(None, dst.bits, src.bits, False, dst)
|
|
1277
1285
|
else:
|
|
1278
1286
|
continue
|
|
@@ -1320,6 +1328,42 @@ class AILSimplifier(Analysis):
|
|
|
1320
1328
|
break
|
|
1321
1329
|
return lst
|
|
1322
1330
|
|
|
1331
|
+
def _loc_within_superblock(
|
|
1332
|
+
self, start_node: Block, block_addr: int, block_idx: int | None, terminate_with_calls=False
|
|
1333
|
+
) -> bool:
|
|
1334
|
+
b = start_node
|
|
1335
|
+
if block_addr == b.addr and block_idx == b.idx:
|
|
1336
|
+
return True
|
|
1337
|
+
|
|
1338
|
+
encountered_block_addrs: set[tuple[int, int | None]] = {(b.addr, b.idx)}
|
|
1339
|
+
while True:
|
|
1340
|
+
if terminate_with_calls and b.statements and isinstance(b.statements[-1], Call):
|
|
1341
|
+
return False
|
|
1342
|
+
|
|
1343
|
+
encountered_block_addrs.add((b.addr, b.idx))
|
|
1344
|
+
successors = list(self.func_graph.successors(b))
|
|
1345
|
+
if len(successors) == 0:
|
|
1346
|
+
# did not encounter the block before running out of successors
|
|
1347
|
+
return False
|
|
1348
|
+
if len(successors) == 1:
|
|
1349
|
+
succ = successors[0]
|
|
1350
|
+
# check its predecessors
|
|
1351
|
+
succ_predecessors = list(self.func_graph.predecessors(succ))
|
|
1352
|
+
if len(succ_predecessors) == 1:
|
|
1353
|
+
if (succ.addr, succ.idx) in encountered_block_addrs:
|
|
1354
|
+
# we are about to form a loop - bad!
|
|
1355
|
+
# example: binary ce1897b492c80bf94083dd783aefb413ab1f6d8d4981adce8420f6669d0cb3e1, block
|
|
1356
|
+
# 0x2976EF7.
|
|
1357
|
+
return False
|
|
1358
|
+
if block_addr == succ.addr and block_idx == succ.idx:
|
|
1359
|
+
return True
|
|
1360
|
+
b = succ
|
|
1361
|
+
else:
|
|
1362
|
+
return False
|
|
1363
|
+
else:
|
|
1364
|
+
# too many successors
|
|
1365
|
+
return False
|
|
1366
|
+
|
|
1323
1367
|
@staticmethod
|
|
1324
1368
|
def _replace_expr_and_update_block(block, stmt_idx, stmt, src_expr, dst_expr) -> tuple[bool, Block | None]:
|
|
1325
1369
|
replaced, new_stmt = stmt.replace(src_expr, dst_expr)
|
|
@@ -1492,9 +1536,18 @@ class AILSimplifier(Analysis):
|
|
|
1492
1536
|
simplified = True
|
|
1493
1537
|
|
|
1494
1538
|
if idx in stmts_to_remove and idx not in stmts_to_keep and not isinstance(stmt, DirtyStatement):
|
|
1495
|
-
if isinstance(stmt, (Assignment, Store)):
|
|
1539
|
+
if isinstance(stmt, (Assignment, WeakAssignment, Store)):
|
|
1496
1540
|
# Special logic for Assignment and Store statements
|
|
1497
1541
|
|
|
1542
|
+
# if this statement writes to a virtual variable that must be preserved, we ignore it
|
|
1543
|
+
if (
|
|
1544
|
+
isinstance(stmt, Assignment)
|
|
1545
|
+
and isinstance(stmt.dst, VirtualVariable)
|
|
1546
|
+
and stmt.dst.varid in self._avoid_vvar_ids
|
|
1547
|
+
):
|
|
1548
|
+
new_statements.append(stmt)
|
|
1549
|
+
continue
|
|
1550
|
+
|
|
1498
1551
|
# if this statement triggers a call, it should only be removed if it's in self._calls_to_remove
|
|
1499
1552
|
codeloc = CodeLocation(block.addr, idx, ins_addr=stmt.ins_addr, block_idx=block.idx)
|
|
1500
1553
|
if codeloc in self._assignments_to_remove:
|
|
@@ -1716,26 +1769,6 @@ class AILSimplifier(Analysis):
|
|
|
1716
1769
|
|
|
1717
1770
|
return False
|
|
1718
1771
|
|
|
1719
|
-
@staticmethod
|
|
1720
|
-
def _count_calls_in_supernodeblocks(blocks: list[Block], start: CodeLocation, end: CodeLocation) -> int:
|
|
1721
|
-
"""
|
|
1722
|
-
Count the number of call statements in a list of blocks for a single super block between two given code
|
|
1723
|
-
locations (exclusive).
|
|
1724
|
-
"""
|
|
1725
|
-
calls = 0
|
|
1726
|
-
started = False
|
|
1727
|
-
for b in blocks:
|
|
1728
|
-
if b.addr == start.block_addr:
|
|
1729
|
-
started = True
|
|
1730
|
-
continue
|
|
1731
|
-
if b.addr == end.block_addr:
|
|
1732
|
-
started = False
|
|
1733
|
-
continue
|
|
1734
|
-
|
|
1735
|
-
if started and b.statements and isinstance(b.statements[-1], Call):
|
|
1736
|
-
calls += 1
|
|
1737
|
-
return calls
|
|
1738
|
-
|
|
1739
1772
|
@staticmethod
|
|
1740
1773
|
def _exprs_contain_vvar(exprs: Iterable[Expression], vvar_ids: set[int]) -> bool:
|
|
1741
1774
|
def _handle_VirtualVariable(expr_idx, expr, stmt_idx, stmt, block): # pylint:disable=unused-argument
|
|
@@ -10,6 +10,7 @@ from ailment import AILBlockWalkerBase
|
|
|
10
10
|
|
|
11
11
|
from angr.code_location import ExternalCodeLocation, CodeLocation
|
|
12
12
|
|
|
13
|
+
from angr.knowledge_plugins.key_definitions import atoms
|
|
13
14
|
from angr.analyses.s_propagator import SPropagatorAnalysis
|
|
14
15
|
from angr.analyses.s_reaching_definitions import SReachingDefinitionsAnalysis, SRDAModel
|
|
15
16
|
from angr.analyses import Analysis, register_analysis
|
|
@@ -62,6 +63,8 @@ class BlockSimplifier(Analysis):
|
|
|
62
63
|
peephole_optimizations: None | (
|
|
63
64
|
Iterable[type[PeepholeOptimizationStmtBase] | type[PeepholeOptimizationExprBase]]
|
|
64
65
|
) = None,
|
|
66
|
+
preserve_vvar_ids: set[int] | None = None,
|
|
67
|
+
type_hints: list[tuple[atoms.VirtualVariable | atoms.MemoryLocation, str]] | None = None,
|
|
65
68
|
cached_reaching_definitions=None,
|
|
66
69
|
cached_propagator=None,
|
|
67
70
|
):
|
|
@@ -74,24 +77,35 @@ class BlockSimplifier(Analysis):
|
|
|
74
77
|
self.func_addr = func_addr
|
|
75
78
|
|
|
76
79
|
self._stack_pointer_tracker = stack_pointer_tracker
|
|
80
|
+
self._preserve_vvar_ids = preserve_vvar_ids
|
|
81
|
+
self._type_hints = type_hints
|
|
77
82
|
|
|
78
83
|
if peephole_optimizations is None:
|
|
79
|
-
self._expr_peephole_opts = [
|
|
80
|
-
|
|
81
|
-
|
|
84
|
+
self._expr_peephole_opts = [
|
|
85
|
+
cls(self.project, self.kb, self.func_addr, self._preserve_vvar_ids, self._type_hints)
|
|
86
|
+
for cls in EXPR_OPTS
|
|
87
|
+
]
|
|
88
|
+
self._stmt_peephole_opts = [
|
|
89
|
+
cls(self.project, self.kb, self.func_addr, self._preserve_vvar_ids, self._type_hints)
|
|
90
|
+
for cls in STMT_OPTS
|
|
91
|
+
]
|
|
92
|
+
self._multistmt_peephole_opts = [
|
|
93
|
+
cls(self.project, self.kb, self.func_addr, self._preserve_vvar_ids, self._type_hints)
|
|
94
|
+
for cls in MULTI_STMT_OPTS
|
|
95
|
+
]
|
|
82
96
|
else:
|
|
83
97
|
self._expr_peephole_opts = [
|
|
84
|
-
cls(self.project, self.kb, self.func_addr)
|
|
98
|
+
cls(self.project, self.kb, self.func_addr, self._preserve_vvar_ids, self._type_hints)
|
|
85
99
|
for cls in peephole_optimizations
|
|
86
100
|
if issubclass(cls, PeepholeOptimizationExprBase)
|
|
87
101
|
]
|
|
88
102
|
self._stmt_peephole_opts = [
|
|
89
|
-
cls(self.project, self.kb, self.func_addr)
|
|
103
|
+
cls(self.project, self.kb, self.func_addr, self._preserve_vvar_ids, self._type_hints)
|
|
90
104
|
for cls in peephole_optimizations
|
|
91
105
|
if issubclass(cls, PeepholeOptimizationStmtBase)
|
|
92
106
|
]
|
|
93
107
|
self._multistmt_peephole_opts = [
|
|
94
|
-
cls(self.project, self.kb, self.func_addr)
|
|
108
|
+
cls(self.project, self.kb, self.func_addr, self._preserve_vvar_ids, self._type_hints)
|
|
95
109
|
for cls in peephole_optimizations
|
|
96
110
|
if issubclass(cls, PeepholeOptimizationMultiStmtBase)
|
|
97
111
|
]
|