angr 9.2.175__cp310-abi3-macosx_11_0_arm64.whl → 9.2.177__cp310-abi3-macosx_11_0_arm64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of angr might be problematic. Click here for more details.
- angr/__init__.py +1 -1
- angr/analyses/calling_convention/calling_convention.py +12 -0
- angr/analyses/complete_calling_conventions.py +39 -26
- angr/analyses/decompiler/ail_simplifier.py +14 -12
- angr/analyses/decompiler/ccall_rewriters/rewriter_base.py +5 -1
- angr/analyses/decompiler/clinic.py +54 -40
- angr/analyses/decompiler/optimization_passes/ite_region_converter.py +3 -3
- angr/analyses/decompiler/optimization_passes/lowered_switch_simplifier.py +2 -2
- angr/analyses/decompiler/peephole_optimizations/__init__.py +4 -4
- angr/analyses/decompiler/peephole_optimizations/cas_intrinsics.py +69 -12
- angr/analyses/decompiler/peephole_optimizations/{inlined_wstrcpy.py → inlined_wcscpy.py} +16 -8
- angr/analyses/decompiler/peephole_optimizations/inlined_wcscpy_consolidation.py +296 -0
- angr/analyses/decompiler/ssailification/rewriting_engine.py +14 -1
- angr/analyses/decompiler/structured_codegen/c.py +6 -5
- angr/analyses/decompiler/structuring/dream.py +2 -2
- angr/analyses/decompiler/structuring/phoenix.py +101 -23
- angr/analyses/decompiler/utils.py +10 -3
- angr/analyses/flirt/flirt.py +5 -4
- angr/analyses/stack_pointer_tracker.py +4 -3
- angr/analyses/typehoon/lifter.py +29 -18
- angr/analyses/typehoon/simple_solver.py +157 -50
- angr/analyses/typehoon/translator.py +34 -34
- angr/analyses/typehoon/typeconsts.py +33 -15
- angr/analyses/typehoon/typevars.py +9 -2
- angr/analyses/variable_recovery/engine_ail.py +43 -2
- angr/analyses/variable_recovery/engine_base.py +4 -1
- angr/analyses/variable_recovery/variable_recovery_fast.py +3 -1
- angr/emulator.py +2 -1
- angr/engines/hook.py +1 -1
- angr/engines/icicle.py +21 -5
- angr/engines/vex/claripy/ccall.py +3 -3
- angr/knowledge_plugins/functions/function.py +19 -2
- angr/procedures/definitions/__init__.py +9 -0
- angr/procedures/definitions/parse_win32json.py +11 -0
- angr/procedures/definitions/wdk/ntoskrnl.json +4 -0
- angr/procedures/posix/pthread.py +4 -4
- angr/procedures/stubs/format_parser.py +3 -3
- angr/rustylib.abi3.so +0 -0
- angr/sim_type.py +11 -6
- angr/simos/windows.py +1 -1
- angr/storage/memory_mixins/paged_memory/page_backer_mixins.py +1 -1
- angr/unicornlib.dylib +0 -0
- angr/utils/constants.py +1 -1
- angr/utils/strings.py +20 -0
- {angr-9.2.175.dist-info → angr-9.2.177.dist-info}/METADATA +5 -5
- {angr-9.2.175.dist-info → angr-9.2.177.dist-info}/RECORD +50 -49
- angr/analyses/decompiler/peephole_optimizations/inlined_wstrcpy_consolidation.py +0 -113
- {angr-9.2.175.dist-info → angr-9.2.177.dist-info}/WHEEL +0 -0
- {angr-9.2.175.dist-info → angr-9.2.177.dist-info}/entry_points.txt +0 -0
- {angr-9.2.175.dist-info → angr-9.2.177.dist-info}/licenses/LICENSE +0 -0
- {angr-9.2.175.dist-info → angr-9.2.177.dist-info}/top_level.txt +0 -0
|
@@ -85,7 +85,7 @@ class TypeTranslator:
|
|
|
85
85
|
internal = sim_type.SimTypeBottom(label="void").with_arch(self.arch)
|
|
86
86
|
else:
|
|
87
87
|
internal = self._tc2simtype(tc.basetype)
|
|
88
|
-
return sim_type.SimTypePointer(internal).with_arch(self.arch)
|
|
88
|
+
return sim_type.SimTypePointer(internal, label=tc.name).with_arch(self.arch)
|
|
89
89
|
|
|
90
90
|
def _translate_Pointer32(self, tc):
|
|
91
91
|
if isinstance(tc.basetype, typeconsts.BottomType):
|
|
@@ -93,11 +93,11 @@ class TypeTranslator:
|
|
|
93
93
|
internal = sim_type.SimTypeBottom(label="void").with_arch(self.arch)
|
|
94
94
|
else:
|
|
95
95
|
internal = self._tc2simtype(tc.basetype)
|
|
96
|
-
return sim_type.SimTypePointer(internal).with_arch(self.arch)
|
|
96
|
+
return sim_type.SimTypePointer(internal, label=tc.name).with_arch(self.arch)
|
|
97
97
|
|
|
98
98
|
def _translate_Array(self, tc: typeconsts.Array) -> sim_type.SimTypeArray:
|
|
99
99
|
elem_type = self._tc2simtype(tc.element)
|
|
100
|
-
return sim_type.SimTypeArray(elem_type, length=tc.count).with_arch(self.arch)
|
|
100
|
+
return sim_type.SimTypeArray(elem_type, length=tc.count, label=tc.name).with_arch(self.arch)
|
|
101
101
|
|
|
102
102
|
def _translate_Struct(self, tc: typeconsts.Struct):
|
|
103
103
|
if tc in self.structs:
|
|
@@ -136,26 +136,26 @@ class TypeTranslator:
|
|
|
136
136
|
|
|
137
137
|
return s
|
|
138
138
|
|
|
139
|
-
def _translate_Int8(self, tc):
|
|
140
|
-
return sim_type.SimTypeChar(signed=False).with_arch(self.arch)
|
|
139
|
+
def _translate_Int8(self, tc):
|
|
140
|
+
return sim_type.SimTypeChar(signed=False, label=tc.name).with_arch(self.arch)
|
|
141
141
|
|
|
142
|
-
def _translate_Int16(self, tc):
|
|
143
|
-
return sim_type.SimTypeShort(signed=False).with_arch(self.arch)
|
|
142
|
+
def _translate_Int16(self, tc):
|
|
143
|
+
return sim_type.SimTypeShort(signed=False, label=tc.name).with_arch(self.arch)
|
|
144
144
|
|
|
145
|
-
def _translate_Int32(self, tc):
|
|
146
|
-
return sim_type.SimTypeInt(signed=False).with_arch(self.arch)
|
|
145
|
+
def _translate_Int32(self, tc):
|
|
146
|
+
return sim_type.SimTypeInt(signed=False, label=tc.name).with_arch(self.arch)
|
|
147
147
|
|
|
148
|
-
def _translate_Int64(self, tc):
|
|
149
|
-
return sim_type.SimTypeLongLong(signed=False).with_arch(self.arch)
|
|
148
|
+
def _translate_Int64(self, tc):
|
|
149
|
+
return sim_type.SimTypeLongLong(signed=False, label=tc.name).with_arch(self.arch)
|
|
150
150
|
|
|
151
|
-
def _translate_Int128(self, tc):
|
|
152
|
-
return sim_type.SimTypeInt128(signed=False).with_arch(self.arch)
|
|
151
|
+
def _translate_Int128(self, tc):
|
|
152
|
+
return sim_type.SimTypeInt128(signed=False, label=tc.name).with_arch(self.arch)
|
|
153
153
|
|
|
154
|
-
def _translate_Int256(self, tc):
|
|
155
|
-
return sim_type.SimTypeInt256(signed=False).with_arch(self.arch)
|
|
154
|
+
def _translate_Int256(self, tc):
|
|
155
|
+
return sim_type.SimTypeInt256(signed=False, label=tc.name).with_arch(self.arch)
|
|
156
156
|
|
|
157
|
-
def _translate_Int512(self, tc):
|
|
158
|
-
return sim_type.SimTypeInt512(signed=False).with_arch(self.arch)
|
|
157
|
+
def _translate_Int512(self, tc):
|
|
158
|
+
return sim_type.SimTypeInt512(signed=False, label=tc.name).with_arch(self.arch)
|
|
159
159
|
|
|
160
160
|
def _translate_TypeVariableReference(self, tc):
|
|
161
161
|
if tc.typevar in self.translated:
|
|
@@ -164,11 +164,11 @@ class TypeTranslator:
|
|
|
164
164
|
self._has_nonexistent_ref = True
|
|
165
165
|
return SimTypeTempRef(tc.typevar)
|
|
166
166
|
|
|
167
|
-
def _translate_Float32(self, tc: typeconsts.Float32) -> sim_type.SimTypeFloat:
|
|
168
|
-
return sim_type.SimTypeFloat().with_arch(self.arch)
|
|
167
|
+
def _translate_Float32(self, tc: typeconsts.Float32) -> sim_type.SimTypeFloat:
|
|
168
|
+
return sim_type.SimTypeFloat(label=tc.name).with_arch(self.arch)
|
|
169
169
|
|
|
170
|
-
def _translate_Float64(self, tc: typeconsts.Float64) -> sim_type.SimTypeDouble:
|
|
171
|
-
return sim_type.SimTypeDouble().with_arch(self.arch)
|
|
170
|
+
def _translate_Float64(self, tc: typeconsts.Float64) -> sim_type.SimTypeDouble:
|
|
171
|
+
return sim_type.SimTypeDouble(label=tc.name).with_arch(self.arch)
|
|
172
172
|
|
|
173
173
|
#
|
|
174
174
|
# Backpatching
|
|
@@ -197,25 +197,25 @@ class TypeTranslator:
|
|
|
197
197
|
#
|
|
198
198
|
|
|
199
199
|
def _translate_SimTypeInt128(self, st: sim_type.SimTypeChar) -> typeconsts.Int128:
|
|
200
|
-
return typeconsts.Int128()
|
|
200
|
+
return typeconsts.Int128(name=st.label)
|
|
201
201
|
|
|
202
202
|
def _translate_SimTypeInt256(self, st: sim_type.SimTypeChar) -> typeconsts.Int256:
|
|
203
|
-
return typeconsts.Int256()
|
|
203
|
+
return typeconsts.Int256(name=st.label)
|
|
204
204
|
|
|
205
205
|
def _translate_SimTypeInt512(self, st: sim_type.SimTypeChar) -> typeconsts.Int512:
|
|
206
|
-
return typeconsts.Int512()
|
|
206
|
+
return typeconsts.Int512(name=st.label)
|
|
207
207
|
|
|
208
208
|
def _translate_SimTypeInt(self, st: sim_type.SimTypeInt) -> typeconsts.Int32:
|
|
209
|
-
return typeconsts.Int32()
|
|
209
|
+
return typeconsts.Int32(name=st.label)
|
|
210
210
|
|
|
211
211
|
def _translate_SimTypeLong(self, st: sim_type.SimTypeLong) -> typeconsts.Int32:
|
|
212
|
-
return typeconsts.Int32()
|
|
212
|
+
return typeconsts.Int32(name=st.label)
|
|
213
213
|
|
|
214
214
|
def _translate_SimTypeLongLong(self, st: sim_type.SimTypeLongLong) -> typeconsts.Int64:
|
|
215
|
-
return typeconsts.Int64()
|
|
215
|
+
return typeconsts.Int64(name=st.label)
|
|
216
216
|
|
|
217
217
|
def _translate_SimTypeChar(self, st: sim_type.SimTypeChar) -> typeconsts.Int8:
|
|
218
|
-
return typeconsts.Int8()
|
|
218
|
+
return typeconsts.Int8(name=st.label)
|
|
219
219
|
|
|
220
220
|
def _translate_SimStruct(self, st: sim_type.SimStruct) -> typeconsts.Struct:
|
|
221
221
|
fields = {}
|
|
@@ -224,25 +224,25 @@ class TypeTranslator:
|
|
|
224
224
|
offset = offsets[name]
|
|
225
225
|
fields[offset] = self._simtype2tc(ty)
|
|
226
226
|
|
|
227
|
-
return typeconsts.Struct(fields=fields)
|
|
227
|
+
return typeconsts.Struct(fields=fields, name=st.label)
|
|
228
228
|
|
|
229
229
|
def _translate_SimTypeArray(self, st: sim_type.SimTypeArray) -> typeconsts.Array:
|
|
230
230
|
elem_type = self._simtype2tc(st.elem_type)
|
|
231
|
-
return typeconsts.Array(elem_type, count=st.length)
|
|
231
|
+
return typeconsts.Array(elem_type, count=st.length, name=st.label)
|
|
232
232
|
|
|
233
233
|
def _translate_SimTypePointer(self, st: sim_type.SimTypePointer) -> typeconsts.Pointer32 | typeconsts.Pointer64:
|
|
234
234
|
base = self._simtype2tc(st.pts_to)
|
|
235
235
|
if self.arch.bits == 32:
|
|
236
|
-
return typeconsts.Pointer32(base)
|
|
236
|
+
return typeconsts.Pointer32(base, name=st.label)
|
|
237
237
|
if self.arch.bits == 64:
|
|
238
|
-
return typeconsts.Pointer64(base)
|
|
238
|
+
return typeconsts.Pointer64(base, name=st.label)
|
|
239
239
|
raise TypeError(f"Unsupported pointer size {self.arch.bits}")
|
|
240
240
|
|
|
241
241
|
def _translate_SimTypeFloat(self, st: sim_type.SimTypeFloat) -> typeconsts.Float32:
|
|
242
|
-
return typeconsts.Float32()
|
|
242
|
+
return typeconsts.Float32(name=st.label)
|
|
243
243
|
|
|
244
244
|
def _translate_SimTypeDouble(self, st: sim_type.SimTypeDouble) -> typeconsts.Float64:
|
|
245
|
-
return typeconsts.Float64()
|
|
245
|
+
return typeconsts.Float64(name=st.label)
|
|
246
246
|
|
|
247
247
|
|
|
248
248
|
TypeConstHandlers = {
|
|
@@ -5,6 +5,7 @@ All type constants used in type inference. They can be mapped, translated, or re
|
|
|
5
5
|
from __future__ import annotations
|
|
6
6
|
|
|
7
7
|
import functools
|
|
8
|
+
import itertools
|
|
8
9
|
|
|
9
10
|
|
|
10
11
|
def memoize(f):
|
|
@@ -24,6 +25,9 @@ def memoize(f):
|
|
|
24
25
|
class TypeConstant:
|
|
25
26
|
SIZE = None
|
|
26
27
|
|
|
28
|
+
def __init__(self, name: str | None = None):
|
|
29
|
+
self.name = name
|
|
30
|
+
|
|
27
31
|
def pp_str(self, mapping) -> str: # pylint:disable=unused-argument
|
|
28
32
|
return repr(self)
|
|
29
33
|
|
|
@@ -115,7 +119,8 @@ class Int512(Int):
|
|
|
115
119
|
|
|
116
120
|
|
|
117
121
|
class IntVar(Int):
|
|
118
|
-
def __init__(self, size):
|
|
122
|
+
def __init__(self, size, name: str | None = None):
|
|
123
|
+
super().__init__(name)
|
|
119
124
|
self._size = size
|
|
120
125
|
|
|
121
126
|
@property
|
|
@@ -146,7 +151,8 @@ class Float64(Float):
|
|
|
146
151
|
|
|
147
152
|
|
|
148
153
|
class Pointer(TypeConstant):
|
|
149
|
-
def __init__(self, basetype: TypeConstant | None):
|
|
154
|
+
def __init__(self, basetype: TypeConstant | None, name: str | None = None):
|
|
155
|
+
super().__init__(name=name)
|
|
150
156
|
self.basetype: TypeConstant | None = basetype
|
|
151
157
|
|
|
152
158
|
def __eq__(self, other):
|
|
@@ -169,13 +175,15 @@ class Pointer32(Pointer, Int32):
|
|
|
169
175
|
32-bit pointers.
|
|
170
176
|
"""
|
|
171
177
|
|
|
172
|
-
def __init__(self, basetype=None):
|
|
173
|
-
Pointer.__init__(self, basetype)
|
|
178
|
+
def __init__(self, basetype=None, name: str | None = None):
|
|
179
|
+
Pointer.__init__(self, basetype, name=name)
|
|
180
|
+
Int32.__init__(self, name=name)
|
|
174
181
|
|
|
175
182
|
@memoize
|
|
176
183
|
def __repr__(self, memo=None):
|
|
177
184
|
bt = self.basetype.__repr__(memo=memo) if isinstance(self.basetype, TypeConstant) else repr(self.basetype)
|
|
178
|
-
|
|
185
|
+
name_str = f"{self.name}#" if self.name else ""
|
|
186
|
+
return f"{name_str}ptr32({bt})"
|
|
179
187
|
|
|
180
188
|
|
|
181
189
|
class Pointer64(Pointer, Int64):
|
|
@@ -183,17 +191,20 @@ class Pointer64(Pointer, Int64):
|
|
|
183
191
|
64-bit pointers.
|
|
184
192
|
"""
|
|
185
193
|
|
|
186
|
-
def __init__(self, basetype=None):
|
|
187
|
-
Pointer.__init__(self, basetype)
|
|
194
|
+
def __init__(self, basetype=None, name: str | None = None):
|
|
195
|
+
Pointer.__init__(self, basetype, name=name)
|
|
196
|
+
Int64.__init__(self, name=name)
|
|
188
197
|
|
|
189
198
|
@memoize
|
|
190
199
|
def __repr__(self, memo=None):
|
|
191
200
|
bt = self.basetype.__repr__(memo=memo) if isinstance(self.basetype, TypeConstant) else repr(self.basetype)
|
|
192
|
-
|
|
201
|
+
name_str = f"{self.name}#" if self.name else ""
|
|
202
|
+
return f"{name_str}ptr64({bt})"
|
|
193
203
|
|
|
194
204
|
|
|
195
205
|
class Array(TypeConstant):
|
|
196
|
-
def __init__(self, element=None, count=None):
|
|
206
|
+
def __init__(self, element=None, count=None, name: str | None = None):
|
|
207
|
+
super().__init__(name=name)
|
|
197
208
|
self.element: TypeConstant | None = element
|
|
198
209
|
self.count: int | None = count
|
|
199
210
|
|
|
@@ -222,18 +233,22 @@ class Array(TypeConstant):
|
|
|
222
233
|
return self._hash(set())
|
|
223
234
|
|
|
224
235
|
|
|
236
|
+
_STRUCT_ID = itertools.count()
|
|
237
|
+
|
|
238
|
+
|
|
225
239
|
class Struct(TypeConstant):
|
|
226
|
-
def __init__(self, fields=None, name=None, field_names=None, is_cppclass: bool = False):
|
|
240
|
+
def __init__(self, fields=None, name=None, field_names=None, is_cppclass: bool = False, idx: int = -1):
|
|
241
|
+
super().__init__(name=name)
|
|
227
242
|
self.fields = {} if fields is None else fields # offset to type
|
|
228
|
-
self.name = name
|
|
229
243
|
self.field_names = field_names
|
|
230
244
|
self.is_cppclass = is_cppclass
|
|
245
|
+
self.idx = idx if idx != -1 else next(_STRUCT_ID)
|
|
231
246
|
|
|
232
247
|
def _hash(self, visited: set[int]):
|
|
233
248
|
if id(self) in visited:
|
|
234
249
|
return 0
|
|
235
250
|
visited.add(id(self))
|
|
236
|
-
return hash((type(self), self._hash_fields(visited)))
|
|
251
|
+
return hash((type(self), self.idx, self._hash_fields(visited)))
|
|
237
252
|
|
|
238
253
|
def _hash_fields(self, visited: set[int]):
|
|
239
254
|
keys = sorted(self.fields.keys())
|
|
@@ -252,6 +267,7 @@ class Struct(TypeConstant):
|
|
|
252
267
|
@memoize
|
|
253
268
|
def __repr__(self, memo=None):
|
|
254
269
|
prefix = "CppClass" if self.is_cppclass else "struct"
|
|
270
|
+
prefix += f"#{self.idx}"
|
|
255
271
|
if self.name:
|
|
256
272
|
prefix = f"{prefix} {self.name}"
|
|
257
273
|
return (
|
|
@@ -262,14 +278,15 @@ class Struct(TypeConstant):
|
|
|
262
278
|
)
|
|
263
279
|
|
|
264
280
|
def __eq__(self, other):
|
|
265
|
-
return type(other) is type(self) and hash(self) == hash(other)
|
|
281
|
+
return type(other) is type(self) and self.idx == other.idx and hash(self) == hash(other)
|
|
266
282
|
|
|
267
283
|
def __hash__(self):
|
|
268
284
|
return self._hash(set())
|
|
269
285
|
|
|
270
286
|
|
|
271
287
|
class Function(TypeConstant):
|
|
272
|
-
def __init__(self, params: list, outputs: list):
|
|
288
|
+
def __init__(self, params: list, outputs: list, name: str | None = None):
|
|
289
|
+
super().__init__(name=name)
|
|
273
290
|
self.params = params
|
|
274
291
|
self.outputs = outputs
|
|
275
292
|
|
|
@@ -298,7 +315,8 @@ class Function(TypeConstant):
|
|
|
298
315
|
|
|
299
316
|
|
|
300
317
|
class TypeVariableReference(TypeConstant):
|
|
301
|
-
def __init__(self, typevar):
|
|
318
|
+
def __init__(self, typevar, name: str | None = None):
|
|
319
|
+
super().__init__(name=name)
|
|
302
320
|
self.typevar = typevar
|
|
303
321
|
|
|
304
322
|
def __repr__(self, memo=None):
|
|
@@ -559,20 +559,27 @@ class ReinterpretAs(BaseLabel):
|
|
|
559
559
|
|
|
560
560
|
|
|
561
561
|
class HasField(BaseLabel):
|
|
562
|
+
"""
|
|
563
|
+
Has a field of the given bit size * elem_count at the given offset.
|
|
564
|
+
"""
|
|
565
|
+
|
|
562
566
|
__slots__ = (
|
|
563
567
|
"bits",
|
|
568
|
+
"elem_count",
|
|
564
569
|
"offset",
|
|
565
570
|
)
|
|
566
571
|
|
|
567
|
-
def __init__(self, bits, offset):
|
|
572
|
+
def __init__(self, bits, offset, elem_count: int = 1):
|
|
568
573
|
self.bits = bits
|
|
569
574
|
self.offset = offset
|
|
575
|
+
self.elem_count = elem_count
|
|
570
576
|
super().__init__()
|
|
571
577
|
|
|
572
578
|
def __repr__(self):
|
|
573
579
|
if self.bits == MAX_POINTSTO_BITS:
|
|
574
580
|
return f"<MAX_POINTSTO_BITS>@{self.offset}"
|
|
575
|
-
|
|
581
|
+
elem_str = str(self.elem_count) if self.elem_count != 1 else ""
|
|
582
|
+
return f"<{self.bits} bits>@{self.offset}{elem_str}"
|
|
576
583
|
|
|
577
584
|
|
|
578
585
|
class IsArray(BaseLabel):
|
|
@@ -34,6 +34,7 @@ class SimEngineVRAIL(
|
|
|
34
34
|
def __init__(
|
|
35
35
|
self,
|
|
36
36
|
*args,
|
|
37
|
+
type_lifter: TypeLifter,
|
|
37
38
|
call_info=None,
|
|
38
39
|
vvar_to_vvar: dict[int, int] | None,
|
|
39
40
|
vvar_type_hints: dict[int, typeconsts.TypeConstant] | None = None,
|
|
@@ -44,6 +45,7 @@ class SimEngineVRAIL(
|
|
|
44
45
|
self._reference_spoffset: bool = False
|
|
45
46
|
self.call_info = call_info or {}
|
|
46
47
|
self.vvar_to_vvar = vvar_to_vvar
|
|
48
|
+
self.type_lifter = type_lifter
|
|
47
49
|
|
|
48
50
|
def _mapped_vvarid(self, vvar_id: int) -> int | None:
|
|
49
51
|
if self.vvar_to_vvar is not None and vvar_id in self.vvar_to_vvar:
|
|
@@ -169,6 +171,45 @@ class SimEngineVRAIL(
|
|
|
169
171
|
if isinstance(funcaddr_typevar, typevars.TypeVariable):
|
|
170
172
|
load_typevar = self._create_access_typevar(funcaddr_typevar, False, self.arch.bytes, 0)
|
|
171
173
|
self.state.add_type_constraint(typevars.Subtype(funcaddr_typevar, load_typevar))
|
|
174
|
+
elif isinstance(target, str):
|
|
175
|
+
# special handling for some intrinsics
|
|
176
|
+
match target:
|
|
177
|
+
case (
|
|
178
|
+
"InterlockedExchange8"
|
|
179
|
+
| "InterlockedExchange16"
|
|
180
|
+
| "InterlockedExchange"
|
|
181
|
+
| "InterlockedExchange64"
|
|
182
|
+
| "InterlockedCompareExchange16"
|
|
183
|
+
| "InterlockedCompareExchange"
|
|
184
|
+
| "InterlockedCompareExchange64"
|
|
185
|
+
| "InterlockedCompareExchange128"
|
|
186
|
+
| "InterlockedExchangeAdd"
|
|
187
|
+
| "InterlockedExchangeAdd64"
|
|
188
|
+
):
|
|
189
|
+
arg_tv = (
|
|
190
|
+
args[0].typevar
|
|
191
|
+
if args[0].typevar is not None
|
|
192
|
+
else args[1].typevar if args[1].typevar is not None else None
|
|
193
|
+
)
|
|
194
|
+
if arg_tv is not None:
|
|
195
|
+
ret_ty = self._create_access_typevar(
|
|
196
|
+
arg_tv, False, args[0].data.size() // self.arch.byte_width, 0
|
|
197
|
+
)
|
|
198
|
+
return RichR(self.state.top(ret_expr_bits), typevar=ret_ty)
|
|
199
|
+
case (
|
|
200
|
+
"InterlockedIncrement"
|
|
201
|
+
| "InterlockedIncrement16"
|
|
202
|
+
| "InterlockedIncrement64"
|
|
203
|
+
| "InterlockedDecrement"
|
|
204
|
+
| "InterlockedDecrement16"
|
|
205
|
+
| "InterlockedDecrement64"
|
|
206
|
+
):
|
|
207
|
+
arg_tv = args[0].typevar if args[0].typevar is not None else None
|
|
208
|
+
if arg_tv is not None:
|
|
209
|
+
ret_ty = self._create_access_typevar(
|
|
210
|
+
arg_tv, False, args[0].data.size() // self.arch.byte_width, 0
|
|
211
|
+
)
|
|
212
|
+
return RichR(self.state.top(ret_expr_bits), typevar=ret_ty)
|
|
172
213
|
|
|
173
214
|
# discover the prototype
|
|
174
215
|
prototype: SimTypeFunction | None = None
|
|
@@ -195,7 +236,7 @@ class SimEngineVRAIL(
|
|
|
195
236
|
arg_type = (
|
|
196
237
|
dereference_simtype_by_lib(arg_type, prototype_libname) if prototype_libname else arg_type
|
|
197
238
|
)
|
|
198
|
-
arg_ty =
|
|
239
|
+
arg_ty = self.type_lifter.lift(arg_type)
|
|
199
240
|
type_constraint = typevars.Subtype(arg.typevar, arg_ty)
|
|
200
241
|
self.state.add_type_constraint(type_constraint)
|
|
201
242
|
|
|
@@ -282,7 +323,7 @@ class SimEngineVRAIL(
|
|
|
282
323
|
arg_type = (
|
|
283
324
|
dereference_simtype_by_lib(arg_type, prototype_libname) if prototype_libname else arg_type
|
|
284
325
|
)
|
|
285
|
-
arg_ty =
|
|
326
|
+
arg_ty = self.type_lifter.lift(arg_type)
|
|
286
327
|
if arg.typevar is not None and isinstance(
|
|
287
328
|
arg_ty, (typeconsts.TypeConstant, typevars.TypeVariable, typevars.DerivedTypeVariable)
|
|
288
329
|
):
|
|
@@ -277,7 +277,10 @@ class SimEngineVRBase(
|
|
|
277
277
|
variable, _ = existing_vars[0]
|
|
278
278
|
|
|
279
279
|
if not self.state.typevars.has_type_variable_for(variable):
|
|
280
|
-
|
|
280
|
+
if isinstance(variable, SimStackVariable) and variable.offset in self.state.stack_offset_typevars:
|
|
281
|
+
variable_typevar = self.state.stack_offset_typevars[variable.offset]
|
|
282
|
+
else:
|
|
283
|
+
variable_typevar = typevars.TypeVariable()
|
|
281
284
|
self.state.typevars.add_type_variable(variable, variable_typevar)
|
|
282
285
|
# we do not add any type constraint here because we are not sure if the given memory address will ever be
|
|
283
286
|
# accessed or not
|
|
@@ -284,6 +284,7 @@ class VariableRecoveryFast(ForwardAnalysis, VariableRecoveryBase): # pylint:dis
|
|
|
284
284
|
self._unify_variables = unify_variables
|
|
285
285
|
|
|
286
286
|
# handle type hints
|
|
287
|
+
self.type_lifter = TypeLifter(self.project.arch.bits)
|
|
287
288
|
self.vvar_type_hints = {}
|
|
288
289
|
if type_hints:
|
|
289
290
|
self._parse_type_hints(type_hints)
|
|
@@ -294,6 +295,7 @@ class VariableRecoveryFast(ForwardAnalysis, VariableRecoveryBase): # pylint:dis
|
|
|
294
295
|
call_info=call_info,
|
|
295
296
|
vvar_to_vvar=self.vvar_to_vvar,
|
|
296
297
|
vvar_type_hints=self.vvar_type_hints,
|
|
298
|
+
type_lifter=self.type_lifter,
|
|
297
299
|
)
|
|
298
300
|
self._vex_engine: SimEngineVRVEX = SimEngineVRVEX(self.project, self.kb, call_info=call_info)
|
|
299
301
|
|
|
@@ -654,7 +656,7 @@ class VariableRecoveryFast(ForwardAnalysis, VariableRecoveryBase): # pylint:dis
|
|
|
654
656
|
if ty is None:
|
|
655
657
|
return None
|
|
656
658
|
ty = ty.with_arch(self.project.arch)
|
|
657
|
-
lifted =
|
|
659
|
+
lifted = self.type_lifter.lift(ty)
|
|
658
660
|
return None if isinstance(lifted, (BottomType, TopType)) else lifted
|
|
659
661
|
|
|
660
662
|
|
angr/emulator.py
CHANGED
|
@@ -95,7 +95,8 @@ class Emulator:
|
|
|
95
95
|
num_inst_executed: int = 0
|
|
96
96
|
while self._state.history.jumpkind != "Ijk_Exit":
|
|
97
97
|
# Check if there is a breakpoint at the current address
|
|
98
|
-
|
|
98
|
+
addr_with_lower_bit_cleared = self._state.addr & ~1
|
|
99
|
+
if completed_engine_execs > 0 and addr_with_lower_bit_cleared in self._engine.get_breakpoints():
|
|
99
100
|
return EmulatorStopReason.BREAKPOINT
|
|
100
101
|
|
|
101
102
|
# Check if we've already executed the requested number of instructions
|
angr/engines/hook.py
CHANGED
|
@@ -54,7 +54,7 @@ class HooksMixin(SuccessorsEngine, ProcedureMixin):
|
|
|
54
54
|
if procedure is None:
|
|
55
55
|
procedure = self._lookup_hook(state, procedure)
|
|
56
56
|
if procedure is None:
|
|
57
|
-
return super().process_successors(successors,
|
|
57
|
+
return super().process_successors(successors, **kwargs)
|
|
58
58
|
|
|
59
59
|
if isinstance(procedure.addr, SootAddressDescriptor):
|
|
60
60
|
l.debug("Running %s (originally at %r)", repr(procedure), procedure.addr)
|
angr/engines/icicle.py
CHANGED
|
@@ -8,7 +8,7 @@ from dataclasses import dataclass
|
|
|
8
8
|
from typing_extensions import override
|
|
9
9
|
|
|
10
10
|
import pypcode
|
|
11
|
-
from archinfo import Arch, Endness
|
|
11
|
+
from archinfo import Arch, ArchPcode, Endness, ArchARMCortexM
|
|
12
12
|
|
|
13
13
|
from angr.engines.concrete import ConcreteEngine, HeavyConcreteState
|
|
14
14
|
from angr.engines.failure import SimEngineFailure
|
|
@@ -72,6 +72,8 @@ class IcicleEngine(ConcreteEngine):
|
|
|
72
72
|
accurate, just a set of heuristics to get the right architecture. When
|
|
73
73
|
adding a new architecture, this function may need to be updated.
|
|
74
74
|
"""
|
|
75
|
+
if isinstance(arch, ArchARMCortexM) or (isinstance(arch, ArchPcode) and arch.pcode_arch == "ARM:LE:32:Cortex"):
|
|
76
|
+
return "armv7m"
|
|
75
77
|
if arch.linux_name == "arm":
|
|
76
78
|
return "armv7a" if arch.memory_endness == Endness.LE else "armeb"
|
|
77
79
|
return arch.linux_name
|
|
@@ -84,11 +86,20 @@ class IcicleEngine(ConcreteEngine):
|
|
|
84
86
|
return icicle_arch.startswith(("arm", "thumb"))
|
|
85
87
|
|
|
86
88
|
@staticmethod
|
|
87
|
-
def
|
|
89
|
+
def __is_cortex_m(angr_arch: Arch, icicle_arch: str) -> bool:
|
|
90
|
+
"""
|
|
91
|
+
Check if the architecture is cortex-m based on the address.
|
|
92
|
+
"""
|
|
93
|
+
return isinstance(angr_arch, ArchARMCortexM) or icicle_arch == "armv7m"
|
|
94
|
+
|
|
95
|
+
@staticmethod
|
|
96
|
+
def __is_thumb(angr_arch: Arch, icicle_arch: str, addr: int) -> bool:
|
|
88
97
|
"""
|
|
89
98
|
Check if the architecture is thumb based on the address.
|
|
90
99
|
"""
|
|
91
|
-
return IcicleEngine.
|
|
100
|
+
return IcicleEngine.__is_cortex_m(angr_arch, icicle_arch) or (
|
|
101
|
+
IcicleEngine.__is_arm(icicle_arch) and addr & 1 == 1
|
|
102
|
+
)
|
|
92
103
|
|
|
93
104
|
@staticmethod
|
|
94
105
|
def __get_pages(state: HeavyConcreteState) -> set[int]:
|
|
@@ -132,13 +143,16 @@ class IcicleEngine(ConcreteEngine):
|
|
|
132
143
|
for register in state.arch.register_list:
|
|
133
144
|
register = register.vex_name.lower() if register.vex_name is not None else register.name
|
|
134
145
|
try:
|
|
135
|
-
emu.reg_write(
|
|
146
|
+
emu.reg_write(
|
|
147
|
+
register,
|
|
148
|
+
state.solver.eval(state.registers.load(register), cast_to=int),
|
|
149
|
+
)
|
|
136
150
|
copied_registers.add(register)
|
|
137
151
|
except KeyError:
|
|
138
152
|
log.debug("Register %s not found in icicle", register)
|
|
139
153
|
|
|
140
154
|
# Unset the thumb bit if necessary
|
|
141
|
-
if IcicleEngine.__is_thumb(icicle_arch, state.addr):
|
|
155
|
+
if IcicleEngine.__is_thumb(state.arch, icicle_arch, state.addr):
|
|
142
156
|
emu.pc = state.addr & ~1
|
|
143
157
|
emu.isa_mode = 1
|
|
144
158
|
elif "arm" in icicle_arch: # Hack to work around us calling it r15t
|
|
@@ -242,11 +256,13 @@ class IcicleEngine(ConcreteEngine):
|
|
|
242
256
|
@override
|
|
243
257
|
def add_breakpoint(self, addr: int) -> None:
|
|
244
258
|
"""Add a breakpoint at the given address."""
|
|
259
|
+
addr = addr & ~1 # Clear thumb bit if set
|
|
245
260
|
self.breakpoints.add(addr)
|
|
246
261
|
|
|
247
262
|
@override
|
|
248
263
|
def remove_breakpoint(self, addr: int) -> None:
|
|
249
264
|
"""Remove a breakpoint at the given address, if present."""
|
|
265
|
+
addr = addr & ~1 # Clear thumb bit if set
|
|
250
266
|
self.breakpoints.discard(addr)
|
|
251
267
|
|
|
252
268
|
@override
|
|
@@ -343,7 +343,7 @@ def pc_make_rdata_if_necessary(nbits, cf, pf, af, zf, sf, of, platform=None):
|
|
|
343
343
|
|
|
344
344
|
|
|
345
345
|
def pc_actions_ADD(state, nbits, arg_l, arg_r, cc_ndep, platform=None):
|
|
346
|
-
data_mask,
|
|
346
|
+
data_mask, _sign_mask = pc_preamble(nbits)
|
|
347
347
|
res = arg_l + arg_r
|
|
348
348
|
|
|
349
349
|
cf = claripy.If(claripy.ULT(res, arg_l), claripy.BVV(1, 1), claripy.BVV(0, 1))
|
|
@@ -701,7 +701,7 @@ def pc_calculate_rdata_all(state, cc_op, cc_dep1, cc_dep2, cc_ndep, platform=Non
|
|
|
701
701
|
def pc_calculate_condition(state, cond, cc_op, cc_dep1, cc_dep2, cc_ndep, platform=None):
|
|
702
702
|
rdata_all = pc_calculate_rdata_all_WRK(state, cc_op, cc_dep1, cc_dep2, cc_ndep, platform=platform)
|
|
703
703
|
if isinstance(rdata_all, tuple):
|
|
704
|
-
cf, pf,
|
|
704
|
+
cf, pf, _af, zf, sf, of = rdata_all
|
|
705
705
|
v = op_concretize(cond)
|
|
706
706
|
|
|
707
707
|
inv = v & 1
|
|
@@ -993,7 +993,7 @@ def pc_calculate_rdata_c(state, cc_op, cc_dep1, cc_dep2, cc_ndep, platform=None)
|
|
|
993
993
|
rdata_all = pc_calculate_rdata_all_WRK(state, cc_op, cc_dep1, cc_dep2, cc_ndep, platform=platform)
|
|
994
994
|
|
|
995
995
|
if isinstance(rdata_all, tuple):
|
|
996
|
-
cf,
|
|
996
|
+
cf, _pf, _af, _zf, _sf, _of = rdata_all
|
|
997
997
|
return claripy.Concat(claripy.BVV(0, data[platform]["size"] - 1), cf & 1)
|
|
998
998
|
return claripy.LShR(rdata_all, data[platform]["CondBitOffsets"]["G_CC_SHIFT_C"]) & 1
|
|
999
999
|
|
|
@@ -759,8 +759,7 @@ class Function(Serializable):
|
|
|
759
759
|
if hooker:
|
|
760
760
|
if hasattr(hooker, "DYNAMIC_RET") and hooker.DYNAMIC_RET:
|
|
761
761
|
return True
|
|
762
|
-
|
|
763
|
-
return not hooker.NO_RET
|
|
762
|
+
return hooker.returns
|
|
764
763
|
|
|
765
764
|
# Cannot determine
|
|
766
765
|
return None
|
|
@@ -1579,6 +1578,7 @@ class Function(Serializable):
|
|
|
1579
1578
|
return False
|
|
1580
1579
|
self.prototype = proto.with_arch(self.project.arch)
|
|
1581
1580
|
self.prototype_libname = library.name
|
|
1581
|
+
self.returning = library.is_returning(name)
|
|
1582
1582
|
|
|
1583
1583
|
# update self.calling_convention if necessary
|
|
1584
1584
|
if self.calling_convention is None:
|
|
@@ -1750,6 +1750,23 @@ class Function(Serializable):
|
|
|
1750
1750
|
_find_called(self.addr)
|
|
1751
1751
|
return {self._function_manager.function(a) for a in called}
|
|
1752
1752
|
|
|
1753
|
+
def holes(self, min_size: int = 8) -> int:
|
|
1754
|
+
"""
|
|
1755
|
+
Find the number of non-consecutive areas in the function that are at least `min_size` bytes large.
|
|
1756
|
+
"""
|
|
1757
|
+
|
|
1758
|
+
block_addrs = sorted(self._local_block_addrs)
|
|
1759
|
+
if not block_addrs:
|
|
1760
|
+
return 0
|
|
1761
|
+
holes = 0
|
|
1762
|
+
for i, addr in enumerate(block_addrs):
|
|
1763
|
+
if i == len(block_addrs) - 1:
|
|
1764
|
+
break
|
|
1765
|
+
next_addr = block_addrs[i + 1]
|
|
1766
|
+
if next_addr > addr + self._block_sizes[addr] and next_addr - (addr + self._block_sizes[addr]) >= min_size:
|
|
1767
|
+
holes += 1
|
|
1768
|
+
return holes
|
|
1769
|
+
|
|
1753
1770
|
def copy(self):
|
|
1754
1771
|
func = Function(self._function_manager, self.addr, name=self.name, syscall=self.is_syscall)
|
|
1755
1772
|
func.transition_graph = networkx.DiGraph(self.transition_graph)
|
|
@@ -427,6 +427,15 @@ class SimLibrary:
|
|
|
427
427
|
|
|
428
428
|
return func_name in self.prototypes or func_name in self.prototypes_json
|
|
429
429
|
|
|
430
|
+
def is_returning(self, name: str) -> bool:
|
|
431
|
+
"""
|
|
432
|
+
Check if a function is known to return.
|
|
433
|
+
|
|
434
|
+
:param name: The name of the function.
|
|
435
|
+
:return: A bool indicating if the function is known to return or not.
|
|
436
|
+
"""
|
|
437
|
+
return name not in self.non_returning
|
|
438
|
+
|
|
430
439
|
|
|
431
440
|
class SimCppLibrary(SimLibrary):
|
|
432
441
|
"""
|
|
@@ -2443,22 +2443,33 @@ def do_it(in_dir):
|
|
|
2443
2443
|
|
|
2444
2444
|
parsed_cprotos[(prefix, lib, suffix)].append((func, proto, ""))
|
|
2445
2445
|
|
|
2446
|
+
non_returning_functions = {
|
|
2447
|
+
"KeBugCheck",
|
|
2448
|
+
"KeBugCheckEx",
|
|
2449
|
+
}
|
|
2450
|
+
|
|
2446
2451
|
# dump to JSON files
|
|
2447
2452
|
for (prefix, libname, suffix), parsed_cprotos_per_lib in parsed_cprotos.items():
|
|
2448
2453
|
filename = libname.replace(".", "_") + ".json"
|
|
2449
2454
|
os.makedirs(prefix, exist_ok=True)
|
|
2450
2455
|
logging.debug("Writing to file %s...", filename)
|
|
2456
|
+
non_returning = []
|
|
2451
2457
|
d = {
|
|
2452
2458
|
"_t": "lib",
|
|
2453
2459
|
"type_collection_names": ["win32"],
|
|
2454
2460
|
"library_names": [libname if not suffix else f"{libname}.{suffix}"],
|
|
2455
2461
|
"default_cc": {"X86": "SimCCStdcall", "AMD64": "SimCCMicrosoftAMD64"},
|
|
2462
|
+
"non_returning": non_returning,
|
|
2456
2463
|
"functions": OrderedDict(),
|
|
2457
2464
|
}
|
|
2458
2465
|
for func, cproto, doc in sorted(parsed_cprotos_per_lib, key=lambda x: x[0]):
|
|
2459
2466
|
d["functions"][func] = {"proto": json.dumps(cproto.to_json()).replace('"', "'")}
|
|
2460
2467
|
if doc:
|
|
2461
2468
|
d["functions"][func]["doc"] = doc
|
|
2469
|
+
if func in non_returning_functions:
|
|
2470
|
+
non_returning.append(func)
|
|
2471
|
+
if not non_returning:
|
|
2472
|
+
del d["non_returning"]
|
|
2462
2473
|
with open(os.path.join(prefix, filename), "w") as f:
|
|
2463
2474
|
f.write(json.dumps(d, indent="\t"))
|
|
2464
2475
|
|
|
@@ -10,6 +10,10 @@
|
|
|
10
10
|
"X86": "SimCCStdcall",
|
|
11
11
|
"AMD64": "SimCCMicrosoftAMD64"
|
|
12
12
|
},
|
|
13
|
+
"non_returning": [
|
|
14
|
+
"KeBugCheck",
|
|
15
|
+
"KeBugCheckEx"
|
|
16
|
+
],
|
|
13
17
|
"functions": {
|
|
14
18
|
"CcAsyncCopyRead": {
|
|
15
19
|
"proto": "{'_t': 'func', 'args': [{'_t': 'ptr', 'pts_to': {'_t': '_ref', 'name': 'FILE_OBJECT', 'ot': '_ref'}}, {'_t': 'ptr', 'pts_to': {'_t': 'llong', 'label': 'Int64'}}, {'_t': 'int', 'signed': false, 'label': 'UInt32'}, {'_t': '_ref', 'name': 'BOOLEAN', 'ot': 'char'}, {'_t': 'ptr', 'pts_to': {'_t': 'bot', 'label': 'Void'}}, {'_t': 'ptr', 'pts_to': {'_t': '_ref', 'name': 'IO_STATUS_BLOCK', 'ot': '_ref'}}, {'_t': '_ref', 'name': 'PETHREAD', 'ot': 'ptr'}, {'_t': 'ptr', 'pts_to': {'_t': '_ref', 'name': 'CC_ASYNC_READ_CONTEXT', 'ot': '_ref'}}], 'returnty': {'_t': '_ref', 'name': 'BOOLEAN', 'ot': 'char'}, 'arg_names': ['FileObject', 'FileOffset', 'Length', 'Wait', 'Buffer', 'IoStatus', 'IoIssuerThread', 'AsyncReadContext']}"
|