angr 9.2.92__py3-none-manylinux2014_x86_64.whl → 9.2.94__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/analyses/cfg/cfg_base.py +20 -10
- angr/analyses/cfg/indirect_jump_resolvers/amd64_elf_got.py +1 -1
- angr/analyses/cfg/indirect_jump_resolvers/arm_elf_fast.py +89 -32
- angr/analyses/cfg/indirect_jump_resolvers/jumptable.py +276 -133
- angr/analyses/complete_calling_conventions.py +1 -1
- angr/analyses/decompiler/ail_simplifier.py +20 -0
- angr/analyses/decompiler/block_io_finder.py +293 -0
- angr/analyses/decompiler/block_similarity.py +190 -0
- angr/analyses/decompiler/callsite_maker.py +5 -0
- angr/analyses/decompiler/clinic.py +103 -1
- angr/analyses/decompiler/decompilation_cache.py +2 -0
- angr/analyses/decompiler/decompiler.py +21 -4
- angr/analyses/decompiler/optimization_passes/__init__.py +6 -0
- angr/analyses/decompiler/optimization_passes/code_motion.py +361 -0
- angr/analyses/decompiler/optimization_passes/optimization_pass.py +1 -0
- angr/analyses/decompiler/optimization_passes/stack_canary_simplifier.py +30 -18
- angr/analyses/decompiler/optimization_passes/switch_default_case_duplicator.py +110 -0
- angr/analyses/decompiler/peephole_optimizations/bswap.py +53 -2
- angr/analyses/decompiler/peephole_optimizations/eager_eval.py +20 -1
- angr/analyses/decompiler/structured_codegen/c.py +76 -41
- angr/analyses/decompiler/structuring/phoenix.py +41 -9
- angr/analyses/decompiler/utils.py +13 -4
- angr/analyses/propagator/engine_ail.py +3 -0
- angr/analyses/reaching_definitions/engine_ail.py +3 -0
- angr/analyses/reaching_definitions/reaching_definitions.py +7 -0
- angr/analyses/stack_pointer_tracker.py +60 -10
- angr/analyses/typehoon/simple_solver.py +95 -24
- angr/analyses/typehoon/typeconsts.py +1 -1
- angr/calling_conventions.py +0 -3
- angr/engines/pcode/cc.py +1 -1
- angr/engines/successors.py +6 -0
- angr/knowledge_plugins/propagations/states.py +2 -1
- angr/procedures/definitions/glibc.py +3 -1
- angr/procedures/definitions/parse_win32json.py +2135 -383
- angr/procedures/definitions/wdk_ntoskrnl.py +956 -0
- angr/sim_type.py +53 -13
- angr/utils/library.py +2 -2
- {angr-9.2.92.dist-info → angr-9.2.94.dist-info}/METADATA +6 -6
- {angr-9.2.92.dist-info → angr-9.2.94.dist-info}/RECORD +44 -41
- {angr-9.2.92.dist-info → angr-9.2.94.dist-info}/WHEEL +1 -1
- angr/procedures/definitions/wdk_ntdll.py +0 -994
- {angr-9.2.92.dist-info → angr-9.2.94.dist-info}/LICENSE +0 -0
- {angr-9.2.92.dist-info → angr-9.2.94.dist-info}/entry_points.txt +0 -0
- {angr-9.2.92.dist-info → angr-9.2.94.dist-info}/top_level.txt +0 -0
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
# pylint:disable=wrong-import-position,wrong-import-order
|
|
2
|
+
import enum
|
|
2
3
|
from typing import Tuple, Optional, Dict, Sequence, Set, List, TYPE_CHECKING
|
|
3
4
|
import logging
|
|
4
5
|
import functools
|
|
@@ -53,9 +54,9 @@ class UninitReadMeta:
|
|
|
53
54
|
uninit_read_base = 0xC000000
|
|
54
55
|
|
|
55
56
|
|
|
56
|
-
class
|
|
57
|
+
class AddressTransformationTypes(int, enum.Enum):
|
|
57
58
|
"""
|
|
58
|
-
|
|
59
|
+
Address transformation operations.
|
|
59
60
|
"""
|
|
60
61
|
|
|
61
62
|
Assignment = 0
|
|
@@ -65,6 +66,44 @@ class AddressTransferringTypes:
|
|
|
65
66
|
Or1 = 4
|
|
66
67
|
ShiftLeft = 5
|
|
67
68
|
ShiftRight = 6
|
|
69
|
+
Add = 7
|
|
70
|
+
Load = 8
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
class AddressTransformation:
|
|
74
|
+
"""
|
|
75
|
+
Describe and record an address transformation operation.
|
|
76
|
+
"""
|
|
77
|
+
|
|
78
|
+
def __init__(self, op: AddressTransformationTypes, operands: List, first_load: bool = False):
|
|
79
|
+
self.op = op
|
|
80
|
+
self.operands = operands
|
|
81
|
+
self.first_load = first_load
|
|
82
|
+
|
|
83
|
+
def __repr__(self):
|
|
84
|
+
return f"<Transformation: {self.op} {self.operands}>"
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
class AddressOperand:
|
|
88
|
+
"""
|
|
89
|
+
The class for the singleton class AddressSingleton. It represents the address being transformed before using as an
|
|
90
|
+
indirect jump target.
|
|
91
|
+
"""
|
|
92
|
+
|
|
93
|
+
def __repr__(self):
|
|
94
|
+
return "ADDR"
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
AddressSingleton = AddressOperand()
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
class Tmp:
|
|
101
|
+
"""
|
|
102
|
+
For modeling Tmp variables.
|
|
103
|
+
"""
|
|
104
|
+
|
|
105
|
+
def __init__(self, tmp_idx):
|
|
106
|
+
self.tmp_idx = tmp_idx
|
|
68
107
|
|
|
69
108
|
|
|
70
109
|
class JumpTargetBaseAddr:
|
|
@@ -867,7 +906,7 @@ class JumpTableResolver(IndirectJumpResolver):
|
|
|
867
906
|
|
|
868
907
|
:param cfg: A CFG instance.
|
|
869
908
|
:param addr: Address of the block where the indirect jump is.
|
|
870
|
-
:param func: The
|
|
909
|
+
:param func: The Function instance.
|
|
871
910
|
:param b: The generated backward slice.
|
|
872
911
|
:return: A bool indicating whether the indirect jump is resolved successfully, and a list of
|
|
873
912
|
resolved targets.
|
|
@@ -887,7 +926,7 @@ class JumpTableResolver(IndirectJumpResolver):
|
|
|
887
926
|
load_size,
|
|
888
927
|
stmts_to_remove,
|
|
889
928
|
stmts_adding_base_addr,
|
|
890
|
-
|
|
929
|
+
transformations,
|
|
891
930
|
) = self._find_load_statement(b, stmt_loc)
|
|
892
931
|
ite_stmt, ite_stmt_loc = None, None
|
|
893
932
|
|
|
@@ -1043,7 +1082,7 @@ class JumpTableResolver(IndirectJumpResolver):
|
|
|
1043
1082
|
load_stmt,
|
|
1044
1083
|
load_size,
|
|
1045
1084
|
stmts_adding_base_addr,
|
|
1046
|
-
|
|
1085
|
+
transformations,
|
|
1047
1086
|
potential_call_table,
|
|
1048
1087
|
)
|
|
1049
1088
|
if ret is None:
|
|
@@ -1145,7 +1184,10 @@ class JumpTableResolver(IndirectJumpResolver):
|
|
|
1145
1184
|
# all_addr_holders will be {(0x4c64c4, 11): (AddressTransferringTypes.SignedExtension, 32, 64,),
|
|
1146
1185
|
# (0x4c64c4, 12); (AddressTransferringTypes.Assignment,),
|
|
1147
1186
|
# }
|
|
1148
|
-
|
|
1187
|
+
transformations: Dict[Tuple[int, int], AddressTransformation] = OrderedDict()
|
|
1188
|
+
|
|
1189
|
+
initial_block_addr = stmt_loc[0]
|
|
1190
|
+
all_load_stmts = sorted(self._all_qualified_load_stmts_in_slice(b, stmt_loc[0]))
|
|
1149
1191
|
|
|
1150
1192
|
while True:
|
|
1151
1193
|
preds = list(b.slice.predecessors(stmt_loc))
|
|
@@ -1162,7 +1204,9 @@ class JumpTableResolver(IndirectJumpResolver):
|
|
|
1162
1204
|
# data transferring
|
|
1163
1205
|
stmts_to_remove.append(stmt_loc)
|
|
1164
1206
|
if isinstance(stmt, pyvex.IRStmt.WrTmp):
|
|
1165
|
-
|
|
1207
|
+
transformations[(stmt_loc[0], stmt.tmp)] = AddressTransformation(
|
|
1208
|
+
AddressTransformationTypes.Assignment, [stmt.tmp, AddressSingleton]
|
|
1209
|
+
)
|
|
1166
1210
|
continue
|
|
1167
1211
|
elif isinstance(stmt.data, pyvex.IRExpr.ITE):
|
|
1168
1212
|
# data transferring
|
|
@@ -1170,7 +1214,9 @@ class JumpTableResolver(IndirectJumpResolver):
|
|
|
1170
1214
|
# > t44 = ITE(t43,t16,0x0000c844)
|
|
1171
1215
|
stmts_to_remove.append(stmt_loc)
|
|
1172
1216
|
if isinstance(stmt, pyvex.IRStmt.WrTmp):
|
|
1173
|
-
|
|
1217
|
+
transformations[(stmt_loc[0], stmt.tmp)] = AddressTransformation(
|
|
1218
|
+
AddressTransformationTypes.Assignment, [stmt.tmp, AddressSingleton]
|
|
1219
|
+
)
|
|
1174
1220
|
continue
|
|
1175
1221
|
elif isinstance(stmt.data, pyvex.IRExpr.Unop):
|
|
1176
1222
|
if stmt.data.op == "Iop_32Sto64":
|
|
@@ -1178,10 +1224,8 @@ class JumpTableResolver(IndirectJumpResolver):
|
|
|
1178
1224
|
# t11 = 32Sto64(t12)
|
|
1179
1225
|
stmts_to_remove.append(stmt_loc)
|
|
1180
1226
|
if isinstance(stmt, pyvex.IRStmt.WrTmp):
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
32,
|
|
1184
|
-
64,
|
|
1227
|
+
transformations[(stmt_loc[0], stmt.tmp)] = AddressTransformation(
|
|
1228
|
+
AddressTransformationTypes.SignedExtension, [32, 64, AddressSingleton]
|
|
1185
1229
|
)
|
|
1186
1230
|
continue
|
|
1187
1231
|
elif stmt.data.op == "Iop_64to32":
|
|
@@ -1189,46 +1233,40 @@ class JumpTableResolver(IndirectJumpResolver):
|
|
|
1189
1233
|
# t24 = 64to32(t21)
|
|
1190
1234
|
stmts_to_remove.append(stmt_loc)
|
|
1191
1235
|
if isinstance(stmt, pyvex.IRStmt.WrTmp):
|
|
1192
|
-
|
|
1236
|
+
transformations[(stmt_loc[0], stmt.tmp)] = AddressTransformation(
|
|
1237
|
+
AddressTransformationTypes.Truncation, [64, 32, AddressSingleton]
|
|
1238
|
+
)
|
|
1193
1239
|
continue
|
|
1194
1240
|
elif stmt.data.op == "Iop_32Uto64":
|
|
1195
1241
|
# data transferring with conversion
|
|
1196
1242
|
# t21 = 32Uto64(t22)
|
|
1197
1243
|
stmts_to_remove.append(stmt_loc)
|
|
1198
1244
|
if isinstance(stmt, pyvex.IRStmt.WrTmp):
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
32,
|
|
1202
|
-
64,
|
|
1245
|
+
transformations[(stmt_loc[0], stmt.tmp)] = AddressTransformation(
|
|
1246
|
+
AddressTransformationTypes.UnsignedExtension, [32, 64, AddressSingleton]
|
|
1203
1247
|
)
|
|
1204
1248
|
continue
|
|
1205
1249
|
elif stmt.data.op == "Iop_16Uto32":
|
|
1206
1250
|
# data transferring with conversion
|
|
1207
1251
|
stmts_to_remove.append(stmt_loc)
|
|
1208
1252
|
if isinstance(stmt, pyvex.IRStmt.WrTmp):
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
16,
|
|
1212
|
-
32,
|
|
1253
|
+
transformations[(stmt_loc[0], stmt.tmp)] = AddressTransformation(
|
|
1254
|
+
AddressTransformationTypes.UnsignedExtension, [16, 32, AddressSingleton]
|
|
1213
1255
|
)
|
|
1214
1256
|
continue
|
|
1215
1257
|
elif stmt.data.op == "Iop_8Uto32":
|
|
1216
1258
|
# data transferring with conversion
|
|
1217
1259
|
stmts_to_remove.append(stmt_loc)
|
|
1218
1260
|
if isinstance(stmt, pyvex.IRStmt.WrTmp):
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
8,
|
|
1222
|
-
32,
|
|
1261
|
+
transformations[(stmt_loc[0], stmt.tmp)] = AddressTransformation(
|
|
1262
|
+
AddressTransformationTypes.UnsignedExtension, [8, 32, AddressSingleton]
|
|
1223
1263
|
)
|
|
1224
1264
|
continue
|
|
1225
1265
|
elif stmt.data.op == "Iop_8Uto64":
|
|
1226
1266
|
stmts_to_remove.append(stmt_loc)
|
|
1227
1267
|
if isinstance(stmt, pyvex.IRStmt.WrTmp):
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
8,
|
|
1231
|
-
64,
|
|
1268
|
+
transformations[(stmt_loc[0], stmt.tmp)] = AddressTransformation(
|
|
1269
|
+
AddressTransformationTypes.UnsignedExtension, [8, 64, AddressSingleton]
|
|
1232
1270
|
)
|
|
1233
1271
|
continue
|
|
1234
1272
|
elif isinstance(stmt.data, pyvex.IRExpr.Binop):
|
|
@@ -1279,25 +1317,34 @@ class JumpTableResolver(IndirectJumpResolver):
|
|
|
1279
1317
|
if isinstance(stmt.data.args[0], pyvex.IRExpr.Const) and isinstance(
|
|
1280
1318
|
stmt.data.args[1], pyvex.IRExpr.RdTmp
|
|
1281
1319
|
):
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
stmt_loc, stmt, stmt.data.args[1].tmp, base_addr=stmt.data.args[0].con.value
|
|
1285
|
-
)
|
|
1320
|
+
transformations[(stmt_loc[0], stmt.tmp)] = AddressTransformation(
|
|
1321
|
+
AddressTransformationTypes.Add, [stmt.data.args[0].con.value, AddressSingleton]
|
|
1286
1322
|
)
|
|
1323
|
+
# we no longer update stmts_adding_base_addr in this case because it's replaced by
|
|
1324
|
+
# transformations
|
|
1287
1325
|
stmts_to_remove.append(stmt_loc)
|
|
1288
1326
|
elif isinstance(stmt.data.args[0], pyvex.IRExpr.RdTmp) and isinstance(
|
|
1289
1327
|
stmt.data.args[1], pyvex.IRExpr.Const
|
|
1290
1328
|
):
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
stmt_loc, stmt, stmt.data.args[0].tmp, base_addr=stmt.data.args[1].con.value
|
|
1294
|
-
)
|
|
1329
|
+
transformations[(stmt_loc[0], stmt.tmp)] = AddressTransformation(
|
|
1330
|
+
AddressTransformationTypes.Add, [AddressSingleton, stmt.data.args[1].con.value]
|
|
1295
1331
|
)
|
|
1332
|
+
# we no longer update stmts_adding_base_addr in this case because it's replaced by
|
|
1333
|
+
# transformations
|
|
1296
1334
|
stmts_to_remove.append(stmt_loc)
|
|
1297
1335
|
elif isinstance(stmt.data.args[0], pyvex.IRExpr.RdTmp) and isinstance(
|
|
1298
1336
|
stmt.data.args[1], pyvex.IRExpr.RdTmp
|
|
1299
1337
|
):
|
|
1300
|
-
# one of the tmps must be holding a concrete value at this point
|
|
1338
|
+
# one of the tmps must be holding a concrete value at this point. we will know this when
|
|
1339
|
+
# we perform constant propagation before running JumpTableResolver. this can act as an
|
|
1340
|
+
# indicator that we need to run constant propagation for this function.
|
|
1341
|
+
# for now, we don't support it :)
|
|
1342
|
+
# FIXME: Run constant propagation for the function when necessary. we can also remove
|
|
1343
|
+
# stmts_adding_base_addr and the surrounding logic then.
|
|
1344
|
+
# transformations[(stmt_loc[0], stmt.tmp)] = AddressTransformation(
|
|
1345
|
+
# AddressTransferringTypes.Add,
|
|
1346
|
+
# [Tmp(stmt.data.args[0].tmp), Tmp(stmt.data.args[1].tmp)],
|
|
1347
|
+
# )
|
|
1301
1348
|
stmts_adding_base_addr.append(
|
|
1302
1349
|
JumpTargetBaseAddr(stmt_loc, stmt, stmt.data.args[0].tmp, tmp_1=stmt.data.args[1].tmp)
|
|
1303
1350
|
)
|
|
@@ -1329,7 +1376,9 @@ class JumpTableResolver(IndirectJumpResolver):
|
|
|
1329
1376
|
):
|
|
1330
1377
|
# great. here it is
|
|
1331
1378
|
stmts_to_remove.append(stmt_loc)
|
|
1332
|
-
|
|
1379
|
+
transformations[(stmt_loc[0], stmt.tmp)] = AddressTransformation(
|
|
1380
|
+
AddressTransformationTypes.Or1, [AddressSingleton]
|
|
1381
|
+
)
|
|
1333
1382
|
continue
|
|
1334
1383
|
elif stmt.data.op.startswith("Iop_Shl"):
|
|
1335
1384
|
# this is sometimes used when dealing with TBx instructions in ARM code.
|
|
@@ -1351,9 +1400,8 @@ class JumpTableResolver(IndirectJumpResolver):
|
|
|
1351
1400
|
):
|
|
1352
1401
|
# found it
|
|
1353
1402
|
stmts_to_remove.append(stmt_loc)
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
stmt.data.args[1].con.value,
|
|
1403
|
+
transformations[(stmt_loc[0], stmt.tmp)] = AddressTransformation(
|
|
1404
|
+
AddressTransformationTypes.ShiftLeft, [AddressSingleton, stmt.data.args[1].con.value]
|
|
1357
1405
|
)
|
|
1358
1406
|
continue
|
|
1359
1407
|
elif stmt.data.op.startswith("Iop_Sar"):
|
|
@@ -1388,9 +1436,8 @@ class JumpTableResolver(IndirectJumpResolver):
|
|
|
1388
1436
|
):
|
|
1389
1437
|
# found it
|
|
1390
1438
|
stmts_to_remove.append(stmt_loc)
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
stmt.data.args[1].con.value,
|
|
1439
|
+
transformations[(stmt_loc[0], stmt.tmp)] = AddressTransformation(
|
|
1440
|
+
AddressTransformationTypes.ShiftRight, [AddressSingleton, stmt.data.args[1].con.value]
|
|
1394
1441
|
)
|
|
1395
1442
|
continue
|
|
1396
1443
|
elif isinstance(stmt.data, pyvex.IRExpr.Load):
|
|
@@ -1401,7 +1448,15 @@ class JumpTableResolver(IndirectJumpResolver):
|
|
|
1401
1448
|
block.tyenv.sizeof(stmt.tmp) // self.project.arch.byte_width,
|
|
1402
1449
|
)
|
|
1403
1450
|
stmts_to_remove.append(stmt_loc)
|
|
1404
|
-
|
|
1451
|
+
is_first_load_stmt = (
|
|
1452
|
+
True if not all_load_stmts else (stmt_loc == (initial_block_addr, all_load_stmts[0]))
|
|
1453
|
+
)
|
|
1454
|
+
transformations[(stmt_loc[0], stmt.tmp)] = AddressTransformation(
|
|
1455
|
+
AddressTransformationTypes.Load, [AddressSingleton, load_size], first_load=is_first_load_stmt
|
|
1456
|
+
)
|
|
1457
|
+
if not is_first_load_stmt:
|
|
1458
|
+
# This is not the first load statement in the block. more to go
|
|
1459
|
+
continue
|
|
1405
1460
|
elif isinstance(stmt, pyvex.IRStmt.LoadG):
|
|
1406
1461
|
# Got it!
|
|
1407
1462
|
#
|
|
@@ -1418,7 +1473,7 @@ class JumpTableResolver(IndirectJumpResolver):
|
|
|
1418
1473
|
|
|
1419
1474
|
break
|
|
1420
1475
|
|
|
1421
|
-
return load_stmt_loc, load_stmt, load_size, stmts_to_remove, stmts_adding_base_addr,
|
|
1476
|
+
return load_stmt_loc, load_stmt, load_size, stmts_to_remove, stmts_adding_base_addr, transformations
|
|
1422
1477
|
|
|
1423
1478
|
def _find_load_pc_ite_statement(self, b: Blade, stmt_loc: Tuple[int, int]):
|
|
1424
1479
|
"""
|
|
@@ -1598,7 +1653,7 @@ class JumpTableResolver(IndirectJumpResolver):
|
|
|
1598
1653
|
load_stmt,
|
|
1599
1654
|
load_size,
|
|
1600
1655
|
stmts_adding_base_addr,
|
|
1601
|
-
|
|
1656
|
+
transformations: Dict[Tuple[int, int], AddressTransformation],
|
|
1602
1657
|
potential_call_table: bool = False,
|
|
1603
1658
|
):
|
|
1604
1659
|
"""
|
|
@@ -1633,7 +1688,29 @@ class JumpTableResolver(IndirectJumpResolver):
|
|
|
1633
1688
|
# sanity check and necessary pre-processing
|
|
1634
1689
|
jump_base_addr = None
|
|
1635
1690
|
if stmts_adding_base_addr:
|
|
1636
|
-
if len(stmts_adding_base_addr)
|
|
1691
|
+
if len(stmts_adding_base_addr) == 1:
|
|
1692
|
+
jump_base_addr = stmts_adding_base_addr[0]
|
|
1693
|
+
if jump_base_addr.base_addr_available:
|
|
1694
|
+
addr_holders = {(jump_base_addr.stmt_loc[0], jump_base_addr.tmp)}
|
|
1695
|
+
else:
|
|
1696
|
+
addr_holders = {
|
|
1697
|
+
(jump_base_addr.stmt_loc[0], jump_base_addr.tmp),
|
|
1698
|
+
(jump_base_addr.stmt_loc[0], jump_base_addr.tmp_1),
|
|
1699
|
+
}
|
|
1700
|
+
if len(set(transformations.keys()).intersection(addr_holders)) != 1:
|
|
1701
|
+
# for some reason it's trying to add a base address onto a different temporary variable that we
|
|
1702
|
+
# are not aware of. skip.
|
|
1703
|
+
return None
|
|
1704
|
+
|
|
1705
|
+
if not jump_base_addr.base_addr_available:
|
|
1706
|
+
# we need to decide which tmp is the address holder and which tmp holds the base address
|
|
1707
|
+
addr_holder = next(iter(set(transformations.keys()).intersection(addr_holders)))
|
|
1708
|
+
if jump_base_addr.tmp_1 == addr_holder[1]:
|
|
1709
|
+
# swap the two tmps
|
|
1710
|
+
jump_base_addr.tmp, jump_base_addr.tmp_1 = jump_base_addr.tmp_1, jump_base_addr.tmp
|
|
1711
|
+
# Load the concrete base address
|
|
1712
|
+
jump_base_addr.base_addr = state.solver.eval(state.scratch.temps[jump_base_addr.tmp_1])
|
|
1713
|
+
else:
|
|
1637
1714
|
# We do not support the cases where the base address involves more than one addition.
|
|
1638
1715
|
# One such case exists in libc-2.27.so shipped with Ubuntu x86 where esi is used as the address of the
|
|
1639
1716
|
# data region.
|
|
@@ -1650,28 +1727,6 @@ class JumpTableResolver(IndirectJumpResolver):
|
|
|
1650
1727
|
# region (in this case, 0x1d8000). we give up in such cases until we can reasonably perform a
|
|
1651
1728
|
# full-function data propagation before performing jump table recovery.
|
|
1652
1729
|
l.debug("Multiple statements adding bases, not supported yet") # FIXME: Just check the addresses?
|
|
1653
|
-
return None
|
|
1654
|
-
jump_base_addr = stmts_adding_base_addr[0]
|
|
1655
|
-
if jump_base_addr.base_addr_available:
|
|
1656
|
-
addr_holders = {(jump_base_addr.stmt_loc[0], jump_base_addr.tmp)}
|
|
1657
|
-
else:
|
|
1658
|
-
addr_holders = {
|
|
1659
|
-
(jump_base_addr.stmt_loc[0], jump_base_addr.tmp),
|
|
1660
|
-
(jump_base_addr.stmt_loc[0], jump_base_addr.tmp_1),
|
|
1661
|
-
}
|
|
1662
|
-
if len(set(all_addr_holders.keys()).intersection(addr_holders)) != 1:
|
|
1663
|
-
# for some reason it's trying to add a base address onto a different temporary variable that we
|
|
1664
|
-
# are not aware of. skip.
|
|
1665
|
-
return None
|
|
1666
|
-
|
|
1667
|
-
if not jump_base_addr.base_addr_available:
|
|
1668
|
-
# we need to decide which tmp is the address holder and which tmp holds the base address
|
|
1669
|
-
addr_holder = next(iter(set(all_addr_holders.keys()).intersection(addr_holders)))
|
|
1670
|
-
if jump_base_addr.tmp_1 == addr_holder[1]:
|
|
1671
|
-
# swap the two tmps
|
|
1672
|
-
jump_base_addr.tmp, jump_base_addr.tmp_1 = jump_base_addr.tmp_1, jump_base_addr.tmp
|
|
1673
|
-
# Load the concrete base address
|
|
1674
|
-
jump_base_addr.base_addr = state.solver.eval(state.scratch.temps[jump_base_addr.tmp_1])
|
|
1675
1730
|
|
|
1676
1731
|
jumptable_addr_vsa = jumptable_addr._model_vsa
|
|
1677
1732
|
|
|
@@ -1785,66 +1840,86 @@ class JumpTableResolver(IndirectJumpResolver):
|
|
|
1785
1840
|
return None
|
|
1786
1841
|
|
|
1787
1842
|
# Adjust entries inside the jump table
|
|
1788
|
-
|
|
1789
|
-
|
|
1790
|
-
|
|
1791
|
-
|
|
1792
|
-
|
|
1793
|
-
|
|
1794
|
-
if conversions:
|
|
1843
|
+
mask = (2**self.project.arch.bits) - 1
|
|
1844
|
+
transformation_list = list(reversed(list(v for v in transformations.values() if not v.first_load)))
|
|
1845
|
+
if transformation_list:
|
|
1846
|
+
|
|
1847
|
+
def handle_signed_ext(a):
|
|
1848
|
+
return (a | 0xFFFFFFFF00000000) if a >= 0x80000000 else a
|
|
1795
1849
|
|
|
1796
|
-
|
|
1797
|
-
|
|
1850
|
+
def handle_unsigned_ext(a):
|
|
1851
|
+
return a
|
|
1798
1852
|
|
|
1799
|
-
|
|
1800
|
-
|
|
1853
|
+
def handle_trunc_64_32(a):
|
|
1854
|
+
return a & 0xFFFFFFFF
|
|
1801
1855
|
|
|
1802
|
-
|
|
1803
|
-
|
|
1856
|
+
def handle_or1(a):
|
|
1857
|
+
return a | 1
|
|
1804
1858
|
|
|
1805
|
-
|
|
1806
|
-
|
|
1859
|
+
def handle_lshift(num_bits, a):
|
|
1860
|
+
return a << num_bits
|
|
1807
1861
|
|
|
1808
|
-
|
|
1809
|
-
|
|
1862
|
+
def handle_rshift(num_bits, a):
|
|
1863
|
+
return a >> num_bits
|
|
1810
1864
|
|
|
1811
|
-
|
|
1812
|
-
|
|
1865
|
+
def handle_add(con, a):
|
|
1866
|
+
return (a + con) & mask
|
|
1813
1867
|
|
|
1814
|
-
|
|
1815
|
-
|
|
1816
|
-
|
|
1817
|
-
|
|
1868
|
+
def handle_load(size, a):
|
|
1869
|
+
return cfg._fast_memory_load_pointer(a, size=size)
|
|
1870
|
+
|
|
1871
|
+
invert_conversion_ops = []
|
|
1872
|
+
for tran in transformation_list:
|
|
1873
|
+
tran_op, args = tran.op, tran.operands
|
|
1874
|
+
if tran_op is AddressTransformationTypes.SignedExtension:
|
|
1875
|
+
if args == [32, 64, AddressSingleton]:
|
|
1876
|
+
lam = handle_signed_ext
|
|
1818
1877
|
else:
|
|
1819
|
-
|
|
1820
|
-
|
|
1821
|
-
|
|
1822
|
-
|
|
1823
|
-
|
|
1824
|
-
|
|
1825
|
-
elif conversion_op is AddressTransferringTypes.UnsignedExtension:
|
|
1826
|
-
lam = handle_unsigned_ext
|
|
1827
|
-
elif conversion_op is AddressTransferringTypes.Truncation:
|
|
1828
|
-
if args == (64, 32):
|
|
1829
|
-
lam = handle_trunc_64_32
|
|
1830
|
-
else:
|
|
1831
|
-
raise NotImplementedError("Unsupported truncation operation.")
|
|
1832
|
-
elif conversion_op is AddressTransferringTypes.Or1:
|
|
1833
|
-
lam = handle_or1
|
|
1834
|
-
elif conversion_op is AddressTransferringTypes.ShiftLeft:
|
|
1835
|
-
lam = functools.partial(handle_lshift, args[0])
|
|
1836
|
-
elif conversion_op is AddressTransferringTypes.ShiftRight:
|
|
1837
|
-
lam = functools.partial(handle_rshift, args[0])
|
|
1878
|
+
raise NotImplementedError("Unsupported signed extension operation.")
|
|
1879
|
+
elif tran_op is AddressTransformationTypes.UnsignedExtension:
|
|
1880
|
+
lam = handle_unsigned_ext
|
|
1881
|
+
elif tran_op is AddressTransformationTypes.Truncation:
|
|
1882
|
+
if args == [64, 32, AddressSingleton]:
|
|
1883
|
+
lam = handle_trunc_64_32
|
|
1838
1884
|
else:
|
|
1839
|
-
raise NotImplementedError("Unsupported
|
|
1840
|
-
|
|
1841
|
-
|
|
1842
|
-
|
|
1843
|
-
|
|
1844
|
-
|
|
1845
|
-
|
|
1846
|
-
|
|
1847
|
-
|
|
1885
|
+
raise NotImplementedError("Unsupported truncation operation.")
|
|
1886
|
+
elif tran_op is AddressTransformationTypes.Or1:
|
|
1887
|
+
lam = handle_or1
|
|
1888
|
+
elif tran_op is AddressTransformationTypes.ShiftLeft:
|
|
1889
|
+
lam = functools.partial(
|
|
1890
|
+
handle_lshift, next(iter(arg for arg in args if arg is not AddressSingleton))
|
|
1891
|
+
)
|
|
1892
|
+
elif tran_op is AddressTransformationTypes.ShiftRight:
|
|
1893
|
+
lam = functools.partial(
|
|
1894
|
+
handle_rshift, next(iter(arg for arg in args if arg is not AddressSingleton))
|
|
1895
|
+
)
|
|
1896
|
+
elif tran_op is AddressTransformationTypes.Add:
|
|
1897
|
+
add_arg = next(iter(arg for arg in args if arg is not AddressSingleton))
|
|
1898
|
+
if not isinstance(add_arg, int):
|
|
1899
|
+
# unsupported cases (Tmp, for example). abort
|
|
1900
|
+
return None
|
|
1901
|
+
lam = functools.partial(handle_add, add_arg)
|
|
1902
|
+
elif tran_op is AddressTransformationTypes.Load:
|
|
1903
|
+
lam = functools.partial(handle_load, args[1])
|
|
1904
|
+
elif tran_op is AddressTransformationTypes.Assignment:
|
|
1905
|
+
continue
|
|
1906
|
+
else:
|
|
1907
|
+
raise NotImplementedError("Unsupported transformation operation.")
|
|
1908
|
+
invert_conversion_ops.append(lam)
|
|
1909
|
+
all_targets_copy = all_targets
|
|
1910
|
+
all_targets = []
|
|
1911
|
+
for target_ in all_targets_copy:
|
|
1912
|
+
for lam in invert_conversion_ops:
|
|
1913
|
+
target_ = lam(target_)
|
|
1914
|
+
if target_ is None:
|
|
1915
|
+
# transformation failed. abort
|
|
1916
|
+
return None
|
|
1917
|
+
all_targets.append(target_)
|
|
1918
|
+
if None in all_targets:
|
|
1919
|
+
return None
|
|
1920
|
+
if len(stmts_adding_base_addr) == 1:
|
|
1921
|
+
stmt_adding_base_addr = stmts_adding_base_addr[0]
|
|
1922
|
+
base_addr = stmt_adding_base_addr.base_addr
|
|
1848
1923
|
all_targets = [(target + base_addr) & mask for target in all_targets]
|
|
1849
1924
|
|
|
1850
1925
|
# special case for ARM: if the source block is in THUMB mode, all jump targets should be in THUMB mode, too
|
|
@@ -2071,20 +2146,21 @@ class JumpTableResolver(IndirectJumpResolver):
|
|
|
2071
2146
|
print(s)
|
|
2072
2147
|
|
|
2073
2148
|
def _initial_state(self, block_addr, cfg, func_addr: int):
|
|
2149
|
+
add_options = {
|
|
2150
|
+
o.DO_RET_EMULATION,
|
|
2151
|
+
o.TRUE_RET_EMULATION_GUARD,
|
|
2152
|
+
o.AVOID_MULTIVALUED_READS,
|
|
2153
|
+
# Keep IP symbolic to avoid unnecessary concretization
|
|
2154
|
+
o.KEEP_IP_SYMBOLIC,
|
|
2155
|
+
o.NO_IP_CONCRETIZATION,
|
|
2156
|
+
# be quiet!!!!!!
|
|
2157
|
+
o.SYMBOL_FILL_UNCONSTRAINED_REGISTERS,
|
|
2158
|
+
o.SYMBOL_FILL_UNCONSTRAINED_MEMORY,
|
|
2159
|
+
}
|
|
2074
2160
|
state = self.project.factory.blank_state(
|
|
2075
2161
|
addr=block_addr,
|
|
2076
2162
|
mode="static",
|
|
2077
|
-
add_options=
|
|
2078
|
-
o.DO_RET_EMULATION,
|
|
2079
|
-
o.TRUE_RET_EMULATION_GUARD,
|
|
2080
|
-
o.AVOID_MULTIVALUED_READS,
|
|
2081
|
-
# Keep IP symbolic to avoid unnecessary concretization
|
|
2082
|
-
o.KEEP_IP_SYMBOLIC,
|
|
2083
|
-
o.NO_IP_CONCRETIZATION,
|
|
2084
|
-
# be quiet!!!!!!
|
|
2085
|
-
o.SYMBOL_FILL_UNCONSTRAINED_REGISTERS,
|
|
2086
|
-
o.SYMBOL_FILL_UNCONSTRAINED_MEMORY,
|
|
2087
|
-
},
|
|
2163
|
+
add_options=add_options,
|
|
2088
2164
|
remove_options={
|
|
2089
2165
|
o.CGC_ZERO_FILL_UNCONSTRAINED_MEMORY,
|
|
2090
2166
|
o.UNINITIALIZED_ACCESS_AWARENESS,
|
|
@@ -2215,5 +2291,72 @@ class JumpTableResolver(IndirectJumpResolver):
|
|
|
2215
2291
|
return False
|
|
2216
2292
|
return True
|
|
2217
2293
|
|
|
2294
|
+
def _is_address_mapped(self, addr: int) -> bool:
|
|
2295
|
+
return (
|
|
2296
|
+
self.project.loader.find_segment_containing(addr) is not None
|
|
2297
|
+
or self.project.loader.find_section_containing(addr) is not None
|
|
2298
|
+
)
|
|
2299
|
+
|
|
2300
|
+
def _all_qualified_load_stmts_in_slice(self, b: Blade, addr: int) -> List[int]:
|
|
2301
|
+
"""
|
|
2302
|
+
Recognize all qualified load statements in a slice. A qualified load statements refers to those that are
|
|
2303
|
+
loading jump targets (or jump offsets) from a jump table, or loading jump table offsets from a jump-table
|
|
2304
|
+
offset table.
|
|
2305
|
+
|
|
2306
|
+
:param b: The Blade object.
|
|
2307
|
+
:param addr: Address of the last block.
|
|
2308
|
+
:return: A list of qualified load statement IDs.
|
|
2309
|
+
"""
|
|
2310
|
+
|
|
2311
|
+
stmt_ids = []
|
|
2312
|
+
for block_addr, stmt_id in b.slice.nodes:
|
|
2313
|
+
if block_addr == addr and stmt_id != DEFAULT_STATEMENT:
|
|
2314
|
+
stmt_ids.append(stmt_id)
|
|
2315
|
+
|
|
2316
|
+
if not stmt_ids:
|
|
2317
|
+
return []
|
|
2318
|
+
stmt_ids = sorted(stmt_ids)
|
|
2319
|
+
qualified_load_stmt_ids = []
|
|
2320
|
+
load_stmt_ids = []
|
|
2321
|
+
block = self.project.factory.block(addr, cross_insn_opt=True, backup_state=self.base_state).vex
|
|
2322
|
+
tmp_values = {}
|
|
2323
|
+
mask = (2**self.project.arch.bits) - 1
|
|
2324
|
+
for stmt_id in stmt_ids:
|
|
2325
|
+
stmt = block.statements[stmt_id]
|
|
2326
|
+
if isinstance(stmt, pyvex.IRStmt.WrTmp):
|
|
2327
|
+
if isinstance(stmt.data, pyvex.IRExpr.Const):
|
|
2328
|
+
tmp_values[stmt.tmp] = stmt.data.con.value
|
|
2329
|
+
elif isinstance(stmt.data, pyvex.IRExpr.Binop) and stmt.data.op.startswith("Iop_Add"):
|
|
2330
|
+
op0 = None
|
|
2331
|
+
if isinstance(stmt.data.args[0], pyvex.IRExpr.RdTmp):
|
|
2332
|
+
op0 = tmp_values.get(stmt.data.args[0].tmp, None)
|
|
2333
|
+
elif isinstance(stmt.data.args[0], pyvex.IRExpr.Const):
|
|
2334
|
+
op0 = stmt.data.args[0].con.value
|
|
2335
|
+
op1 = None
|
|
2336
|
+
if isinstance(stmt.data.args[1], pyvex.IRExpr.RdTmp):
|
|
2337
|
+
op1 = tmp_values.get(stmt.data.args[1].tmp, None)
|
|
2338
|
+
elif isinstance(stmt.data.args[1], pyvex.IRExpr.Const):
|
|
2339
|
+
op1 = stmt.data.args[1].con.value
|
|
2340
|
+
if isinstance(op1, int) and not isinstance(op0, int):
|
|
2341
|
+
op0, op1 = op1, op0
|
|
2342
|
+
if isinstance(op0, int):
|
|
2343
|
+
if op1 is None:
|
|
2344
|
+
tmp_values[stmt.tmp] = ("+", op0, op1)
|
|
2345
|
+
elif isinstance(op1, int):
|
|
2346
|
+
tmp_values[stmt.tmp] = (op0 + op1) & mask
|
|
2347
|
+
elif isinstance(op1, tuple) and op1[0] == "+":
|
|
2348
|
+
tmp_values[stmt.tmp] = ("+", (op0 + op1[1]) & mask, op1[2])
|
|
2349
|
+
elif isinstance(stmt.data, pyvex.IRExpr.Load) and isinstance(stmt.data.addr, pyvex.IRExpr.RdTmp):
|
|
2350
|
+
# is this load statement loading from a static address + an offset?
|
|
2351
|
+
v = tmp_values.get(stmt.data.addr.tmp, None)
|
|
2352
|
+
if isinstance(v, tuple) and v[0] == "+" and v[2] is None and self._is_address_mapped(v[1]):
|
|
2353
|
+
qualified_load_stmt_ids.append(stmt_id)
|
|
2354
|
+
load_stmt_ids.append(stmt_id)
|
|
2355
|
+
if qualified_load_stmt_ids and len(qualified_load_stmt_ids) <= 2:
|
|
2356
|
+
return qualified_load_stmt_ids
|
|
2357
|
+
if load_stmt_ids:
|
|
2358
|
+
return [load_stmt_ids[-1]]
|
|
2359
|
+
return []
|
|
2360
|
+
|
|
2218
2361
|
|
|
2219
2362
|
from angr.analyses.propagator import PropagatorAnalysis
|
|
@@ -373,7 +373,7 @@ class CompleteCallingConventionsAnalysis(Analysis):
|
|
|
373
373
|
for callee in self.kb.functions.callgraph.successors(caller_func_addr):
|
|
374
374
|
if callee != caller_func_addr and callee not in d:
|
|
375
375
|
func = self.kb.functions.get_by_addr(callee)
|
|
376
|
-
tpl = func.calling_convention, func.prototype, func.
|
|
376
|
+
tpl = func.calling_convention, func.prototype, func.prototype_libname
|
|
377
377
|
d[callee] = tpl
|
|
378
378
|
return d
|
|
379
379
|
|
|
@@ -23,6 +23,7 @@ from ...code_location import CodeLocation, ExternalCodeLocation
|
|
|
23
23
|
from ...sim_variable import SimStackVariable, SimMemoryVariable
|
|
24
24
|
from ...knowledge_plugins.propagations.states import Equivalence
|
|
25
25
|
from ...knowledge_plugins.key_definitions import atoms
|
|
26
|
+
from ...knowledge_plugins.key_definitions.atoms import Register as RegisterAtom
|
|
26
27
|
from ...knowledge_plugins.key_definitions.definition import Definition
|
|
27
28
|
from ...knowledge_plugins.key_definitions.constants import OP_BEFORE
|
|
28
29
|
from .. import Analysis, AnalysesHub
|
|
@@ -856,6 +857,25 @@ class AILSimplifier(Analysis):
|
|
|
856
857
|
all_uses_replaced = True
|
|
857
858
|
for def_, use_and_expr in all_uses_with_def:
|
|
858
859
|
u, used_expr = use_and_expr
|
|
860
|
+
|
|
861
|
+
use_expr_defns = []
|
|
862
|
+
for d in rd.all_uses.get_uses_by_location(u):
|
|
863
|
+
if (
|
|
864
|
+
isinstance(d.atom, RegisterAtom)
|
|
865
|
+
and isinstance(def_.atom, RegisterAtom)
|
|
866
|
+
and d.atom.reg_offset == def_.atom.reg_offset
|
|
867
|
+
):
|
|
868
|
+
use_expr_defns.append(d)
|
|
869
|
+
elif d.atom == def_.atom:
|
|
870
|
+
use_expr_defns.append(d)
|
|
871
|
+
# you can never replace a use with dependencies from outside the checked defn
|
|
872
|
+
if len(use_expr_defns) != 1 or list(use_expr_defns)[0] != def_:
|
|
873
|
+
if not use_expr_defns:
|
|
874
|
+
_l.warning("There was no use_expr_defns for %s, this is likely a bug", u)
|
|
875
|
+
# TODO: can you have multiple definitions which can all be eliminated?
|
|
876
|
+
all_uses_replaced = False
|
|
877
|
+
continue
|
|
878
|
+
|
|
859
879
|
if u == eq.codeloc:
|
|
860
880
|
# skip the very initial assignment location
|
|
861
881
|
continue
|