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.

Files changed (45) hide show
  1. angr/__init__.py +1 -1
  2. angr/analyses/cfg/cfg_base.py +20 -10
  3. angr/analyses/cfg/indirect_jump_resolvers/amd64_elf_got.py +1 -1
  4. angr/analyses/cfg/indirect_jump_resolvers/arm_elf_fast.py +89 -32
  5. angr/analyses/cfg/indirect_jump_resolvers/jumptable.py +276 -133
  6. angr/analyses/complete_calling_conventions.py +1 -1
  7. angr/analyses/decompiler/ail_simplifier.py +20 -0
  8. angr/analyses/decompiler/block_io_finder.py +293 -0
  9. angr/analyses/decompiler/block_similarity.py +190 -0
  10. angr/analyses/decompiler/callsite_maker.py +5 -0
  11. angr/analyses/decompiler/clinic.py +103 -1
  12. angr/analyses/decompiler/decompilation_cache.py +2 -0
  13. angr/analyses/decompiler/decompiler.py +21 -4
  14. angr/analyses/decompiler/optimization_passes/__init__.py +6 -0
  15. angr/analyses/decompiler/optimization_passes/code_motion.py +361 -0
  16. angr/analyses/decompiler/optimization_passes/optimization_pass.py +1 -0
  17. angr/analyses/decompiler/optimization_passes/stack_canary_simplifier.py +30 -18
  18. angr/analyses/decompiler/optimization_passes/switch_default_case_duplicator.py +110 -0
  19. angr/analyses/decompiler/peephole_optimizations/bswap.py +53 -2
  20. angr/analyses/decompiler/peephole_optimizations/eager_eval.py +20 -1
  21. angr/analyses/decompiler/structured_codegen/c.py +76 -41
  22. angr/analyses/decompiler/structuring/phoenix.py +41 -9
  23. angr/analyses/decompiler/utils.py +13 -4
  24. angr/analyses/propagator/engine_ail.py +3 -0
  25. angr/analyses/reaching_definitions/engine_ail.py +3 -0
  26. angr/analyses/reaching_definitions/reaching_definitions.py +7 -0
  27. angr/analyses/stack_pointer_tracker.py +60 -10
  28. angr/analyses/typehoon/simple_solver.py +95 -24
  29. angr/analyses/typehoon/typeconsts.py +1 -1
  30. angr/calling_conventions.py +0 -3
  31. angr/engines/pcode/cc.py +1 -1
  32. angr/engines/successors.py +6 -0
  33. angr/knowledge_plugins/propagations/states.py +2 -1
  34. angr/procedures/definitions/glibc.py +3 -1
  35. angr/procedures/definitions/parse_win32json.py +2135 -383
  36. angr/procedures/definitions/wdk_ntoskrnl.py +956 -0
  37. angr/sim_type.py +53 -13
  38. angr/utils/library.py +2 -2
  39. {angr-9.2.92.dist-info → angr-9.2.94.dist-info}/METADATA +6 -6
  40. {angr-9.2.92.dist-info → angr-9.2.94.dist-info}/RECORD +44 -41
  41. {angr-9.2.92.dist-info → angr-9.2.94.dist-info}/WHEEL +1 -1
  42. angr/procedures/definitions/wdk_ntdll.py +0 -994
  43. {angr-9.2.92.dist-info → angr-9.2.94.dist-info}/LICENSE +0 -0
  44. {angr-9.2.92.dist-info → angr-9.2.94.dist-info}/entry_points.txt +0 -0
  45. {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 AddressTransferringTypes:
57
+ class AddressTransformationTypes(int, enum.Enum):
57
58
  """
58
- Types of address transfer.
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 Functio instance.
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
- all_addr_holders,
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
- all_addr_holders,
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
- all_addr_holders = OrderedDict()
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
- all_addr_holders[(stmt_loc[0], stmt.tmp)] = (AddressTransferringTypes.Assignment,)
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
- all_addr_holders[(stmt_loc[0], stmt.tmp)] = (AddressTransferringTypes.Assignment,)
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
- all_addr_holders[(stmt_loc[0], stmt.tmp)] = (
1182
- AddressTransferringTypes.SignedExtension,
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
- all_addr_holders[(stmt_loc[0], stmt.tmp)] = (AddressTransferringTypes.Truncation, 64, 32)
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
- all_addr_holders[(stmt_loc[0], stmt.tmp)] = (
1200
- AddressTransferringTypes.UnsignedExtension,
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
- all_addr_holders[(stmt_loc[0], stmt.tmp)] = (
1210
- AddressTransferringTypes.UnsignedExtension,
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
- all_addr_holders[(stmt_loc[0], stmt.tmp)] = (
1220
- AddressTransferringTypes.UnsignedExtension,
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
- all_addr_holders[(stmt_loc[0], stmt.tmp)] = (
1229
- AddressTransferringTypes.UnsignedExtension,
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
- stmts_adding_base_addr.append(
1283
- JumpTargetBaseAddr(
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
- stmts_adding_base_addr.append(
1292
- JumpTargetBaseAddr(
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
- all_addr_holders[(stmt_loc[0], stmt.tmp)] = (AddressTransferringTypes.Or1,)
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
- all_addr_holders[(stmt_loc[0], stmt.tmp)] = (
1355
- AddressTransferringTypes.ShiftLeft,
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
- all_addr_holders[(stmt_loc[0], stmt.tmp)] = (
1392
- AddressTransferringTypes.ShiftRight,
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
- all_addr_holders[(stmt_loc[0], stmt.tmp)] = (AddressTransferringTypes.Assignment,)
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, all_addr_holders
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
- all_addr_holders,
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) != 1:
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
- if stmts_adding_base_addr:
1789
- stmt_adding_base_addr = stmts_adding_base_addr[0]
1790
- base_addr = stmt_adding_base_addr.base_addr
1791
- conversions = list(
1792
- reversed(list(v for v in all_addr_holders.values() if v[0] is not AddressTransferringTypes.Assignment))
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
- def handle_signed_ext(a):
1797
- return (a | 0xFFFFFFFF00000000) if a >= 0x80000000 else a
1850
+ def handle_unsigned_ext(a):
1851
+ return a
1798
1852
 
1799
- def handle_unsigned_ext(a):
1800
- return a
1853
+ def handle_trunc_64_32(a):
1854
+ return a & 0xFFFFFFFF
1801
1855
 
1802
- def handle_trunc_64_32(a):
1803
- return a & 0xFFFFFFFF
1856
+ def handle_or1(a):
1857
+ return a | 1
1804
1858
 
1805
- def handle_or1(a):
1806
- return a | 1
1859
+ def handle_lshift(num_bits, a):
1860
+ return a << num_bits
1807
1861
 
1808
- def handle_lshift(num_bits, a):
1809
- return a << num_bits
1862
+ def handle_rshift(num_bits, a):
1863
+ return a >> num_bits
1810
1864
 
1811
- def handle_rshift(num_bits, a):
1812
- return a >> num_bits
1865
+ def handle_add(con, a):
1866
+ return (a + con) & mask
1813
1867
 
1814
- invert_conversion_ops = []
1815
- for conv in conversions:
1816
- if len(conv) == 1:
1817
- conversion_op, args = conv[0], None
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
- conversion_op, args = conv[0], conv[1:]
1820
- if conversion_op is AddressTransferringTypes.SignedExtension:
1821
- if args == (32, 64):
1822
- lam = handle_signed_ext
1823
- else:
1824
- raise NotImplementedError("Unsupported signed extension operation.")
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 conversion operation.")
1840
- invert_conversion_ops.append(lam)
1841
- all_targets_copy = all_targets
1842
- all_targets = []
1843
- for target_ in all_targets_copy:
1844
- for lam in invert_conversion_ops:
1845
- target_ = lam(target_)
1846
- all_targets.append(target_)
1847
- mask = (2**self.project.arch.bits) - 1
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.prototype.name
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