angr 9.2.156__cp310-cp310-macosx_11_0_arm64.whl → 9.2.157__cp310-cp310-macosx_11_0_arm64.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 +87 -71
- angr/analyses/cfg/cfg_fast.py +5 -0
- angr/analyses/decompiler/clinic.py +182 -104
- angr/analyses/decompiler/decompiler.py +11 -0
- angr/analyses/decompiler/dephication/graph_vvar_mapping.py +1 -1
- angr/analyses/decompiler/structured_codegen/c.py +18 -5
- angr/analyses/disassembly.py +5 -11
- angr/analyses/s_propagator.py +2 -4
- angr/analyses/stack_pointer_tracker.py +3 -7
- angr/analyses/typehoon/simple_solver.py +3 -3
- angr/analyses/variable_recovery/engine_base.py +2 -8
- angr/analyses/variable_recovery/variable_recovery.py +4 -3
- angr/calling_conventions.py +3 -3
- angr/engines/hook.py +1 -1
- angr/engines/icicle.py +229 -0
- angr/engines/pcode/behavior.py +1 -4
- angr/engines/pcode/emulate.py +1 -4
- angr/engines/pcode/lifter.py +2 -10
- angr/engines/vex/claripy/irop.py +2 -2
- angr/knowledge_plugins/functions/function.py +18 -10
- angr/knowledge_plugins/functions/function_manager.py +68 -5
- angr/knowledge_plugins/variables/variable_manager.py +15 -3
- angr/lib/angr_native.dylib +0 -0
- angr/rustylib.cpython-310-darwin.so +0 -0
- angr/sim_variable.py +31 -0
- angr/storage/memory_mixins/address_concretization_mixin.py +2 -2
- angr/storage/memory_mixins/convenient_mappings_mixin.py +1 -1
- {angr-9.2.156.dist-info → angr-9.2.157.dist-info}/METADATA +7 -8
- {angr-9.2.156.dist-info → angr-9.2.157.dist-info}/RECORD +34 -34
- {angr-9.2.156.dist-info → angr-9.2.157.dist-info}/WHEEL +1 -1
- angr/rustylib.pyi +0 -165
- {angr-9.2.156.dist-info → angr-9.2.157.dist-info}/entry_points.txt +0 -0
- {angr-9.2.156.dist-info → angr-9.2.157.dist-info}/licenses/LICENSE +0 -0
- {angr-9.2.156.dist-info → angr-9.2.157.dist-info}/top_level.txt +0 -0
|
@@ -87,6 +87,27 @@ class DataRefDesc:
|
|
|
87
87
|
data_type_str: str
|
|
88
88
|
|
|
89
89
|
|
|
90
|
+
class ClinicStage(enum.IntEnum):
|
|
91
|
+
"""
|
|
92
|
+
Different stages of treating an ailment.
|
|
93
|
+
"""
|
|
94
|
+
|
|
95
|
+
INITIALIZATION = 0
|
|
96
|
+
AIL_GRAPH_CONVERSION = 1
|
|
97
|
+
MAKE_RETURN_SITES = 2
|
|
98
|
+
MAKE_ARGUMENT_LIST = 3
|
|
99
|
+
PRE_SSA_LEVEL0_FIXUPS = 4
|
|
100
|
+
SSA_LEVEL0_TRANSFORMATION = 5
|
|
101
|
+
CONSTANT_PROPAGATION = 6
|
|
102
|
+
TRACK_STACK_POINTERS = 7
|
|
103
|
+
PRE_SSA_LEVEL1_SIMPLIFICATIONS = 8
|
|
104
|
+
SSA_LEVEL1_TRANSFORMATION = 9
|
|
105
|
+
POST_SSA_LEVEL1_SIMPLIFICATIONS = 10
|
|
106
|
+
MAKE_CALLSITES = 11
|
|
107
|
+
POST_CALLSITES = 12
|
|
108
|
+
RECOVER_VARIABLES = 13
|
|
109
|
+
|
|
110
|
+
|
|
90
111
|
class Clinic(Analysis):
|
|
91
112
|
"""
|
|
92
113
|
A Clinic deals with AILments.
|
|
@@ -123,6 +144,9 @@ class Clinic(Analysis):
|
|
|
123
144
|
force_loop_single_exit: bool = True,
|
|
124
145
|
complete_successors: bool = False,
|
|
125
146
|
max_type_constraints: int = 4000,
|
|
147
|
+
ail_graph: networkx.DiGraph | None = None,
|
|
148
|
+
arg_vvars: dict[int, tuple[ailment.Expr.VirtualVariable, SimVariable]] | None = None,
|
|
149
|
+
start_stage: ClinicStage | None = ClinicStage.INITIALIZATION,
|
|
126
150
|
):
|
|
127
151
|
if not func.normalized and mode == ClinicMode.DECOMPILE:
|
|
128
152
|
raise ValueError("Decompilation must work on normalized function graphs.")
|
|
@@ -134,12 +158,16 @@ class Clinic(Analysis):
|
|
|
134
158
|
self.unoptimized_graph: networkx.DiGraph | None = None
|
|
135
159
|
self.arg_list = None
|
|
136
160
|
self.arg_vvars: dict[int, tuple[ailment.Expr.VirtualVariable, SimVariable]] | None = None
|
|
161
|
+
self.func_args = None
|
|
137
162
|
self.variable_kb = variable_kb
|
|
138
163
|
self.externs: set[SimMemoryVariable] = set()
|
|
139
164
|
self.data_refs: dict[int, list[DataRefDesc]] = {} # data address to data reference description
|
|
140
165
|
self.optimization_scratch = optimization_scratch if optimization_scratch is not None else {}
|
|
141
166
|
|
|
142
167
|
self._func_graph: networkx.DiGraph | None = None
|
|
168
|
+
self._init_ail_graph = ail_graph
|
|
169
|
+
self._init_arg_vvars = arg_vvars
|
|
170
|
+
self._start_stage = start_stage if start_stage is not None else ClinicStage.INITIALIZATION
|
|
143
171
|
self._blocks_by_addr_and_size = {}
|
|
144
172
|
self.entry_node_addr: tuple[int, int | None] = self.function.addr, None
|
|
145
173
|
|
|
@@ -163,6 +191,17 @@ class Clinic(Analysis):
|
|
|
163
191
|
# actual stack variables. these secondary stack variables can be safely eliminated if not used by anything.
|
|
164
192
|
self.secondary_stackvars: set[int] = set()
|
|
165
193
|
|
|
194
|
+
#
|
|
195
|
+
# intermediate variables used during decompilation
|
|
196
|
+
#
|
|
197
|
+
|
|
198
|
+
self._ail_graph: networkx.DiGraph = None # type:ignore
|
|
199
|
+
self._spt = None
|
|
200
|
+
# cached block-level reaching definition analysis results and propagator results
|
|
201
|
+
self._block_simplification_cache: dict[ailment.Block, NamedTuple] | None = {}
|
|
202
|
+
self._preserve_vvar_ids: set[int] = set()
|
|
203
|
+
self._type_hints: list[tuple[atoms.VirtualVariable | atoms.MemoryLocation, str]] = []
|
|
204
|
+
|
|
166
205
|
# inlining help
|
|
167
206
|
self._sp_shift = sp_shift
|
|
168
207
|
self._max_stack_depth = 0
|
|
@@ -236,9 +275,14 @@ class Clinic(Analysis):
|
|
|
236
275
|
#
|
|
237
276
|
|
|
238
277
|
def _analyze_for_decompiling(self):
|
|
239
|
-
|
|
278
|
+
# initialize the AIL conversion manager
|
|
279
|
+
self._ail_manager = ailment.Manager(arch=self.project.arch)
|
|
280
|
+
|
|
281
|
+
ail_graph = self._init_ail_graph if self._init_ail_graph is not None else self._decompilation_graph_recovery()
|
|
282
|
+
if not ail_graph:
|
|
240
283
|
return
|
|
241
|
-
|
|
284
|
+
if self._start_stage <= ClinicStage.INITIALIZATION:
|
|
285
|
+
ail_graph = self._decompilation_fixups(ail_graph)
|
|
242
286
|
|
|
243
287
|
if self._inline_functions:
|
|
244
288
|
self._max_stack_depth += self.calculate_stack_depth()
|
|
@@ -270,9 +314,6 @@ class Clinic(Analysis):
|
|
|
270
314
|
self._update_progress(10.0, text="Recovering calling conventions")
|
|
271
315
|
self._recover_calling_conventions()
|
|
272
316
|
|
|
273
|
-
# initialize the AIL conversion manager
|
|
274
|
-
self._ail_manager = ailment.Manager(arch=self.project.arch)
|
|
275
|
-
|
|
276
317
|
# Convert VEX blocks to AIL blocks and then simplify them
|
|
277
318
|
|
|
278
319
|
self._update_progress(20.0, text="Converting VEX to AIL")
|
|
@@ -467,34 +508,68 @@ class Clinic(Analysis):
|
|
|
467
508
|
return depth
|
|
468
509
|
|
|
469
510
|
def _decompilation_simplifications(self, ail_graph):
|
|
470
|
-
|
|
511
|
+
self.arg_vvars = self._init_arg_vvars if self._init_arg_vvars is not None else {}
|
|
512
|
+
self.func_args = {arg_vvar for arg_vvar, _ in self.arg_vvars.values()}
|
|
513
|
+
self._ail_graph = ail_graph
|
|
514
|
+
|
|
515
|
+
stages = {
|
|
516
|
+
ClinicStage.MAKE_RETURN_SITES: self._stage_make_return_sites,
|
|
517
|
+
ClinicStage.MAKE_ARGUMENT_LIST: self._stage_make_function_argument_list,
|
|
518
|
+
ClinicStage.PRE_SSA_LEVEL0_FIXUPS: self._stage_pre_ssa_level0_fixups,
|
|
519
|
+
ClinicStage.SSA_LEVEL0_TRANSFORMATION: self._stage_transform_to_ssa_level0,
|
|
520
|
+
ClinicStage.CONSTANT_PROPAGATION: self._stage_constant_propagation,
|
|
521
|
+
ClinicStage.TRACK_STACK_POINTERS: self._stage_track_stack_pointers,
|
|
522
|
+
ClinicStage.PRE_SSA_LEVEL1_SIMPLIFICATIONS: self._stage_pre_ssa_level1_simplifications,
|
|
523
|
+
ClinicStage.SSA_LEVEL1_TRANSFORMATION: self._stage_transform_to_ssa_level1,
|
|
524
|
+
ClinicStage.POST_SSA_LEVEL1_SIMPLIFICATIONS: self._stage_post_ssa_level1_simplifications,
|
|
525
|
+
ClinicStage.MAKE_CALLSITES: self._stage_make_function_callsites,
|
|
526
|
+
ClinicStage.POST_CALLSITES: self._stage_post_callsite_simplifications,
|
|
527
|
+
ClinicStage.RECOVER_VARIABLES: self._stage_recover_variables,
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
for stage in sorted(stages):
|
|
531
|
+
if stage < self._start_stage:
|
|
532
|
+
continue
|
|
533
|
+
stages[stage]()
|
|
534
|
+
|
|
535
|
+
# remove empty nodes from the graph
|
|
536
|
+
self._ail_graph = self.remove_empty_nodes(self._ail_graph)
|
|
537
|
+
# note that there are still edges to remove before we can structure this graph!
|
|
538
|
+
|
|
539
|
+
self.cc_graph = self.copy_graph(self._ail_graph)
|
|
540
|
+
self.externs = self._collect_externs(self._ail_graph, self.variable_kb)
|
|
541
|
+
return self._ail_graph
|
|
542
|
+
|
|
543
|
+
def _stage_make_return_sites(self) -> None:
|
|
471
544
|
self._update_progress(30.0, text="Making return sites")
|
|
472
545
|
if self.function.prototype is None or not isinstance(self.function.prototype.returnty, SimTypeBottom):
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
ail_graph, stage=OptimizationPassStage.BEFORE_SSA_LEVEL0_TRANSFORMATION
|
|
546
|
+
self._ail_graph = self._make_returns(self._ail_graph)
|
|
547
|
+
self._ail_graph = self._run_simplification_passes(
|
|
548
|
+
self._ail_graph, stage=OptimizationPassStage.BEFORE_SSA_LEVEL0_TRANSFORMATION
|
|
477
549
|
)
|
|
478
550
|
|
|
479
|
-
|
|
551
|
+
def _stage_make_function_argument_list(self) -> None:
|
|
480
552
|
self._update_progress(33.0, text="Making argument list")
|
|
481
|
-
arg_list = self._make_argument_list()
|
|
482
|
-
arg_vvars = self._create_function_argument_vvars(arg_list)
|
|
483
|
-
func_args = {arg_vvar for arg_vvar, _ in arg_vvars.values()}
|
|
553
|
+
self.arg_list = self._make_argument_list()
|
|
554
|
+
self.arg_vvars = self._create_function_argument_vvars(self.arg_list)
|
|
555
|
+
self.func_args = {arg_vvar for arg_vvar, _ in self.arg_vvars.values()}
|
|
484
556
|
|
|
557
|
+
def _stage_pre_ssa_level0_fixups(self) -> None:
|
|
485
558
|
# duplicate orphaned conditional jump blocks
|
|
486
|
-
|
|
559
|
+
self._ail_graph = self._duplicate_orphaned_cond_jumps(self._ail_graph)
|
|
487
560
|
# rewrite jmp_rax function calls
|
|
488
|
-
|
|
561
|
+
self._ail_graph = self._rewrite_jump_rax_calls(self._ail_graph)
|
|
489
562
|
|
|
490
|
-
|
|
491
|
-
self._update_progress(35.0, text="Transforming to partial-SSA form")
|
|
492
|
-
|
|
563
|
+
def _stage_transform_to_ssa_level0(self) -> None:
|
|
564
|
+
self._update_progress(35.0, text="Transforming to partial-SSA form (registers)")
|
|
565
|
+
assert self.func_args is not None
|
|
566
|
+
self._ail_graph = self._transform_to_ssa_level0(self._ail_graph, self.func_args)
|
|
493
567
|
|
|
568
|
+
def _stage_constant_propagation(self) -> None:
|
|
494
569
|
# full-function constant-only propagation
|
|
495
570
|
self._update_progress(36.0, text="Constant propagation")
|
|
496
571
|
self._simplify_function(
|
|
497
|
-
|
|
572
|
+
self._ail_graph,
|
|
498
573
|
remove_dead_memdefs=False,
|
|
499
574
|
unify_variables=False,
|
|
500
575
|
narrow_expressions=False,
|
|
@@ -503,34 +578,34 @@ class Clinic(Analysis):
|
|
|
503
578
|
max_iterations=1,
|
|
504
579
|
)
|
|
505
580
|
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
# Track stack pointers
|
|
510
|
-
self._update_progress(37.0, text="Tracking stack pointers")
|
|
511
|
-
spt = self._track_stack_pointers()
|
|
581
|
+
def _stage_track_stack_pointers(self) -> None:
|
|
582
|
+
self._spt = self._track_stack_pointers()
|
|
512
583
|
|
|
513
|
-
|
|
514
|
-
|
|
584
|
+
def _stage_transform_to_ssa_level1(self) -> None:
|
|
585
|
+
self._update_progress(37.0, text="Transforming to partial-SSA form (stack variables)")
|
|
586
|
+
# rewrite (qualified) stack variables into SSA form
|
|
587
|
+
assert self.func_args is not None
|
|
588
|
+
self._ail_graph = self._transform_to_ssa_level1(self._ail_graph, self.func_args)
|
|
515
589
|
|
|
590
|
+
def _stage_pre_ssa_level1_simplifications(self) -> None:
|
|
516
591
|
# Simplify blocks
|
|
517
592
|
# we never remove dead memory definitions before making callsites. otherwise stack arguments may go missing
|
|
518
593
|
# before they are recognized as stack arguments.
|
|
519
594
|
self._update_progress(38.0, text="Simplifying blocks 1")
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
stack_pointer_tracker=
|
|
523
|
-
cache=
|
|
524
|
-
preserve_vvar_ids=
|
|
525
|
-
type_hints=
|
|
595
|
+
self._ail_graph = self._simplify_blocks(
|
|
596
|
+
self._ail_graph,
|
|
597
|
+
stack_pointer_tracker=self._spt,
|
|
598
|
+
cache=self._block_simplification_cache,
|
|
599
|
+
preserve_vvar_ids=self._preserve_vvar_ids,
|
|
600
|
+
type_hints=self._type_hints,
|
|
526
601
|
)
|
|
527
|
-
self._rewrite_alloca(
|
|
602
|
+
self._rewrite_alloca(self._ail_graph)
|
|
528
603
|
|
|
529
604
|
# Run simplification passes
|
|
530
605
|
self._update_progress(40.0, text="Running simplifications 1")
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
stack_pointer_tracker=
|
|
606
|
+
self._ail_graph = self._run_simplification_passes(
|
|
607
|
+
self._ail_graph,
|
|
608
|
+
stack_pointer_tracker=self._spt,
|
|
534
609
|
stack_items=self.stack_items,
|
|
535
610
|
stage=OptimizationPassStage.AFTER_SINGLE_BLOCK_SIMPLIFICATION,
|
|
536
611
|
)
|
|
@@ -538,160 +613,161 @@ class Clinic(Analysis):
|
|
|
538
613
|
# Simplify the entire function for the first time
|
|
539
614
|
self._update_progress(45.0, text="Simplifying function 1")
|
|
540
615
|
self._simplify_function(
|
|
541
|
-
|
|
616
|
+
self._ail_graph,
|
|
542
617
|
remove_dead_memdefs=False,
|
|
543
618
|
unify_variables=False,
|
|
544
619
|
narrow_expressions=True,
|
|
545
620
|
fold_callexprs_into_conditions=self._fold_callexprs_into_conditions,
|
|
546
|
-
arg_vvars=arg_vvars,
|
|
621
|
+
arg_vvars=self.arg_vvars,
|
|
547
622
|
)
|
|
548
623
|
|
|
549
624
|
# Run simplification passes again. there might be more chances for peephole optimizations after function-level
|
|
550
625
|
# simplification
|
|
551
626
|
self._update_progress(48.0, text="Simplifying blocks 2")
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
stack_pointer_tracker=
|
|
555
|
-
cache=
|
|
556
|
-
preserve_vvar_ids=
|
|
557
|
-
type_hints=
|
|
627
|
+
self._ail_graph = self._simplify_blocks(
|
|
628
|
+
self._ail_graph,
|
|
629
|
+
stack_pointer_tracker=self._spt,
|
|
630
|
+
cache=self._block_simplification_cache,
|
|
631
|
+
preserve_vvar_ids=self._preserve_vvar_ids,
|
|
632
|
+
type_hints=self._type_hints,
|
|
558
633
|
)
|
|
559
634
|
|
|
560
635
|
# Run simplification passes
|
|
561
636
|
self._update_progress(49.0, text="Running simplifications 2")
|
|
562
|
-
|
|
563
|
-
|
|
637
|
+
self._ail_graph = self._run_simplification_passes(
|
|
638
|
+
self._ail_graph, stage=OptimizationPassStage.BEFORE_SSA_LEVEL1_TRANSFORMATION
|
|
564
639
|
)
|
|
565
640
|
|
|
566
|
-
|
|
567
|
-
ail_graph = self._transform_to_ssa_level1(ail_graph, func_args)
|
|
568
|
-
|
|
569
|
-
# clear _blocks_by_addr_and_size so no one can use it again
|
|
570
|
-
# TODO: Totally remove this dict
|
|
571
|
-
self._blocks_by_addr_and_size = None
|
|
572
|
-
|
|
641
|
+
def _stage_post_ssa_level1_simplifications(self) -> None:
|
|
573
642
|
# Rust-specific; only call this on Rust binaries when we can identify language and compiler
|
|
574
|
-
|
|
643
|
+
self._ail_graph = self._rewrite_rust_probestack_call(self._ail_graph)
|
|
575
644
|
# Windows-specific
|
|
576
|
-
|
|
645
|
+
self._ail_graph = self._rewrite_windows_chkstk_call(self._ail_graph)
|
|
646
|
+
|
|
647
|
+
def _stage_make_function_callsites(self) -> None:
|
|
648
|
+
assert self.func_args is not None
|
|
577
649
|
|
|
578
650
|
# Make call-sites
|
|
579
651
|
self._update_progress(50.0, text="Making callsites")
|
|
580
652
|
_, stackarg_offsets, removed_vvar_ids = self._make_callsites(
|
|
581
|
-
|
|
653
|
+
self._ail_graph, self.func_args, stack_pointer_tracker=self._spt, preserve_vvar_ids=self._preserve_vvar_ids
|
|
582
654
|
)
|
|
583
655
|
|
|
584
656
|
# Run simplification passes
|
|
585
657
|
self._update_progress(53.0, text="Running simplifications 2")
|
|
586
|
-
|
|
658
|
+
self._ail_graph = self._run_simplification_passes(
|
|
659
|
+
self._ail_graph, stage=OptimizationPassStage.AFTER_MAKING_CALLSITES
|
|
660
|
+
)
|
|
587
661
|
|
|
588
662
|
# Simplify the entire function for the second time
|
|
589
663
|
self._update_progress(55.0, text="Simplifying function 2")
|
|
590
664
|
self._simplify_function(
|
|
591
|
-
|
|
665
|
+
self._ail_graph,
|
|
592
666
|
remove_dead_memdefs=self._remove_dead_memdefs,
|
|
593
667
|
stack_arg_offsets=stackarg_offsets,
|
|
594
668
|
unify_variables=True,
|
|
595
669
|
narrow_expressions=True,
|
|
596
670
|
fold_callexprs_into_conditions=self._fold_callexprs_into_conditions,
|
|
597
671
|
removed_vvar_ids=removed_vvar_ids,
|
|
598
|
-
arg_vvars=arg_vvars,
|
|
599
|
-
preserve_vvar_ids=
|
|
672
|
+
arg_vvars=self.arg_vvars,
|
|
673
|
+
preserve_vvar_ids=self._preserve_vvar_ids,
|
|
600
674
|
)
|
|
601
675
|
|
|
602
676
|
# After global optimization, there might be more chances for peephole optimizations.
|
|
603
677
|
# Simplify blocks for the second time
|
|
604
678
|
self._update_progress(60.0, text="Simplifying blocks 3")
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
stack_pointer_tracker=
|
|
608
|
-
cache=
|
|
609
|
-
preserve_vvar_ids=
|
|
610
|
-
type_hints=
|
|
679
|
+
self._ail_graph = self._simplify_blocks(
|
|
680
|
+
self._ail_graph,
|
|
681
|
+
stack_pointer_tracker=self._spt,
|
|
682
|
+
cache=self._block_simplification_cache,
|
|
683
|
+
preserve_vvar_ids=self._preserve_vvar_ids,
|
|
684
|
+
type_hints=self._type_hints,
|
|
611
685
|
)
|
|
612
686
|
|
|
613
687
|
# Run simplification passes
|
|
614
688
|
self._update_progress(65.0, text="Running simplifications 3")
|
|
615
|
-
|
|
616
|
-
|
|
689
|
+
self._ail_graph = self._run_simplification_passes(
|
|
690
|
+
self._ail_graph, stack_items=self.stack_items, stage=OptimizationPassStage.AFTER_GLOBAL_SIMPLIFICATION
|
|
617
691
|
)
|
|
618
692
|
|
|
619
693
|
# Simplify the entire function for the third time
|
|
620
694
|
self._update_progress(70.0, text="Simplifying function 3")
|
|
621
695
|
self._simplify_function(
|
|
622
|
-
|
|
696
|
+
self._ail_graph,
|
|
623
697
|
remove_dead_memdefs=self._remove_dead_memdefs,
|
|
624
698
|
stack_arg_offsets=stackarg_offsets,
|
|
625
699
|
unify_variables=True,
|
|
626
700
|
narrow_expressions=True,
|
|
627
701
|
fold_callexprs_into_conditions=self._fold_callexprs_into_conditions,
|
|
628
|
-
arg_vvars=arg_vvars,
|
|
629
|
-
preserve_vvar_ids=
|
|
702
|
+
arg_vvars=self.arg_vvars,
|
|
703
|
+
preserve_vvar_ids=self._preserve_vvar_ids,
|
|
630
704
|
)
|
|
631
705
|
|
|
632
706
|
self._update_progress(75.0, text="Simplifying blocks 4")
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
stack_pointer_tracker=
|
|
636
|
-
cache=
|
|
637
|
-
preserve_vvar_ids=
|
|
638
|
-
type_hints=
|
|
707
|
+
self._ail_graph = self._simplify_blocks(
|
|
708
|
+
self._ail_graph,
|
|
709
|
+
stack_pointer_tracker=self._spt,
|
|
710
|
+
cache=self._block_simplification_cache,
|
|
711
|
+
preserve_vvar_ids=self._preserve_vvar_ids,
|
|
712
|
+
type_hints=self._type_hints,
|
|
639
713
|
)
|
|
640
714
|
|
|
641
715
|
# Simplify the entire function for the fourth time
|
|
642
716
|
self._update_progress(78.0, text="Simplifying function 4")
|
|
643
717
|
self._simplify_function(
|
|
644
|
-
|
|
718
|
+
self._ail_graph,
|
|
645
719
|
remove_dead_memdefs=self._remove_dead_memdefs,
|
|
646
720
|
stack_arg_offsets=stackarg_offsets,
|
|
647
721
|
unify_variables=True,
|
|
648
722
|
narrow_expressions=True,
|
|
649
723
|
fold_callexprs_into_conditions=self._fold_callexprs_into_conditions,
|
|
650
|
-
arg_vvars=arg_vvars,
|
|
651
|
-
preserve_vvar_ids=
|
|
724
|
+
arg_vvars=self.arg_vvars,
|
|
725
|
+
preserve_vvar_ids=self._preserve_vvar_ids,
|
|
652
726
|
)
|
|
653
727
|
|
|
654
728
|
self._update_progress(79.0, text="Running simplifications 4")
|
|
655
|
-
|
|
656
|
-
|
|
729
|
+
self._ail_graph = self._run_simplification_passes(
|
|
730
|
+
self._ail_graph, stack_items=self.stack_items, stage=OptimizationPassStage.BEFORE_VARIABLE_RECOVERY
|
|
657
731
|
)
|
|
658
732
|
|
|
733
|
+
def _stage_post_callsite_simplifications(self) -> None:
|
|
734
|
+
self.arg_list = []
|
|
735
|
+
self.vvar_to_vvar = {}
|
|
736
|
+
self.copied_var_ids = set()
|
|
737
|
+
|
|
738
|
+
assert self.arg_vvars is not None
|
|
739
|
+
|
|
659
740
|
# update arg_list
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
arg_list.append(arg_vvars[idx][1])
|
|
741
|
+
for idx in sorted(self.arg_vvars):
|
|
742
|
+
self.arg_list.append(self.arg_vvars[idx][1])
|
|
663
743
|
|
|
664
744
|
# Get virtual variable mapping that can de-phi the SSA representation
|
|
665
|
-
|
|
745
|
+
self.vvar_to_vvar, self.copied_var_ids = self._collect_dephi_vvar_mapping_and_rewrite_blocks(
|
|
746
|
+
self._ail_graph, self.arg_vvars
|
|
747
|
+
)
|
|
748
|
+
|
|
749
|
+
def _stage_recover_variables(self) -> None:
|
|
750
|
+
assert self.arg_list is not None and self.arg_vvars is not None and self.vvar_to_vvar is not None
|
|
666
751
|
|
|
667
752
|
# Recover variables on AIL blocks
|
|
668
753
|
self._update_progress(80.0, text="Recovering variables")
|
|
669
|
-
variable_kb = self._recover_and_link_variables(
|
|
754
|
+
variable_kb = self._recover_and_link_variables(
|
|
755
|
+
self._ail_graph, self.arg_list, self.arg_vvars, self.vvar_to_vvar, self._type_hints
|
|
756
|
+
)
|
|
670
757
|
|
|
671
758
|
# Run simplification passes
|
|
672
759
|
self._update_progress(85.0, text="Running simplifications 4")
|
|
673
|
-
|
|
674
|
-
|
|
760
|
+
self._ail_graph = self._run_simplification_passes(
|
|
761
|
+
self._ail_graph,
|
|
675
762
|
stage=OptimizationPassStage.AFTER_VARIABLE_RECOVERY,
|
|
676
|
-
avoid_vvar_ids=
|
|
763
|
+
avoid_vvar_ids=self.copied_var_ids,
|
|
677
764
|
)
|
|
678
765
|
|
|
679
766
|
# Make function prototype
|
|
680
767
|
self._update_progress(90.0, text="Making function prototype")
|
|
681
|
-
self._make_function_prototype(arg_list, variable_kb)
|
|
768
|
+
self._make_function_prototype(self.arg_list, variable_kb)
|
|
682
769
|
|
|
683
|
-
# remove empty nodes from the graph
|
|
684
|
-
ail_graph = self.remove_empty_nodes(ail_graph)
|
|
685
|
-
# note that there are still edges to remove before we can structure this graph!
|
|
686
|
-
|
|
687
|
-
self.arg_list = arg_list
|
|
688
|
-
self.arg_vvars = arg_vvars
|
|
689
770
|
self.variable_kb = variable_kb
|
|
690
|
-
self.cc_graph = self.copy_graph(ail_graph)
|
|
691
|
-
self.externs = self._collect_externs(ail_graph, variable_kb)
|
|
692
|
-
self.vvar_to_vvar = vvar2vvar
|
|
693
|
-
self.copied_var_ids = copied_vvar_ids
|
|
694
|
-
return ail_graph
|
|
695
771
|
|
|
696
772
|
def _analyze_for_data_refs(self):
|
|
697
773
|
# Set up the function graph according to configurations
|
|
@@ -1813,6 +1889,8 @@ class Clinic(Analysis):
|
|
|
1813
1889
|
},
|
|
1814
1890
|
)
|
|
1815
1891
|
except Exception: # pylint:disable=broad-except
|
|
1892
|
+
if self._fail_fast:
|
|
1893
|
+
raise
|
|
1816
1894
|
l.warning(
|
|
1817
1895
|
"Typehoon analysis failed. Variables will not have types. Please report to GitHub.", exc_info=True
|
|
1818
1896
|
)
|
|
@@ -72,6 +72,9 @@ class Decompiler(Analysis):
|
|
|
72
72
|
generate_code: bool = True,
|
|
73
73
|
use_cache: bool = True,
|
|
74
74
|
expr_collapse_depth: int = 16,
|
|
75
|
+
clinic_graph=None,
|
|
76
|
+
clinic_arg_vvars=None,
|
|
77
|
+
clinic_start_stage=None,
|
|
75
78
|
):
|
|
76
79
|
if not isinstance(func, Function):
|
|
77
80
|
func = self.kb.functions[func]
|
|
@@ -129,6 +132,9 @@ class Decompiler(Analysis):
|
|
|
129
132
|
)
|
|
130
133
|
|
|
131
134
|
self.clinic = None # mostly for debugging purposes
|
|
135
|
+
self._clinic_graph = clinic_graph
|
|
136
|
+
self._clinic_arg_vvars = clinic_arg_vvars
|
|
137
|
+
self._clinic_start_stage = clinic_start_stage
|
|
132
138
|
self.codegen: CStructuredCodeGenerator | None = None
|
|
133
139
|
self.cache: DecompilationCache | None = None
|
|
134
140
|
self.options_by_class = None
|
|
@@ -256,6 +262,9 @@ class Decompiler(Analysis):
|
|
|
256
262
|
optimization_scratch=self._optimization_scratch,
|
|
257
263
|
force_loop_single_exit=self._force_loop_single_exit,
|
|
258
264
|
complete_successors=self._complete_successors,
|
|
265
|
+
ail_graph=self._clinic_graph,
|
|
266
|
+
arg_vvars=self._clinic_arg_vvars,
|
|
267
|
+
start_stage=self._clinic_start_stage,
|
|
259
268
|
**self.options_to_params(self.options_by_class["clinic"]),
|
|
260
269
|
)
|
|
261
270
|
else:
|
|
@@ -616,6 +625,8 @@ class Decompiler(Analysis):
|
|
|
616
625
|
self.func.prototype.args[:i] + (new_type,) + self.func.prototype.args[i + 1 :]
|
|
617
626
|
)
|
|
618
627
|
except Exception: # pylint:disable=broad-except
|
|
628
|
+
if self._fail_fast:
|
|
629
|
+
raise
|
|
619
630
|
l.warning(
|
|
620
631
|
"Typehoon analysis failed. Variables will not have types. Please report to GitHub.", exc_info=True
|
|
621
632
|
)
|
|
@@ -158,7 +158,7 @@ class GraphDephicationVVarMapping(Analysis): # pylint:disable=abstract-method
|
|
|
158
158
|
for vvar_id in live_outs[src]:
|
|
159
159
|
interference.add_edge(new_vvar_id, vvar_id)
|
|
160
160
|
|
|
161
|
-
else: # insertion_type == 1
|
|
161
|
+
else: # insertion_type == 1, i.e. the set has only one element
|
|
162
162
|
phi_block_loc, old_phi_varid, new_phi_varid = next(iter(new_vvar_ids))
|
|
163
163
|
self.copied_vvar_ids.add(new_phi_varid)
|
|
164
164
|
|
|
@@ -1332,10 +1332,13 @@ class CFunctionCall(CStatement, CExpression):
|
|
|
1332
1332
|
return False
|
|
1333
1333
|
|
|
1334
1334
|
@staticmethod
|
|
1335
|
-
def
|
|
1335
|
+
def _is_func_likely_method(func_name: str, rust: bool) -> bool:
|
|
1336
1336
|
if "::" not in func_name:
|
|
1337
1337
|
return False
|
|
1338
1338
|
chunks = func_name.split("::")
|
|
1339
|
+
if rust and re.match(r"[A-Z][a-zA-Z0-9_]*", chunks[-2]) is None:
|
|
1340
|
+
# let's say that rust structs are always UpperCamelCase
|
|
1341
|
+
return False
|
|
1339
1342
|
return re.match(r"[a-zA-Z_][a-zA-Z0-9_]*", chunks[-1]) is not None
|
|
1340
1343
|
|
|
1341
1344
|
def c_repr_chunks(self, indent=0, asexpr: bool = False):
|
|
@@ -1357,7 +1360,11 @@ class CFunctionCall(CStatement, CExpression):
|
|
|
1357
1360
|
func_name = get_cpp_function_name(self.callee_func.demangled_name, specialized=False, qualified=True)
|
|
1358
1361
|
else:
|
|
1359
1362
|
func_name = self.callee_func.name
|
|
1360
|
-
if
|
|
1363
|
+
if (
|
|
1364
|
+
self.prettify_thiscall
|
|
1365
|
+
and self.args
|
|
1366
|
+
and self._is_func_likely_method(func_name, self.callee_func.is_rust_function())
|
|
1367
|
+
):
|
|
1361
1368
|
func_name = self.callee_func.short_name
|
|
1362
1369
|
yield from self._c_repr_chunks_thiscall(func_name, asexpr=asexpr)
|
|
1363
1370
|
return
|
|
@@ -3571,7 +3578,13 @@ class CStructuredCodeGenerator(BaseStructuredCodeGenerator, Analysis):
|
|
|
3571
3578
|
return self._variable(SimTemporaryVariable(expr.tmp_idx, expr.bits), expr.size)
|
|
3572
3579
|
|
|
3573
3580
|
def _handle_Expr_Const(
|
|
3574
|
-
self,
|
|
3581
|
+
self,
|
|
3582
|
+
expr: Expr.Const,
|
|
3583
|
+
type_=None,
|
|
3584
|
+
reference_values: dict[SimType | str, str | bytes | int | float | Function | CExpression] | None = None,
|
|
3585
|
+
variable=None,
|
|
3586
|
+
likely_signed=True,
|
|
3587
|
+
**kwargs,
|
|
3575
3588
|
):
|
|
3576
3589
|
inline_string = False
|
|
3577
3590
|
function_pointer = False
|
|
@@ -3581,8 +3594,8 @@ class CStructuredCodeGenerator(BaseStructuredCodeGenerator, Analysis):
|
|
|
3581
3594
|
|
|
3582
3595
|
if type_ is None and reference_values is None and hasattr(expr, "reference_values"):
|
|
3583
3596
|
reference_values = expr.reference_values.copy()
|
|
3584
|
-
if reference_values:
|
|
3585
|
-
type_ = next(iter(reference_values))
|
|
3597
|
+
if len(reference_values) == 1: # type: ignore
|
|
3598
|
+
type_ = next(iter(reference_values)) # type: ignore
|
|
3586
3599
|
|
|
3587
3600
|
if reference_values is None:
|
|
3588
3601
|
reference_values = {}
|
angr/analyses/disassembly.py
CHANGED
|
@@ -6,12 +6,13 @@ from collections import defaultdict
|
|
|
6
6
|
from collections.abc import Sequence
|
|
7
7
|
from typing import Any
|
|
8
8
|
|
|
9
|
-
import pyvex
|
|
10
9
|
import archinfo
|
|
10
|
+
import pypcode
|
|
11
|
+
import pyvex
|
|
11
12
|
|
|
12
13
|
from . import Analysis
|
|
13
|
-
|
|
14
14
|
from angr.analyses import AnalysesHub
|
|
15
|
+
from angr.engines import pcode
|
|
15
16
|
from angr.errors import AngrTypeError
|
|
16
17
|
from angr.knowledge_plugins import Function
|
|
17
18
|
from angr.utils.library import get_cpp_function_name
|
|
@@ -20,16 +21,9 @@ from angr.block import DisassemblerInsn, CapstoneInsn, SootBlockNode
|
|
|
20
21
|
from angr.codenode import BlockNode
|
|
21
22
|
from .disassembly_utils import decode_instruction
|
|
22
23
|
|
|
23
|
-
try:
|
|
24
|
-
from angr.engines import pcode
|
|
25
|
-
import pypcode
|
|
26
24
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
except ImportError:
|
|
30
|
-
pcode = None
|
|
31
|
-
IRSBType = pyvex.IRSB
|
|
32
|
-
IROpObjType = pyvex.stmt
|
|
25
|
+
IRSBType = pyvex.IRSB | pcode.lifter.IRSB
|
|
26
|
+
IROpObjType = pyvex.stmt.IRStmt | pypcode.PcodeOp
|
|
33
27
|
|
|
34
28
|
l = logging.getLogger(name=__name__)
|
|
35
29
|
|
angr/analyses/s_propagator.py
CHANGED
|
@@ -409,9 +409,8 @@ class SPropagatorAnalysis(Analysis):
|
|
|
409
409
|
][tmp_used] = v
|
|
410
410
|
continue
|
|
411
411
|
|
|
412
|
-
if len(tmp_uses) <= 2:
|
|
413
|
-
tmp_used, tmp_use_stmtidx
|
|
414
|
-
if is_const_vvar_load_dirty_assignment(stmt):
|
|
412
|
+
if len(tmp_uses) <= 2 and is_const_vvar_load_dirty_assignment(stmt):
|
|
413
|
+
for tmp_used, tmp_use_stmtidx in tmp_uses:
|
|
415
414
|
same_inst = (
|
|
416
415
|
block.statements[tmp_def_stmtidx].ins_addr == block.statements[tmp_use_stmtidx].ins_addr
|
|
417
416
|
)
|
|
@@ -426,7 +425,6 @@ class SPropagatorAnalysis(Analysis):
|
|
|
426
425
|
replacements[
|
|
427
426
|
CodeLocation(block_loc.block_addr, tmp_use_stmtidx, block_idx=block_loc.block_idx)
|
|
428
427
|
][tmp_used] = stmt.src
|
|
429
|
-
continue
|
|
430
428
|
|
|
431
429
|
self.model.replacements = replacements
|
|
432
430
|
|
|
@@ -7,10 +7,12 @@ import re
|
|
|
7
7
|
import logging
|
|
8
8
|
from collections import defaultdict
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
import pypcode
|
|
11
11
|
import pyvex
|
|
12
|
+
from archinfo.arch_arm import is_arm_arch
|
|
12
13
|
|
|
13
14
|
from angr.analyses import ForwardAnalysis, visitors
|
|
15
|
+
from angr.engines import pcode
|
|
14
16
|
from angr.utils.constants import is_alignment_mask
|
|
15
17
|
from angr.analyses import AnalysesHub
|
|
16
18
|
from angr.knowledge_plugins import Function
|
|
@@ -21,12 +23,6 @@ from angr.utils.types import dereference_simtype_by_lib
|
|
|
21
23
|
|
|
22
24
|
from .analysis import Analysis
|
|
23
25
|
|
|
24
|
-
try:
|
|
25
|
-
import pypcode
|
|
26
|
-
from angr.engines import pcode
|
|
27
|
-
except ImportError:
|
|
28
|
-
pypcode = None
|
|
29
|
-
pcode = None
|
|
30
26
|
|
|
31
27
|
if TYPE_CHECKING:
|
|
32
28
|
from angr.block import Block
|