angr 9.2.164__cp310-abi3-win_amd64.whl → 9.2.166__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/analyses/analysis.py +27 -4
- angr/analyses/cfg/cfg_fast.py +16 -1
- angr/analyses/decompiler/condition_processor.py +9 -8
- angr/analyses/decompiler/peephole_optimizations/__init__.py +2 -0
- angr/analyses/decompiler/peephole_optimizations/inlined_memcpy.py +78 -0
- angr/analyses/decompiler/peephole_optimizations/inlined_strcpy.py +67 -10
- angr/analyses/decompiler/peephole_optimizations/inlined_strcpy_consolidation.py +10 -13
- angr/analyses/deobfuscator/string_obf_finder.py +130 -32
- angr/engines/icicle.py +10 -2
- angr/rustylib.pyd +0 -0
- angr/state_plugins/history.py +16 -0
- angr/unicornlib.dll +0 -0
- {angr-9.2.164.dist-info → angr-9.2.166.dist-info}/METADATA +5 -5
- {angr-9.2.164.dist-info → angr-9.2.166.dist-info}/RECORD +19 -18
- {angr-9.2.164.dist-info → angr-9.2.166.dist-info}/WHEEL +0 -0
- {angr-9.2.164.dist-info → angr-9.2.166.dist-info}/entry_points.txt +0 -0
- {angr-9.2.164.dist-info → angr-9.2.166.dist-info}/licenses/LICENSE +0 -0
- {angr-9.2.164.dist-info → angr-9.2.166.dist-info}/top_level.txt +0 -0
angr/__init__.py
CHANGED
angr/analyses/analysis.py
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
import functools
|
|
3
|
+
import os
|
|
3
4
|
import sys
|
|
4
5
|
import contextlib
|
|
5
6
|
from collections import defaultdict
|
|
@@ -14,6 +15,8 @@ import logging
|
|
|
14
15
|
import time
|
|
15
16
|
import typing
|
|
16
17
|
|
|
18
|
+
import psutil
|
|
19
|
+
|
|
17
20
|
from rich import progress
|
|
18
21
|
|
|
19
22
|
from angr.misc.plugins import PluginVendor, VendorPreset
|
|
@@ -287,6 +290,8 @@ class Analysis:
|
|
|
287
290
|
_name: str
|
|
288
291
|
errors: list[AnalysisLogEntry] = []
|
|
289
292
|
named_errors: defaultdict[str, list[AnalysisLogEntry]] = defaultdict(list)
|
|
293
|
+
_ram_usage: float | None = None
|
|
294
|
+
_last_ramusage_update: float = 0.0
|
|
290
295
|
_progress_callback = None
|
|
291
296
|
_show_progressbar = False
|
|
292
297
|
_progressbar = None
|
|
@@ -295,7 +300,7 @@ class Analysis:
|
|
|
295
300
|
_PROGRESS_WIDGETS = [
|
|
296
301
|
progress.TaskProgressColumn(),
|
|
297
302
|
progress.BarColumn(),
|
|
298
|
-
progress.TextColumn("Elapsed
|
|
303
|
+
progress.TextColumn("Elapsed:"),
|
|
299
304
|
progress.TimeElapsedColumn(),
|
|
300
305
|
progress.TextColumn("Time:"),
|
|
301
306
|
progress.TimeRemainingColumn(),
|
|
@@ -311,7 +316,9 @@ class Analysis:
|
|
|
311
316
|
raise
|
|
312
317
|
else:
|
|
313
318
|
error = AnalysisLogEntry("exception occurred", exc_info=True)
|
|
314
|
-
l.error(
|
|
319
|
+
l.error(
|
|
320
|
+
"Caught and logged %s with resilience: %s", error.exc_type.__name__, error.exc_value # type:ignore
|
|
321
|
+
)
|
|
315
322
|
if name is None:
|
|
316
323
|
self.errors.append(error)
|
|
317
324
|
else:
|
|
@@ -342,10 +349,12 @@ class Analysis:
|
|
|
342
349
|
if self._progressbar is None:
|
|
343
350
|
self._initialize_progressbar()
|
|
344
351
|
|
|
352
|
+
assert self._task is not None
|
|
353
|
+
assert self._progressbar is not None
|
|
345
354
|
self._progressbar.update(self._task, completed=percentage)
|
|
346
355
|
|
|
347
|
-
|
|
348
|
-
|
|
356
|
+
if text is not None and self._progressbar:
|
|
357
|
+
self._progressbar.update(self._task, description=text)
|
|
349
358
|
|
|
350
359
|
if self._progress_callback is not None:
|
|
351
360
|
self._progress_callback(percentage, text=text, **kwargs) # pylint:disable=not-callable
|
|
@@ -360,6 +369,7 @@ class Analysis:
|
|
|
360
369
|
if self._progressbar is None:
|
|
361
370
|
self._initialize_progressbar()
|
|
362
371
|
if self._progressbar is not None:
|
|
372
|
+
assert self._task is not None
|
|
363
373
|
self._progressbar.update(self._task, completed=100)
|
|
364
374
|
self._progressbar.stop()
|
|
365
375
|
self._progressbar = None
|
|
@@ -384,6 +394,19 @@ class Analysis:
|
|
|
384
394
|
if ctr != 0 and ctr % freq == 0:
|
|
385
395
|
time.sleep(sleep_time)
|
|
386
396
|
|
|
397
|
+
@property
|
|
398
|
+
def ram_usage(self) -> float:
|
|
399
|
+
"""
|
|
400
|
+
Return the current RAM usage of the Python process, in bytes. The value is updated at most once per second.
|
|
401
|
+
"""
|
|
402
|
+
|
|
403
|
+
if time.time() - self._last_ramusage_update > 1:
|
|
404
|
+
self._last_ramusage_update = time.time()
|
|
405
|
+
proc = psutil.Process(os.getpid())
|
|
406
|
+
meminfo = proc.memory_info()
|
|
407
|
+
self._ram_usage = meminfo.rss
|
|
408
|
+
return self._ram_usage if self._ram_usage is not None else -0.1
|
|
409
|
+
|
|
387
410
|
def __getstate__(self):
|
|
388
411
|
d = dict(self.__dict__)
|
|
389
412
|
d.pop("_progressbar", None)
|
angr/analyses/cfg/cfg_fast.py
CHANGED
|
@@ -846,6 +846,8 @@ class CFGFast(ForwardAnalysis[CFGNode, CFGNode, CFGJob, int], CFGBase): # pylin
|
|
|
846
846
|
# exception handling
|
|
847
847
|
self._exception_handling_by_endaddr = SortedDict()
|
|
848
848
|
|
|
849
|
+
self.stage: str = ""
|
|
850
|
+
|
|
849
851
|
#
|
|
850
852
|
# Variables used during analysis
|
|
851
853
|
#
|
|
@@ -1361,6 +1363,8 @@ class CFGFast(ForwardAnalysis[CFGNode, CFGNode, CFGJob, int], CFGBase): # pylin
|
|
|
1361
1363
|
return job.addr
|
|
1362
1364
|
|
|
1363
1365
|
def _pre_analysis(self):
|
|
1366
|
+
self.stage = "Pre-analysis"
|
|
1367
|
+
|
|
1364
1368
|
# Create a read-only memory view in loader for faster data loading
|
|
1365
1369
|
self.project.loader.gen_ro_memview()
|
|
1366
1370
|
|
|
@@ -1446,6 +1450,8 @@ class CFGFast(ForwardAnalysis[CFGNode, CFGNode, CFGJob, int], CFGBase): # pylin
|
|
|
1446
1450
|
|
|
1447
1451
|
self._job_ctr = 0
|
|
1448
1452
|
|
|
1453
|
+
self.stage = "Analysis (Stage 1)"
|
|
1454
|
+
|
|
1449
1455
|
def _pre_job_handling(self, job: CFGJob): # pylint:disable=arguments-differ
|
|
1450
1456
|
"""
|
|
1451
1457
|
Some pre job-processing tasks, like update progress bar.
|
|
@@ -1481,7 +1487,13 @@ class CFGFast(ForwardAnalysis[CFGNode, CFGNode, CFGJob, int], CFGBase): # pylin
|
|
|
1481
1487
|
percentage = min(
|
|
1482
1488
|
self._seg_list.occupied_size * max_percentage_stage_1 / self._regions_size, max_percentage_stage_1
|
|
1483
1489
|
)
|
|
1484
|
-
self.
|
|
1490
|
+
ram_usage = self.ram_usage / (1024 * 1024)
|
|
1491
|
+
text = (
|
|
1492
|
+
f"{self.stage} | {len(self.functions)} funcs, {len(self.graph)} blocks | "
|
|
1493
|
+
f"{len(self._indirect_jumps_to_resolve)}/{len(self.indirect_jumps)} IJs | "
|
|
1494
|
+
f"{ram_usage:0.2f} MB RAM"
|
|
1495
|
+
)
|
|
1496
|
+
self._update_progress(percentage, text=text, cfg=self)
|
|
1485
1497
|
|
|
1486
1498
|
def _intra_analysis(self):
|
|
1487
1499
|
pass
|
|
@@ -1780,6 +1792,9 @@ class CFGFast(ForwardAnalysis[CFGNode, CFGNode, CFGJob, int], CFGBase): # pylin
|
|
|
1780
1792
|
self._model.edges_to_repair = remaining_edges_to_repair
|
|
1781
1793
|
|
|
1782
1794
|
def _post_analysis(self):
|
|
1795
|
+
|
|
1796
|
+
self.stage = "Analysis (Stage 2)"
|
|
1797
|
+
|
|
1783
1798
|
self._repair_edges()
|
|
1784
1799
|
|
|
1785
1800
|
self._make_completed_functions()
|
|
@@ -13,8 +13,6 @@ from unique_log_filter import UniqueLogFilter
|
|
|
13
13
|
|
|
14
14
|
|
|
15
15
|
from angr.utils.graph import GraphUtils
|
|
16
|
-
from angr.utils.lazy_import import lazy_import
|
|
17
|
-
from angr.utils import is_pyinstaller
|
|
18
16
|
from angr.utils.graph import dominates, inverted_idoms
|
|
19
17
|
from angr.utils.ail import is_head_controlled_loop_block
|
|
20
18
|
from angr.block import Block, BlockNode
|
|
@@ -37,12 +35,6 @@ from .structuring.structurer_nodes import (
|
|
|
37
35
|
from .graph_region import GraphRegion
|
|
38
36
|
from .utils import peephole_optimize_expr
|
|
39
37
|
|
|
40
|
-
if is_pyinstaller():
|
|
41
|
-
# PyInstaller is not happy with lazy import
|
|
42
|
-
import sympy
|
|
43
|
-
else:
|
|
44
|
-
sympy = lazy_import("sympy")
|
|
45
|
-
|
|
46
38
|
|
|
47
39
|
l = logging.getLogger(__name__)
|
|
48
40
|
l.addFilter(UniqueLogFilter())
|
|
@@ -953,6 +945,9 @@ class ConditionProcessor:
|
|
|
953
945
|
|
|
954
946
|
@staticmethod
|
|
955
947
|
def claripy_ast_to_sympy_expr(ast, memo=None):
|
|
948
|
+
|
|
949
|
+
import sympy # pylint:disable=import-outside-toplevel
|
|
950
|
+
|
|
956
951
|
if ast.op == "And":
|
|
957
952
|
return sympy.And(*(ConditionProcessor.claripy_ast_to_sympy_expr(arg, memo=memo) for arg in ast.args))
|
|
958
953
|
if ast.op == "Or":
|
|
@@ -974,6 +969,9 @@ class ConditionProcessor:
|
|
|
974
969
|
|
|
975
970
|
@staticmethod
|
|
976
971
|
def sympy_expr_to_claripy_ast(expr, memo: dict):
|
|
972
|
+
|
|
973
|
+
import sympy # pylint:disable=import-outside-toplevel
|
|
974
|
+
|
|
977
975
|
if expr.is_Symbol:
|
|
978
976
|
return memo[expr]
|
|
979
977
|
if isinstance(expr, sympy.Or):
|
|
@@ -990,6 +988,9 @@ class ConditionProcessor:
|
|
|
990
988
|
|
|
991
989
|
@staticmethod
|
|
992
990
|
def simplify_condition(cond, depth_limit=8, variables_limit=8):
|
|
991
|
+
|
|
992
|
+
import sympy # pylint:disable=import-outside-toplevel
|
|
993
|
+
|
|
993
994
|
memo = {}
|
|
994
995
|
if cond.depth > depth_limit or len(cond.variables) > variables_limit:
|
|
995
996
|
return cond
|
|
@@ -43,6 +43,7 @@ from .sar_to_signed_div import SarToSignedDiv
|
|
|
43
43
|
from .tidy_stack_addr import TidyStackAddr
|
|
44
44
|
from .invert_negated_logical_conjuction_disjunction import InvertNegatedLogicalConjunctionsAndDisjunctions
|
|
45
45
|
from .rol_ror import RolRorRewriter
|
|
46
|
+
from .inlined_memcpy import InlinedMemcpy
|
|
46
47
|
from .inlined_strcpy import InlinedStrcpy
|
|
47
48
|
from .inlined_strcpy_consolidation import InlinedStrcpyConsolidation
|
|
48
49
|
from .inlined_wstrcpy import InlinedWstrcpy
|
|
@@ -99,6 +100,7 @@ ALL_PEEPHOLE_OPTS: list[type[PeepholeOptimizationExprBase]] = [
|
|
|
99
100
|
TidyStackAddr,
|
|
100
101
|
InvertNegatedLogicalConjunctionsAndDisjunctions,
|
|
101
102
|
RolRorRewriter,
|
|
103
|
+
InlinedMemcpy,
|
|
102
104
|
InlinedStrcpy,
|
|
103
105
|
InlinedStrcpyConsolidation,
|
|
104
106
|
InlinedWstrcpy,
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
# pylint:disable=arguments-differ
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
|
|
4
|
+
from angr.ailment.expression import Const, StackBaseOffset, VirtualVariable, Load, UnaryOp
|
|
5
|
+
from angr.ailment.statement import Call, Assignment, Store
|
|
6
|
+
from angr import SIM_LIBRARIES
|
|
7
|
+
from .base import PeepholeOptimizationStmtBase
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class InlinedMemcpy(PeepholeOptimizationStmtBase):
|
|
11
|
+
"""
|
|
12
|
+
Simplifies inlined data copying logic into calls to memcpy.
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
__slots__ = ()
|
|
16
|
+
|
|
17
|
+
NAME = "Simplifying inlined strcpy"
|
|
18
|
+
stmt_classes = (Assignment, Store)
|
|
19
|
+
|
|
20
|
+
def optimize(self, stmt: Assignment | Store, stmt_idx: int | None = None, block=None, **kwargs):
|
|
21
|
+
should_replace = False
|
|
22
|
+
dst_offset, src_offset, store_size = None, None, None
|
|
23
|
+
if (
|
|
24
|
+
isinstance(stmt, Assignment)
|
|
25
|
+
and isinstance(stmt.dst, VirtualVariable)
|
|
26
|
+
and stmt.dst.was_stack
|
|
27
|
+
and stmt.dst.size == 16
|
|
28
|
+
and isinstance(stmt.src, Load)
|
|
29
|
+
):
|
|
30
|
+
dst_offset = stmt.dst.stack_offset
|
|
31
|
+
store_size = stmt.dst.size
|
|
32
|
+
if (
|
|
33
|
+
isinstance(stmt.src.addr, UnaryOp)
|
|
34
|
+
and stmt.src.addr.op == "Reference"
|
|
35
|
+
and isinstance(stmt.src.addr.operand, VirtualVariable)
|
|
36
|
+
):
|
|
37
|
+
should_replace = True
|
|
38
|
+
src_offset = stmt.src.addr.operand.stack_offset
|
|
39
|
+
elif isinstance(stmt.src.addr, StackBaseOffset):
|
|
40
|
+
should_replace = True
|
|
41
|
+
src_offset = stmt.src.addr.offset
|
|
42
|
+
|
|
43
|
+
if (
|
|
44
|
+
isinstance(stmt, Store)
|
|
45
|
+
and isinstance(stmt.addr, StackBaseOffset)
|
|
46
|
+
and stmt.size == 16
|
|
47
|
+
and isinstance(stmt.data, Load)
|
|
48
|
+
):
|
|
49
|
+
dst_offset = stmt.addr.offset
|
|
50
|
+
store_size = stmt.size
|
|
51
|
+
if (
|
|
52
|
+
isinstance(stmt.data.addr, UnaryOp)
|
|
53
|
+
and stmt.data.addr.op == "Reference"
|
|
54
|
+
and isinstance(stmt.data.addr.operand, VirtualVariable)
|
|
55
|
+
):
|
|
56
|
+
should_replace = True
|
|
57
|
+
src_offset = stmt.data.addr.operand.stack_offset
|
|
58
|
+
elif isinstance(stmt.data.addr, StackBaseOffset):
|
|
59
|
+
should_replace = True
|
|
60
|
+
src_offset = stmt.data.addr.offset
|
|
61
|
+
|
|
62
|
+
if should_replace:
|
|
63
|
+
assert dst_offset is not None and src_offset is not None and store_size is not None
|
|
64
|
+
# replace it with a call to memcpy
|
|
65
|
+
assert self.project is not None
|
|
66
|
+
return Call(
|
|
67
|
+
stmt.idx,
|
|
68
|
+
"memcpy",
|
|
69
|
+
args=[
|
|
70
|
+
StackBaseOffset(None, self.project.arch.bits, dst_offset),
|
|
71
|
+
StackBaseOffset(None, self.project.arch.bits, src_offset),
|
|
72
|
+
Const(None, None, store_size, self.project.arch.bits),
|
|
73
|
+
],
|
|
74
|
+
prototype=SIM_LIBRARIES["libc.so"][0].get_prototype("memcpy"),
|
|
75
|
+
**stmt.tags,
|
|
76
|
+
)
|
|
77
|
+
|
|
78
|
+
return None
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
# pylint:disable=arguments-differ
|
|
1
|
+
# pylint:disable=arguments-differ,too-many-boolean-expressions
|
|
2
2
|
from __future__ import annotations
|
|
3
3
|
import string
|
|
4
4
|
|
|
5
5
|
from archinfo import Endness
|
|
6
6
|
|
|
7
|
-
from angr.ailment.expression import Const, StackBaseOffset, VirtualVariable
|
|
8
|
-
from angr.ailment.statement import Call, Assignment
|
|
7
|
+
from angr.ailment.expression import Const, StackBaseOffset, VirtualVariable, UnaryOp
|
|
8
|
+
from angr.ailment.statement import Call, Assignment, Store, Statement
|
|
9
9
|
|
|
10
10
|
from angr import SIM_LIBRARIES
|
|
11
11
|
from angr.utils.endness import ail_const_to_be
|
|
@@ -24,24 +24,54 @@ class InlinedStrcpy(PeepholeOptimizationStmtBase):
|
|
|
24
24
|
__slots__ = ()
|
|
25
25
|
|
|
26
26
|
NAME = "Simplifying inlined strcpy"
|
|
27
|
-
stmt_classes = (Assignment,)
|
|
27
|
+
stmt_classes = (Assignment, Store)
|
|
28
|
+
|
|
29
|
+
def optimize(self, stmt: Assignment | Store, stmt_idx: int | None = None, block=None, **kwargs):
|
|
30
|
+
inlined_strcpy_candidate = False
|
|
31
|
+
src: Const | None = None
|
|
32
|
+
strcpy_dst: StackBaseOffset | UnaryOp | None = None
|
|
33
|
+
|
|
34
|
+
assert self.project is not None
|
|
28
35
|
|
|
29
|
-
def optimize(self, stmt: Assignment, stmt_idx: int | None = None, block=None, **kwargs):
|
|
30
36
|
if (
|
|
31
|
-
isinstance(stmt
|
|
37
|
+
isinstance(stmt, Assignment)
|
|
38
|
+
and isinstance(stmt.dst, VirtualVariable)
|
|
32
39
|
and stmt.dst.was_stack
|
|
33
40
|
and isinstance(stmt.src, Const)
|
|
34
41
|
and isinstance(stmt.src.value, int)
|
|
35
42
|
):
|
|
36
|
-
|
|
43
|
+
inlined_strcpy_candidate = True
|
|
44
|
+
src = stmt.src
|
|
45
|
+
strcpy_dst = StackBaseOffset(None, self.project.arch.bits, stmt.dst.stack_offset)
|
|
46
|
+
elif (
|
|
47
|
+
isinstance(stmt, Store)
|
|
48
|
+
and isinstance(stmt.addr, UnaryOp)
|
|
49
|
+
and stmt.addr.op == "Reference"
|
|
50
|
+
and isinstance(stmt.addr.operand, VirtualVariable)
|
|
51
|
+
and stmt.addr.operand.was_stack
|
|
52
|
+
and isinstance(stmt.data, Const)
|
|
53
|
+
and isinstance(stmt.data.value, int)
|
|
54
|
+
):
|
|
55
|
+
inlined_strcpy_candidate = True
|
|
56
|
+
src = stmt.data
|
|
57
|
+
strcpy_dst = stmt.addr
|
|
58
|
+
|
|
59
|
+
if inlined_strcpy_candidate:
|
|
60
|
+
assert src is not None and strcpy_dst is not None
|
|
61
|
+
assert isinstance(src.value, int)
|
|
62
|
+
assert self.kb is not None
|
|
63
|
+
|
|
64
|
+
r, s = self.is_integer_likely_a_string(src.value, src.size, self.project.arch.memory_endness)
|
|
37
65
|
if r:
|
|
66
|
+
assert s is not None
|
|
67
|
+
|
|
38
68
|
# replace it with a call to strncpy
|
|
39
69
|
str_id = self.kb.custom_strings.allocate(s.encode("ascii"))
|
|
40
70
|
return Call(
|
|
41
71
|
stmt.idx,
|
|
42
72
|
"strncpy",
|
|
43
73
|
args=[
|
|
44
|
-
|
|
74
|
+
strcpy_dst,
|
|
45
75
|
Const(None, None, str_id, self.project.arch.bits, custom_string=True),
|
|
46
76
|
Const(None, None, len(s), self.project.arch.bits),
|
|
47
77
|
],
|
|
@@ -68,9 +98,21 @@ class InlinedStrcpy(PeepholeOptimizationStmtBase):
|
|
|
68
98
|
next_offset = None
|
|
69
99
|
stride = []
|
|
70
100
|
|
|
101
|
+
if not stride:
|
|
102
|
+
return None
|
|
103
|
+
min_stride_stmt_idx = min(stmt_idx_ for _, stmt_idx_, _ in stride)
|
|
104
|
+
if min_stride_stmt_idx > stmt_idx:
|
|
105
|
+
# the current statement is not involved in the stride. we can't simplify here, otherwise we
|
|
106
|
+
# will incorrectly remove the current statement
|
|
107
|
+
return None
|
|
108
|
+
|
|
71
109
|
integer, size = self.stride_to_int(stride)
|
|
72
|
-
|
|
110
|
+
prev_stmt = None if stmt_idx == 0 else block.statements[stmt_idx - 1]
|
|
111
|
+
min_str_length = 1 if prev_stmt is not None and self.is_inlined_strcpy(prev_stmt) else 4
|
|
112
|
+
r, s = self.is_integer_likely_a_string(integer, size, Endness.BE, min_length=min_str_length)
|
|
73
113
|
if r:
|
|
114
|
+
assert s is not None
|
|
115
|
+
|
|
74
116
|
# we remove all involved statements whose statement IDs are greater than the current one
|
|
75
117
|
for _, stmt_idx_, _ in reversed(stride):
|
|
76
118
|
if stmt_idx_ <= stmt_idx:
|
|
@@ -83,7 +125,7 @@ class InlinedStrcpy(PeepholeOptimizationStmtBase):
|
|
|
83
125
|
stmt.idx,
|
|
84
126
|
"strncpy",
|
|
85
127
|
args=[
|
|
86
|
-
|
|
128
|
+
strcpy_dst,
|
|
87
129
|
Const(None, None, str_id, self.project.arch.bits, custom_string=True),
|
|
88
130
|
Const(None, None, len(s), self.project.arch.bits),
|
|
89
131
|
],
|
|
@@ -101,10 +143,13 @@ class InlinedStrcpy(PeepholeOptimizationStmtBase):
|
|
|
101
143
|
for _, _, v in stride:
|
|
102
144
|
size += v.size
|
|
103
145
|
n <<= v.bits
|
|
146
|
+
assert isinstance(v.value, int)
|
|
104
147
|
n |= v.value
|
|
105
148
|
return n, size
|
|
106
149
|
|
|
107
150
|
def collect_constant_stores(self, block, starting_stmt_idx: int) -> dict[int, tuple[int, Const | None]]:
|
|
151
|
+
assert self.project is not None
|
|
152
|
+
|
|
108
153
|
r = {}
|
|
109
154
|
for idx, stmt in enumerate(block.statements):
|
|
110
155
|
if idx < starting_stmt_idx:
|
|
@@ -158,3 +203,15 @@ class InlinedStrcpy(PeepholeOptimizationStmtBase):
|
|
|
158
203
|
return False, None
|
|
159
204
|
return True, "".join(chars)
|
|
160
205
|
return False, None
|
|
206
|
+
|
|
207
|
+
@staticmethod
|
|
208
|
+
def is_inlined_strcpy(stmt: Statement) -> bool:
|
|
209
|
+
return (
|
|
210
|
+
isinstance(stmt, Call)
|
|
211
|
+
and isinstance(stmt.target, str)
|
|
212
|
+
and stmt.target == "strncpy"
|
|
213
|
+
and stmt.args is not None
|
|
214
|
+
and len(stmt.args) == 3
|
|
215
|
+
and isinstance(stmt.args[1], Const)
|
|
216
|
+
and hasattr(stmt.args[1], "custom_string")
|
|
217
|
+
)
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# pylint:disable=arguments-differ
|
|
2
2
|
from __future__ import annotations
|
|
3
3
|
|
|
4
|
-
from angr.ailment.expression import Expression, BinaryOp, Const, Register, StackBaseOffset
|
|
4
|
+
from angr.ailment.expression import Expression, BinaryOp, Const, Register, StackBaseOffset, UnaryOp, VirtualVariable
|
|
5
5
|
from angr.ailment.statement import Call, Store
|
|
6
6
|
|
|
7
7
|
from angr import SIM_LIBRARIES
|
|
@@ -21,12 +21,12 @@ class InlinedStrcpyConsolidation(PeepholeOptimizationMultiStmtBase):
|
|
|
21
21
|
|
|
22
22
|
def optimize(self, stmts: list[Call], **kwargs):
|
|
23
23
|
last_stmt, stmt = stmts
|
|
24
|
-
if
|
|
24
|
+
if InlinedStrcpy.is_inlined_strcpy(last_stmt):
|
|
25
25
|
s_last: bytes = self.kb.custom_strings[last_stmt.args[1].value]
|
|
26
26
|
addr_last = last_stmt.args[0]
|
|
27
27
|
new_str = None # will be set if consolidation should happen
|
|
28
28
|
|
|
29
|
-
if isinstance(stmt, Call) and
|
|
29
|
+
if isinstance(stmt, Call) and InlinedStrcpy.is_inlined_strcpy(stmt):
|
|
30
30
|
# consolidating two calls
|
|
31
31
|
s_curr: bytes = self.kb.custom_strings[stmt.args[1].value]
|
|
32
32
|
addr_curr = stmt.args[0]
|
|
@@ -74,22 +74,19 @@ class InlinedStrcpyConsolidation(PeepholeOptimizationMultiStmtBase):
|
|
|
74
74
|
|
|
75
75
|
return None
|
|
76
76
|
|
|
77
|
-
@staticmethod
|
|
78
|
-
def _is_inlined_strcpy(stmt: Call):
|
|
79
|
-
return (
|
|
80
|
-
isinstance(stmt.target, str)
|
|
81
|
-
and stmt.target == "strncpy"
|
|
82
|
-
and len(stmt.args) == 3
|
|
83
|
-
and isinstance(stmt.args[1], Const)
|
|
84
|
-
and hasattr(stmt.args[1], "custom_string")
|
|
85
|
-
)
|
|
86
|
-
|
|
87
77
|
@staticmethod
|
|
88
78
|
def _parse_addr(addr: Expression) -> tuple[Expression, int]:
|
|
89
79
|
if isinstance(addr, Register):
|
|
90
80
|
return addr, 0
|
|
91
81
|
if isinstance(addr, StackBaseOffset):
|
|
92
82
|
return StackBaseOffset(None, addr.bits, 0), addr.offset
|
|
83
|
+
if (
|
|
84
|
+
isinstance(addr, UnaryOp)
|
|
85
|
+
and addr.op == "Reference"
|
|
86
|
+
and isinstance(addr.operand, VirtualVariable)
|
|
87
|
+
and addr.operand.was_stack
|
|
88
|
+
):
|
|
89
|
+
return StackBaseOffset(None, addr.bits, 0), addr.operand.stack_offset
|
|
93
90
|
if isinstance(addr, BinaryOp):
|
|
94
91
|
if addr.op == "Add" and isinstance(addr.operands[1], Const):
|
|
95
92
|
base_0, offset_0 = InlinedStrcpyConsolidation._parse_addr(addr.operands[0])
|
|
@@ -27,6 +27,42 @@ STEP_LIMIT_FIND = 500
|
|
|
27
27
|
STEP_LIMIT_ANALYSIS = 5000
|
|
28
28
|
|
|
29
29
|
|
|
30
|
+
ALL_X64_XMM_REGS = {
|
|
31
|
+
capstone.x86.X86_REG_XMM0,
|
|
32
|
+
capstone.x86.X86_REG_XMM1,
|
|
33
|
+
capstone.x86.X86_REG_XMM2,
|
|
34
|
+
capstone.x86.X86_REG_XMM3,
|
|
35
|
+
capstone.x86.X86_REG_XMM4,
|
|
36
|
+
capstone.x86.X86_REG_XMM5,
|
|
37
|
+
capstone.x86.X86_REG_XMM6,
|
|
38
|
+
capstone.x86.X86_REG_XMM7,
|
|
39
|
+
capstone.x86.X86_REG_XMM8,
|
|
40
|
+
capstone.x86.X86_REG_XMM9,
|
|
41
|
+
capstone.x86.X86_REG_XMM10,
|
|
42
|
+
capstone.x86.X86_REG_XMM11,
|
|
43
|
+
capstone.x86.X86_REG_XMM12,
|
|
44
|
+
capstone.x86.X86_REG_XMM13,
|
|
45
|
+
capstone.x86.X86_REG_XMM14,
|
|
46
|
+
capstone.x86.X86_REG_XMM15,
|
|
47
|
+
capstone.x86.X86_REG_XMM16,
|
|
48
|
+
capstone.x86.X86_REG_XMM17,
|
|
49
|
+
capstone.x86.X86_REG_XMM18,
|
|
50
|
+
capstone.x86.X86_REG_XMM19,
|
|
51
|
+
capstone.x86.X86_REG_XMM20,
|
|
52
|
+
capstone.x86.X86_REG_XMM21,
|
|
53
|
+
capstone.x86.X86_REG_XMM22,
|
|
54
|
+
capstone.x86.X86_REG_XMM23,
|
|
55
|
+
capstone.x86.X86_REG_XMM24,
|
|
56
|
+
capstone.x86.X86_REG_XMM25,
|
|
57
|
+
capstone.x86.X86_REG_XMM26,
|
|
58
|
+
capstone.x86.X86_REG_XMM27,
|
|
59
|
+
capstone.x86.X86_REG_XMM28,
|
|
60
|
+
capstone.x86.X86_REG_XMM29,
|
|
61
|
+
capstone.x86.X86_REG_XMM30,
|
|
62
|
+
capstone.x86.X86_REG_XMM31,
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
|
|
30
66
|
class StringDeobFuncDescriptor:
|
|
31
67
|
"""
|
|
32
68
|
Describes a string deobfuscation function.
|
|
@@ -478,10 +514,12 @@ class StringObfuscationFinder(Analysis):
|
|
|
478
514
|
actual_addrs = action.actual_addrs
|
|
479
515
|
if action.type == "mem":
|
|
480
516
|
if action.action == "read":
|
|
517
|
+
assert action.size is not None
|
|
481
518
|
for a in actual_addrs:
|
|
482
519
|
for size in range(action.size.ast // 8):
|
|
483
520
|
all_global_reads.append(a + size)
|
|
484
521
|
elif action.action == "write":
|
|
522
|
+
assert action.size is not None
|
|
485
523
|
for a in actual_addrs:
|
|
486
524
|
for size in range(action.size.ast // 8):
|
|
487
525
|
all_global_writes.append(a + size)
|
|
@@ -598,16 +636,16 @@ class StringObfuscationFinder(Analysis):
|
|
|
598
636
|
type3_functions = []
|
|
599
637
|
|
|
600
638
|
for func in function_candidates:
|
|
601
|
-
if not
|
|
639
|
+
if not 1 <= len(func.block_addrs_set) < 14:
|
|
602
640
|
continue
|
|
603
641
|
|
|
604
642
|
# if it has a prototype recovered, it must have four arguments
|
|
605
|
-
if func.prototype is not None and len(func.prototype.args)
|
|
643
|
+
if func.prototype is not None and len(func.prototype.args) not in {3, 4}:
|
|
606
644
|
continue
|
|
607
645
|
|
|
608
646
|
# the function must call some other functions
|
|
609
|
-
if callgraph_digraph.out_degree[func.addr] == 0:
|
|
610
|
-
|
|
647
|
+
# if callgraph_digraph.out_degree[func.addr] == 0:
|
|
648
|
+
# continue
|
|
611
649
|
|
|
612
650
|
# take a look at its call sites
|
|
613
651
|
func_node = cfg.get_any_node(func.addr)
|
|
@@ -635,30 +673,34 @@ class StringObfuscationFinder(Analysis):
|
|
|
635
673
|
continue
|
|
636
674
|
if dec.codegen is None or not dec.codegen.text:
|
|
637
675
|
continue
|
|
676
|
+
|
|
638
677
|
if not self._like_type3_deobfuscation_function(dec.codegen.text):
|
|
639
678
|
continue
|
|
640
679
|
|
|
641
680
|
# examine the first 100 call sites and see if any of them returns a valid string
|
|
642
681
|
valid = False
|
|
682
|
+
guessed_size = False
|
|
643
683
|
for i in range(min(100, len(call_sites))):
|
|
644
684
|
call_site_block = self.project.factory.block(call_sites[i].addr)
|
|
645
685
|
if not self._is_block_setting_constants_to_stack(call_site_block):
|
|
646
686
|
continue
|
|
647
687
|
|
|
648
688
|
# simulate an execution to see if it really works
|
|
649
|
-
data = self._type3_prepare_and_execute(
|
|
650
|
-
func.addr, call_sites[i].addr, call_sites[i].function_address, cfg
|
|
689
|
+
data, guessed_size = self._type3_prepare_and_execute(
|
|
690
|
+
func.addr, call_sites[i].addr, call_sites[i].function_address, cfg # type:ignore
|
|
651
691
|
)
|
|
652
692
|
if data is None:
|
|
653
693
|
continue
|
|
654
|
-
if len(data) > 3
|
|
655
|
-
|
|
656
|
-
|
|
694
|
+
if len(data) > 3:
|
|
695
|
+
consecutive_printable_strs = self._consecutive_printable_substrings(data, min_length=4)
|
|
696
|
+
if consecutive_printable_strs:
|
|
697
|
+
valid = True
|
|
698
|
+
break
|
|
657
699
|
|
|
658
700
|
if valid:
|
|
659
701
|
desc = StringDeobFuncDescriptor()
|
|
660
702
|
desc.string_output_arg_idx = 0
|
|
661
|
-
desc.string_length_arg_idx = 1
|
|
703
|
+
desc.string_length_arg_idx = 1 if not guessed_size else None
|
|
662
704
|
desc.string_null_terminating = False
|
|
663
705
|
type3_functions.append((func.addr, desc))
|
|
664
706
|
|
|
@@ -687,11 +729,15 @@ class StringObfuscationFinder(Analysis):
|
|
|
687
729
|
if cfg is None:
|
|
688
730
|
raise AngrAnalysisError("StringObfuscationFinder needs a CFG for the analysis")
|
|
689
731
|
|
|
690
|
-
|
|
732
|
+
cfg_node = cfg.get_any_node(func_addr)
|
|
733
|
+
if cfg_node is None:
|
|
734
|
+
raise AngrAnalysisError(f"Cannot find the CFG node for function {func_addr:#x}")
|
|
735
|
+
call_sites = cfg.get_predecessors(cfg_node)
|
|
691
736
|
callinsn2content = {}
|
|
692
737
|
for idx, call_site in enumerate(call_sites):
|
|
693
738
|
_l.debug("Analyzing type 3 candidate call site %#x (%d/%d)...", call_site.addr, idx + 1, len(call_sites))
|
|
694
|
-
|
|
739
|
+
assert call_site.function_address is not None
|
|
740
|
+
data, _ = self._type3_prepare_and_execute(func_addr, call_site.addr, call_site.function_address, cfg)
|
|
695
741
|
if data:
|
|
696
742
|
callinsn2content[call_site.instruction_addrs[-1]] = data
|
|
697
743
|
# print(hex(call_site.addr), data)
|
|
@@ -722,12 +768,14 @@ class StringObfuscationFinder(Analysis):
|
|
|
722
768
|
|
|
723
769
|
@staticmethod
|
|
724
770
|
def _like_type3_deobfuscation_function(code: str) -> bool:
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
)
|
|
729
|
-
|
|
730
|
-
def _type3_prepare_and_execute(
|
|
771
|
+
has_bitwise_ops = "^" in code or ">>" in code or "<<" in code or "~" in code
|
|
772
|
+
has_loops = "do" in code or "while" in code or "for" in code
|
|
773
|
+
has_many_bitwise_ops = code.count("^") + code.count(">>") + code.count("<<") + code.count("~") > 5
|
|
774
|
+
return has_bitwise_ops and (has_loops or has_many_bitwise_ops)
|
|
775
|
+
|
|
776
|
+
def _type3_prepare_and_execute(
|
|
777
|
+
self, func_addr: int, call_site_addr: int, call_site_func_addr: int, cfg
|
|
778
|
+
) -> tuple[bytes | None, bool]:
|
|
731
779
|
blocks_at_callsite = [call_site_addr]
|
|
732
780
|
|
|
733
781
|
# backtrack from call site to include all previous consecutive blocks
|
|
@@ -773,6 +821,7 @@ class StringObfuscationFinder(Analysis):
|
|
|
773
821
|
# setup sp and bp, just in case
|
|
774
822
|
state.regs._sp = 0x7FFF0000
|
|
775
823
|
bp_set = False
|
|
824
|
+
assert prop.model.input_states is not None
|
|
776
825
|
prop_state = prop.model.input_states.get(call_site_addr, None)
|
|
777
826
|
if prop_state is not None:
|
|
778
827
|
for reg_offset, reg_width in reg_reads:
|
|
@@ -798,7 +847,7 @@ class StringObfuscationFinder(Analysis):
|
|
|
798
847
|
else:
|
|
799
848
|
simgr.step()
|
|
800
849
|
if not simgr.active:
|
|
801
|
-
return None
|
|
850
|
+
return None, False
|
|
802
851
|
|
|
803
852
|
in_state = simgr.active[0]
|
|
804
853
|
|
|
@@ -821,33 +870,63 @@ class StringObfuscationFinder(Analysis):
|
|
|
821
870
|
try:
|
|
822
871
|
ret_value = callable_0()
|
|
823
872
|
except (AngrCallableMultistateError, AngrCallableError):
|
|
824
|
-
return None
|
|
873
|
+
return None, False
|
|
825
874
|
|
|
826
875
|
out_state = callable_0.result_state
|
|
827
876
|
|
|
828
877
|
# figure out what was written
|
|
878
|
+
assert out_state is not None
|
|
829
879
|
ptr = out_state.memory.load(ret_value, size=self.project.arch.bytes, endness=self.project.arch.memory_endness)
|
|
880
|
+
if out_state.memory.load(ptr, size=4).concrete_value == 0:
|
|
881
|
+
# fall back to using the return value as the pointer
|
|
882
|
+
ptr = ret_value
|
|
883
|
+
if out_state.memory.load(ptr, size=4).concrete_value == 0:
|
|
884
|
+
# can't find a valid pointer
|
|
885
|
+
return None, False
|
|
886
|
+
|
|
830
887
|
size = out_state.memory.load(ret_value + 8, size=4, endness=self.project.arch.memory_endness)
|
|
888
|
+
guessed_size = False
|
|
889
|
+
if size.symbolic or size.concrete_value == 0 or size.concrete_value >= 1024:
|
|
890
|
+
size = 64
|
|
891
|
+
guessed_size = True
|
|
831
892
|
# TODO: Support lists with varied-length elements
|
|
832
893
|
data = out_state.memory.load(ptr, size=size, endness="Iend_BE")
|
|
833
894
|
if data.symbolic:
|
|
834
|
-
return None
|
|
895
|
+
return None, False
|
|
835
896
|
|
|
836
|
-
return out_state.solver.eval(data, cast_to=bytes)
|
|
897
|
+
return out_state.solver.eval(data, cast_to=bytes), guessed_size
|
|
837
898
|
|
|
838
899
|
@staticmethod
|
|
839
900
|
def _is_block_setting_constants_to_stack(block, threshold: int = 5) -> bool:
|
|
840
|
-
|
|
901
|
+
insn_setting_const_bytes = 0
|
|
902
|
+
xmm_has_const = False
|
|
841
903
|
for insn in block.capstone.insns:
|
|
842
|
-
if (
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
904
|
+
if insn.mnemonic.startswith("mov") and len(insn.operands) == 2:
|
|
905
|
+
if (
|
|
906
|
+
insn.operands[0].type == capstone.x86.X86_OP_MEM
|
|
907
|
+
and insn.operands[0].mem.base in {capstone.x86.X86_REG_RSP, capstone.x86.X86_REG_RBP}
|
|
908
|
+
and insn.operands[1].type == capstone.x86.X86_OP_IMM
|
|
909
|
+
):
|
|
910
|
+
# mov [rsp|rbp + offset], imm
|
|
911
|
+
insn_setting_const_bytes += 1 # FIXME: How to get the size of the mov in capstone?
|
|
912
|
+
if (
|
|
913
|
+
insn.operands[0].type == capstone.x86.X86_OP_REG
|
|
914
|
+
and insn.operands[0].reg in ALL_X64_XMM_REGS
|
|
915
|
+
and insn.operands[1].type == capstone.x86.X86_OP_MEM
|
|
916
|
+
and insn.operands[1].mem.base == capstone.x86.X86_REG_RIP
|
|
917
|
+
):
|
|
918
|
+
xmm_has_const = True
|
|
919
|
+
if (
|
|
920
|
+
xmm_has_const
|
|
921
|
+
and insn.operands[0].type == capstone.x86.X86_OP_MEM
|
|
922
|
+
and insn.operands[0].mem.base in {capstone.x86.X86_REG_RSP, capstone.x86.X86_REG_RBP}
|
|
923
|
+
and insn.operands[1].type == capstone.x86.X86_OP_REG
|
|
924
|
+
and insn.operands[1].reg in ALL_X64_XMM_REGS
|
|
925
|
+
):
|
|
926
|
+
# mov [rsp|rbp + offset], xmm0 - 31
|
|
927
|
+
insn_setting_const_bytes += 16
|
|
928
|
+
|
|
929
|
+
return insn_setting_const_bytes >= threshold
|
|
851
930
|
|
|
852
931
|
@staticmethod
|
|
853
932
|
def _is_string_reasonable(s: bytes) -> bool:
|
|
@@ -857,5 +936,24 @@ class StringObfuscationFinder(Analysis):
|
|
|
857
936
|
s = s.replace(b"\x00", b"")
|
|
858
937
|
return all(chr(ch) in string.printable for ch in s)
|
|
859
938
|
|
|
939
|
+
@staticmethod
|
|
940
|
+
def _consecutive_printable_substrings(s: bytes, min_length: int = 3) -> list[bytes]:
|
|
941
|
+
"""
|
|
942
|
+
Find all consecutive printable substrings in a string.
|
|
943
|
+
"""
|
|
944
|
+
substrings = []
|
|
945
|
+
current_substring = b""
|
|
946
|
+
for ch in s:
|
|
947
|
+
if chr(ch) in string.printable:
|
|
948
|
+
current_substring += bytes([ch])
|
|
949
|
+
else:
|
|
950
|
+
if current_substring:
|
|
951
|
+
if len(current_substring) >= min_length:
|
|
952
|
+
substrings.append(current_substring)
|
|
953
|
+
current_substring = b""
|
|
954
|
+
if current_substring:
|
|
955
|
+
substrings.append(current_substring)
|
|
956
|
+
return substrings
|
|
957
|
+
|
|
860
958
|
|
|
861
959
|
AnalysesHub.register_default("StringObfuscationFinder", StringObfuscationFinder)
|
angr/engines/icicle.py
CHANGED
|
@@ -123,7 +123,7 @@ class IcicleEngine(ConcreteEngine):
|
|
|
123
123
|
if proj is None:
|
|
124
124
|
raise ValueError("IcicleEngine requires a project to be set")
|
|
125
125
|
|
|
126
|
-
emu = Icicle(icicle_arch, PROCESSORS_DIR, True)
|
|
126
|
+
emu = Icicle(icicle_arch, PROCESSORS_DIR, True, True)
|
|
127
127
|
|
|
128
128
|
copied_registers = set()
|
|
129
129
|
|
|
@@ -174,6 +174,11 @@ class IcicleEngine(ConcreteEngine):
|
|
|
174
174
|
initial_cpu_icount=emu.cpu_icount,
|
|
175
175
|
)
|
|
176
176
|
|
|
177
|
+
# 3. Copy edge hitmap
|
|
178
|
+
edge_hitmap = state.history.last_edge_hitmap
|
|
179
|
+
if edge_hitmap is not None:
|
|
180
|
+
emu.edge_hitmap = edge_hitmap
|
|
181
|
+
|
|
177
182
|
return (emu, translation_data)
|
|
178
183
|
|
|
179
184
|
@staticmethod
|
|
@@ -221,9 +226,12 @@ class IcicleEngine(ConcreteEngine):
|
|
|
221
226
|
# Skip the last block, because it will be added by Successors
|
|
222
227
|
state.history.recent_bbl_addrs.extend([b[0] for b in emu.recent_blocks][:-1])
|
|
223
228
|
|
|
224
|
-
#
|
|
229
|
+
# 3.3. Set history.recent_instruction_count
|
|
225
230
|
state.history.recent_instruction_count = emu.cpu_icount - translation_data.initial_cpu_icount
|
|
226
231
|
|
|
232
|
+
# 3.4. Set edge hitmap
|
|
233
|
+
state.history.edge_hitmap = emu.edge_hitmap
|
|
234
|
+
|
|
227
235
|
return state
|
|
228
236
|
|
|
229
237
|
@override
|
angr/rustylib.pyd
CHANGED
|
Binary file
|
angr/state_plugins/history.py
CHANGED
|
@@ -59,6 +59,9 @@ class SimStateHistory(SimStatePlugin):
|
|
|
59
59
|
self.recent_syscall_count = 0 if clone is None else clone.recent_syscall_count
|
|
60
60
|
self.recent_instruction_count = -1 if clone is None else clone.recent_instruction_count
|
|
61
61
|
|
|
62
|
+
# afl-style hitmap
|
|
63
|
+
self.edge_hitmap: bytes | None = None if clone is None else clone.edge_hitmap
|
|
64
|
+
|
|
62
65
|
# satness stuff
|
|
63
66
|
self._all_constraints = ()
|
|
64
67
|
self._satisfiable = None
|
|
@@ -402,6 +405,19 @@ class SimStateHistory(SimStatePlugin):
|
|
|
402
405
|
def stack_actions(self):
|
|
403
406
|
return LambdaIterIter(self, operator.attrgetter("recent_stack_actions"))
|
|
404
407
|
|
|
408
|
+
@property
|
|
409
|
+
def last_edge_hitmap(self) -> bytes | None:
|
|
410
|
+
"""
|
|
411
|
+
Returns the last edge hitmap in the history chain, or None if there is no edge hitmap.
|
|
412
|
+
"""
|
|
413
|
+
history = self
|
|
414
|
+
while history is not None:
|
|
415
|
+
if history.edge_hitmap is not None:
|
|
416
|
+
return history.edge_hitmap
|
|
417
|
+
# Traverse to the previous state in the history chain
|
|
418
|
+
history = history.parent
|
|
419
|
+
return None
|
|
420
|
+
|
|
405
421
|
#
|
|
406
422
|
# Merging support
|
|
407
423
|
#
|
angr/unicornlib.dll
CHANGED
|
Binary file
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: angr
|
|
3
|
-
Version: 9.2.
|
|
3
|
+
Version: 9.2.166
|
|
4
4
|
Summary: A multi-architecture binary analysis toolkit, with the ability to perform dynamic symbolic execution and various static analyses on binaries
|
|
5
5
|
License: BSD-2-Clause
|
|
6
6
|
Project-URL: Homepage, https://angr.io/
|
|
@@ -16,12 +16,12 @@ Description-Content-Type: text/markdown
|
|
|
16
16
|
License-File: LICENSE
|
|
17
17
|
Requires-Dist: cxxheaderparser
|
|
18
18
|
Requires-Dist: GitPython
|
|
19
|
-
Requires-Dist: archinfo==9.2.
|
|
19
|
+
Requires-Dist: archinfo==9.2.166
|
|
20
20
|
Requires-Dist: cachetools
|
|
21
21
|
Requires-Dist: capstone==5.0.3
|
|
22
22
|
Requires-Dist: cffi>=1.14.0
|
|
23
|
-
Requires-Dist: claripy==9.2.
|
|
24
|
-
Requires-Dist: cle==9.2.
|
|
23
|
+
Requires-Dist: claripy==9.2.166
|
|
24
|
+
Requires-Dist: cle==9.2.166
|
|
25
25
|
Requires-Dist: mulpyplexer
|
|
26
26
|
Requires-Dist: networkx!=2.8.1,>=2.0
|
|
27
27
|
Requires-Dist: protobuf>=5.28.2
|
|
@@ -30,7 +30,7 @@ Requires-Dist: pycparser>=2.18
|
|
|
30
30
|
Requires-Dist: pydemumble
|
|
31
31
|
Requires-Dist: pyformlang
|
|
32
32
|
Requires-Dist: pypcode<4.0,>=3.2.1
|
|
33
|
-
Requires-Dist: pyvex==9.2.
|
|
33
|
+
Requires-Dist: pyvex==9.2.166
|
|
34
34
|
Requires-Dist: rich>=13.1.0
|
|
35
35
|
Requires-Dist: sortedcontainers
|
|
36
36
|
Requires-Dist: sympy
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
angr/__init__.py,sha256=
|
|
1
|
+
angr/__init__.py,sha256=QA1GCXMLkM8Ngg8PGamnWMZorq80p6f3ZJuK1hWbs5g,9246
|
|
2
2
|
angr/__main__.py,sha256=AK9V6uPZ58UuTKmmiH_Kgn5pG9AvjnmJCPOku69A-WU,4993
|
|
3
3
|
angr/annocfg.py,sha256=0NIvcuCskwz45hbBzigUTAuCrYutjDMwEXtMJf0y0S0,10742
|
|
4
4
|
angr/blade.py,sha256=OGGW-oggqI9_LvgZhiQuh9Ktkvf3vhRBmH0XviNyZ6o,15801
|
|
@@ -15,7 +15,7 @@ angr/keyed_region.py,sha256=Cx6dadqFgEvRmEHTbCJpg9mXkBtKGc_BKckHc6bk1IU,17992
|
|
|
15
15
|
angr/knowledge_base.py,sha256=hRoSLuLaOXmddTSF9FN5TVs7liftpBGq_IICz5AaYBk,4533
|
|
16
16
|
angr/project.py,sha256=AJmBgv3U8iv-hGEfnpmESVVjK16NiBAemmahLuqz7yk,38096
|
|
17
17
|
angr/py.typed,sha256=la67KBlbjXN-_-DfGNcdOcjYumVpKG_Tkw-8n5dnGB4,8
|
|
18
|
-
angr/rustylib.pyd,sha256=
|
|
18
|
+
angr/rustylib.pyd,sha256=iw_FVBIuVxeKmAOV00s--qkAGMlp-KTGZFZ1vkGqykM,4456960
|
|
19
19
|
angr/serializable.py,sha256=l908phj_KcqopEEL_oCufbP_H6cm3Wc9v-5xdux1-6g,1533
|
|
20
20
|
angr/sim_manager.py,sha256=w7yTfWR-P9yoN5x85eeiNpj9dTrnjpJ3o5aoFpDAPnc,39396
|
|
21
21
|
angr/sim_options.py,sha256=tfl57MFECmA7uvMMtQrRRbpG8g_A9jKOzwY6nApTW6Y,17782
|
|
@@ -27,7 +27,7 @@ angr/sim_variable.py,sha256=3DssmMw5G7m_-MYToJ3LBP-ooy2UQEuI2YgxIuX3d4Y,13177
|
|
|
27
27
|
angr/slicer.py,sha256=DND0BERanYKafasRH9MDFAng0rSjdjmzXj2-phCD6CQ,10634
|
|
28
28
|
angr/state_hierarchy.py,sha256=qDQCUGXmQm3vOxE3CSoiqTH4OAFFOWZZt9BLhNpeOhA,8484
|
|
29
29
|
angr/tablespecs.py,sha256=Kx1e87FxTx3_ZN7cAHWZSRpdInT4Vfj5gExAWtLkLTw,3259
|
|
30
|
-
angr/unicornlib.dll,sha256=
|
|
30
|
+
angr/unicornlib.dll,sha256=eUwgddCJ-jHUsx1XezNYEZ5e6Roh5ucCPZd1-1QB2Mg,813568
|
|
31
31
|
angr/vaults.py,sha256=D_gkDegCyPlZMKGC5E8zINYAaZfSXNWbmhX0rXCYpvM,9718
|
|
32
32
|
angr/ailment/__init__.py,sha256=X1LTS6MuTovGtbXBjZendUVOzRk-ib-bP0imuqJDOYI,2039
|
|
33
33
|
angr/ailment/block.py,sha256=rkmimsNPhrUabVVbRd2IgCaW0hA2_isvAsKlYtHZhgY,2428
|
|
@@ -42,7 +42,7 @@ angr/ailment/statement.py,sha256=3JEhg-JDRrNjaeHFgO-liEIrZRW6v5sIsOqcGHiuM3A,304
|
|
|
42
42
|
angr/ailment/tagged_object.py,sha256=48xIMC5WKebEpA12Zq6dQz3evvKxT3ULEu2cPdw9w-Y,1566
|
|
43
43
|
angr/ailment/utils.py,sha256=YprhO7yJcd5jUKDbCXFMmPdCd8BIOhqXti-zb3mtxRQ,2830
|
|
44
44
|
angr/analyses/__init__.py,sha256=KFu0Otm7bqAcjX8dsnQzphJmkUVxMLssjFIJJOci32U,3479
|
|
45
|
-
angr/analyses/analysis.py,sha256=
|
|
45
|
+
angr/analyses/analysis.py,sha256=2ABUppMZr97ZEAmxOQuXo-eyw5aF0ZASAii8SuuncNo,15685
|
|
46
46
|
angr/analyses/backward_slice.py,sha256=fdE1GbppXjGufLzfOQkeuIzGX0yx9ISHJlOGqS6m1lg,27218
|
|
47
47
|
angr/analyses/binary_optimizer.py,sha256=xFDv8c1s5nQUKY_EWYRCuVroSXFkMiSLl5LngPiysDA,26145
|
|
48
48
|
angr/analyses/bindiff.py,sha256=ysphJ9cg7yxnW7HxOSLYEohrTdq9ZK-8cVvKQ0U9u9M,64020
|
|
@@ -88,7 +88,7 @@ angr/analyses/cfg/cfg.py,sha256=dc9M91CaLeEKduYfMwpsT_01x6XyYuoNvgvcDKtbN-I,3177
|
|
|
88
88
|
angr/analyses/cfg/cfg_arch_options.py,sha256=_XRewFZ51SeNaxChadb6_ER7-8LW8KXeTIpoP8_iRj0,3506
|
|
89
89
|
angr/analyses/cfg/cfg_base.py,sha256=eleUmM_znfsl6KV7T2tUmSEy2iLmPsrT3dNB2BYudd4,124964
|
|
90
90
|
angr/analyses/cfg/cfg_emulated.py,sha256=4lKrmGVfCGt8l3Nz9zH6EcUcAVLwyOM7p81DlxUVNGA,148351
|
|
91
|
-
angr/analyses/cfg/cfg_fast.py,sha256=
|
|
91
|
+
angr/analyses/cfg/cfg_fast.py,sha256=e0rl_AIM1ne-GZK7yuDPNkceyNSZIYY77sg0-jvjsyo,232943
|
|
92
92
|
angr/analyses/cfg/cfg_fast_soot.py,sha256=8YgMtY_8w4nAMcHR6n-q_eFvKwsvNz0anUH7EzIL1B4,25924
|
|
93
93
|
angr/analyses/cfg/cfg_job_base.py,sha256=Zshze972MakTsd-licQz77lac17igQaaTsAteHeHhYQ,5974
|
|
94
94
|
angr/analyses/cfg/indirect_jump_resolvers/__init__.py,sha256=qWiTSIAQgXWmaYa9YYaiKsSTwUVClymaXv9sCX-bY-k,835
|
|
@@ -123,7 +123,7 @@ angr/analyses/decompiler/block_similarity.py,sha256=S1lTlXFyOmJlQa7I3y7xgLsENLS4
|
|
|
123
123
|
angr/analyses/decompiler/block_simplifier.py,sha256=XcX9wsBM4AL_WWqmFrtSUDeSv0a125cC1-Q1NhmTrNE,14777
|
|
124
124
|
angr/analyses/decompiler/callsite_maker.py,sha256=O7vjwNTmCLijzjKgSCaoX3IX4_sC-u-OqoKhE7lahlc,23427
|
|
125
125
|
angr/analyses/decompiler/clinic.py,sha256=1TnX_kIvZ4kFoK818Tyq98ONATP82T9n7fB4akx9yHg,150921
|
|
126
|
-
angr/analyses/decompiler/condition_processor.py,sha256=
|
|
126
|
+
angr/analyses/decompiler/condition_processor.py,sha256=ECv0HHJt48tOGjzKUQezZ1lUS3_Qqu2a8E-6W5SMerI,54425
|
|
127
127
|
angr/analyses/decompiler/decompilation_cache.py,sha256=gAZtyXs-eoFj3680bTrJVAZcIoaPsFK0kayu30NYLb4,1509
|
|
128
128
|
angr/analyses/decompiler/decompilation_options.py,sha256=NDB67DI1L-stvJ4b1eQkfV26HgDJ_rG9-6PEv08G9-8,8195
|
|
129
129
|
angr/analyses/decompiler/decompiler.py,sha256=3TsG9Tz4OQInSXcHhoASqxY7VhRsaK8xw-ZV9-Y-zhc,30533
|
|
@@ -197,7 +197,7 @@ angr/analyses/decompiler/optimization_passes/duplication_reverter/duplication_re
|
|
|
197
197
|
angr/analyses/decompiler/optimization_passes/duplication_reverter/errors.py,sha256=dJq1F3jbGBFWi0zIUmDu8bwUAKPt-JyAh5iegY9rYuU,527
|
|
198
198
|
angr/analyses/decompiler/optimization_passes/duplication_reverter/similarity.py,sha256=H9FGTyxHm-KbqgxuTe2qjMotboRbUyOTeiPVcD_8DSk,4411
|
|
199
199
|
angr/analyses/decompiler/optimization_passes/duplication_reverter/utils.py,sha256=_WiRuxiMaxRAYtU5LiHGQ383PiI0sCt-KgG2QFG0KX4,5176
|
|
200
|
-
angr/analyses/decompiler/peephole_optimizations/__init__.py,sha256=
|
|
200
|
+
angr/analyses/decompiler/peephole_optimizations/__init__.py,sha256=TSpLThx8U5YK05r779be8SozeTya0zbziPOZDKCGa6M,4930
|
|
201
201
|
angr/analyses/decompiler/peephole_optimizations/a_div_const_add_a_mul_n_div_const.py,sha256=HY6EQkThiyMaahz3bodJUqLBKWY2n4aKGbKyspMXN50,1641
|
|
202
202
|
angr/analyses/decompiler/peephole_optimizations/a_mul_const_div_shr_const.py,sha256=-V60wMaBKz1Ld1NcaQ8Dl0T4Xo9Qq6nfAQpXJ-MNsDI,1379
|
|
203
203
|
angr/analyses/decompiler/peephole_optimizations/a_mul_const_sub_a.py,sha256=5Gsq3DSQEWt3tZSkrxnbAEePkKC_dmpoQHZ2PVNlSfs,1158
|
|
@@ -221,8 +221,9 @@ angr/analyses/decompiler/peephole_optimizations/conv_a_sub0_shr_and.py,sha256=4f
|
|
|
221
221
|
angr/analyses/decompiler/peephole_optimizations/conv_shl_shr.py,sha256=STmu5FE0EHOkCdxFJt44DhMAjbAagnuics5VV6aNmnM,2110
|
|
222
222
|
angr/analyses/decompiler/peephole_optimizations/eager_eval.py,sha256=t1Kn5ffzwio7AUO3EDtAbGvBFiR2gaRLIXBpOZ9LSIU,20612
|
|
223
223
|
angr/analyses/decompiler/peephole_optimizations/extended_byte_and_mask.py,sha256=NU1D1xqyQi4SaCUrJ9bk51-hjcFNseQgqD0wgQkh558,2049
|
|
224
|
-
angr/analyses/decompiler/peephole_optimizations/
|
|
225
|
-
angr/analyses/decompiler/peephole_optimizations/
|
|
224
|
+
angr/analyses/decompiler/peephole_optimizations/inlined_memcpy.py,sha256=5OAgdFMTRlTggLQSUbVcUdgUmkJN7_p4wYkqt1A4AYQ,2944
|
|
225
|
+
angr/analyses/decompiler/peephole_optimizations/inlined_strcpy.py,sha256=q2IVsIFhfo0TGY3PfeOmCZqdpzUI2B3Tjv_p3_jpwl4,8668
|
|
226
|
+
angr/analyses/decompiler/peephole_optimizations/inlined_strcpy_consolidation.py,sha256=d-O_rIm0OrwK88P0zYBZcOY0ewTdCp4bnkJZDdWUUVw,4883
|
|
226
227
|
angr/analyses/decompiler/peephole_optimizations/inlined_wstrcpy.py,sha256=irbBK2HB75f27L2EnHPuwDHumz1GBYqVwB96zoe-SFM,6787
|
|
227
228
|
angr/analyses/decompiler/peephole_optimizations/invert_negated_logical_conjuction_disjunction.py,sha256=hRx0tuK_s47AEgPfaWYbzh5lPfBhx_anGDTVoIxHYkg,1990
|
|
228
229
|
angr/analyses/decompiler/peephole_optimizations/modulo_simplifier.py,sha256=M09Whprj6tOJdFI5n9a7b-82YZOgnm3QvIbISJ9Lvaw,3724
|
|
@@ -294,7 +295,7 @@ angr/analyses/deobfuscator/api_obf_finder.py,sha256=044ZCXK6D5BZjVyPfe0isAFDzDDD
|
|
|
294
295
|
angr/analyses/deobfuscator/api_obf_peephole_optimizer.py,sha256=jtUxKYTdmGu0c_8zmP8V3JUYzTcac0j1CNctic3e7QA,2215
|
|
295
296
|
angr/analyses/deobfuscator/api_obf_type2_finder.py,sha256=tPUfe_2jJV1uZB5cetgglf3T75E_UQZYVUFAfMACV9g,6389
|
|
296
297
|
angr/analyses/deobfuscator/irsb_reg_collector.py,sha256=q91IYpepptTQWcF0MJLHVCuvUsUuzPcL2XbbcIDV4eo,1290
|
|
297
|
-
angr/analyses/deobfuscator/string_obf_finder.py,sha256=
|
|
298
|
+
angr/analyses/deobfuscator/string_obf_finder.py,sha256=cbwako92izix5V6tct95PpqK6nUE7YEUyNU8EAcyTes,40528
|
|
298
299
|
angr/analyses/deobfuscator/string_obf_opt_passes.py,sha256=YzrsEKsUaUPshB8LqfwDso8aK7m0ySmR3i50T5ZiwNo,5360
|
|
299
300
|
angr/analyses/deobfuscator/string_obf_peephole_optimizer.py,sha256=_VQv2E2yOAZDAi53smQL5KcSLNe5FMqNUYC8jNSYXGs,1957
|
|
300
301
|
angr/analyses/fcp/__init__.py,sha256=E9dxFckDM9DijfU4RRg9SGL6xDKCz7yBBP-XSkS-S9U,115
|
|
@@ -434,7 +435,7 @@ angr/engines/concrete.py,sha256=kEt6Dyp8QAIaOP3oW5lRcDs_2UMP2vbiNzylGiqvf7g,2143
|
|
|
434
435
|
angr/engines/engine.py,sha256=2kwOT-sbxKXAVX2PmsPTr8Ax36Vxq6hkRdDKaITBQNc,657
|
|
435
436
|
angr/engines/failure.py,sha256=redqmkSuJoIc828hpmX3CTk4EqQ-PeEn7MK2uIqSAc0,1040
|
|
436
437
|
angr/engines/hook.py,sha256=lAEYYAXQY_GDOpsz3JZ7IswxrBccZnZ6EaQwyNBb4W8,2590
|
|
437
|
-
angr/engines/icicle.py,sha256=
|
|
438
|
+
angr/engines/icicle.py,sha256=8mAL_YEumoP95C3p0r7yoGdi68Xq2sz9-qpGjAu5ffE,10333
|
|
438
439
|
angr/engines/procedure.py,sha256=8kgFH56nkqSWm0p1apuGBaFngl-4BnAzE0bXhq9mc6Y,2561
|
|
439
440
|
angr/engines/successors.py,sha256=oQCW7Knxb4zz7EP6Mi6RrRNrwuhbv5fnX8UL76nn0sY,29501
|
|
440
441
|
angr/engines/syscall.py,sha256=7wYTriURsDTTi3PEBj4u3ZWDi7RHBV-gRrxTRxwMAVk,2166
|
|
@@ -1291,7 +1292,7 @@ angr/state_plugins/debug_variables.py,sha256=LR-lsjnn6FVrEr8RCVkhA_gyeeh1jiHC92u
|
|
|
1291
1292
|
angr/state_plugins/filesystem.py,sha256=qkM2zCfcrSBjt-g3RO1VYbjHPNRSdvsNRQR_M47pqFU,15765
|
|
1292
1293
|
angr/state_plugins/gdb.py,sha256=CrilA-FPDNm7Fk5fWx9wOn_gVb4SRJyFyNPcef7oOr0,5175
|
|
1293
1294
|
angr/state_plugins/globals.py,sha256=pU8_VPSjLLsW2x7vr_f2uFRMEIobqDjXQJUp5YDbkNU,1593
|
|
1294
|
-
angr/state_plugins/history.py,sha256=
|
|
1295
|
+
angr/state_plugins/history.py,sha256=f_d3QxcN0TYe2tZxCz1ojBKmb2oNjIAuKWYNZFEfL8I,19782
|
|
1295
1296
|
angr/state_plugins/inspect.py,sha256=9hXBRAL9C8rGqGdS9joydSsBsIrgu_pVLNmZeO_fqFs,11350
|
|
1296
1297
|
angr/state_plugins/javavm_classloader.py,sha256=QOkvHSVnoiaEKX6HK520viBemFpxXBcaXeC_csLSmhY,5589
|
|
1297
1298
|
angr/state_plugins/jni_references.py,sha256=ufNi66U9-O2c7bzOv1cAxykcEu3uj6PvbIOy_CV2Z2I,3451
|
|
@@ -1400,9 +1401,9 @@ angr/utils/vex.py,sha256=epcrCexi_NjKnPGM2gfpiRsUea_Scd-71UMuF32ZAQo,306
|
|
|
1400
1401
|
angr/utils/ssa/__init__.py,sha256=xbuVllFoPane9lHACdRQP5OO99Mca-4sqpFrtoAvnxo,17464
|
|
1401
1402
|
angr/utils/ssa/tmp_uses_collector.py,sha256=digAUQpYoFR1VYfwoXlF3T1pYdDi6Pdq_ck54SjMabQ,813
|
|
1402
1403
|
angr/utils/ssa/vvar_uses_collector.py,sha256=HewqUQluNE9EsaiLeFo7LaBvws_DDBDYNt9RBExy464,1367
|
|
1403
|
-
angr-9.2.
|
|
1404
|
-
angr-9.2.
|
|
1405
|
-
angr-9.2.
|
|
1406
|
-
angr-9.2.
|
|
1407
|
-
angr-9.2.
|
|
1408
|
-
angr-9.2.
|
|
1404
|
+
angr-9.2.166.dist-info/licenses/LICENSE,sha256=PmWf0IlSz6Jjp9n7nyyBQA79Q5C2ma68LRykY1V3GF0,1456
|
|
1405
|
+
angr-9.2.166.dist-info/METADATA,sha256=J6TW7xu4LbJtsuM__h0zOXs7SczMgfkZrBDGxRoz-Uw,4453
|
|
1406
|
+
angr-9.2.166.dist-info/WHEEL,sha256=OJ2zpOfp3Fst0GC5jHtFuY8tAf46LLgZ9O920dE4b3c,100
|
|
1407
|
+
angr-9.2.166.dist-info/entry_points.txt,sha256=Vjh1C8PMyr5dZFMnik5WkEP01Uwr2T73I3a6N32sgQU,44
|
|
1408
|
+
angr-9.2.166.dist-info/top_level.txt,sha256=dKw0KWTbwLXytFvv15oAAG4sUs3ey47tt6DorJG9-hw,5
|
|
1409
|
+
angr-9.2.166.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|