angr 9.2.84__py3-none-win_amd64.whl → 9.2.85__py3-none-win_amd64.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 (58) hide show
  1. angr/__init__.py +1 -1
  2. angr/analyses/cfg/cfg_base.py +6 -1
  3. angr/analyses/cfg/cfg_fast.py +32 -10
  4. angr/analyses/decompiler/clinic.py +204 -4
  5. angr/analyses/decompiler/condition_processor.py +8 -2
  6. angr/analyses/decompiler/decompiler.py +19 -17
  7. angr/analyses/decompiler/goto_manager.py +34 -51
  8. angr/analyses/decompiler/optimization_passes/__init__.py +5 -5
  9. angr/analyses/decompiler/optimization_passes/div_simplifier.py +2 -0
  10. angr/analyses/decompiler/optimization_passes/lowered_switch_simplifier.py +1 -1
  11. angr/analyses/decompiler/optimization_passes/mod_simplifier.py +2 -0
  12. angr/analyses/decompiler/optimization_passes/multi_simplifier.py +2 -0
  13. angr/analyses/decompiler/optimization_passes/optimization_pass.py +131 -3
  14. angr/analyses/decompiler/optimization_passes/ret_deduplicator.py +3 -3
  15. angr/analyses/decompiler/optimization_passes/return_duplicator.py +519 -0
  16. angr/analyses/decompiler/peephole_optimizations/constant_derefs.py +14 -2
  17. angr/analyses/decompiler/region_identifier.py +8 -2
  18. angr/analyses/decompiler/region_simplifiers/goto.py +5 -4
  19. angr/analyses/decompiler/structured_codegen/c.py +33 -1
  20. angr/analyses/decompiler/structuring/phoenix.py +3 -1
  21. angr/analyses/decompiler/structuring/structurer_nodes.py +11 -5
  22. angr/analyses/decompiler/utils.py +50 -0
  23. angr/analyses/disassembly.py +10 -3
  24. angr/analyses/propagator/engine_ail.py +125 -0
  25. angr/analyses/reaching_definitions/engine_ail.py +36 -2
  26. angr/analyses/reaching_definitions/rd_initializer.py +15 -1
  27. angr/analyses/reaching_definitions/rd_state.py +9 -4
  28. angr/analyses/stack_pointer_tracker.py +10 -17
  29. angr/analyses/variable_recovery/engine_ail.py +27 -1
  30. angr/angrdb/serializers/loader.py +10 -3
  31. angr/calling_conventions.py +2 -0
  32. angr/engines/pcode/behavior.py +7 -2
  33. angr/engines/pcode/cc.py +1 -0
  34. angr/engines/pcode/emulate.py +144 -104
  35. angr/engines/pcode/lifter.py +135 -79
  36. angr/knowledge_plugins/functions/function_manager.py +5 -3
  37. angr/knowledge_plugins/propagations/states.py +14 -0
  38. angr/lib/angr_native.dll +0 -0
  39. angr/procedures/cgc/deallocate.py +5 -2
  40. angr/procedures/posix/gethostbyname.py +23 -8
  41. angr/project.py +4 -0
  42. angr/simos/__init__.py +2 -0
  43. angr/simos/simos.py +1 -0
  44. angr/simos/snimmuc_nxp.py +152 -0
  45. angr/state_plugins/history.py +3 -1
  46. angr/utils/graph.py +20 -18
  47. {angr-9.2.84.dist-info → angr-9.2.85.dist-info}/METADATA +9 -8
  48. {angr-9.2.84.dist-info → angr-9.2.85.dist-info}/RECORD +57 -55
  49. tests/analyses/cfg/test_cfg_rust_got_resolution.py +2 -1
  50. tests/analyses/cfg/test_jumptables.py +2 -1
  51. tests/analyses/decompiler/test_decompiler.py +130 -103
  52. tests/engines/pcode/test_emulate.py +607 -0
  53. tests/serialization/test_db.py +30 -0
  54. angr/analyses/decompiler/optimization_passes/eager_returns.py +0 -285
  55. {angr-9.2.84.dist-info → angr-9.2.85.dist-info}/LICENSE +0 -0
  56. {angr-9.2.84.dist-info → angr-9.2.85.dist-info}/WHEEL +0 -0
  57. {angr-9.2.84.dist-info → angr-9.2.85.dist-info}/entry_points.txt +0 -0
  58. {angr-9.2.84.dist-info → angr-9.2.85.dist-info}/top_level.txt +0 -0
@@ -6,7 +6,7 @@ import unittest
6
6
 
7
7
  import angr
8
8
 
9
- from ...common import bin_location
9
+ from ...common import bin_location, slow_test
10
10
 
11
11
 
12
12
  test_location = os.path.join(bin_location, "tests")
@@ -15,6 +15,7 @@ test_location = os.path.join(bin_location, "tests")
15
15
  # pylint: disable=missing-class-docstring
16
16
  # pylint: disable=no-self-use
17
17
  class TestCfgRustGotResolution(unittest.TestCase):
18
+ @slow_test
18
19
  def test_rust_got_resolution(self):
19
20
  # Test a simple Rust binary sample.
20
21
  #
@@ -16,7 +16,7 @@ from angr.analyses.cfg.indirect_jump_resolvers import JumpTableResolver
16
16
  if TYPE_CHECKING:
17
17
  from angr.knowledge_plugins.cfg import IndirectJump
18
18
 
19
- from ...common import bin_location, compile_c, has_32_bit_compiler_support, skip_if_not_linux
19
+ from ...common import bin_location, compile_c, has_32_bit_compiler_support, skip_if_not_linux, slow_test
20
20
 
21
21
 
22
22
  test_location = os.path.join(bin_location, "tests")
@@ -2796,6 +2796,7 @@ class TestJumpTableResolver(unittest.TestCase):
2796
2796
  # Some jump tables are in fact vtables
2797
2797
  #
2798
2798
 
2799
+ @slow_test
2799
2800
  def test_vtable_amd64_libc_ubuntu_2004(self):
2800
2801
  p = angr.Project(
2801
2802
  os.path.join(test_location, "x86_64", "elf_with_static_libc_ubuntu_2004_stripped"), auto_load_libs=False
@@ -129,7 +129,7 @@ class TestDecompiler(unittest.TestCase):
129
129
  assert dec.codegen is not None, "Failed to decompile function %s." % repr(f)
130
130
  self._print_decompilation_result(dec)
131
131
 
132
- @for_all_structuring_algos
132
+ @structuring_algo("dream")
133
133
  def test_decompiling_loop_x86_64(self, decompiler_options=None):
134
134
  bin_path = os.path.join(test_location, "x86_64", "decompiler", "loop")
135
135
  p = angr.Project(bin_path, auto_load_libs=False, load_debug_info=True)
@@ -139,8 +139,8 @@ class TestDecompiler(unittest.TestCase):
139
139
  dec = p.analyses[Decompiler].prep()(f, cfg=cfg.model, options=decompiler_options)
140
140
  assert dec.codegen is not None, "Failed to decompile function %s." % repr(f)
141
141
  self._print_decompilation_result(dec)
142
- # it should be properly structured to a while loop without conditional breaks.
143
- assert "break" not in dec.codegen.text
142
+ # it should be properly structured to a while loop with conditional breaks.
143
+ assert "break" in dec.codegen.text
144
144
 
145
145
  @for_all_structuring_algos
146
146
  def test_decompiling_all_i386(self, decompiler_options=None):
@@ -266,9 +266,7 @@ class TestDecompiler(unittest.TestCase):
266
266
  "AMD64", "linux"
267
267
  )
268
268
  all_optimization_passes = [
269
- p
270
- for p in all_optimization_passes
271
- if p is not angr.analyses.decompiler.optimization_passes.EagerReturnsSimplifier
269
+ p for p in all_optimization_passes if p is not angr.analyses.decompiler.optimization_passes.ReturnDuplicator
272
270
  ]
273
271
 
274
272
  f = cfg.functions["main"]
@@ -301,9 +299,7 @@ class TestDecompiler(unittest.TestCase):
301
299
  "AMD64", "linux"
302
300
  )
303
301
  all_optimization_passes = [
304
- p
305
- for p in all_optimization_passes
306
- if p is not angr.analyses.decompiler.optimization_passes.EagerReturnsSimplifier
302
+ p for p in all_optimization_passes if p is not angr.analyses.decompiler.optimization_passes.ReturnDuplicator
307
303
  ]
308
304
 
309
305
  f = cfg.functions["main"]
@@ -341,9 +337,7 @@ class TestDecompiler(unittest.TestCase):
341
337
  "AMD64", "linux"
342
338
  )
343
339
  all_optimization_passes = [
344
- p
345
- for p in all_optimization_passes
346
- if p is not angr.analyses.decompiler.optimization_passes.EagerReturnsSimplifier
340
+ p for p in all_optimization_passes if p is not angr.analyses.decompiler.optimization_passes.ReturnDuplicator
347
341
  ]
348
342
 
349
343
  f = cfg.functions[0x4048C0]
@@ -368,9 +362,7 @@ class TestDecompiler(unittest.TestCase):
368
362
  "AMD64", "linux"
369
363
  )
370
364
  all_optimization_passes = [
371
- p
372
- for p in all_optimization_passes
373
- if p is not angr.analyses.decompiler.optimization_passes.EagerReturnsSimplifier
365
+ p for p in all_optimization_passes if p is not angr.analyses.decompiler.optimization_passes.ReturnDuplicator
374
366
  ]
375
367
 
376
368
  f = cfg.functions[0x404DC0]
@@ -406,9 +398,7 @@ class TestDecompiler(unittest.TestCase):
406
398
  "AMD64", "linux"
407
399
  )
408
400
  all_optimization_passes = [
409
- p
410
- for p in all_optimization_passes
411
- if p is not angr.analyses.decompiler.optimization_passes.EagerReturnsSimplifier
401
+ p for p in all_optimization_passes if p is not angr.analyses.decompiler.optimization_passes.ReturnDuplicator
412
402
  ]
413
403
 
414
404
  f = cfg.functions[0x401E60]
@@ -432,9 +422,7 @@ class TestDecompiler(unittest.TestCase):
432
422
  "AMD64", "linux"
433
423
  )
434
424
  all_optimization_passes = [
435
- p
436
- for p in all_optimization_passes
437
- if p is not angr.analyses.decompiler.optimization_passes.EagerReturnsSimplifier
425
+ p for p in all_optimization_passes if p is not angr.analyses.decompiler.optimization_passes.ReturnDuplicator
438
426
  ]
439
427
 
440
428
  f = cfg.functions[0x404410]
@@ -550,9 +538,9 @@ class TestDecompiler(unittest.TestCase):
550
538
  optimization_passes = angr.analyses.decompiler.optimization_passes.get_default_optimization_passes(
551
539
  p.arch, p.simos.name
552
540
  )
553
- if angr.analyses.decompiler.optimization_passes.EagerReturnsSimplifier not in optimization_passes:
541
+ if angr.analyses.decompiler.optimization_passes.ReturnDuplicator not in optimization_passes:
554
542
  optimization_passes += [
555
- angr.analyses.decompiler.optimization_passes.EagerReturnsSimplifier,
543
+ angr.analyses.decompiler.optimization_passes.ReturnDuplicator,
556
544
  ]
557
545
  dec = p.analyses[Decompiler].prep()(
558
546
  f, cfg=cfg.model, options=decompiler_options, optimization_passes=optimization_passes
@@ -561,8 +549,8 @@ class TestDecompiler(unittest.TestCase):
561
549
  self._print_decompilation_result(dec)
562
550
 
563
551
  code = dec.codegen.text
564
- # with EagerReturnSimplifier applied, there should be no goto!
565
- assert "goto" not in code.lower(), "Found goto statements. EagerReturnSimplifier might have failed."
552
+ # with ReturnDuplicator applied, there should be no goto!
553
+ assert "goto" not in code.lower(), "Found goto statements. ReturnDuplicator might have failed."
566
554
  # with global variables discovered, there should not be any loads of constant addresses.
567
555
  assert "fflush(stdout);" in code.lower()
568
556
 
@@ -833,7 +821,14 @@ class TestDecompiler(unittest.TestCase):
833
821
 
834
822
  f = proj.kb.functions[0x401A70]
835
823
 
836
- d = proj.analyses[Decompiler].prep()(f, cfg=cfg.model, options=decompiler_options)
824
+ # enable Lowered Switch Simplifier
825
+ all_optimization_passes = angr.analyses.decompiler.optimization_passes.get_default_optimization_passes(
826
+ "AMD64", "linux"
827
+ )
828
+ all_optimization_passes.append(angr.analyses.decompiler.optimization_passes.LoweredSwitchSimplifier)
829
+ d = proj.analyses[Decompiler].prep()(
830
+ f, cfg=cfg.model, options=decompiler_options, optimization_passes=all_optimization_passes
831
+ )
837
832
  self._print_decompilation_result(d)
838
833
 
839
834
  # we structure the giant if-else tree into a switch-case
@@ -854,9 +849,7 @@ class TestDecompiler(unittest.TestCase):
854
849
  "AMD64", "linux"
855
850
  )
856
851
  all_optimization_passes = [
857
- p
858
- for p in all_optimization_passes
859
- if p is not angr.analyses.decompiler.optimization_passes.EagerReturnsSimplifier
852
+ p for p in all_optimization_passes if p is not angr.analyses.decompiler.optimization_passes.ReturnDuplicator
860
853
  ]
861
854
  all_optimization_passes.append(angr.analyses.decompiler.optimization_passes.LoweredSwitchSimplifier)
862
855
  d = proj.analyses[Decompiler].prep()(
@@ -1178,6 +1171,7 @@ class TestDecompiler(unittest.TestCase):
1178
1171
 
1179
1172
  assert "__stack_chk_fail" not in code # stack canary checks should be removed by default
1180
1173
 
1174
+ @slow_test
1181
1175
  @for_all_structuring_algos
1182
1176
  def test_decompiling_newburry_main(self, decompiler_options=None):
1183
1177
  bin_path = os.path.join(test_location, "x86_64", "decompiler", "newbury")
@@ -1262,6 +1256,7 @@ class TestDecompiler(unittest.TestCase):
1262
1256
  @slow_test
1263
1257
  @for_all_structuring_algos
1264
1258
  def test_decompiling_x8664_cvs(self, decompiler_options=None):
1259
+ # TODO: this is broken, but not shown in CI b/c slow, and tracked by https://github.com/angr/angr/issues/4406
1265
1260
  bin_path = os.path.join(test_location, "x86_64", "cvs")
1266
1261
  p = angr.Project(bin_path, auto_load_libs=False)
1267
1262
 
@@ -1283,14 +1278,12 @@ class TestDecompiler(unittest.TestCase):
1283
1278
 
1284
1279
  cfg = p.analyses.CFGFast(normalize=True)
1285
1280
 
1286
- # disable eager returns simplifier
1281
+ # disable return duplicator
1287
1282
  all_optimization_passes = angr.analyses.decompiler.optimization_passes.get_default_optimization_passes(
1288
1283
  "AMD64", "linux"
1289
1284
  )
1290
1285
  all_optimization_passes = [
1291
- p
1292
- for p in all_optimization_passes
1293
- if p is not angr.analyses.decompiler.optimization_passes.EagerReturnsSimplifier
1286
+ p for p in all_optimization_passes if p is not angr.analyses.decompiler.optimization_passes.ReturnDuplicator
1294
1287
  ]
1295
1288
 
1296
1289
  f = p.kb.functions["func_1"]
@@ -1314,9 +1307,7 @@ class TestDecompiler(unittest.TestCase):
1314
1307
  "AMD64", "linux"
1315
1308
  )
1316
1309
  all_optimization_passes = [
1317
- p
1318
- for p in all_optimization_passes
1319
- if p is not angr.analyses.decompiler.optimization_passes.EagerReturnsSimplifier
1310
+ p for p in all_optimization_passes if p is not angr.analyses.decompiler.optimization_passes.ReturnDuplicator
1320
1311
  ]
1321
1312
 
1322
1313
  f = p.kb.functions["func_2"]
@@ -1546,9 +1537,7 @@ class TestDecompiler(unittest.TestCase):
1546
1537
  "AMD64", "linux"
1547
1538
  )
1548
1539
  all_optimization_passes = [
1549
- p
1550
- for p in all_optimization_passes
1551
- if p is not angr.analyses.decompiler.optimization_passes.EagerReturnsSimplifier
1540
+ p for p in all_optimization_passes if p is not angr.analyses.decompiler.optimization_passes.ReturnDuplicator
1552
1541
  ]
1553
1542
  d = proj.analyses.Decompiler(
1554
1543
  proj.kb.functions["division3"], optimization_passes=all_optimization_passes, options=decompiler_options
@@ -1693,9 +1682,7 @@ class TestDecompiler(unittest.TestCase):
1693
1682
  "AMD64", "linux"
1694
1683
  )
1695
1684
  all_optimization_passes = [
1696
- p
1697
- for p in all_optimization_passes
1698
- if p is not angr.analyses.decompiler.optimization_passes.EagerReturnsSimplifier
1685
+ p for p in all_optimization_passes if p is not angr.analyses.decompiler.optimization_passes.ReturnDuplicator
1699
1686
  ]
1700
1687
 
1701
1688
  dec = proj.analyses.Decompiler(
@@ -1718,9 +1705,7 @@ class TestDecompiler(unittest.TestCase):
1718
1705
  "AMD64", "linux"
1719
1706
  )
1720
1707
  all_optimization_passes = [
1721
- p
1722
- for p in all_optimization_passes
1723
- if p is not angr.analyses.decompiler.optimization_passes.EagerReturnsSimplifier
1708
+ p for p in all_optimization_passes if p is not angr.analyses.decompiler.optimization_passes.ReturnDuplicator
1724
1709
  ]
1725
1710
 
1726
1711
  d = proj.analyses[Decompiler].prep()(
@@ -1756,9 +1741,7 @@ class TestDecompiler(unittest.TestCase):
1756
1741
  "AMD64", "linux"
1757
1742
  )
1758
1743
  all_optimization_passes = [
1759
- p
1760
- for p in all_optimization_passes
1761
- if p is not angr.analyses.decompiler.optimization_passes.EagerReturnsSimplifier
1744
+ p for p in all_optimization_passes if p is not angr.analyses.decompiler.optimization_passes.ReturnDuplicator
1762
1745
  ]
1763
1746
 
1764
1747
  d = proj.analyses[Decompiler].prep()(
@@ -1872,9 +1855,7 @@ class TestDecompiler(unittest.TestCase):
1872
1855
  "linux",
1873
1856
  )
1874
1857
  all_optimization_passes = [
1875
- p
1876
- for p in all_optimization_passes
1877
- if p is not angr.analyses.decompiler.optimization_passes.EagerReturnsSimplifier
1858
+ p for p in all_optimization_passes if p is not angr.analyses.decompiler.optimization_passes.ReturnDuplicator
1878
1859
  ]
1879
1860
 
1880
1861
  f = proj.kb.functions["argmatch_to_argument"]
@@ -1945,9 +1926,7 @@ class TestDecompiler(unittest.TestCase):
1945
1926
  "AMD64", "linux"
1946
1927
  )
1947
1928
  all_optimization_passes = [
1948
- p
1949
- for p in all_optimization_passes
1950
- if p is not angr.analyses.decompiler.optimization_passes.EagerReturnsSimplifier
1929
+ p for p in all_optimization_passes if p is not angr.analyses.decompiler.optimization_passes.ReturnDuplicator
1951
1930
  ]
1952
1931
 
1953
1932
  d = proj.analyses[Decompiler].prep()(
@@ -2095,9 +2074,7 @@ class TestDecompiler(unittest.TestCase):
2095
2074
  "AMD64", "linux"
2096
2075
  )
2097
2076
  all_optimization_passes = [
2098
- p
2099
- for p in all_optimization_passes
2100
- if p is not angr.analyses.decompiler.optimization_passes.EagerReturnsSimplifier
2077
+ p for p in all_optimization_passes if p is not angr.analyses.decompiler.optimization_passes.ReturnDuplicator
2101
2078
  ]
2102
2079
  d = proj.analyses[Decompiler].prep()(
2103
2080
  f, cfg=cfg.model, options=decompiler_options, optimization_passes=all_optimization_passes
@@ -2190,18 +2167,16 @@ class TestDecompiler(unittest.TestCase):
2190
2167
  )
2191
2168
  # lowered-switch simplifier cannot be enabled. otherwise we will have an extra goto that goes into the fake
2192
2169
  # switch-case.
2193
-
2194
- # also, setting max_level to 3 in EagerReturnsSimplifier will eliminate the other unexpected goto
2195
-
2196
2170
  d = proj.analyses[Decompiler].prep()(
2197
2171
  f, cfg=cfg.model, options=decompiler_options, optimization_passes=all_optimization_passes
2198
2172
  )
2199
2173
  self._print_decompilation_result(d)
2200
2174
 
2201
2175
  assert d.codegen.text.count("goto ") == 3
2202
- assert d.codegen.text.count("goto LABEL_400d08;") == 1
2176
+ # `LABEL_400d08` is the label `try_bracketed_repeat` found in the source, which is jumped to twice
2177
+ assert d.codegen.text.count("goto LABEL_400d08;") == 2
2178
+ # this goto may go away in the future if the loops are structured correctly
2203
2179
  assert d.codegen.text.count("goto LABEL_400d2a;") == 1
2204
- assert d.codegen.text.count("goto LABEL_400e1c;") == 1
2205
2180
 
2206
2181
  @structuring_algo("phoenix")
2207
2182
  def test_decompiling_sha384sum_digest_bsd_split_3(self, decompiler_options=None):
@@ -2217,9 +2192,7 @@ class TestDecompiler(unittest.TestCase):
2217
2192
  "AMD64", "linux"
2218
2193
  )
2219
2194
  all_optimization_passes = [
2220
- p
2221
- for p in all_optimization_passes
2222
- if p is not angr.analyses.decompiler.optimization_passes.EagerReturnsSimplifier
2195
+ p for p in all_optimization_passes if p is not angr.analyses.decompiler.optimization_passes.ReturnDuplicator
2223
2196
  ]
2224
2197
  d = proj.analyses[Decompiler].prep()(
2225
2198
  f, cfg=cfg.model, options=decompiler_options, optimization_passes=all_optimization_passes
@@ -2355,7 +2328,9 @@ class TestDecompiler(unittest.TestCase):
2355
2328
  assert d.codegen.text.count("switch ") == 2
2356
2329
  assert d.codegen.text.count("case 92:") == 2
2357
2330
  assert d.codegen.text.count("case 0:") == 1
2358
- assert "goto" not in d.codegen.text
2331
+ # TODO: structuring failed when removing this goto with ReturnDuplicator.
2332
+ # Fix in: https://github.com/angr/angr/issues/4252
2333
+ # assert "goto" not in d.codegen.text
2359
2334
  # TODO: the following check requires angr decompiler to implement assignment de-duplication
2360
2335
  # assert d.codegen.text.count("case 110:") == 1
2361
2336
  # TODO: the following check requires angr decompiler correctly support rewriting gotos inside nested loops and
@@ -2397,9 +2372,7 @@ class TestDecompiler(unittest.TestCase):
2397
2372
  )
2398
2373
  # turn off eager returns simplifier
2399
2374
  all_optimization_passes = [
2400
- p
2401
- for p in all_optimization_passes
2402
- if p is not angr.analyses.decompiler.optimization_passes.EagerReturnsSimplifier
2375
+ p for p in all_optimization_passes if p is not angr.analyses.decompiler.optimization_passes.ReturnDuplicator
2403
2376
  ]
2404
2377
  all_optimization_passes += [angr.analyses.decompiler.optimization_passes.LoweredSwitchSimplifier]
2405
2378
 
@@ -2479,9 +2452,7 @@ class TestDecompiler(unittest.TestCase):
2479
2452
  "AMD64", "linux"
2480
2453
  )
2481
2454
  all_optimization_passes = [
2482
- p
2483
- for p in all_optimization_passes
2484
- if p is not angr.analyses.decompiler.optimization_passes.EagerReturnsSimplifier
2455
+ p for p in all_optimization_passes if p is not angr.analyses.decompiler.optimization_passes.ReturnDuplicator
2485
2456
  ]
2486
2457
 
2487
2458
  cfg = proj.analyses.CFGFast(normalize=True, data_references=True)
@@ -2505,9 +2476,7 @@ class TestDecompiler(unittest.TestCase):
2505
2476
  "AMD64", "linux"
2506
2477
  )
2507
2478
  all_optimization_passes = [
2508
- p
2509
- for p in all_optimization_passes
2510
- if p is not angr.analyses.decompiler.optimization_passes.EagerReturnsSimplifier
2479
+ p for p in all_optimization_passes if p is not angr.analyses.decompiler.optimization_passes.ReturnDuplicator
2511
2480
  ]
2512
2481
 
2513
2482
  cfg = proj.analyses.CFGFast(normalize=True, data_references=True)
@@ -2519,6 +2488,7 @@ class TestDecompiler(unittest.TestCase):
2519
2488
 
2520
2489
  assert d.codegen.text.count("switch") == 0
2521
2490
 
2491
+ @slow_test
2522
2492
  @structuring_algo("phoenix")
2523
2493
  def test_eager_returns_simplifier_no_duplication_of_default_case(self, decompiler_options=None):
2524
2494
  bin_path = os.path.join(test_location, "x86_64", "ls_ubuntu_2004")
@@ -2555,17 +2525,25 @@ class TestDecompiler(unittest.TestCase):
2555
2525
  proj = angr.Project(bin_path, auto_load_libs=False)
2556
2526
  cfg = proj.analyses.CFGFast(normalize=True, data_references=True)
2557
2527
  f = proj.kb.functions["skip"]
2558
- d = proj.analyses[Decompiler].prep()(f, cfg=cfg.model, options=decompiler_options)
2528
+ d = proj.analyses[Decompiler].prep()(
2529
+ f, cfg=cfg.model, options=set_decompiler_option(decompiler_options, [("cstyle_ifs", False)])
2530
+ )
2559
2531
  self._print_decompilation_result(d)
2560
2532
 
2561
2533
  text = d.codegen.text
2562
- good_if_return = "if (!a0)\n return 1;\n"
2534
+ # find an if-stmt that has the following properties:
2535
+ # 1. Condition: (!a0)
2536
+ # 2. Has a scope ending in a return
2537
+ # 3. Has no else scope after the return
2538
+ good_if_pattern = r"if \(!a0\)\s*\{[^}]*return 1;\s*\}(?!\s*else)"
2539
+ good_if = re.search(good_if_pattern, text)
2540
+ assert good_if is not None
2541
+
2563
2542
  first_if_location = text.find("if")
2543
+ assert first_if_location != -1
2564
2544
 
2565
2545
  # the first if in the program should have no else, and that first else should be a simple return
2566
- assert first_if_location != -1
2567
- assert first_if_location == text.find(good_if_return)
2568
- assert not text[first_if_location + len(good_if_return) :].startswith(" else")
2546
+ assert first_if_location == good_if.start()
2569
2547
 
2570
2548
  @structuring_algo("phoenix")
2571
2549
  def test_sensitive_eager_returns(self, decompiler_options=None):
@@ -2712,9 +2690,7 @@ class TestDecompiler(unittest.TestCase):
2712
2690
  "AMD64", "linux"
2713
2691
  )
2714
2692
  all_optimization_passes = [
2715
- p
2716
- for p in all_optimization_passes
2717
- if p is not angr.analyses.decompiler.optimization_passes.EagerReturnsSimplifier
2693
+ p for p in all_optimization_passes if p is not angr.analyses.decompiler.optimization_passes.ReturnDuplicator
2718
2694
  ]
2719
2695
  d = proj.analyses[Decompiler].prep()(
2720
2696
  f, cfg=cfg.model, options=decompiler_options, optimization_passes=all_optimization_passes
@@ -2767,9 +2743,7 @@ class TestDecompiler(unittest.TestCase):
2767
2743
  "AMD64", "linux"
2768
2744
  )
2769
2745
  all_optimization_passes = [
2770
- p
2771
- for p in all_optimization_passes
2772
- if p is not angr.analyses.decompiler.optimization_passes.EagerReturnsSimplifier
2746
+ p for p in all_optimization_passes if p is not angr.analyses.decompiler.optimization_passes.ReturnDuplicator
2773
2747
  ]
2774
2748
  d = proj.analyses[Decompiler].prep()(
2775
2749
  f, cfg=cfg.model, options=decompiler_options, optimization_passes=all_optimization_passes
@@ -2931,9 +2905,7 @@ class TestDecompiler(unittest.TestCase):
2931
2905
  "AMD64", "linux"
2932
2906
  )
2933
2907
  all_optimization_passes = [
2934
- p
2935
- for p in all_optimization_passes
2936
- if p is not angr.analyses.decompiler.optimization_passes.EagerReturnsSimplifier
2908
+ p for p in all_optimization_passes if p is not angr.analyses.decompiler.optimization_passes.ReturnDuplicator
2937
2909
  ]
2938
2910
 
2939
2911
  d = proj.analyses[Decompiler](
@@ -2992,9 +2964,7 @@ class TestDecompiler(unittest.TestCase):
2992
2964
  "AMD64", "linux"
2993
2965
  )
2994
2966
  all_optimization_passes = [
2995
- p
2996
- for p in all_optimization_passes
2997
- if p is not angr.analyses.decompiler.optimization_passes.EagerReturnsSimplifier
2967
+ p for p in all_optimization_passes if p is not angr.analyses.decompiler.optimization_passes.ReturnDuplicator
2998
2968
  ]
2999
2969
 
3000
2970
  # always use multi-statement expressions
@@ -3033,6 +3003,7 @@ class TestDecompiler(unittest.TestCase):
3033
3003
  self._print_decompilation_result(dec)
3034
3004
  assert dec.codegen.text == saved
3035
3005
 
3006
+ @slow_test
3036
3007
  @for_all_structuring_algos
3037
3008
  def test_function_pointer_identification(self, decompiler_options=None):
3038
3009
  bin_path = os.path.join(test_location, "x86_64", "rust_hello_world")
@@ -3062,9 +3033,7 @@ class TestDecompiler(unittest.TestCase):
3062
3033
  "AMD64", "linux"
3063
3034
  )
3064
3035
  all_optimization_passes = [
3065
- p
3066
- for p in all_optimization_passes
3067
- if p is not angr.analyses.decompiler.optimization_passes.EagerReturnsSimplifier
3036
+ p for p in all_optimization_passes if p is not angr.analyses.decompiler.optimization_passes.ReturnDuplicator
3068
3037
  ]
3069
3038
 
3070
3039
  d = proj.analyses[Decompiler].prep()(
@@ -3095,8 +3064,8 @@ class TestDecompiler(unittest.TestCase):
3095
3064
  self._print_decompilation_result(d)
3096
3065
 
3097
3066
  # incorrect region replacement was causing the while loop be duplicated, so we would end up with four while
3098
- # loops.
3099
- assert d.codegen.text.count("while (") == 2
3067
+ # loops. In the original source, there is only a single while loop.
3068
+ assert d.codegen.text.count("while (") == 1
3100
3069
 
3101
3070
  @structuring_algo("phoenix")
3102
3071
  def test_decompiling_function_with_long_cascading_data_flows(self, decompiler_options=None):
@@ -3202,16 +3171,20 @@ class TestDecompiler(unittest.TestCase):
3202
3171
  d = proj.analyses[Decompiler](f, cfg=cfg.model, options=decompiler_options)
3203
3172
 
3204
3173
  self._print_decompilation_result(d)
3174
+
3205
3175
  # XXX: this a hack that should be fixed in some other place
3206
3176
  text = d.codegen.text.replace("4294967295", "-1")
3177
+ text = text.replace("\n", " ")
3207
3178
 
3208
- # first if-stmt should be a single scope with a return.
3209
- good_if_return = re.search("if \\(.*?\\)\n {8}return -1;", text)
3210
- assert good_if_return is not None
3179
+ first_if_location = text.find("if (")
3180
+ # the very first if-stmt in this function should be a single scope with a return.
3181
+ # there should be no else scope as well.
3182
+ # TODO: fix the dead-variable elimination pass so that it does remove the extra assign here
3183
+ correct_ifs = list(re.finditer(r"if \(.*?\) {5}\{.*? return -1; {5}}", text))
3184
+ assert len(correct_ifs) >= 1
3211
3185
 
3212
- first_if_location = text.find("if")
3213
- assert first_if_location != -1
3214
- assert first_if_location == good_if_return.start()
3186
+ first_correct_if = correct_ifs[0]
3187
+ assert first_correct_if.start() == first_if_location
3215
3188
 
3216
3189
  @structuring_algo("phoenix")
3217
3190
  def test_ifelseflatten_clientloop(self, decompiler_options=None):
@@ -3270,6 +3243,60 @@ class TestDecompiler(unittest.TestCase):
3270
3243
  # bad_matches = re.findall(r'\bif\s*\(\s*[^!].*\)', text)
3271
3244
  # assert len(bad_matches) == 0
3272
3245
 
3246
+ def test_test_binop_ret_dup(self, decompiler_options=None):
3247
+ bin_path = os.path.join(test_location, "x86_64", "decompiler", "test.o")
3248
+ proj = angr.Project(bin_path, auto_load_libs=False)
3249
+ cfg = proj.analyses.CFGFast(normalize=True, data_references=True)
3250
+ proj.analyses.CompleteCallingConventions(cfg=cfg, recover_variables=True)
3251
+ f = proj.kb.functions["binop"]
3252
+ d = proj.analyses[Decompiler].prep()(f, cfg=cfg.model, options=decompiler_options)
3253
+ text = d.codegen.text
3254
+
3255
+ assert "{\n}" not in text
3256
+ assert "goto" not in text
3257
+
3258
+ def test_tail_tail_bytes_ret_dup(self, decompiler_options=None):
3259
+ bin_path = os.path.join(test_location, "x86_64", "decompiler", "tail.o")
3260
+ proj = angr.Project(bin_path, auto_load_libs=False)
3261
+ cfg = proj.analyses.CFGFast(normalize=True, data_references=True)
3262
+ proj.analyses.CompleteCallingConventions(cfg=cfg, recover_variables=True)
3263
+ f = proj.kb.functions["tail_bytes"]
3264
+ d = proj.analyses[Decompiler].prep()(f, cfg=cfg.model, options=decompiler_options)
3265
+ text = d.codegen.text
3266
+
3267
+ assert "{\n}" not in text
3268
+ # TODO: should be 0, but we got the wrong address from the GotoManager
3269
+ # and our virtualization choice is not optimal
3270
+ assert text.count("goto") <= 2
3271
+
3272
+ def test_dd_iread_ret_dup_region(self, decompiler_options=None):
3273
+ bin_path = os.path.join(test_location, "x86_64", "decompiler", "dd.o")
3274
+ proj = angr.Project(bin_path, auto_load_libs=False)
3275
+ cfg = proj.analyses.CFGFast(normalize=True, data_references=True)
3276
+ proj.analyses.CompleteCallingConventions(cfg=cfg, recover_variables=True)
3277
+ f = proj.kb.functions["iread"]
3278
+ d = proj.analyses[Decompiler].prep()(f, cfg=cfg.model, options=decompiler_options)
3279
+ text = d.codegen.text
3280
+
3281
+ assert "{\n}" not in text
3282
+ assert "goto" not in text
3283
+ # there are 4 or less in the source
3284
+ assert text.count("return") <= 4
3285
+
3286
+ def test_stty_recover_mode_ret_dup_region(self, decompiler_options=None):
3287
+ bin_path = os.path.join(test_location, "x86_64", "decompiler", "stty.o")
3288
+ proj = angr.Project(bin_path, auto_load_libs=False)
3289
+ cfg = proj.analyses.CFGFast(normalize=True, data_references=True)
3290
+ proj.analyses.CompleteCallingConventions(cfg=cfg, recover_variables=True)
3291
+ f = proj.kb.functions["recover_mode"]
3292
+ d = proj.analyses[Decompiler].prep()(f, cfg=cfg.model, options=decompiler_options)
3293
+ text = d.codegen.text
3294
+
3295
+ assert "{\n}" not in text
3296
+ assert "goto" not in text
3297
+ # there are 4 or less in the source
3298
+ assert text.count("return") <= 4
3299
+
3273
3300
  def test_plt_stub_annotation(self):
3274
3301
  bin_path = os.path.join(test_location, "x86_64", "fauxware")
3275
3302
  proj = angr.Project(bin_path, auto_load_libs=False)