angr 9.2.148__py3-none-manylinux2014_x86_64.whl → 9.2.150__py3-none-manylinux2014_x86_64.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/__main__.py +100 -37
- angr/analyses/calling_convention/calling_convention.py +42 -2
- angr/analyses/cfg/cfg_emulated.py +5 -2
- angr/analyses/cfg/cfg_fast.py +48 -46
- angr/analyses/decompiler/ail_simplifier.py +65 -32
- angr/analyses/decompiler/block_simplifier.py +20 -6
- angr/analyses/decompiler/clinic.py +80 -13
- angr/analyses/decompiler/dephication/rewriting_engine.py +24 -2
- angr/analyses/decompiler/optimization_passes/__init__.py +5 -0
- angr/analyses/decompiler/optimization_passes/base_ptr_save_simplifier.py +15 -13
- angr/analyses/decompiler/optimization_passes/determine_load_sizes.py +64 -0
- angr/analyses/decompiler/optimization_passes/eager_std_string_concatenation.py +165 -0
- angr/analyses/decompiler/optimization_passes/engine_base.py +11 -2
- angr/analyses/decompiler/optimization_passes/flip_boolean_cmp.py +2 -1
- angr/analyses/decompiler/optimization_passes/inlined_string_transformation_simplifier.py +17 -2
- angr/analyses/decompiler/optimization_passes/optimization_pass.py +10 -6
- angr/analyses/decompiler/optimization_passes/win_stack_canary_simplifier.py +99 -30
- angr/analyses/decompiler/peephole_optimizations/__init__.py +6 -0
- angr/analyses/decompiler/peephole_optimizations/base.py +43 -3
- angr/analyses/decompiler/peephole_optimizations/constant_derefs.py +1 -1
- angr/analyses/decompiler/peephole_optimizations/inlined_strcpy.py +3 -0
- angr/analyses/decompiler/peephole_optimizations/inlined_strcpy_consolidation.py +4 -1
- angr/analyses/decompiler/peephole_optimizations/remove_cxx_destructor_calls.py +32 -0
- angr/analyses/decompiler/peephole_optimizations/remove_redundant_bitmasks.py +69 -2
- angr/analyses/decompiler/peephole_optimizations/rewrite_conv_mul.py +40 -0
- angr/analyses/decompiler/peephole_optimizations/rewrite_cxx_operator_calls.py +90 -0
- angr/analyses/decompiler/presets/fast.py +2 -0
- angr/analyses/decompiler/presets/full.py +2 -0
- angr/analyses/decompiler/ssailification/rewriting_engine.py +51 -4
- angr/analyses/decompiler/ssailification/ssailification.py +23 -3
- angr/analyses/decompiler/ssailification/traversal_engine.py +15 -1
- angr/analyses/decompiler/structured_codegen/c.py +141 -10
- angr/analyses/decompiler/utils.py +23 -1
- angr/analyses/disassembly.py +2 -1
- angr/analyses/patchfinder.py +1 -1
- angr/analyses/s_reaching_definitions/s_rda_view.py +1 -0
- angr/analyses/typehoon/lifter.py +20 -0
- angr/analyses/typehoon/simple_solver.py +42 -9
- angr/analyses/typehoon/translator.py +4 -1
- angr/analyses/typehoon/typeconsts.py +17 -6
- angr/analyses/typehoon/typehoon.py +25 -6
- angr/analyses/variable_recovery/engine_ail.py +44 -5
- angr/analyses/variable_recovery/engine_base.py +35 -12
- angr/analyses/variable_recovery/variable_recovery_fast.py +33 -2
- angr/calling_conventions.py +23 -5
- angr/engines/light/engine.py +7 -0
- angr/engines/pcode/lifter.py +7 -0
- angr/knowledge_plugins/functions/function.py +68 -0
- angr/knowledge_plugins/propagations/states.py +5 -2
- angr/knowledge_plugins/variables/variable_manager.py +3 -3
- angr/procedures/definitions/__init__.py +1 -1
- angr/procedures/definitions/types_stl.py +22 -0
- angr/sim_type.py +251 -130
- angr/utils/graph.py +51 -27
- {angr-9.2.148.dist-info → angr-9.2.150.dist-info}/METADATA +7 -7
- {angr-9.2.148.dist-info → angr-9.2.150.dist-info}/RECORD +61 -55
- {angr-9.2.148.dist-info → angr-9.2.150.dist-info}/WHEEL +1 -1
- {angr-9.2.148.dist-info → angr-9.2.150.dist-info}/licenses/LICENSE +3 -0
- {angr-9.2.148.dist-info → angr-9.2.150.dist-info}/entry_points.txt +0 -0
- {angr-9.2.148.dist-info → angr-9.2.150.dist-info}/top_level.txt +0 -0
angr/calling_conventions.py
CHANGED
|
@@ -1196,7 +1196,7 @@ class SimCC:
|
|
|
1196
1196
|
|
|
1197
1197
|
@staticmethod
|
|
1198
1198
|
def find_cc(
|
|
1199
|
-
arch: archinfo.Arch, args: list[SimRegArg | SimStackArg], sp_delta: int, platform: str = "Linux"
|
|
1199
|
+
arch: archinfo.Arch, args: list[SimRegArg | SimStackArg], sp_delta: int, platform: str | None = "Linux"
|
|
1200
1200
|
) -> SimCC | None:
|
|
1201
1201
|
"""
|
|
1202
1202
|
Pinpoint the best-fit calling convention and return the corresponding SimCC instance, or None if no fit is
|
|
@@ -1335,6 +1335,21 @@ class SimCCMicrosoftCdecl(SimCCCdecl):
|
|
|
1335
1335
|
STRUCT_RETURN_THRESHOLD = 64
|
|
1336
1336
|
|
|
1337
1337
|
|
|
1338
|
+
class SimCCMicrosoftThiscall(SimCCCdecl):
|
|
1339
|
+
CALLEE_CLEANUP = True
|
|
1340
|
+
ARG_REGS = ["ecx"]
|
|
1341
|
+
CALLER_SAVED_REGS = ["eax", "ecx", "edx"]
|
|
1342
|
+
STRUCT_RETURN_THRESHOLD = 64
|
|
1343
|
+
|
|
1344
|
+
def arg_locs(self, prototype) -> list[SimFunctionArgument]:
|
|
1345
|
+
if prototype._arch is None:
|
|
1346
|
+
prototype = prototype.with_arch(self.arch)
|
|
1347
|
+
session = self.arg_session(prototype.returnty)
|
|
1348
|
+
if not prototype.args:
|
|
1349
|
+
return []
|
|
1350
|
+
return [SimRegArg("ecx", self.arch.bytes)] + [self.next_arg(session, arg_ty) for arg_ty in prototype.args[1:]]
|
|
1351
|
+
|
|
1352
|
+
|
|
1338
1353
|
class SimCCStdcall(SimCCMicrosoftCdecl):
|
|
1339
1354
|
CALLEE_CLEANUP = True
|
|
1340
1355
|
|
|
@@ -1469,7 +1484,7 @@ class SimCCSyscall(SimCC):
|
|
|
1469
1484
|
self.ERROR_REG.set_value(state, error_reg_val)
|
|
1470
1485
|
return expr
|
|
1471
1486
|
|
|
1472
|
-
def set_return_val(self, state, val, ty, **kwargs): # pylint:disable=arguments-differ
|
|
1487
|
+
def set_return_val(self, state, val, ty, **kwargs): # type:ignore # pylint:disable=arguments-differ
|
|
1473
1488
|
if self.ERROR_REG is not None:
|
|
1474
1489
|
val = self.linux_syscall_update_error_reg(state, val)
|
|
1475
1490
|
super().set_return_val(state, val, ty, **kwargs)
|
|
@@ -1607,6 +1622,7 @@ class SimCCSystemVAMD64(SimCC):
|
|
|
1607
1622
|
classification = self._classify(ty)
|
|
1608
1623
|
if any(cls == "MEMORY" for cls in classification):
|
|
1609
1624
|
assert all(cls == "MEMORY" for cls in classification)
|
|
1625
|
+
assert ty.size is not None
|
|
1610
1626
|
byte_size = ty.size // self.arch.byte_width
|
|
1611
1627
|
referenced_locs = [SimStackArg(offset, self.arch.bytes) for offset in range(0, byte_size, self.arch.bytes)]
|
|
1612
1628
|
referenced_loc = refine_locs_with_struct_type(self.arch, referenced_locs, ty)
|
|
@@ -1645,6 +1661,7 @@ class SimCCSystemVAMD64(SimCC):
|
|
|
1645
1661
|
if isinstance(ty, (SimTypeFloat,)):
|
|
1646
1662
|
return ["SSE"] + ["SSEUP"] * (nchunks - 1)
|
|
1647
1663
|
if isinstance(ty, (SimStruct, SimTypeFixedSizeArray, SimUnion)):
|
|
1664
|
+
assert ty.size is not None
|
|
1648
1665
|
if ty.size > 512:
|
|
1649
1666
|
return ["MEMORY"] * nchunks
|
|
1650
1667
|
flattened = self._flatten(ty)
|
|
@@ -1723,7 +1740,7 @@ class SimCCAMD64LinuxSyscall(SimCCSyscall):
|
|
|
1723
1740
|
CALLER_SAVED_REGS = ["rax", "rcx", "r11"]
|
|
1724
1741
|
|
|
1725
1742
|
@staticmethod
|
|
1726
|
-
def _match(arch, args, sp_delta): # pylint: disable=unused-argument
|
|
1743
|
+
def _match(arch, args, sp_delta): # type:ignore # pylint: disable=unused-argument
|
|
1727
1744
|
# doesn't appear anywhere but syscalls
|
|
1728
1745
|
return False
|
|
1729
1746
|
|
|
@@ -1855,6 +1872,7 @@ class SimCCARM(SimCC):
|
|
|
1855
1872
|
for suboffset, subsubty_list in subresult.items():
|
|
1856
1873
|
result[offset + suboffset] += subsubty_list
|
|
1857
1874
|
elif isinstance(ty, SimTypeFixedSizeArray):
|
|
1875
|
+
assert ty.elem_type.size is not None
|
|
1858
1876
|
subresult = self._flatten(ty.elem_type)
|
|
1859
1877
|
if subresult is None:
|
|
1860
1878
|
return None
|
|
@@ -2273,7 +2291,7 @@ class SimCCUnknown(SimCC):
|
|
|
2273
2291
|
"""
|
|
2274
2292
|
|
|
2275
2293
|
@staticmethod
|
|
2276
|
-
def _match(arch, args, sp_delta): # pylint: disable=unused-argument
|
|
2294
|
+
def _match(arch, args, sp_delta): # type:ignore # pylint: disable=unused-argument
|
|
2277
2295
|
# It always returns True
|
|
2278
2296
|
return True
|
|
2279
2297
|
|
|
@@ -2317,7 +2335,7 @@ CC: dict[str, dict[str, list[type[SimCC]]]] = {
|
|
|
2317
2335
|
"default": [SimCCCdecl],
|
|
2318
2336
|
"Linux": [SimCCCdecl],
|
|
2319
2337
|
"CGC": [SimCCCdecl],
|
|
2320
|
-
"Win32": [SimCCMicrosoftCdecl, SimCCMicrosoftFastcall],
|
|
2338
|
+
"Win32": [SimCCMicrosoftCdecl, SimCCMicrosoftFastcall, SimCCMicrosoftThiscall],
|
|
2321
2339
|
},
|
|
2322
2340
|
"ARMEL": {
|
|
2323
2341
|
"default": [SimCCARM],
|
angr/engines/light/engine.py
CHANGED
|
@@ -533,6 +533,7 @@ class SimEngineLightAIL(
|
|
|
533
533
|
def __init__(self, *args, **kwargs):
|
|
534
534
|
self._stmt_handlers: dict[str, Callable[[Any], StmtDataType]] = {
|
|
535
535
|
"Assignment": self._handle_stmt_Assignment,
|
|
536
|
+
"WeakAssignment": self._handle_stmt_WeakAssignment,
|
|
536
537
|
"Store": self._handle_stmt_Store,
|
|
537
538
|
"Jump": self._handle_stmt_Jump,
|
|
538
539
|
"ConditionalJump": self._handle_stmt_ConditionalJump,
|
|
@@ -697,6 +698,9 @@ class SimEngineLightAIL(
|
|
|
697
698
|
@abstractmethod
|
|
698
699
|
def _handle_stmt_Assignment(self, stmt: ailment.statement.Assignment) -> StmtDataType: ...
|
|
699
700
|
|
|
701
|
+
@abstractmethod
|
|
702
|
+
def _handle_stmt_WeakAssignment(self, stmt: ailment.statement.WeakAssignment) -> StmtDataType: ...
|
|
703
|
+
|
|
700
704
|
@abstractmethod
|
|
701
705
|
def _handle_stmt_Store(self, stmt: ailment.statement.Store) -> StmtDataType: ...
|
|
702
706
|
|
|
@@ -1006,6 +1010,9 @@ class SimEngineNostmtAIL(
|
|
|
1006
1010
|
def _handle_stmt_Assignment(self, stmt) -> StmtDataType | None:
|
|
1007
1011
|
pass
|
|
1008
1012
|
|
|
1013
|
+
def _handle_stmt_WeakAssignment(self, stmt) -> StmtDataType | None:
|
|
1014
|
+
pass
|
|
1015
|
+
|
|
1009
1016
|
def _handle_stmt_Store(self, stmt) -> StmtDataType | None:
|
|
1010
1017
|
pass
|
|
1011
1018
|
|
angr/engines/pcode/lifter.py
CHANGED
|
@@ -427,6 +427,13 @@ class IRSB:
|
|
|
427
427
|
|
|
428
428
|
return exits
|
|
429
429
|
|
|
430
|
+
@property
|
|
431
|
+
def is_noop_block(self) -> bool:
|
|
432
|
+
"""
|
|
433
|
+
Returns True if this block is a no-op block (i.e. it has no instructions and no jumps).
|
|
434
|
+
"""
|
|
435
|
+
return not any(op.opcode != pypcode.OpCode.IMARK for op in self._ops)
|
|
436
|
+
|
|
430
437
|
#
|
|
431
438
|
# private methods
|
|
432
439
|
#
|
|
@@ -26,6 +26,7 @@ from angr.calling_conventions import DEFAULT_CC, default_cc
|
|
|
26
26
|
from angr.sim_type import SimTypeFunction, parse_defns
|
|
27
27
|
from angr.calling_conventions import SimCC
|
|
28
28
|
from angr.project import Project
|
|
29
|
+
from angr.utils.library import get_cpp_function_name
|
|
29
30
|
from .function_parser import FunctionParser
|
|
30
31
|
|
|
31
32
|
l = logging.getLogger(name=__name__)
|
|
@@ -1582,11 +1583,78 @@ class Function(Serializable):
|
|
|
1582
1583
|
# int, long
|
|
1583
1584
|
return addr
|
|
1584
1585
|
|
|
1586
|
+
def is_rust_function(self):
|
|
1587
|
+
ast = pydemumble.demangle(self.name)
|
|
1588
|
+
if ast:
|
|
1589
|
+
nodes = ast.split("::")
|
|
1590
|
+
if len(nodes) >= 2:
|
|
1591
|
+
last_node = nodes[-1]
|
|
1592
|
+
return (
|
|
1593
|
+
len(last_node) == 17
|
|
1594
|
+
and last_node.startswith("h")
|
|
1595
|
+
and all(c in "0123456789abcdef" for c in last_node[1:])
|
|
1596
|
+
)
|
|
1597
|
+
return False
|
|
1598
|
+
|
|
1599
|
+
@staticmethod
|
|
1600
|
+
def _rust_fmt_node(node):
|
|
1601
|
+
result = []
|
|
1602
|
+
rest = node
|
|
1603
|
+
if rest.startswith("_$"):
|
|
1604
|
+
rest = rest[1:]
|
|
1605
|
+
while True:
|
|
1606
|
+
if rest.startswith("."):
|
|
1607
|
+
if len(rest) > 1 and rest[1] == ".":
|
|
1608
|
+
result.append("::")
|
|
1609
|
+
rest = rest[2:]
|
|
1610
|
+
else:
|
|
1611
|
+
result.append(".")
|
|
1612
|
+
rest = rest[1:]
|
|
1613
|
+
elif rest.startswith("$"):
|
|
1614
|
+
if "$" in rest[1:]:
|
|
1615
|
+
escape, rest = rest[1:].split("$", 1)
|
|
1616
|
+
else:
|
|
1617
|
+
break
|
|
1618
|
+
|
|
1619
|
+
unescaped = {"SP": "@", "BP": "*", "RF": "&", "LT": "<", "GT": ">", "LP": "(", "RP": ")", "C": ","}.get(
|
|
1620
|
+
escape
|
|
1621
|
+
)
|
|
1622
|
+
|
|
1623
|
+
if unescaped is None and escape.startswith("u"):
|
|
1624
|
+
digits = escape[1:]
|
|
1625
|
+
if all(c in "0123456789abcdef" for c in digits):
|
|
1626
|
+
c = chr(int(digits, 16))
|
|
1627
|
+
if ord(c) >= 32 and ord(c) != 127:
|
|
1628
|
+
result.append(c)
|
|
1629
|
+
continue
|
|
1630
|
+
if unescaped:
|
|
1631
|
+
result.append(unescaped)
|
|
1632
|
+
else:
|
|
1633
|
+
break
|
|
1634
|
+
else:
|
|
1635
|
+
idx = min((rest.find(c) for c in "$." if c in rest), default=len(rest))
|
|
1636
|
+
result.append(rest[:idx])
|
|
1637
|
+
rest = rest[idx:]
|
|
1638
|
+
if not rest:
|
|
1639
|
+
break
|
|
1640
|
+
return "".join(result)
|
|
1641
|
+
|
|
1585
1642
|
@property
|
|
1586
1643
|
def demangled_name(self):
|
|
1587
1644
|
ast = pydemumble.demangle(self.name)
|
|
1645
|
+
if self.is_rust_function():
|
|
1646
|
+
nodes = ast.split("::")[:-1]
|
|
1647
|
+
ast = "::".join([Function._rust_fmt_node(node) for node in nodes])
|
|
1588
1648
|
return ast if ast else self.name
|
|
1589
1649
|
|
|
1650
|
+
@property
|
|
1651
|
+
def short_name(self):
|
|
1652
|
+
if self.is_rust_function():
|
|
1653
|
+
ast = pydemumble.demangle(self.name)
|
|
1654
|
+
return Function._rust_fmt_node(ast.split("::")[-2])
|
|
1655
|
+
func_name = get_cpp_function_name(self.demangled_name, specialized=False, qualified=True)
|
|
1656
|
+
return func_name.split("::")[-1]
|
|
1657
|
+
|
|
1590
1658
|
def get_unambiguous_name(self, display_name: str | None = None) -> str:
|
|
1591
1659
|
"""
|
|
1592
1660
|
Get a disambiguated function name.
|
|
@@ -527,12 +527,14 @@ class Equivalence:
|
|
|
527
527
|
"atom0",
|
|
528
528
|
"atom1",
|
|
529
529
|
"codeloc",
|
|
530
|
+
"is_weakassignment",
|
|
530
531
|
)
|
|
531
532
|
|
|
532
|
-
def __init__(self, codeloc, atom0, atom1):
|
|
533
|
+
def __init__(self, codeloc, atom0, atom1, is_weakassignment: bool = False):
|
|
533
534
|
self.codeloc = codeloc
|
|
534
535
|
self.atom0 = atom0
|
|
535
536
|
self.atom1 = atom1
|
|
537
|
+
self.is_weakassignment = is_weakassignment
|
|
536
538
|
|
|
537
539
|
def __repr__(self):
|
|
538
540
|
return f"<Eq@{self.codeloc!r}: {self.atom0!r}=={self.atom1!r}>"
|
|
@@ -543,7 +545,8 @@ class Equivalence:
|
|
|
543
545
|
and other.codeloc == self.codeloc
|
|
544
546
|
and other.atom0 == self.atom0
|
|
545
547
|
and other.atom1 == self.atom1
|
|
548
|
+
and other.is_weakassignment == self.is_weakassignment
|
|
546
549
|
)
|
|
547
550
|
|
|
548
551
|
def __hash__(self):
|
|
549
|
-
return hash((Equivalence, self.codeloc, self.atom0, self.atom1))
|
|
552
|
+
return hash((Equivalence, self.codeloc, self.atom0, self.atom1, self.is_weakassignment))
|
|
@@ -934,7 +934,7 @@ class VariableManagerInternal(Serializable):
|
|
|
934
934
|
|
|
935
935
|
for var in chain(sorted_stack_variables, sorted_reg_variables, phi_only_vars):
|
|
936
936
|
idx = next(var_ctr)
|
|
937
|
-
if var.name is not None and not reset:
|
|
937
|
+
if var.name is not None and var.name != var.ident and not reset:
|
|
938
938
|
continue
|
|
939
939
|
if isinstance(var, (SimStackVariable, SimRegisterVariable)):
|
|
940
940
|
var.name = f"v{idx}"
|
|
@@ -946,7 +946,7 @@ class VariableManagerInternal(Serializable):
|
|
|
946
946
|
arg_vars = sorted(arg_vars, key=lambda v: _id_from_varident(v.ident))
|
|
947
947
|
for var in arg_vars:
|
|
948
948
|
idx = next(arg_ctr)
|
|
949
|
-
if var.name is not None and not reset:
|
|
949
|
+
if var.name is not None and var.name != var.ident and not reset:
|
|
950
950
|
continue
|
|
951
951
|
var.name = arg_names[idx] if arg_names else f"a{idx}"
|
|
952
952
|
var._hash = None
|
|
@@ -1040,7 +1040,7 @@ class VariableManagerInternal(Serializable):
|
|
|
1040
1040
|
reg_vars: set[SimRegisterVariable] = set()
|
|
1041
1041
|
|
|
1042
1042
|
# unify stack variables based on their locations
|
|
1043
|
-
for v in self.get_variables():
|
|
1043
|
+
for v in self.get_variables() + list(self._phi_variables):
|
|
1044
1044
|
if v in self._variables_to_unified_variables:
|
|
1045
1045
|
# do not unify twice
|
|
1046
1046
|
continue
|
|
@@ -397,7 +397,7 @@ class SimCppLibrary(SimLibrary):
|
|
|
397
397
|
stub = super().get_stub(demangled_name, arch)
|
|
398
398
|
# try to determine a prototype from the function name if possible
|
|
399
399
|
if demangled_name != name:
|
|
400
|
-
#
|
|
400
|
+
# mangled function name
|
|
401
401
|
stub.prototype = self._proto_from_demangled_name(demangled_name)
|
|
402
402
|
if stub.prototype is not None:
|
|
403
403
|
stub.prototype = stub.prototype.with_arch(arch)
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# pylint:disable=line-too-long
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
from collections import OrderedDict
|
|
4
|
+
|
|
5
|
+
from angr.procedures.definitions import SimTypeCollection
|
|
6
|
+
from angr.sim_type import SimCppClass, SimTypePointer, SimTypeChar, SimTypeInt
|
|
7
|
+
|
|
8
|
+
typelib = SimTypeCollection()
|
|
9
|
+
typelib.set_names("cpp::std")
|
|
10
|
+
typelib.types = {
|
|
11
|
+
"class std::basic_string<char, struct std::char_traits<char>, class std::allocator<char>>": SimCppClass(
|
|
12
|
+
unique_name="class std::basic_string<char, struct std::char_traits<char>, class std::allocator<char>>",
|
|
13
|
+
name="std::string",
|
|
14
|
+
members=OrderedDict(
|
|
15
|
+
[
|
|
16
|
+
("m_data", SimTypePointer(SimTypeChar())),
|
|
17
|
+
("m_size", SimTypeInt(signed=False)),
|
|
18
|
+
("m_capacity", SimTypeInt(signed=False)),
|
|
19
|
+
]
|
|
20
|
+
),
|
|
21
|
+
),
|
|
22
|
+
}
|