angr 9.2.146__py3-none-manylinux2014_aarch64.whl → 9.2.148__py3-none-manylinux2014_aarch64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of angr might be problematic. Click here for more details.
- angr/__init__.py +1 -1
- angr/analyses/analysis.py +3 -11
- angr/analyses/bindiff.py +343 -68
- angr/analyses/calling_convention/fact_collector.py +5 -4
- angr/analyses/calling_convention/utils.py +1 -0
- angr/analyses/cfg/cfg_arch_options.py +10 -0
- angr/analyses/cfg/cfg_base.py +42 -74
- angr/analyses/cfg/cfg_emulated.py +12 -12
- angr/analyses/cfg/cfg_fast.py +39 -20
- angr/analyses/cfg/cfg_fast_soot.py +3 -3
- angr/analyses/decompiler/callsite_maker.py +28 -18
- angr/analyses/decompiler/clinic.py +4 -4
- angr/analyses/decompiler/condition_processor.py +0 -21
- angr/analyses/decompiler/counters/call_counter.py +3 -0
- angr/analyses/decompiler/optimization_passes/const_prop_reverter.py +1 -1
- angr/analyses/decompiler/peephole_optimizations/remove_redundant_conversions.py +14 -0
- angr/analyses/decompiler/structured_codegen/c.py +5 -5
- angr/analyses/decompiler/structuring/phoenix.py +11 -3
- angr/analyses/deobfuscator/api_obf_finder.py +5 -1
- angr/analyses/deobfuscator/api_obf_peephole_optimizer.py +1 -1
- angr/analyses/flirt/__init__.py +47 -0
- angr/analyses/flirt/consts.py +160 -0
- angr/analyses/{flirt.py → flirt/flirt.py} +99 -38
- angr/analyses/flirt/flirt_function.py +20 -0
- angr/analyses/flirt/flirt_matcher.py +351 -0
- angr/analyses/flirt/flirt_module.py +32 -0
- angr/analyses/flirt/flirt_node.py +23 -0
- angr/analyses/flirt/flirt_sig.py +356 -0
- angr/analyses/flirt/flirt_utils.py +31 -0
- angr/analyses/forward_analysis/visitors/graph.py +0 -8
- angr/analyses/identifier/runner.py +1 -1
- angr/analyses/reaching_definitions/function_handler.py +4 -4
- angr/analyses/reassembler.py +1 -1
- angr/analyses/stack_pointer_tracker.py +35 -1
- angr/analyses/static_hooker.py +11 -9
- angr/analyses/variable_recovery/engine_ail.py +8 -8
- angr/analyses/variable_recovery/engine_base.py +2 -0
- angr/block.py +6 -6
- angr/calling_conventions.py +74 -23
- angr/engines/vex/heavy/concretizers.py +10 -0
- angr/exploration_techniques/director.py +1 -1
- angr/flirt/__init__.py +15 -44
- angr/knowledge_plugins/functions/function.py +42 -39
- angr/knowledge_plugins/functions/function_manager.py +9 -0
- angr/knowledge_plugins/functions/function_parser.py +9 -1
- angr/knowledge_plugins/functions/soot_function.py +1 -1
- angr/knowledge_plugins/key_definitions/key_definition_manager.py +1 -1
- angr/procedures/definitions/__init__.py +14 -11
- angr/procedures/stubs/format_parser.py +1 -1
- angr/project.py +23 -29
- angr/protos/cfg_pb2.py +14 -25
- angr/protos/function_pb2.py +11 -22
- angr/protos/primitives_pb2.py +36 -47
- angr/protos/variables_pb2.py +28 -39
- angr/protos/xrefs_pb2.py +8 -19
- angr/sim_type.py +0 -16
- angr/simos/cgc.py +1 -1
- angr/simos/linux.py +5 -5
- angr/simos/windows.py +5 -5
- angr/storage/memory_mixins/paged_memory/paged_memory_mixin.py +1 -1
- {angr-9.2.146.dist-info → angr-9.2.148.dist-info}/METADATA +8 -8
- {angr-9.2.146.dist-info → angr-9.2.148.dist-info}/RECORD +66 -58
- {angr-9.2.146.dist-info → angr-9.2.148.dist-info}/WHEEL +1 -1
- {angr-9.2.146.dist-info → angr-9.2.148.dist-info}/entry_points.txt +0 -0
- {angr-9.2.146.dist-info → angr-9.2.148.dist-info/licenses}/LICENSE +0 -0
- {angr-9.2.146.dist-info → angr-9.2.148.dist-info}/top_level.txt +0 -0
|
@@ -90,6 +90,7 @@ class PhoenixStructurer(StructurerBase):
|
|
|
90
90
|
parent_region=None,
|
|
91
91
|
improve_algorithm=False,
|
|
92
92
|
use_multistmtexprs: MultiStmtExprMode = MultiStmtExprMode.MAX_ONE_CALL,
|
|
93
|
+
multistmtexpr_stmt_threshold: int = 5,
|
|
93
94
|
**kwargs,
|
|
94
95
|
):
|
|
95
96
|
super().__init__(
|
|
@@ -126,6 +127,7 @@ class PhoenixStructurer(StructurerBase):
|
|
|
126
127
|
self._edge_virtualization_hints = []
|
|
127
128
|
|
|
128
129
|
self._use_multistmtexprs = use_multistmtexprs
|
|
130
|
+
self._multistmtexpr_stmt_threshold = multistmtexpr_stmt_threshold
|
|
129
131
|
self._analyze()
|
|
130
132
|
|
|
131
133
|
@staticmethod
|
|
@@ -540,7 +542,11 @@ class PhoenixStructurer(StructurerBase):
|
|
|
540
542
|
):
|
|
541
543
|
stmts = self._build_multistatementexpr_statements(succ)
|
|
542
544
|
assert stmts is not None
|
|
543
|
-
if
|
|
545
|
+
if (
|
|
546
|
+
stmts
|
|
547
|
+
and sum(1 for stmt in stmts if not isinstance(stmt, Label))
|
|
548
|
+
<= self._multistmtexpr_stmt_threshold
|
|
549
|
+
):
|
|
544
550
|
edge_cond_succhead = MultiStatementExpression(
|
|
545
551
|
None,
|
|
546
552
|
stmts,
|
|
@@ -2612,12 +2618,14 @@ class PhoenixStructurer(StructurerBase):
|
|
|
2612
2618
|
if self._use_multistmtexprs == MultiStmtExprMode.NEVER:
|
|
2613
2619
|
return False
|
|
2614
2620
|
if self._use_multistmtexprs == MultiStmtExprMode.ALWAYS:
|
|
2615
|
-
|
|
2621
|
+
ctr = AILCallCounter()
|
|
2622
|
+
ctr.walk(node)
|
|
2623
|
+
return ctr.non_label_stmts <= self._multistmtexpr_stmt_threshold
|
|
2616
2624
|
if self._use_multistmtexprs == MultiStmtExprMode.MAX_ONE_CALL:
|
|
2617
2625
|
# count the number of calls
|
|
2618
2626
|
ctr = AILCallCounter()
|
|
2619
2627
|
ctr.walk(node)
|
|
2620
|
-
return ctr.calls <= 1
|
|
2628
|
+
return ctr.calls <= 1 and ctr.non_label_stmts <= self._multistmtexpr_stmt_threshold
|
|
2621
2629
|
l.warning("Unsupported enum value for _use_multistmtexprs: %s", self._use_multistmtexprs)
|
|
2622
2630
|
return False
|
|
2623
2631
|
|
|
@@ -315,7 +315,11 @@ class APIObfuscationFinder(Analysis):
|
|
|
315
315
|
|
|
316
316
|
@staticmethod
|
|
317
317
|
def is_apiname(name: str) -> bool:
|
|
318
|
-
return any(
|
|
318
|
+
return any(
|
|
319
|
+
not isinstance(lib, SimSyscallLibrary) and lib.has_prototype(name)
|
|
320
|
+
for libs in SIM_LIBRARIES.values()
|
|
321
|
+
for lib in libs
|
|
322
|
+
)
|
|
319
323
|
|
|
320
324
|
|
|
321
325
|
AnalysesHub.register_default("APIObfuscationFinder", APIObfuscationFinder)
|
|
@@ -30,7 +30,7 @@ class APIObfType1PeepholeOptimizer(PeepholeOptimizationExprBase):
|
|
|
30
30
|
# assign a new function on-demand
|
|
31
31
|
symbol = self.project.loader.extern_object.make_extern(funcname)
|
|
32
32
|
hook_addr = self.project.hook_symbol(
|
|
33
|
-
symbol.rebased_addr, SIM_LIBRARIES["linux"].get_stub(funcname, self.project.arch)
|
|
33
|
+
symbol.rebased_addr, SIM_LIBRARIES["linux"][0].get_stub(funcname, self.project.arch)
|
|
34
34
|
)
|
|
35
35
|
func = self.kb.functions.function(addr=hook_addr, name=funcname, create=True)
|
|
36
36
|
func.is_simprocedure = True
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
from .flirt import FlirtAnalysis
|
|
3
|
+
from .flirt_sig import FlirtSignature, FlirtSignatureParsed, FlirtSignatureError
|
|
4
|
+
from .consts import FLIRT_ARCH_TO_ARCHNAME, FLIRT_OS_TO_OSNAME, FlirtAppType, FlirtOSType
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def flirt_arch_to_arch_name(flirt_arch: int, app_types: int) -> str:
|
|
8
|
+
"""
|
|
9
|
+
Convert FLIRT architecture ID to architecture name.
|
|
10
|
+
|
|
11
|
+
:param flirt_arch: FLIRT architecture ID.
|
|
12
|
+
:param app_types: FLIRT application types.
|
|
13
|
+
:return: Architecture name.
|
|
14
|
+
"""
|
|
15
|
+
try:
|
|
16
|
+
arches = FLIRT_ARCH_TO_ARCHNAME[flirt_arch]
|
|
17
|
+
except KeyError:
|
|
18
|
+
return "Unknown"
|
|
19
|
+
if app_types & FlirtAppType.APP_32_BIT and 32 in arches:
|
|
20
|
+
return arches[32]
|
|
21
|
+
if app_types & FlirtAppType.APP_64_BIT and 64 in arches:
|
|
22
|
+
return arches[64]
|
|
23
|
+
return "Unknown"
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def flirt_os_type_to_os_name(os_type: int) -> str:
|
|
27
|
+
"""
|
|
28
|
+
Convert FLIRT OS type to OS name.
|
|
29
|
+
|
|
30
|
+
:param os_type: FLIRT OS type.
|
|
31
|
+
:return: OS name.
|
|
32
|
+
"""
|
|
33
|
+
try:
|
|
34
|
+
v = FlirtOSType(os_type)
|
|
35
|
+
return FLIRT_OS_TO_OSNAME.get(v, v.name)
|
|
36
|
+
except ValueError:
|
|
37
|
+
return "UnknownOS"
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
__all__ = [
|
|
41
|
+
"FlirtAnalysis",
|
|
42
|
+
"FlirtSignature",
|
|
43
|
+
"FlirtSignatureError",
|
|
44
|
+
"FlirtSignatureParsed",
|
|
45
|
+
"flirt_arch_to_arch_name",
|
|
46
|
+
"flirt_os_type_to_os_name",
|
|
47
|
+
]
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
# pylint:disable=missing-class-docstring
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
from enum import Enum
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class FlirtArch(int, Enum):
|
|
7
|
+
ARCH_386 = 0 # Intel 80x86
|
|
8
|
+
ARCH_Z80 = 1 # 8085, Z80
|
|
9
|
+
ARCH_I860 = 2 # Intel 860
|
|
10
|
+
ARCH_8051 = 3 # 8051
|
|
11
|
+
ARCH_TMS = 4 # Texas Instruments TMS320C5x
|
|
12
|
+
ARCH_6502 = 5 # 6502
|
|
13
|
+
ARCH_PDP = 6 # PDP11
|
|
14
|
+
ARCH_68K = 7 # Motorola 680x0
|
|
15
|
+
ARCH_JAVA = 8 # Java
|
|
16
|
+
ARCH_6800 = 9 # Motorola 68xx
|
|
17
|
+
ARCH_ST7 = 10 # SGS-Thomson ST7
|
|
18
|
+
ARCH_MC6812 = 11 # Motorola 68HC12
|
|
19
|
+
ARCH_MIPS = 12 # MIPS
|
|
20
|
+
ARCH_ARM = 13 # Advanced RISC Machines
|
|
21
|
+
ARCH_TMSC6 = 14 # Texas Instruments TMS320C6x
|
|
22
|
+
ARCH_PPC = 15 # PowerPC
|
|
23
|
+
ARCH_80196 = 16 # Intel 80196
|
|
24
|
+
ARCH_Z8 = 17 # Z8
|
|
25
|
+
ARCH_SH = 18 # Renesas (formerly Hitachi) SuperH
|
|
26
|
+
ARCH_NET = 19 # Microsoft Visual Studio.Net
|
|
27
|
+
ARCH_AVR = 20 # Atmel 8-bit RISC processor(s)
|
|
28
|
+
ARCH_H8 = 21 # Hitachi H8/300, H8/2000
|
|
29
|
+
ARCH_PIC = 22 # Microchip's PIC
|
|
30
|
+
ARCH_SPARC = 23 # SPARC
|
|
31
|
+
ARCH_ALPHA = 24 # DEC Alpha
|
|
32
|
+
ARCH_HPPA = 25 # Hewlett-Packard PA-RISC
|
|
33
|
+
ARCH_H8500 = 26 # Hitachi H8/500
|
|
34
|
+
ARCH_TRICORE = 27 # Tasking Tricore
|
|
35
|
+
ARCH_DSP56K = 28 # Motorola DSP5600x
|
|
36
|
+
ARCH_C166 = 29 # Siemens C166 family
|
|
37
|
+
ARCH_ST20 = 30 # SGS-Thomson ST20
|
|
38
|
+
ARCH_IA64 = 31 # Intel Itanium IA64
|
|
39
|
+
ARCH_I960 = 32 # Intel 960
|
|
40
|
+
ARCH_F2MC = 33 # Fujitsu F2MC-16
|
|
41
|
+
ARCH_TMS320C54 = 34 # Texas Instruments TMS320C54xx
|
|
42
|
+
ARCH_TMS320C55 = 35 # Texas Instruments TMS320C55xx
|
|
43
|
+
ARCH_TRIMEDIA = 36 # Trimedia
|
|
44
|
+
ARCH_M32R = 37 # Mitsubishi 32bit RISC
|
|
45
|
+
ARCH_NEC_78K0 = 38 # NEC 78K0
|
|
46
|
+
ARCH_NEC_78K0S = 39 # NEC 78K0S
|
|
47
|
+
ARCH_M740 = 40 # Mitsubishi 8bit
|
|
48
|
+
ARCH_M7700 = 41 # Mitsubishi 16bit
|
|
49
|
+
ARCH_ST9 = 42 # ST9+
|
|
50
|
+
ARCH_FR = 43 # Fujitsu FR Family
|
|
51
|
+
ARCH_MC6816 = 44 # Motorola 68HC16
|
|
52
|
+
ARCH_M7900 = 45 # Mitsubishi 7900
|
|
53
|
+
ARCH_TMS320C3 = 46 # Texas Instruments TMS320C3
|
|
54
|
+
ARCH_KR1878 = 47 # Angstrem KR1878
|
|
55
|
+
ARCH_AD218X = 48 # Analog Devices ADSP 218X
|
|
56
|
+
ARCH_OAKDSP = 49 # Atmel OAK DSP
|
|
57
|
+
ARCH_TLCS900 = 50 # Toshiba TLCS-900
|
|
58
|
+
ARCH_C39 = 51 # Rockwell C39
|
|
59
|
+
ARCH_CR16 = 52 # NSC CR16
|
|
60
|
+
ARCH_MN102L00 = 53 # Panasonic MN10200
|
|
61
|
+
ARCH_TMS320C1X = 54 # Texas Instruments TMS320C1x
|
|
62
|
+
ARCH_NEC_V850X = 55 # NEC V850 and V850ES/E1/E2
|
|
63
|
+
ARCH_SCR_ADPT = 56 # Processor module adapter for processor modules written in scripting languages
|
|
64
|
+
ARCH_EBC = 57 # EFI Bytecode
|
|
65
|
+
ARCH_MSP430 = 58 # Texas Instruments MSP430
|
|
66
|
+
ARCH_SPU = 59 # Cell Broadband Engine Synergistic Processor Unit
|
|
67
|
+
ARCH_DALVIK = 60 # Android Dalvik Virtual Machine
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
FLIRT_ARCH_TO_ARCHNAME: dict[int, dict[int, str]] = {
|
|
71
|
+
FlirtArch.ARCH_386: {32: "X86", 64: "AMD64"},
|
|
72
|
+
FlirtArch.ARCH_MIPS: {32: "MIPS32", 64: "MIPS64"},
|
|
73
|
+
FlirtArch.ARCH_ARM: {32: "ARM", 64: "AARCH64"},
|
|
74
|
+
FlirtArch.ARCH_PPC: {32: "PPC32", 64: "PPC64"},
|
|
75
|
+
FlirtArch.ARCH_SPARC: {32: "SPARC32", 64: "SPARC64"},
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
class FlirtFileType(int, Enum):
|
|
80
|
+
FILE_DOS_EXE_OLD = 0x00000001
|
|
81
|
+
FILE_DOS_COM_OLD = 0x00000002
|
|
82
|
+
FILE_BIN = 0x00000004
|
|
83
|
+
FILE_DOSDRV = 0x00000008
|
|
84
|
+
FILE_NE = 0x00000010
|
|
85
|
+
FILE_INTELHEX = 0x00000020
|
|
86
|
+
FILE_MOSHEX = 0x00000040
|
|
87
|
+
FILE_LX = 0x00000080
|
|
88
|
+
FILE_LE = 0x00000100
|
|
89
|
+
FILE_NLM = 0x00000200
|
|
90
|
+
FILE_COFF = 0x00000400
|
|
91
|
+
FILE_PE = 0x00000800
|
|
92
|
+
FILE_OMF = 0x00001000
|
|
93
|
+
FILE_SREC = 0x00002000
|
|
94
|
+
FILE_ZIP = 0x00004000
|
|
95
|
+
FILE_OMFLIB = 0x00008000
|
|
96
|
+
FILE_AR = 0x00010000
|
|
97
|
+
FILE_LOADER = 0x00020000
|
|
98
|
+
FILE_ELF = 0x00040000
|
|
99
|
+
FILE_W32RUN = 0x00080000
|
|
100
|
+
FILE_AOUT = 0x00100000
|
|
101
|
+
FILE_PILOT = 0x00200000
|
|
102
|
+
FILE_DOS_EXE = 0x00400000
|
|
103
|
+
FILE_DOS_COM = 0x00800000
|
|
104
|
+
FILE_AIXAR = 0x01000000
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
class FlirtOSType(int, Enum):
|
|
108
|
+
"""
|
|
109
|
+
Actually no longer used in IDA.
|
|
110
|
+
"""
|
|
111
|
+
|
|
112
|
+
OS_MSDOS = 0x01
|
|
113
|
+
OS_WIN = 0x02
|
|
114
|
+
OS_OS2 = 0x04
|
|
115
|
+
OS_NETWARE = 0x08
|
|
116
|
+
OS_UNIX = 0x10
|
|
117
|
+
OS_OTHER = 0x20
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
FLIRT_OS_TO_OSNAME = {
|
|
121
|
+
FlirtOSType.OS_MSDOS: "MSDOS",
|
|
122
|
+
FlirtOSType.OS_WIN: "Win32",
|
|
123
|
+
FlirtOSType.OS_OS2: "OS/2",
|
|
124
|
+
FlirtOSType.OS_UNIX: "Linux",
|
|
125
|
+
FlirtOSType.OS_OTHER: "Other",
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
class FlirtAppType(int, Enum):
|
|
130
|
+
APP_CONSOLE = 0x0001
|
|
131
|
+
APP_GRAPHICS = 0x0002
|
|
132
|
+
APP_EXE = 0x0004
|
|
133
|
+
APP_DLL = 0x0008
|
|
134
|
+
APP_DRV = 0x0010
|
|
135
|
+
APP_SINGLE_THREADED = 0x0020
|
|
136
|
+
APP_MULTI_THREADED = 0x0040
|
|
137
|
+
APP_16_BIT = 0x0080
|
|
138
|
+
APP_32_BIT = 0x0100
|
|
139
|
+
APP_64_BIT = 0x0200
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
class FlirtFeatureFlag(int, Enum):
|
|
143
|
+
FEATURE_STARTUP = 0x1
|
|
144
|
+
FEATURE_CTYPE_CRC = 0x2
|
|
145
|
+
FEATURE_2BYTE_CTYPE = 0x4
|
|
146
|
+
FEATURE_ALT_CTYPE_CRC = 0x8
|
|
147
|
+
FEATURE_COMPRESSED = 0x10
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
class FlirtParseFlag(int, Enum):
|
|
151
|
+
PARSE_MORE_PUBLIC_NAMES = 0x1
|
|
152
|
+
PARSE_READ_TAIL_BYTES = 0x2
|
|
153
|
+
PARSE_READ_REFERENCED_FUNCTIONS = 0x4
|
|
154
|
+
PARSE_MORE_MODULES_WITH_SAME_CRC = 0x8
|
|
155
|
+
PARSE_MORE_MODULES = 0x10
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
class FlirtFunctionFlag(int, Enum):
|
|
159
|
+
FUNCTION_LOCAL = 0x2
|
|
160
|
+
FUNCTION_UNRESOLVED_COLLISION = 0x8
|
|
@@ -1,17 +1,19 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
from typing import TYPE_CHECKING
|
|
3
|
-
|
|
3
|
+
|
|
4
|
+
from collections.abc import Generator
|
|
4
5
|
from collections import defaultdict
|
|
6
|
+
import contextlib
|
|
5
7
|
import logging
|
|
6
8
|
|
|
7
|
-
import nampa
|
|
8
9
|
from archinfo.arch_arm import is_arm_arch
|
|
9
10
|
|
|
10
11
|
from angr.analyses import AnalysesHub
|
|
12
|
+
from angr.analyses.analysis import Analysis
|
|
11
13
|
from angr.errors import AngrRuntimeError
|
|
12
|
-
from
|
|
13
|
-
from .
|
|
14
|
-
import
|
|
14
|
+
from .flirt_sig import FlirtSignature, FlirtSignatureParsed
|
|
15
|
+
from .flirt_function import FlirtFunction
|
|
16
|
+
from .flirt_matcher import FlirtMatcher
|
|
15
17
|
|
|
16
18
|
if TYPE_CHECKING:
|
|
17
19
|
from angr.knowledge_plugins.functions import Function
|
|
@@ -33,19 +35,22 @@ class FlirtAnalysis(Analysis):
|
|
|
33
35
|
current binary, and then match all possible signatures for the architecture.
|
|
34
36
|
"""
|
|
35
37
|
|
|
36
|
-
def __init__(self, sig: FlirtSignature | str | None = None):
|
|
38
|
+
def __init__(self, sig: FlirtSignature | str | None = None, max_mismatched_bytes: int = 0):
|
|
39
|
+
|
|
40
|
+
from angr.flirt import FLIRT_SIGNATURES_BY_ARCH # pylint:disable=import-outside-toplevel
|
|
41
|
+
|
|
37
42
|
self._is_arm = is_arm_arch(self.project.arch)
|
|
38
43
|
self._all_suggestions: dict[str, dict[str, dict[int, str]]] = {}
|
|
39
44
|
self._suggestions: dict[int, str] = {}
|
|
40
45
|
self.matched_suggestions: dict[str, tuple[FlirtSignature, dict[int, str]]] = {}
|
|
41
46
|
self._temporary_sig = False
|
|
47
|
+
self._max_mismatched_bytes = max_mismatched_bytes
|
|
42
48
|
|
|
43
49
|
if sig:
|
|
44
50
|
if isinstance(sig, str):
|
|
45
51
|
# this is a file path
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
)
|
|
52
|
+
simos_name = self.project.arch.name if self.project.simos.name is not None else "UnknownOS"
|
|
53
|
+
sig = FlirtSignature(simos_name.lower(), simos_name.lower(), "Temporary", sig, None)
|
|
49
54
|
|
|
50
55
|
self.signatures = [sig]
|
|
51
56
|
self._temporary_sig = True
|
|
@@ -87,13 +92,17 @@ class FlirtAnalysis(Analysis):
|
|
|
87
92
|
|
|
88
93
|
if max_suggestion_sig_path is not None:
|
|
89
94
|
sig_ = path_to_sig.get(max_suggestion_sig_path)
|
|
95
|
+
assert sig_ is not None
|
|
90
96
|
_l.info("Applying FLIRT signature %s for library %s.", sig_, lib)
|
|
91
97
|
self._apply_changes(
|
|
92
98
|
sig_.sig_name if not self._temporary_sig else None, sig_to_suggestions[max_suggestion_sig_path]
|
|
93
99
|
)
|
|
94
100
|
self.matched_suggestions[lib] = (sig_, sig_to_suggestions[max_suggestion_sig_path])
|
|
95
101
|
|
|
96
|
-
def _find_hits_by_strings(self, regions: list[bytes]) ->
|
|
102
|
+
def _find_hits_by_strings(self, regions: list[bytes]) -> Generator[FlirtSignature]:
|
|
103
|
+
|
|
104
|
+
from angr.flirt import STRING_TO_LIBRARIES, LIBRARY_TO_SIGNATURES # pylint:disable=import-outside-toplevel
|
|
105
|
+
|
|
97
106
|
library_hits: dict[str, int] = defaultdict(int)
|
|
98
107
|
for s, libs in STRING_TO_LIBRARIES.items():
|
|
99
108
|
for region in regions:
|
|
@@ -117,39 +126,91 @@ class FlirtAnalysis(Analysis):
|
|
|
117
126
|
# match each function
|
|
118
127
|
self._suggestions = {}
|
|
119
128
|
with open(sig.sig_path, "rb") as sigfile:
|
|
120
|
-
flirt =
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
129
|
+
flirt = FlirtSignatureParsed.parse(sigfile)
|
|
130
|
+
tolerances = range(self._max_mismatched_bytes + 1)
|
|
131
|
+
for tolerance in tolerances:
|
|
132
|
+
# we iteratively match until we find no new matches
|
|
133
|
+
updated_funcs = set()
|
|
134
|
+
while True:
|
|
135
|
+
matched = False
|
|
136
|
+
|
|
137
|
+
funcs = (
|
|
138
|
+
self.project.kb.functions.values()
|
|
139
|
+
if not updated_funcs
|
|
140
|
+
else {self.project.kb.functions.get_by_addr(a) for a in self._get_caller_funcs(updated_funcs)}
|
|
141
|
+
)
|
|
142
|
+
updated_funcs = set()
|
|
143
|
+
|
|
144
|
+
for func in funcs:
|
|
145
|
+
func: Function
|
|
146
|
+
if func.is_simprocedure or func.is_plt:
|
|
147
|
+
continue
|
|
148
|
+
if func.addr in self._suggestions:
|
|
149
|
+
# we already have a suggestion for this function
|
|
150
|
+
continue
|
|
151
|
+
if not func.is_default_name:
|
|
152
|
+
# it already has a name. skip
|
|
153
|
+
continue
|
|
154
|
+
|
|
155
|
+
# print(tolerance, repr(func))
|
|
156
|
+
start = func.addr
|
|
157
|
+
if self._is_arm:
|
|
158
|
+
start = start & 0xFFFF_FFFE
|
|
159
|
+
|
|
160
|
+
max_block_addr = max(func.block_addrs_set)
|
|
161
|
+
end_block = func.get_block(max_block_addr)
|
|
162
|
+
end = max_block_addr + end_block.size
|
|
163
|
+
|
|
164
|
+
if self._is_arm:
|
|
165
|
+
end = end & 0xFFFF_FFFE
|
|
166
|
+
|
|
167
|
+
# load all bytes
|
|
168
|
+
func_bytes = self.project.loader.memory.load(start, end - start + 0x100)
|
|
169
|
+
matcher = FlirtMatcher(
|
|
170
|
+
flirt,
|
|
171
|
+
func,
|
|
172
|
+
self._get_callee_name,
|
|
173
|
+
self._on_func_matched,
|
|
174
|
+
mismatch_bytes_tolerance=tolerance,
|
|
175
|
+
)
|
|
176
|
+
func_matched = matcher.match_function(func_bytes, start)
|
|
177
|
+
if func_matched:
|
|
178
|
+
updated_funcs.add(func.addr)
|
|
179
|
+
matched |= func_matched
|
|
180
|
+
|
|
181
|
+
if not matched:
|
|
182
|
+
break
|
|
183
|
+
|
|
184
|
+
def _get_caller_funcs(self, update_func_addrs: set[int]) -> set[int]:
|
|
185
|
+
caller_funcs = set()
|
|
186
|
+
for func_addr in update_func_addrs:
|
|
187
|
+
for pred in self.kb.functions.callgraph.predecessors(func_addr):
|
|
188
|
+
if pred != func_addr:
|
|
189
|
+
caller_funcs.add(pred)
|
|
190
|
+
return caller_funcs
|
|
191
|
+
|
|
192
|
+
def _get_callee_name(
|
|
193
|
+
self, func, func_addr: int, call_addr: int, expected_name: str # pylint:disable=unused-argument
|
|
194
|
+
) -> str | None:
|
|
195
|
+
for block_addr, (call_target, _) in func._call_sites.items():
|
|
196
|
+
block = func.get_block(block_addr)
|
|
197
|
+
call_ins_addr = (
|
|
198
|
+
block.instruction_addrs[-2] if self.project.arch.branch_delay_slot else block.instruction_addrs[-1]
|
|
199
|
+
)
|
|
200
|
+
if block_addr <= call_addr < block_addr + block.size and call_ins_addr <= call_addr:
|
|
201
|
+
if call_target is None or not self.kb.functions.contains_addr(call_target):
|
|
202
|
+
return None
|
|
203
|
+
callee = self.kb.functions.get_by_addr(call_target)
|
|
204
|
+
return callee.name
|
|
205
|
+
return None
|
|
206
|
+
|
|
207
|
+
def _on_func_matched(self, func: Function, base_addr: int, flirt_func: FlirtFunction):
|
|
146
208
|
func_addr = base_addr + flirt_func.offset
|
|
147
209
|
_l.debug(
|
|
148
210
|
"_on_func_matched() is called with func_addr %#x with a suggested name %s.", func_addr, flirt_func.name
|
|
149
211
|
)
|
|
150
|
-
if func_addr != base_addr:
|
|
212
|
+
if func_addr != base_addr and (self._is_arm and func_addr != base_addr + 1):
|
|
151
213
|
# get the correct function
|
|
152
|
-
func = None
|
|
153
214
|
try:
|
|
154
215
|
func = self.kb.functions.get_by_addr(func_addr)
|
|
155
216
|
except KeyError:
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class FlirtFunction:
|
|
5
|
+
"""
|
|
6
|
+
Describes a function object in a FLIRT signature.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
__slots__ = (
|
|
10
|
+
"collision",
|
|
11
|
+
"local",
|
|
12
|
+
"name",
|
|
13
|
+
"offset",
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
def __init__(self, name: str, offset: int, local: bool, collision: bool):
|
|
17
|
+
self.name = name
|
|
18
|
+
self.offset = offset
|
|
19
|
+
self.local = local
|
|
20
|
+
self.collision = collision
|