angr 9.2.181__cp310-abi3-win_amd64.whl → 9.2.182__cp310-abi3-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/ailment/expression.py +2 -2
- angr/analyses/decompiler/ail_simplifier.py +77 -5
- angr/analyses/decompiler/callsite_maker.py +6 -1
- angr/analyses/decompiler/clinic.py +22 -10
- angr/analyses/decompiler/dephication/graph_vvar_mapping.py +4 -10
- angr/analyses/decompiler/ssailification/rewriting.py +82 -10
- angr/analyses/decompiler/ssailification/rewriting_engine.py +22 -11
- angr/analyses/decompiler/ssailification/ssailification.py +7 -5
- angr/analyses/s_reaching_definitions/s_rda_view.py +38 -16
- angr/analyses/s_reaching_definitions/s_reaching_definitions.py +59 -6
- angr/engines/pcode/behavior.py +6 -2
- angr/knowledge_plugins/functions/function_manager.py +1 -1
- angr/knowledge_plugins/variables/variable_manager.py +10 -19
- angr/procedures/definitions/parse_glibc.py +0 -1
- angr/procedures/definitions/parse_win32json.py +12 -3
- angr/procedures/definitions/wdk/fltmgr.json +11 -11
- angr/procedures/definitions/wdk/fwpuclnt.json +32 -32
- angr/procedures/definitions/wdk/gdi32.json +1 -1
- angr/procedures/definitions/wdk/ntoskrnl.json +61 -61
- angr/procedures/definitions/win32/_types_win32.json +1103 -1102
- angr/procedures/definitions/win32/activeds.json +2 -2
- angr/procedures/definitions/win32/advapi32.json +47 -47
- angr/procedures/definitions/win32/apphelp.json +1 -1
- angr/procedures/definitions/win32/avifil32.json +10 -10
- angr/procedures/definitions/win32/avrt.json +4 -4
- angr/procedures/definitions/win32/bluetoothapis.json +3 -3
- angr/procedures/definitions/win32/certpoleng.json +1 -1
- angr/procedures/definitions/win32/cfgmgr32.json +43 -43
- angr/procedures/definitions/win32/clusapi.json +1 -1
- angr/procedures/definitions/win32/comctl32.json +3 -3
- angr/procedures/definitions/win32/computenetwork.json +14 -14
- angr/procedures/definitions/win32/comsvcs.json +3 -3
- angr/procedures/definitions/win32/crypt32.json +5 -5
- angr/procedures/definitions/win32/d2d1.json +1 -1
- angr/procedures/definitions/win32/d3d12.json +6 -6
- angr/procedures/definitions/win32/d3dcompiler_47.json +2 -2
- angr/procedures/definitions/win32/dbgeng.json +4 -4
- angr/procedures/definitions/win32/dbghelp.json +2 -2
- angr/procedures/definitions/win32/dcomp.json +4 -4
- angr/procedures/definitions/win32/ddraw.json +6 -6
- angr/procedures/definitions/win32/diagnosticdataquery.json +1 -1
- angr/procedures/definitions/win32/dinput8.json +1 -1
- angr/procedures/definitions/win32/directml.json +2 -2
- angr/procedures/definitions/win32/dsound.json +10 -10
- angr/procedures/definitions/win32/dsparse.json +2 -2
- angr/procedures/definitions/win32/dwmapi.json +1 -1
- angr/procedures/definitions/win32/dwrite.json +1 -1
- angr/procedures/definitions/win32/dxcompiler.json +2 -2
- angr/procedures/definitions/win32/dxcore.json +1 -1
- angr/procedures/definitions/win32/dxgi.json +4 -4
- angr/procedures/definitions/win32/dxva2.json +1 -1
- angr/procedures/definitions/win32/eappprxy.json +3 -3
- angr/procedures/definitions/win32/evr.json +4 -4
- angr/procedures/definitions/win32/fwpuclnt.json +32 -32
- angr/procedures/definitions/win32/gdiplus.json +9 -9
- angr/procedures/definitions/win32/hid.json +1 -1
- angr/procedures/definitions/win32/hlink.json +7 -7
- angr/procedures/definitions/win32/ieframe.json +4 -4
- angr/procedures/definitions/win32/imgutil.json +1 -1
- angr/procedures/definitions/win32/inkobjcore.json +4 -4
- angr/procedures/definitions/win32/iphlpapi.json +8 -8
- angr/procedures/definitions/win32/kernel32.json +5 -5
- angr/procedures/definitions/win32/ksproxy_ax.json +2 -2
- angr/procedures/definitions/win32/ktmw32.json +10 -10
- angr/procedures/definitions/win32/mapi32.json +2 -2
- angr/procedures/definitions/win32/mf.json +5 -5
- angr/procedures/definitions/win32/mfplat.json +33 -33
- angr/procedures/definitions/win32/mfsensorgroup.json +2 -2
- angr/procedures/definitions/win32/mmdevapi.json +1 -1
- angr/procedures/definitions/win32/mqrt.json +2 -2
- angr/procedures/definitions/win32/mscoree.json +9 -9
- angr/procedures/definitions/win32/msdmo.json +5 -5
- angr/procedures/definitions/win32/mswsock.json +8 -8
- angr/procedures/definitions/win32/ndfapi.json +1 -1
- angr/procedures/definitions/win32/netapi32.json +6 -6
- angr/procedures/definitions/win32/netsh.json +1 -1
- angr/procedures/definitions/win32/ntdll.json +1 -1
- angr/procedures/definitions/win32/ntdsapi.json +14 -14
- angr/procedures/definitions/win32/ntlanman.json +3 -3
- angr/procedures/definitions/win32/ole32.json +78 -78
- angr/procedures/definitions/win32/oleacc.json +6 -6
- angr/procedures/definitions/win32/oleaut32.json +15 -15
- angr/procedures/definitions/win32/oledlg.json +1 -1
- angr/procedures/definitions/win32/p2p.json +11 -11
- angr/procedures/definitions/win32/p2pgraph.json +7 -7
- angr/procedures/definitions/win32/pdh.json +1 -1
- angr/procedures/definitions/win32/powrprof.json +47 -47
- angr/procedures/definitions/win32/projectedfslib.json +2 -2
- angr/procedures/definitions/win32/propsys.json +25 -25
- angr/procedures/definitions/win32/query.json +1 -1
- angr/procedures/definitions/win32/resutils.json +1 -1
- angr/procedures/definitions/win32/rpcns4.json +5 -5
- angr/procedures/definitions/win32/rpcrt4.json +33 -33
- angr/procedures/definitions/win32/rtm.json +1 -1
- angr/procedures/definitions/win32/sensorsutilsv2.json +4 -4
- angr/procedures/definitions/win32/setupapi.json +49 -49
- angr/procedures/definitions/win32/shell32.json +34 -34
- angr/procedures/definitions/win32/shlwapi.json +7 -7
- angr/procedures/definitions/win32/slc.json +25 -25
- angr/procedures/definitions/win32/slcext.json +2 -2
- angr/procedures/definitions/win32/slwga.json +1 -1
- angr/procedures/definitions/win32/tapi32.json +4 -4
- angr/procedures/definitions/win32/tdh.json +6 -6
- angr/procedures/definitions/win32/traffic.json +6 -6
- angr/procedures/definitions/win32/txfw32.json +1 -1
- angr/procedures/definitions/win32/uiautomationcore.json +1 -1
- angr/procedures/definitions/win32/urlmon.json +6 -6
- angr/procedures/definitions/win32/user32.json +1 -1
- angr/procedures/definitions/win32/userenv.json +4 -4
- angr/procedures/definitions/win32/virtdisk.json +4 -4
- angr/procedures/definitions/win32/vmdevicehost.json +1 -1
- angr/procedures/definitions/win32/wcmapi.json +2 -2
- angr/procedures/definitions/win32/webauthn.json +2 -2
- angr/procedures/definitions/win32/winbio.json +2 -2
- angr/procedures/definitions/win32/windows_ui_xaml.json +2 -2
- angr/procedures/definitions/win32/windowscodecs.json +9 -9
- angr/procedures/definitions/win32/winhttp.json +1 -1
- angr/procedures/definitions/win32/winhvplatform.json +1 -1
- angr/procedures/definitions/win32/winscard.json +12 -12
- angr/procedures/definitions/win32/winspool_drv.json +4 -4
- angr/procedures/definitions/win32/wintrust.json +9 -9
- angr/procedures/definitions/win32/wlanapi.json +27 -27
- angr/procedures/definitions/win32/wlanui.json +1 -1
- angr/procedures/definitions/win32/wldp.json +4 -4
- angr/procedures/definitions/win32/ws2_32.json +34 -34
- angr/procedures/definitions/win32/xaudio2_8.json +1 -1
- angr/procedures/definitions/win32/xmllite.json +2 -2
- angr/procedures/definitions/win32/xolehlp.json +4 -4
- angr/project.py +4 -1
- angr/rustylib.pyd +0 -0
- angr/unicornlib.dll +0 -0
- angr/utils/ail.py +107 -1
- {angr-9.2.181.dist-info → angr-9.2.182.dist-info}/METADATA +5 -5
- {angr-9.2.181.dist-info → angr-9.2.182.dist-info}/RECORD +139 -139
- {angr-9.2.181.dist-info → angr-9.2.182.dist-info}/WHEEL +0 -0
- {angr-9.2.181.dist-info → angr-9.2.182.dist-info}/entry_points.txt +0 -0
- {angr-9.2.181.dist-info → angr-9.2.182.dist-info}/licenses/LICENSE +0 -0
- {angr-9.2.181.dist-info → angr-9.2.182.dist-info}/top_level.txt +0 -0
angr/__init__.py
CHANGED
angr/ailment/expression.py
CHANGED
|
@@ -345,9 +345,9 @@ class VirtualVariable(Atom):
|
|
|
345
345
|
ori_str = ""
|
|
346
346
|
match self.category:
|
|
347
347
|
case VirtualVariableCategory.REGISTER:
|
|
348
|
-
ori_str = f"{{
|
|
348
|
+
ori_str = f"{{r{self.reg_offset}|{self.size}b}}"
|
|
349
349
|
case VirtualVariableCategory.STACK:
|
|
350
|
-
ori_str = f"{{
|
|
350
|
+
ori_str = f"{{s{self.oident}|{self.size}b}}"
|
|
351
351
|
return f"vvar_{self.varid}{ori_str}"
|
|
352
352
|
|
|
353
353
|
__hash__ = TaggedObject.__hash__ # type: ignore
|
|
@@ -37,7 +37,7 @@ from angr.ailment.expression import (
|
|
|
37
37
|
|
|
38
38
|
from angr.analyses.s_propagator import SPropagatorAnalysis
|
|
39
39
|
from angr.analyses.s_reaching_definitions import SRDAModel
|
|
40
|
-
from angr.utils.ail import is_phi_assignment, HasExprWalker
|
|
40
|
+
from angr.utils.ail import is_phi_assignment, HasExprWalker, is_expr_used_as_reg_base_value
|
|
41
41
|
from angr.utils.ssa import (
|
|
42
42
|
has_call_in_between_stmts,
|
|
43
43
|
has_store_stmt_in_between_stmts,
|
|
@@ -315,7 +315,7 @@ class AILSimplifier(Analysis):
|
|
|
315
315
|
subject=self.func,
|
|
316
316
|
func_graph=self.func_graph,
|
|
317
317
|
func_args=func_args,
|
|
318
|
-
|
|
318
|
+
use_callee_saved_regs_at_return=self._use_callee_saved_regs_at_return,
|
|
319
319
|
# track_tmps=True,
|
|
320
320
|
).model
|
|
321
321
|
self._reaching_definitions = rd
|
|
@@ -406,6 +406,10 @@ class AILSimplifier(Analysis):
|
|
|
406
406
|
|
|
407
407
|
rd = self._compute_reaching_definitions()
|
|
408
408
|
sorted_defs = sorted(rd.all_definitions, key=lambda d: d.codeloc, reverse=True)
|
|
409
|
+
|
|
410
|
+
# compute effective sizes for each vvar
|
|
411
|
+
effective_sizes = self._compute_effective_sizes(rd, sorted_defs, addr_and_idx_to_block)
|
|
412
|
+
|
|
409
413
|
narrowing_candidates: dict[int, tuple[Definition, ExprNarrowingInfo]] = {}
|
|
410
414
|
for def_ in (d_ for d_ in sorted_defs if d_.codeloc.context is None):
|
|
411
415
|
if isinstance(def_.atom, atoms.VirtualVariable) and (def_.atom.was_reg or def_.atom.was_parameter):
|
|
@@ -421,7 +425,7 @@ class AILSimplifier(Analysis):
|
|
|
421
425
|
if skip_def:
|
|
422
426
|
continue
|
|
423
427
|
|
|
424
|
-
narrow = self._narrowing_needed(def_, rd, addr_and_idx_to_block)
|
|
428
|
+
narrow = self._narrowing_needed(def_, rd, addr_and_idx_to_block, effective_sizes)
|
|
425
429
|
if narrow.narrowable:
|
|
426
430
|
# we cannot narrow it immediately because any definition that is used by phi variables must be
|
|
427
431
|
# narrowed together with all other definitions that can reach the phi variables.
|
|
@@ -466,6 +470,47 @@ class AILSimplifier(Analysis):
|
|
|
466
470
|
|
|
467
471
|
return narrowed
|
|
468
472
|
|
|
473
|
+
def _compute_effective_sizes(self, rd, defs, addr_and_idx_to_block) -> dict[int, int]:
|
|
474
|
+
|
|
475
|
+
vvar_effective_sizes: dict[int, int] = {}
|
|
476
|
+
|
|
477
|
+
# determine effective sizes for non-phi vvars
|
|
478
|
+
for def_ in defs:
|
|
479
|
+
# find its def statement
|
|
480
|
+
old_block = addr_and_idx_to_block.get((def_.codeloc.block_addr, def_.codeloc.block_idx), None)
|
|
481
|
+
if old_block is None:
|
|
482
|
+
continue
|
|
483
|
+
block = self.blocks.get(old_block, old_block)
|
|
484
|
+
if def_.codeloc.stmt_idx is None or def_.codeloc.stmt_idx >= len(block.statements):
|
|
485
|
+
continue
|
|
486
|
+
def_stmt = block.statements[def_.codeloc.stmt_idx]
|
|
487
|
+
if (
|
|
488
|
+
isinstance(def_stmt, Assignment)
|
|
489
|
+
and isinstance(def_stmt.src, Convert)
|
|
490
|
+
and not def_stmt.src.is_signed
|
|
491
|
+
and def_stmt.src.from_type == Convert.TYPE_INT
|
|
492
|
+
and def_stmt.src.to_type == Convert.TYPE_INT
|
|
493
|
+
and def_stmt.src.from_bits < def_stmt.src.to_bits
|
|
494
|
+
):
|
|
495
|
+
effective_size = def_stmt.src.from_bits // self.project.arch.byte_width
|
|
496
|
+
vvar_effective_sizes[def_.atom.varid] = effective_size
|
|
497
|
+
|
|
498
|
+
# update effective sizes for phi vvars
|
|
499
|
+
changed = True
|
|
500
|
+
while changed:
|
|
501
|
+
changed = False
|
|
502
|
+
for phi_vvar in rd.phivarid_to_varids:
|
|
503
|
+
if phi_vvar in vvar_effective_sizes:
|
|
504
|
+
continue
|
|
505
|
+
if rd.phivarid_to_varids[phi_vvar] and all(
|
|
506
|
+
src_vvar in vvar_effective_sizes for src_vvar in rd.phivarid_to_varids[phi_vvar]
|
|
507
|
+
):
|
|
508
|
+
effective_size = max(vvar_effective_sizes[src_vvar] for src_vvar in rd.phivarid_to_varids[phi_vvar])
|
|
509
|
+
vvar_effective_sizes[phi_vvar] = effective_size
|
|
510
|
+
changed = True
|
|
511
|
+
|
|
512
|
+
return vvar_effective_sizes
|
|
513
|
+
|
|
469
514
|
@staticmethod
|
|
470
515
|
def _compute_narrowables_once(
|
|
471
516
|
rd, narrowing_candidates: dict, vvar_to_narrowing_size: dict[int, int], blacklist_varids: set
|
|
@@ -513,7 +558,9 @@ class AILSimplifier(Analysis):
|
|
|
513
558
|
|
|
514
559
|
return repeat, narrowables
|
|
515
560
|
|
|
516
|
-
def _narrowing_needed(
|
|
561
|
+
def _narrowing_needed(
|
|
562
|
+
self, def_: Definition, rd: SRDAModel, addr_and_idx_to_block, effective_sizes: dict[int, int]
|
|
563
|
+
) -> ExprNarrowingInfo:
|
|
517
564
|
|
|
518
565
|
def_size = def_.size
|
|
519
566
|
# find its uses
|
|
@@ -524,6 +571,7 @@ class AILSimplifier(Analysis):
|
|
|
524
571
|
use_and_exprs, phi_vars = result
|
|
525
572
|
|
|
526
573
|
all_used_sizes = set()
|
|
574
|
+
noncall_used_sizes = set()
|
|
527
575
|
used_by: list[tuple[atoms.VirtualVariable, CodeLocation, tuple[str, tuple[Expression, ...]]]] = []
|
|
528
576
|
used_by_loc = defaultdict(list)
|
|
529
577
|
|
|
@@ -543,10 +591,16 @@ class AILSimplifier(Analysis):
|
|
|
543
591
|
# special case: if the statement is a Call statement and expr is None, it means we have not been able to
|
|
544
592
|
# determine if the expression is really used by the call or not. skip it in this case
|
|
545
593
|
if isinstance(stmt, Call) and expr is None:
|
|
594
|
+
all_used_sizes.add(atom.size)
|
|
546
595
|
continue
|
|
547
596
|
# special case: if the statement is a phi statement, we ignore it
|
|
548
597
|
if is_phi_assignment(stmt):
|
|
549
598
|
continue
|
|
599
|
+
# special case: if the statement is an assignment to a destination vvar A, and the source is the bitwise-or
|
|
600
|
+
# of two expressions where one of them is the high bits of expr, and expr is a phi var that relies on
|
|
601
|
+
# vvar A, then we skip it.
|
|
602
|
+
if is_expr_used_as_reg_base_value(stmt, expr, rd):
|
|
603
|
+
continue
|
|
550
604
|
|
|
551
605
|
expr_size, used_by_exprs = self._extract_expression_effective_size(stmt, expr)
|
|
552
606
|
if expr_size is None:
|
|
@@ -554,9 +608,27 @@ class AILSimplifier(Analysis):
|
|
|
554
608
|
return ExprNarrowingInfo(False)
|
|
555
609
|
|
|
556
610
|
all_used_sizes.add(expr_size)
|
|
611
|
+
if not isinstance(stmt, Call):
|
|
612
|
+
noncall_used_sizes.add(expr_size)
|
|
557
613
|
used_by_loc[loc].append((atom, used_by_exprs))
|
|
558
614
|
|
|
615
|
+
target_size = None
|
|
559
616
|
if len(all_used_sizes) == 1 and next(iter(all_used_sizes)) < def_size:
|
|
617
|
+
target_size = next(iter(all_used_sizes))
|
|
618
|
+
else:
|
|
619
|
+
effective_size = effective_sizes.get(def_.atom.varid, None)
|
|
620
|
+
if (
|
|
621
|
+
effective_size is not None
|
|
622
|
+
and any(used_size <= effective_size for used_size in all_used_sizes)
|
|
623
|
+
and all(used_size <= effective_size for used_size in noncall_used_sizes)
|
|
624
|
+
):
|
|
625
|
+
# special case: sometimes we have an explicit Convert that narrows the value, all other uses are either
|
|
626
|
+
# in the effective size or narrower, but we pass the full register to a function call as an argument
|
|
627
|
+
# because we do not know the real type of the argument, or there are cases like putchar(int ch) while
|
|
628
|
+
# ch is actually a char. We use effective size in such cases to narrow the variable.
|
|
629
|
+
target_size = effective_size
|
|
630
|
+
|
|
631
|
+
if target_size is not None:
|
|
560
632
|
for loc, atom_expr_pairs in used_by_loc.items():
|
|
561
633
|
if len(atom_expr_pairs) == 1:
|
|
562
634
|
atom, used_by_exprs = atom_expr_pairs[0]
|
|
@@ -582,7 +654,7 @@ class AILSimplifier(Analysis):
|
|
|
582
654
|
for atom, used_by_exprs in ordered:
|
|
583
655
|
used_by.append((atom, loc, used_by_exprs))
|
|
584
656
|
|
|
585
|
-
return ExprNarrowingInfo(True, to_size=
|
|
657
|
+
return ExprNarrowingInfo(True, to_size=target_size, use_exprs=used_by, phi_vars=phi_vars)
|
|
586
658
|
|
|
587
659
|
return ExprNarrowingInfo(False)
|
|
588
660
|
|
|
@@ -364,7 +364,12 @@ class CallSiteMaker(Analysis):
|
|
|
364
364
|
# Find its definition
|
|
365
365
|
view = SRDAView(self._reaching_definitions.model)
|
|
366
366
|
vvar = view.get_reg_vvar_by_stmt(
|
|
367
|
-
offset,
|
|
367
|
+
offset,
|
|
368
|
+
arg_loc.size,
|
|
369
|
+
self.block.addr,
|
|
370
|
+
self.block.idx,
|
|
371
|
+
len(self.block.statements) - 1,
|
|
372
|
+
OP_BEFORE,
|
|
368
373
|
)
|
|
369
374
|
|
|
370
375
|
if vvar is not None:
|
|
@@ -1740,7 +1740,7 @@ class Clinic(Analysis):
|
|
|
1740
1740
|
func_graph=ail_graph,
|
|
1741
1741
|
func_args=func_args,
|
|
1742
1742
|
fail_fast=self._fail_fast,
|
|
1743
|
-
|
|
1743
|
+
use_callee_saved_regs_at_return=not self._register_save_areas_removed,
|
|
1744
1744
|
)
|
|
1745
1745
|
|
|
1746
1746
|
class TempClass: # pylint:disable=missing-class-docstring
|
|
@@ -2008,9 +2008,7 @@ class Clinic(Analysis):
|
|
|
2008
2008
|
|
|
2009
2009
|
# link struct member info
|
|
2010
2010
|
if isinstance(stmt.variable, SimStackVariable):
|
|
2011
|
-
|
|
2012
|
-
if off in variable_manager.stack_offset_to_struct_member_info:
|
|
2013
|
-
stmt.tags["struct_member_info"] = variable_manager.stack_offset_to_struct_member_info[off]
|
|
2011
|
+
self._map_stackvar_to_struct_member(variable_manager, stmt, stmt.variable.offset)
|
|
2014
2012
|
|
|
2015
2013
|
elif stmt_type is ailment.Stmt.Assignment or stmt_type is ailment.Stmt.WeakAssignment:
|
|
2016
2014
|
self._link_variables_on_expr(variable_manager, global_variables, block, stmt_idx, stmt, stmt.dst)
|
|
@@ -2094,9 +2092,7 @@ class Clinic(Analysis):
|
|
|
2094
2092
|
expr.variable_offset = offset
|
|
2095
2093
|
|
|
2096
2094
|
if isinstance(expr, ailment.Expr.VirtualVariable) and expr.was_stack:
|
|
2097
|
-
|
|
2098
|
-
if off in variable_manager.stack_offset_to_struct_member_info:
|
|
2099
|
-
expr.tags["struct_member_info"] = variable_manager.stack_offset_to_struct_member_info[off]
|
|
2095
|
+
self._map_stackvar_to_struct_member(variable_manager, expr, expr.stack_offset)
|
|
2100
2096
|
|
|
2101
2097
|
elif type(expr) is ailment.Expr.Load:
|
|
2102
2098
|
variables = variable_manager.find_variables_by_atom(block.addr, stmt_idx, expr, block_idx=block.idx)
|
|
@@ -2133,9 +2129,7 @@ class Clinic(Analysis):
|
|
|
2133
2129
|
expr.variable_offset = offset
|
|
2134
2130
|
|
|
2135
2131
|
if isinstance(var, SimStackVariable):
|
|
2136
|
-
|
|
2137
|
-
if off in variable_manager.stack_offset_to_struct_member_info:
|
|
2138
|
-
expr.tags["struct_member_info"] = variable_manager.stack_offset_to_struct_member_info[off]
|
|
2132
|
+
self._map_stackvar_to_struct_member(variable_manager, expr, var.offset)
|
|
2139
2133
|
|
|
2140
2134
|
elif type(expr) is ailment.Expr.BinaryOp:
|
|
2141
2135
|
variables = variable_manager.find_variables_by_atom(block.addr, stmt_idx, expr, block_idx=block.idx)
|
|
@@ -2227,6 +2221,24 @@ class Clinic(Analysis):
|
|
|
2227
2221
|
if vvar is not None:
|
|
2228
2222
|
self._link_variables_on_expr(variable_manager, global_variables, block, stmt_idx, stmt, vvar)
|
|
2229
2223
|
|
|
2224
|
+
def _map_stackvar_to_struct_member(
|
|
2225
|
+
self,
|
|
2226
|
+
variable_manager,
|
|
2227
|
+
expr_or_stmt: ailment.expression.Expression | ailment.statement.Statement,
|
|
2228
|
+
the_stack_offset: int,
|
|
2229
|
+
) -> bool:
|
|
2230
|
+
any_struct_found = False
|
|
2231
|
+
off = the_stack_offset
|
|
2232
|
+
for stack_off in variable_manager.stack_offset_to_struct.irange(maximum=off, reverse=True):
|
|
2233
|
+
the_var, vartype = variable_manager.stack_offset_to_struct[stack_off]
|
|
2234
|
+
if stack_off <= off < stack_off + vartype.size // self.project.arch.byte_width:
|
|
2235
|
+
expr_or_stmt.tags["struct_member_info"] = off - stack_off, the_var, vartype
|
|
2236
|
+
any_struct_found = True
|
|
2237
|
+
break
|
|
2238
|
+
if stack_off + vartype.size // self.project.arch.byte_width <= off:
|
|
2239
|
+
break
|
|
2240
|
+
return any_struct_found
|
|
2241
|
+
|
|
2230
2242
|
def _function_graph_to_ail_graph(self, func_graph, blocks_by_addr_and_size=None):
|
|
2231
2243
|
if blocks_by_addr_and_size is None:
|
|
2232
2244
|
blocks_by_addr_and_size = self._blocks_by_addr_and_size
|
|
@@ -4,14 +4,14 @@ from collections import defaultdict
|
|
|
4
4
|
|
|
5
5
|
from angr.ailment import AILBlockWalker
|
|
6
6
|
from angr.ailment.block import Block
|
|
7
|
-
from angr.ailment.expression import Phi, VirtualVariable
|
|
7
|
+
from angr.ailment.expression import Phi, VirtualVariable
|
|
8
8
|
from angr.ailment.statement import Assignment, Jump, ConditionalJump, Label
|
|
9
9
|
|
|
10
10
|
from angr.analyses import Analysis
|
|
11
11
|
from angr.analyses.s_reaching_definitions import SRDAModel
|
|
12
12
|
from angr.knowledge_plugins.functions import Function
|
|
13
13
|
from angr.analyses import register_analysis
|
|
14
|
-
from angr.utils.ssa import is_phi_assignment
|
|
14
|
+
from angr.utils.ssa import is_phi_assignment
|
|
15
15
|
|
|
16
16
|
l = logging.getLogger(name=__name__)
|
|
17
17
|
|
|
@@ -232,14 +232,8 @@ class GraphDephicationVVarMapping(Analysis): # pylint:disable=abstract-method
|
|
|
232
232
|
# we have not yet appended a statement to this block
|
|
233
233
|
the_block = self._blocks[src]
|
|
234
234
|
ins_addr = the_block.addr + the_block.original_size - 1
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
# a parameter vvar should never be assigned to
|
|
238
|
-
new_category = VirtualVariableCategory.REGISTER
|
|
239
|
-
new_oident = DEPHI_VVAR_REG_OFFSET
|
|
240
|
-
else:
|
|
241
|
-
new_category = vvar.category
|
|
242
|
-
new_oident = vvar.oident
|
|
235
|
+
new_category = phi_stmt.dst.category
|
|
236
|
+
new_oident = phi_stmt.dst.oident
|
|
243
237
|
new_vvar = VirtualVariable(
|
|
244
238
|
None, new_vvar_id, vvar.bits, new_category, oident=new_oident, ins_addr=ins_addr
|
|
245
239
|
)
|
|
@@ -9,12 +9,13 @@ import networkx
|
|
|
9
9
|
import angr.ailment as ailment
|
|
10
10
|
from angr.ailment import Block
|
|
11
11
|
from angr.ailment.expression import Phi, VirtualVariable, VirtualVariableCategory
|
|
12
|
-
from angr.ailment.statement import Assignment, Label
|
|
12
|
+
from angr.ailment.statement import Assignment, Label, Statement
|
|
13
13
|
|
|
14
14
|
from angr.code_location import CodeLocation
|
|
15
15
|
from angr.analyses import ForwardAnalysis
|
|
16
16
|
from angr.analyses.forward_analysis import FunctionGraphVisitor
|
|
17
|
-
from angr.utils.ail import is_head_controlled_loop_block
|
|
17
|
+
from angr.utils.ail import is_head_controlled_loop_block, extract_partial_expr
|
|
18
|
+
from angr.utils.ssa import get_reg_offset_base_and_size, is_phi_assignment
|
|
18
19
|
from .rewriting_engine import SimEngineSSARewriting, DefExprType, AT
|
|
19
20
|
from .rewriting_state import RewritingState
|
|
20
21
|
|
|
@@ -192,6 +193,7 @@ class RewritingAnalysis(ForwardAnalysis[RewritingState, ailment.Block, object, o
|
|
|
192
193
|
else self.out_states[(node_.addr, node_.idx)]
|
|
193
194
|
)
|
|
194
195
|
if reg_offset in out_state.registers and reg_size in out_state.registers[reg_offset]:
|
|
196
|
+
# we found a perfect hit
|
|
195
197
|
existing_var = out_state.registers[reg_offset][reg_size]
|
|
196
198
|
if existing_var is None:
|
|
197
199
|
# the vvar is not set. it should never be referenced
|
|
@@ -199,6 +201,25 @@ class RewritingAnalysis(ForwardAnalysis[RewritingState, ailment.Block, object, o
|
|
|
199
201
|
vvar = existing_var.copy()
|
|
200
202
|
vvar.idx = self._ail_manager.next_atom()
|
|
201
203
|
return True, vvar
|
|
204
|
+
|
|
205
|
+
# try to see if any register writes overlap with the requested one
|
|
206
|
+
# note that we only support full overlaps for now...
|
|
207
|
+
for off in out_state.registers:
|
|
208
|
+
if reg_offset + reg_size <= off or (
|
|
209
|
+
out_state.registers[off] and reg_offset > off + max(out_state.registers[off])
|
|
210
|
+
):
|
|
211
|
+
continue
|
|
212
|
+
for sz in sorted(out_state.registers[off], reverse=True):
|
|
213
|
+
if reg_offset >= off and reg_offset + reg_size <= off + sz:
|
|
214
|
+
existing_var = out_state.registers[off][sz]
|
|
215
|
+
if existing_var is None:
|
|
216
|
+
# the vvar is not set.
|
|
217
|
+
return True, None
|
|
218
|
+
|
|
219
|
+
# return the base vvar
|
|
220
|
+
base_vvar = existing_var.copy()
|
|
221
|
+
base_vvar.idx = self._ail_manager.next_atom()
|
|
222
|
+
return True, base_vvar
|
|
202
223
|
return False, None
|
|
203
224
|
|
|
204
225
|
def _stack_predicate(self, node_: Block, *, stack_offset: int, stackvar_size: int) -> tuple[bool, Any]:
|
|
@@ -319,19 +340,26 @@ class RewritingAnalysis(ForwardAnalysis[RewritingState, ailment.Block, object, o
|
|
|
319
340
|
for stmt in node.statements
|
|
320
341
|
):
|
|
321
342
|
# there we go
|
|
322
|
-
|
|
343
|
+
phi_stmts = []
|
|
344
|
+
phi_extraction_stmts = []
|
|
345
|
+
other_stmts = []
|
|
323
346
|
for stmt in node.statements:
|
|
324
|
-
if
|
|
347
|
+
if (
|
|
325
348
|
isinstance(stmt, Assignment)
|
|
326
349
|
and isinstance(stmt.dst, VirtualVariable)
|
|
327
350
|
and isinstance(stmt.src, Phi)
|
|
328
|
-
and len(stmt.src.src_and_vvars)
|
|
351
|
+
and len(stmt.src.src_and_vvars) > 0
|
|
329
352
|
):
|
|
330
|
-
|
|
353
|
+
# avoid re-assignment
|
|
354
|
+
phi_stmts.append(stmt)
|
|
355
|
+
continue
|
|
356
|
+
if not is_phi_assignment(stmt):
|
|
357
|
+
other_stmts.append(stmt)
|
|
331
358
|
continue
|
|
332
359
|
|
|
333
360
|
src_and_vvars = []
|
|
334
361
|
if stmt.dst.was_reg:
|
|
362
|
+
perfect_matches = []
|
|
335
363
|
for pred in self.graph.predecessors(original_node):
|
|
336
364
|
vvar = self._follow_one_path_backward(
|
|
337
365
|
self.graph,
|
|
@@ -339,6 +367,36 @@ class RewritingAnalysis(ForwardAnalysis[RewritingState, ailment.Block, object, o
|
|
|
339
367
|
partial(self._reg_predicate, reg_offset=stmt.dst.reg_offset, reg_size=stmt.dst.size),
|
|
340
368
|
)
|
|
341
369
|
src_and_vvars.append(((pred.addr, pred.idx), vvar))
|
|
370
|
+
perfect_matches.append(
|
|
371
|
+
(vvar.reg_offset == stmt.dst.reg_offset and vvar.size == stmt.dst.size)
|
|
372
|
+
if vvar is not None
|
|
373
|
+
else True
|
|
374
|
+
)
|
|
375
|
+
if all(perfect_matches):
|
|
376
|
+
phi_var = Phi(stmt.src.idx, stmt.src.bits, src_and_vvars=src_and_vvars)
|
|
377
|
+
phi_stmt = Assignment(stmt.idx, stmt.dst, phi_var, **stmt.tags)
|
|
378
|
+
phi_stmts.append(phi_stmt)
|
|
379
|
+
else:
|
|
380
|
+
# different sizes of vvars found; we need to resort to the base register and extract the
|
|
381
|
+
# requested register out of the base register
|
|
382
|
+
# here we rely on the fact that the larger register vvar must be created in this block when
|
|
383
|
+
# the smaller register has been created
|
|
384
|
+
base_reg_offset, max_reg_size = get_reg_offset_base_and_size(
|
|
385
|
+
stmt.dst.reg_offset, self.project.arch, size=stmt.dst.size
|
|
386
|
+
)
|
|
387
|
+
# find the phi assignment statement of the larger base register
|
|
388
|
+
base_vvar = self._find_phi_vvar_for_reg(base_reg_offset, max_reg_size, node.statements)
|
|
389
|
+
assert base_vvar is not None
|
|
390
|
+
partial_base_vvar = extract_partial_expr(
|
|
391
|
+
base_vvar,
|
|
392
|
+
stmt.dst.reg_offset - base_reg_offset,
|
|
393
|
+
stmt.dst.size,
|
|
394
|
+
self._ail_manager,
|
|
395
|
+
byte_width=self.project.arch.byte_width,
|
|
396
|
+
)
|
|
397
|
+
new_stmt = Assignment(stmt.idx, stmt.dst, partial_base_vvar, **base_vvar.tags)
|
|
398
|
+
phi_extraction_stmts.append(new_stmt)
|
|
399
|
+
|
|
342
400
|
elif stmt.dst.was_stack:
|
|
343
401
|
for pred in self.graph.predecessors(original_node):
|
|
344
402
|
vvar = self._follow_one_path_backward(
|
|
@@ -351,13 +409,14 @@ class RewritingAnalysis(ForwardAnalysis[RewritingState, ailment.Block, object, o
|
|
|
351
409
|
),
|
|
352
410
|
)
|
|
353
411
|
src_and_vvars.append(((pred.addr, pred.idx), vvar))
|
|
412
|
+
|
|
413
|
+
phi_var = Phi(stmt.src.idx, stmt.src.bits, src_and_vvars=src_and_vvars)
|
|
414
|
+
phi_stmt = Assignment(stmt.idx, stmt.dst, phi_var, **stmt.tags)
|
|
415
|
+
phi_stmts.append(phi_stmt)
|
|
354
416
|
else:
|
|
355
417
|
raise NotImplementedError
|
|
356
418
|
|
|
357
|
-
|
|
358
|
-
new_stmt = Assignment(stmt.idx, stmt.dst, phi_var, **stmt.tags)
|
|
359
|
-
new_stmts.append(new_stmt)
|
|
360
|
-
node = node.copy(statements=new_stmts)
|
|
419
|
+
node = node.copy(statements=phi_stmts + phi_extraction_stmts + other_stmts)
|
|
361
420
|
self.out_blocks[node_key] = node
|
|
362
421
|
|
|
363
422
|
@staticmethod
|
|
@@ -377,3 +436,16 @@ class RewritingAnalysis(ForwardAnalysis[RewritingState, ailment.Block, object, o
|
|
|
377
436
|
break
|
|
378
437
|
the_node = more_preds[0]
|
|
379
438
|
return return_value
|
|
439
|
+
|
|
440
|
+
@staticmethod
|
|
441
|
+
def _find_phi_vvar_for_reg(reg_offset: int, reg_size: int, stmts: list[Statement]) -> VirtualVariable | None:
|
|
442
|
+
for stmt in stmts:
|
|
443
|
+
if (
|
|
444
|
+
is_phi_assignment(stmt)
|
|
445
|
+
and isinstance(stmt.dst, VirtualVariable)
|
|
446
|
+
and stmt.dst.was_reg
|
|
447
|
+
and stmt.dst.reg_offset == reg_offset
|
|
448
|
+
and stmt.dst.size == reg_size
|
|
449
|
+
):
|
|
450
|
+
return stmt.dst
|
|
451
|
+
return None
|
|
@@ -153,7 +153,7 @@ class SimEngineSSARewriting(
|
|
|
153
153
|
else:
|
|
154
154
|
new_dst = self._replace_def_expr(self.block.addr, self.block.idx, self.stmt_idx, stmt.dst)
|
|
155
155
|
|
|
156
|
-
|
|
156
|
+
additional_stmts = []
|
|
157
157
|
if new_dst is not None:
|
|
158
158
|
if isinstance(stmt.dst, Register):
|
|
159
159
|
# remove everything else that is an alias
|
|
@@ -163,10 +163,11 @@ class SimEngineSSARewriting(
|
|
|
163
163
|
|
|
164
164
|
self.state.registers[stmt.dst.reg_offset][stmt.dst.size] = new_dst
|
|
165
165
|
|
|
166
|
-
# generate an assignment that updates the base register if needed
|
|
167
166
|
base_offset, base_size = get_reg_offset_base_and_size(
|
|
168
167
|
stmt.dst.reg_offset, self.arch, size=stmt.dst.size
|
|
169
168
|
)
|
|
169
|
+
|
|
170
|
+
# generate an assignment that updates the base register if needed
|
|
170
171
|
if base_offset != stmt.dst.reg_offset or base_size != stmt.dst.size:
|
|
171
172
|
base_reg_expr = Register(
|
|
172
173
|
self.ail_manager.next_atom(),
|
|
@@ -180,15 +181,25 @@ class SimEngineSSARewriting(
|
|
|
180
181
|
self.block.addr, self.block.idx, self.stmt_idx, base_reg_expr
|
|
181
182
|
)
|
|
182
183
|
assert base_reg_vvar is not None
|
|
184
|
+
base_reg_value = self._partial_update_expr(
|
|
185
|
+
existing_base_reg_vvar,
|
|
186
|
+
base_offset,
|
|
187
|
+
base_size,
|
|
188
|
+
new_dst,
|
|
189
|
+
stmt.dst.reg_offset,
|
|
190
|
+
stmt.dst.size,
|
|
191
|
+
)
|
|
183
192
|
stmt_base_reg = Assignment(
|
|
184
193
|
self.ail_manager.next_atom(),
|
|
185
194
|
base_reg_vvar,
|
|
186
|
-
|
|
187
|
-
existing_base_reg_vvar, base_offset, base_size, new_dst, stmt.dst.reg_offset, stmt.dst.size
|
|
188
|
-
),
|
|
195
|
+
base_reg_value,
|
|
189
196
|
**stmt.tags,
|
|
190
197
|
)
|
|
198
|
+
additional_stmts.append(stmt_base_reg)
|
|
191
199
|
self.state.registers[base_offset][base_size] = base_reg_vvar
|
|
200
|
+
else:
|
|
201
|
+
base_reg_vvar = new_dst
|
|
202
|
+
|
|
192
203
|
elif isinstance(stmt.dst, Tmp):
|
|
193
204
|
pass
|
|
194
205
|
else:
|
|
@@ -201,8 +212,8 @@ class SimEngineSSARewriting(
|
|
|
201
212
|
stmt.src if new_src is None else new_src,
|
|
202
213
|
**stmt.tags,
|
|
203
214
|
)
|
|
204
|
-
if
|
|
205
|
-
return new_stmt,
|
|
215
|
+
if additional_stmts:
|
|
216
|
+
return new_stmt, *additional_stmts
|
|
206
217
|
return new_stmt
|
|
207
218
|
return None
|
|
208
219
|
|
|
@@ -612,12 +623,12 @@ class SimEngineSSARewriting(
|
|
|
612
623
|
existing_vvar: Expression,
|
|
613
624
|
base_offset: int,
|
|
614
625
|
base_size: int,
|
|
615
|
-
|
|
626
|
+
new_value: Expression,
|
|
616
627
|
offset: int,
|
|
617
628
|
size: int,
|
|
618
629
|
) -> VirtualVariable | Expression:
|
|
619
630
|
if offset == base_offset and base_size == size:
|
|
620
|
-
return
|
|
631
|
+
return new_value
|
|
621
632
|
if base_offset > offset:
|
|
622
633
|
raise ValueError(f"Base offset {base_offset} is greater than expression offset {offset}")
|
|
623
634
|
|
|
@@ -639,8 +650,8 @@ class SimEngineSSARewriting(
|
|
|
639
650
|
size * self.arch.byte_width,
|
|
640
651
|
base_size * self.arch.byte_width,
|
|
641
652
|
False,
|
|
642
|
-
|
|
643
|
-
**
|
|
653
|
+
new_value,
|
|
654
|
+
**new_value.tags,
|
|
644
655
|
)
|
|
645
656
|
if base_offset < offset:
|
|
646
657
|
shift_amount = Const(
|
|
@@ -85,9 +85,9 @@ class Ssailification(Analysis): # pylint:disable=abstract-method
|
|
|
85
85
|
)
|
|
86
86
|
|
|
87
87
|
# calculate virtual variables and phi nodes
|
|
88
|
-
self._udef_to_phiid: dict[tuple, set[int]] =
|
|
89
|
-
self._phiid_to_loc: dict[int, tuple[int, int | None]] =
|
|
90
|
-
self._stackvar_locs: dict[int, set[int]] =
|
|
88
|
+
self._udef_to_phiid: dict[tuple, set[int]] = {}
|
|
89
|
+
self._phiid_to_loc: dict[int, tuple[int, int | None]] = {}
|
|
90
|
+
self._stackvar_locs: dict[int, set[int]] = {}
|
|
91
91
|
self._calculate_virtual_variables(ail_graph, traversal.def_to_loc, traversal.loc_to_defs)
|
|
92
92
|
|
|
93
93
|
# insert phi variables and rewrite uses
|
|
@@ -140,14 +140,16 @@ class Ssailification(Analysis): # pylint:disable=abstract-method
|
|
|
140
140
|
# handle function arguments
|
|
141
141
|
if self._func_args:
|
|
142
142
|
for func_arg in self._func_args:
|
|
143
|
-
if func_arg.
|
|
144
|
-
|
|
143
|
+
if func_arg.parameter_category == VirtualVariableCategory.STACK:
|
|
144
|
+
assert isinstance(func_arg.parameter_stack_offset, int)
|
|
145
|
+
stackvar_locs[func_arg.parameter_stack_offset] = {func_arg.size}
|
|
145
146
|
sorted_stackvar_offs = sorted(stackvar_locs)
|
|
146
147
|
else:
|
|
147
148
|
stackvar_locs = {}
|
|
148
149
|
sorted_stackvar_offs = []
|
|
149
150
|
|
|
150
151
|
# compute phi node locations for each unified definition
|
|
152
|
+
# compute udef_to_blockkeys
|
|
151
153
|
udef_to_defs = defaultdict(set)
|
|
152
154
|
udef_to_blockkeys = defaultdict(set)
|
|
153
155
|
for def_, loc in def_to_loc:
|