angr 9.2.83__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 (62) 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/decompilation_options.py +10 -0
  7. angr/analyses/decompiler/decompiler.py +19 -17
  8. angr/analyses/decompiler/goto_manager.py +34 -51
  9. angr/analyses/decompiler/optimization_passes/__init__.py +5 -5
  10. angr/analyses/decompiler/optimization_passes/div_simplifier.py +2 -0
  11. angr/analyses/decompiler/optimization_passes/lowered_switch_simplifier.py +1 -1
  12. angr/analyses/decompiler/optimization_passes/mod_simplifier.py +2 -0
  13. angr/analyses/decompiler/optimization_passes/multi_simplifier.py +2 -0
  14. angr/analyses/decompiler/optimization_passes/optimization_pass.py +131 -3
  15. angr/analyses/decompiler/optimization_passes/ret_deduplicator.py +3 -3
  16. angr/analyses/decompiler/optimization_passes/return_duplicator.py +519 -0
  17. angr/analyses/decompiler/peephole_optimizations/constant_derefs.py +14 -2
  18. angr/analyses/decompiler/region_identifier.py +8 -2
  19. angr/analyses/decompiler/region_simplifiers/goto.py +5 -4
  20. angr/analyses/decompiler/structured_codegen/c.py +66 -5
  21. angr/analyses/decompiler/structuring/phoenix.py +3 -1
  22. angr/analyses/decompiler/structuring/structurer_nodes.py +11 -5
  23. angr/analyses/decompiler/utils.py +50 -0
  24. angr/analyses/disassembly.py +10 -3
  25. angr/analyses/propagator/engine_ail.py +125 -0
  26. angr/analyses/reaching_definitions/engine_ail.py +36 -2
  27. angr/analyses/reaching_definitions/rd_initializer.py +15 -1
  28. angr/analyses/reaching_definitions/rd_state.py +9 -4
  29. angr/analyses/stack_pointer_tracker.py +10 -17
  30. angr/analyses/variable_recovery/engine_ail.py +27 -1
  31. angr/angrdb/serializers/loader.py +10 -3
  32. angr/calling_conventions.py +2 -0
  33. angr/engines/pcode/behavior.py +7 -2
  34. angr/engines/pcode/cc.py +1 -0
  35. angr/engines/pcode/emulate.py +144 -104
  36. angr/engines/pcode/lifter.py +135 -79
  37. angr/knowledge_plugins/functions/function.py +28 -0
  38. angr/knowledge_plugins/functions/function_manager.py +48 -5
  39. angr/knowledge_plugins/propagations/states.py +14 -0
  40. angr/lib/angr_native.dll +0 -0
  41. angr/procedures/cgc/deallocate.py +5 -2
  42. angr/procedures/posix/gethostbyname.py +23 -8
  43. angr/project.py +4 -0
  44. angr/simos/__init__.py +2 -0
  45. angr/simos/simos.py +1 -0
  46. angr/simos/snimmuc_nxp.py +152 -0
  47. angr/state_plugins/history.py +3 -1
  48. angr/utils/graph.py +20 -18
  49. {angr-9.2.83.dist-info → angr-9.2.85.dist-info}/METADATA +9 -8
  50. {angr-9.2.83.dist-info → angr-9.2.85.dist-info}/RECORD +61 -59
  51. tests/analyses/cfg/test_cfg_rust_got_resolution.py +2 -1
  52. tests/analyses/cfg/test_jumptables.py +2 -1
  53. tests/analyses/decompiler/test_decompiler.py +155 -103
  54. tests/engines/pcode/test_emulate.py +607 -0
  55. tests/engines/test_java.py +609 -663
  56. tests/knowledge_plugins/functions/test_function_manager.py +13 -0
  57. tests/serialization/test_db.py +30 -0
  58. angr/analyses/decompiler/optimization_passes/eager_returns.py +0 -285
  59. {angr-9.2.83.dist-info → angr-9.2.85.dist-info}/LICENSE +0 -0
  60. {angr-9.2.83.dist-info → angr-9.2.85.dist-info}/WHEEL +0 -0
  61. {angr-9.2.83.dist-info → angr-9.2.85.dist-info}/entry_points.txt +0 -0
  62. {angr-9.2.83.dist-info → angr-9.2.85.dist-info}/top_level.txt +0 -0
@@ -4,10 +4,6 @@ __package__ = __package__ or "tests.engines" # pylint:disable=redefined-builtin
4
4
  import os
5
5
  import unittest
6
6
 
7
- import angr
8
- from angr.storage.memory_mixins import JavaVmMemory, DefaultMemory, KeyValueMemory
9
- from angr.engines.soot.values import SimSootValue_ArrayRef, SimSootValue_ThisRef
10
- from angr.engines.soot.method_dispatcher import resolve_method
11
7
  from archinfo.arch_amd64 import ArchAMD64
12
8
  from archinfo.arch_soot import (
13
9
  ArchSoot,
@@ -18,6 +14,11 @@ from archinfo.arch_soot import (
18
14
  )
19
15
  from claripy.backends.backend_smtlib_solvers import z3str_popen # noqa: F401
20
16
 
17
+ import angr
18
+ from angr.storage.memory_mixins import JavaVmMemory, DefaultMemory, KeyValueMemory
19
+ from angr.engines.soot.values import SimSootValue_ArrayRef, SimSootValue_ThisRef
20
+ from angr.engines.soot.method_dispatcher import resolve_method
21
+
21
22
  try:
22
23
  import pysoot
23
24
  except ModuleNotFoundError:
@@ -26,726 +27,671 @@ except ModuleNotFoundError:
26
27
  from ..common import bin_location
27
28
 
28
29
 
29
- test_location = os.path.join(bin_location, "tests", "java")
30
-
31
-
32
- @unittest.skipUnless(pysoot, "pysoot not available")
33
- def test_fauxware():
34
- # create project
35
- binary_path = os.path.join(test_location, "fauxware_java_jni", "fauxware.jar")
36
- jni_options = {"jni_libs": ["libfauxware.so"]}
37
- project = angr.Project(binary_path, main_opts=jni_options)
38
- entry = project.factory.entry_state()
39
- simgr = project.factory.simgr(entry)
40
-
41
- # find path to `accepted()` method
42
- accepted_method = SootMethodDescriptor.from_string("Fauxware.accepted()").address()
43
- simgr.explore(find=lambda s: s.addr == accepted_method)
44
-
45
- state = simgr.found[0]
46
-
47
- # eval password
48
- cmd_line_args = project.simos.get_cmd_line_args(state)
49
- password = state.solver.eval(cmd_line_args[0])
50
- assert password == "SOSNEAKY"
30
+ class TestJava(unittest.TestCase):
31
+ test_location = os.path.join(bin_location, "tests", "java")
32
+ sdk_path = os.path.join(os.path.expanduser("~"), "Android", "Sdk", "platforms")
33
+
34
+ @unittest.skipUnless(pysoot, "pysoot not available")
35
+ def test_fauxware(self):
36
+ # create project
37
+ binary_path = os.path.join(self.test_location, "fauxware_java_jni", "fauxware.jar")
38
+ jni_options = {"jni_libs": ["libfauxware.so"]}
39
+ project = angr.Project(binary_path, main_opts=jni_options)
40
+ entry = project.factory.entry_state()
41
+ simgr = project.factory.simgr(entry)
42
+
43
+ # find path to `accepted()` method
44
+ accepted_method = SootMethodDescriptor.from_string("Fauxware.accepted()").address()
45
+ simgr.explore(find=lambda s: s.addr == accepted_method)
46
+
47
+ assert len(simgr.found) == 1
48
+ state = simgr.found[0]
49
+
50
+ # eval password
51
+ cmd_line_args = project.simos.get_cmd_line_args(state)
52
+ password = state.solver.eval(cmd_line_args[0])
53
+ assert password == "SOSNEAKY"
54
+
55
+ @unittest.skipUnless(os.path.exists(sdk_path), "Android SDK found")
56
+ def test_apk_loading(self):
57
+ loading_opts = {
58
+ "android_sdk": self.sdk_path,
59
+ "entry_point": "com.example.antoniob.android1.MainActivity.onCreate",
60
+ "entry_point_params": ("android.os.Bundle",),
61
+ }
62
+ project = angr.Project(
63
+ os.path.join(self.test_location, "android1.apk"), main_opts=loading_opts, auto_load_libs=False
64
+ )
65
+
66
+ blank_state = project.factory.blank_state()
67
+ a1 = SimSootValue_ThisRef.new_object(blank_state, "com.example.antoniob.android1.MainActivity")
68
+ a2 = SimSootValue_ThisRef.new_object(blank_state, "android.os.Bundle", symbolic=True)
69
+ args = [SootArgument(arg, arg.type) for arg in [a1, a2]]
70
+ entry = project.factory.entry_state(args=args)
71
+
72
+ simgr = project.factory.simgr(entry)
73
+ simgr.step()
74
+ simgr.step()
75
+ assert simgr.active[0].addr.block_idx == 0
76
+ assert simgr.active[0].addr.stmt_idx == 3
77
+ simgr.run()
78
+ assert len(simgr.deadended) == 1
79
+ assert type(simgr.deadended[0].addr) is SootAddressTerminator
51
80
 
81
+ #
82
+ # Command line arguments
83
+ #
52
84
 
53
- def test_apk_loading():
54
- sdk_path = os.path.join(os.path.expanduser("~"), "Android/Sdk/platforms/")
55
- if not os.path.exists(sdk_path):
56
- print("cannot run test_apk_loading since there is no Android SDK folder")
57
- return
58
-
59
- loading_opts = {
60
- "android_sdk": sdk_path,
61
- "entry_point": "com.example.antoniob.android1.MainActivity.onCreate",
62
- "entry_point_params": ("android.os.Bundle",),
63
- }
64
- project = angr.Project(os.path.join(test_location, "android1.apk"), main_opts=loading_opts, auto_load_libs=False)
85
+ @unittest.skipUnless(pysoot, "pysoot not available")
86
+ def test_cmd_line_args(self):
87
+ project = self.create_project("cmd_line_args", load_native_libs=False)
88
+ entry = project.factory.entry_state()
89
+ simgr = project.factory.simgr(entry)
90
+ simgr.run()
91
+ assert len(simgr.deadended) == 2
92
+ state1, state2 = tuple(simgr.deadended)
93
+
94
+ # get symbol of args[0] from memory
95
+ args = state1.globals["cmd_line_args"]
96
+ args0_arrref = SimSootValue_ArrayRef(args, 0)
97
+ args0_strref = state1.memory.load(args0_arrref)
98
+ args0_strval = state1.memory.load(args0_strref)
99
+
100
+ # eval args[0] on both states
101
+ str1 = state1.solver.eval(args0_strval)
102
+ str2 = state2.solver.eval(args0_strval)
103
+ assert "secret_value" in [str1, str2]
65
104
 
66
- blank_state = project.factory.blank_state()
67
- a1 = SimSootValue_ThisRef.new_object(blank_state, "com.example.antoniob.android1.MainActivity")
68
- a2 = SimSootValue_ThisRef.new_object(blank_state, "android.os.Bundle", symbolic=True)
69
- args = [SootArgument(arg, arg.type) for arg in [a1, a2]]
70
- entry = project.factory.entry_state(args=args)
105
+ #
106
+ # JNI Version Information
107
+ #
71
108
 
72
- simgr = project.factory.simgr(entry)
73
- simgr.step()
74
- simgr.step()
75
- assert simgr.active[0].addr.block_idx == 0
76
- assert simgr.active[0].addr.stmt_idx == 3
77
- simgr.run()
78
- assert len(simgr.deadended) == 1
79
- assert type(simgr.deadended[0].addr) is SootAddressTerminator
109
+ @unittest.skipUnless(pysoot, "pysoot not available")
110
+ def test_jni_version_information(self):
111
+ project = self.create_project("jni_version_information")
80
112
 
113
+ self.run_method(project=project, method="MixedJava.test_jni_get_version", assert_locals={"i0": 0x10008})
81
114
 
82
- #
83
- # Command line arguments
84
- #
115
+ #
116
+ # JNI Global and Local References
117
+ #
85
118
 
119
+ @unittest.skipUnless(pysoot, "pysoot not available")
120
+ def test_jni_global_and_local_refs(self):
121
+ project = self.create_project("jni_global_and_local_refs")
86
122
 
87
- @unittest.skipUnless(pysoot, "pysoot not available")
88
- def test_cmd_line_args():
89
- project = create_project("cmd_line_args", load_native_libs=False)
90
- entry = project.factory.entry_state()
91
- simgr = project.factory.simgr(entry)
92
- simgr.run()
93
- assert len(simgr.deadended) == 2
94
- state1, state2 = tuple(simgr.deadended)
123
+ assertions = {"global refs dict": lambda state: (state.jni_references.global_refs == {})}
124
+ self.run_method(
125
+ project=project, method="MixedJava.test_jni_global_refs", assert_locals={"i0": 0xA}, assertions=assertions
126
+ )
95
127
 
96
- # get symbol of args[0] from memory
97
- args = state1.globals["cmd_line_args"]
98
- args0_arrref = SimSootValue_ArrayRef(args, 0)
99
- args0_strref = state1.memory.load(args0_arrref)
100
- args0_strval = state1.memory.load(args0_strref)
128
+ #
129
+ # JNI Object Operations
130
+ #
101
131
 
102
- # eval args[0] on both states
103
- str1 = state1.solver.eval(args0_strval)
104
- str2 = state2.solver.eval(args0_strval)
105
- assert "secret_value" in [str1, str2]
132
+ def test_jni_object_operations(self):
133
+ project = self.create_project("jni_object_operations")
106
134
 
135
+ self.run_method(project=project, method="MixedJava.test_jni_alloc_object", assert_locals={"i0": 0})
107
136
 
108
- #
109
- # JNI Version Information
110
- #
137
+ self.run_method(project=project, method="MixedJava.test_jni_new_object", assert_locals={"i0": 1})
111
138
 
139
+ self.run_method(project=project, method="MixedJava.test_jni_new_subclass_object", assert_locals={"i0": 2})
112
140
 
113
- @unittest.skipUnless(pysoot, "pysoot not available")
114
- def test_jni_version_information():
115
- project = create_project("jni_version_information")
141
+ self.run_method(
142
+ project=project,
143
+ method="MixedJava.test_jni_isinstanceof",
144
+ assert_locals={"i0": 1, "i1": 1, "i2": 0, "i3": 1},
145
+ )
116
146
 
117
- run_method(project=project, method="MixedJava.test_jni_get_version", assert_locals={"i0": 0x10008})
147
+ self.run_method(project=project, method="MixedJava.test_jni_issameobject", assert_locals={"i0": 0, "i1": 1})
118
148
 
149
+ #
150
+ # JNI String Operations
151
+ #
119
152
 
120
- #
121
- # JNI Global and Local References
122
- #
153
+ def test_jni_string_operations(self):
154
+ project = self.create_project("jni_string_operations")
123
155
 
156
+ assertions = {
157
+ "1st string": lambda state: (state.solver.eval_one(self.load_string(state, "r0")) == "mum"),
158
+ "2nd string": lambda state: (state.solver.eval_one(self.load_string(state, "r1")) == "himum!"),
159
+ }
160
+ self.run_method(
161
+ project=project,
162
+ method="MixedJava.test_jni_string_operations",
163
+ assert_locals={"i0": 0x3, "i1": 0x6},
164
+ assertions=assertions,
165
+ )
124
166
 
125
- @unittest.skipUnless(pysoot, "pysoot not available")
126
- def test_jni_global_and_local_refs():
127
- project = create_project("jni_global_and_local_refs")
167
+ #
168
+ # JNI Field Access
169
+ #
128
170
 
129
- assertions = {"global refs dict": lambda state: (state.jni_references.global_refs == {})}
130
- run_method(
131
- project=project, method="MixedJava.test_jni_global_refs", assert_locals={"i0": 0xA}, assertions=assertions
132
- )
171
+ def test_jni_field_access(self):
172
+ project = self.create_project("jni_field_access")
173
+
174
+ self.run_method(
175
+ project=project,
176
+ method="MixedJava.test_static_field_access_basic",
177
+ assert_locals={"i0": 0x0, "i1": 0x1, "i2": 0xA, "i3": 0xB, "i4": 0x7, "i5": 0xB, "i6": 0x0, "i7": 0x9},
178
+ )
179
+
180
+ self.run_method(
181
+ project=project, method="MixedJava.test_jni_static_field_access", assert_locals={"i0": 0, "i1": 5}
182
+ )
183
+
184
+ self.run_method(
185
+ project=project,
186
+ method="MixedJava.test_jni_static_field_access_subclass",
187
+ assert_locals={"i0": 1, "i1": 10, "i2": 30, "i3": 1},
188
+ )
189
+
190
+ self.run_method(
191
+ project=project,
192
+ method="MixedJava.test_instance_field_access_0",
193
+ assert_locals={"i0": 0, "i1": 10, "i2": 5, "i3": 5},
194
+ )
195
+
196
+ self.run_method(
197
+ project=project,
198
+ method="MixedJava.test_instance_field_access_1",
199
+ assert_locals={"i0": 0, "i1": 1, "i2": 10, "i3": 4, "i4": 4, "i5": 1},
200
+ )
133
201
 
202
+ #
203
+ # JNI Method Calls
204
+ #
134
205
 
135
- #
136
- # JNI Object Operations
137
- #
206
+ @unittest.skipUnless(pysoot, "pysoot not available")
207
+ def test_jni_method_calls(self):
208
+ project = self.create_project("jni_method_calls")
138
209
 
210
+ self.run_method(
211
+ project=project, method="MixedJava.test_jni_non_virtual_instance_method_call", assert_locals={"i0": 5}
212
+ )
139
213
 
140
- def test_jni_object_operations():
141
- project = create_project("jni_object_operations")
214
+ self.run_method(
215
+ project=project, method="MixedJava.test_jni_instance_method_calls_basic", assert_locals={"i0": 7, "i1": 7}
216
+ )
142
217
 
143
- run_method(project=project, method="MixedJava.test_jni_alloc_object", assert_locals={"i0": 0})
218
+ self.run_method(
219
+ project=project,
220
+ method="MixedJava.test_jni_instance_method_calls_subclass",
221
+ assert_locals={"i0": 2, "i1": 2},
222
+ )
144
223
 
145
- run_method(project=project, method="MixedJava.test_jni_new_object", assert_locals={"i0": 1})
224
+ self.run_method(
225
+ project=project,
226
+ method="MixedJava.test_jni_instance_method_calls_shared_method_id",
227
+ assert_locals={"i0": 8, "i1": 2},
228
+ )
146
229
 
147
- run_method(project=project, method="MixedJava.test_jni_new_subclass_object", assert_locals={"i0": 2})
230
+ self.run_method(
231
+ project=project, method="MixedJava.test_jni_instance_method_calls_args", assert_locals={"i0": 11}
232
+ )
148
233
 
149
- run_method(
150
- project=project, method="MixedJava.test_jni_isinstanceof", assert_locals={"i0": 1, "i1": 1, "i2": 0, "i3": 1}
151
- )
234
+ self.run_method(project=project, method="MixedJava.test_jni_static_method_call", assert_locals={"i0": 10})
152
235
 
153
- run_method(project=project, method="MixedJava.test_jni_issameobject", assert_locals={"i0": 0, "i1": 1})
236
+ self.run_method(
237
+ project=project, method="MixedJava.test_jni_static_method_call_return_obj", assert_locals={"i0": 7}
238
+ )
154
239
 
240
+ #
241
+ # JNI Primitive Datatypes
242
+ #
155
243
 
156
- #
157
- # JNI String Operations
158
- #
244
+ @unittest.skipUnless(pysoot, "pysoot not available")
245
+ def test_jni_primitive_datatypes(self):
246
+ project = self.create_project("jni_primitive_datatypes")
159
247
 
248
+ self.run_method(
249
+ project=project,
250
+ method="MixedJava.test_boolean",
251
+ assert_locals={"z0": 1, "z1": 0, "z2": 1, "z3": 0, "z4": 1},
252
+ )
160
253
 
161
- def test_jni_string_operations():
162
- project = create_project("jni_string_operations")
254
+ self.run_method(
255
+ project=project, method="MixedJava.test_byte", assert_locals={"b5": 30, "b8": 0xFFFFFF80, "b11": 0}
256
+ )
163
257
 
164
- assertions = {
165
- "1st string": lambda state: (state.solver.eval_one(load_string(state, "r0")) == "mum"),
166
- "2nd string": lambda state: (state.solver.eval_one(load_string(state, "r1")) == "himum!"),
167
- }
168
- run_method(
169
- project=project,
170
- method="MixedJava.test_jni_string_operations",
171
- assert_locals={"i0": 0x3, "i1": 0x6},
172
- assertions=assertions,
173
- )
258
+ self.run_method(project=project, method="MixedJava.test_char", assert_locals={"c4": 21, "c6": 0, "c9": 1})
174
259
 
260
+ self.run_method(
261
+ project=project,
262
+ method="MixedJava.test_short",
263
+ assert_locals={"s3": 0x1000, "s5": 0xFFFFF000, "s0": 11, "s9": 0},
264
+ )
175
265
 
176
- #
177
- # JNI Field Access
178
- #
266
+ self.run_method(
267
+ project=project,
268
+ method="MixedJava.test_int",
269
+ assert_locals={"i1": 0xFFFFFFF6, "i3": 0, "i5": 0x80000001, "i7": 0x7FFFFFFF},
270
+ )
179
271
 
272
+ self.run_method(
273
+ project=project, method="MixedJava.test_long", assert_locals={"l1": 0xFFFFFFFFFFFFFFFF, "l3": 1}
274
+ )
180
275
 
181
- def test_jni_field_access():
182
- project = create_project("jni_field_access")
276
+ @unittest.skipUnless(pysoot, "pysoot not available")
277
+ def test_jni_object_arrays(self):
278
+ project = self.create_project("jni_object_array_operations")
183
279
 
184
- run_method(
185
- project=project,
186
- method="MixedJava.test_static_field_access_basic",
187
- assert_locals={"i0": 0x0, "i1": 0x1, "i2": 0xA, "i3": 0xB, "i4": 0x7, "i5": 0xB, "i6": 0x0, "i7": 0x9},
188
- )
280
+ self.run_method(project=project, method="MixedJava.test_jni_access_object_array", assert_locals={"i0": 7})
189
281
 
190
- run_method(project=project, method="MixedJava.test_jni_static_field_access", assert_locals={"i0": 0, "i1": 5})
282
+ self.run_method(project=project, method="MixedJava.test_jni_new_object_array", assert_locals={"i0": 10})
191
283
 
192
- run_method(
193
- project=project,
194
- method="MixedJava.test_jni_static_field_access_subclass",
195
- assert_locals={"i0": 1, "i1": 10, "i2": 30, "i3": 1},
196
- )
284
+ #
285
+ # JNI Array Operations
286
+ #
197
287
 
198
- run_method(
199
- project=project,
200
- method="MixedJava.test_instance_field_access_0",
201
- assert_locals={"i0": 0, "i1": 10, "i2": 5, "i3": 5},
202
- )
288
+ @unittest.skipUnless(pysoot, "pysoot not available")
289
+ def test_jni_array_operations(self):
290
+ project = self.create_project("jni_array_operations")
291
+
292
+ # test_jni_newarray
293
+ self.run_method(
294
+ project=project,
295
+ method="MixedJava.test_jni_newarray",
296
+ assert_locals={"i0": 0, "i1": 1, "i2": 2, "i3": 3, "i4": 4},
297
+ )
298
+
299
+ # test_jni_getarrayregion
300
+ state = self.run_method(project=project, method="MixedJava.test_jni_getarrayregion")
301
+ a = self.load_value_from_stack(state, "i1")
302
+ state.solver.add(a == 15)
303
+ idx = state.posix.stdin.content[0][0]
304
+ assert state.solver.eval_one(idx) == 7
305
+
306
+ # test_jni_setarrayregion1
307
+ self.run_method(
308
+ project=project,
309
+ method="MixedJava.test_jni_setarrayregion1",
310
+ assert_locals={"i0": 0, "i1": 3, "i2": 2, "i3": 1, "i4": 4},
311
+ )
312
+
313
+ # test_jni_setarrayregion2
314
+ state = self.run_method(project=project, method="MixedJava.test_jni_setarrayregion2")
315
+ a = self.load_value_from_stack(state, "i1")
316
+ state.solver.add(a == 2)
317
+ idx = state.posix.stdin.content[0][0]
318
+ idx_value = state.solver.eval_one(idx)
319
+ assert idx_value == 0
320
+
321
+ # test_jni_setarrayregion2
322
+ state = self.run_method(project=project, method="MixedJava.test_jni_setarrayregion2")
323
+ a = self.load_value_from_stack(state, "i1")
324
+ state.solver.add(a == 0)
325
+ idx = state.posix.stdin.content[0][0]
326
+ idx_value = state.solver.eval_exact(idx, 2)
327
+ assert 1 in idx_value
328
+ assert 2 in idx_value
329
+ assert 3 not in idx_value
330
+
331
+ # test_jni_getarrayelements_symbolic
332
+ winning_path = self.get_winning_path(
333
+ project=project, method_fullname="MixedJava.test_jni_getarrayelements_symbolic"
334
+ )
335
+ stdin_packets = winning_path.posix.stdin.content
336
+ idx = winning_path.solver.eval_one(stdin_packets[0][0])
337
+ min_length = winning_path.solver.min(stdin_packets[1][0])
338
+ assert idx == 223
339
+ assert min_length == 224
340
+
341
+ # test_jni_releasearrayelements
342
+ self.run_method(
343
+ project=project,
344
+ method="MixedJava.test_jni_releasearrayelments",
345
+ assert_locals={"i0": 4, "i1": 3, "i2": 2, "i3": 1, "i4": 0},
346
+ )
347
+
348
+ # test_jni_getarrayelements_and_releasearrayelements
349
+ self.run_method(
350
+ project=project,
351
+ method="MixedJava.test_jni_getarrayelements_and_releasearrayelements",
352
+ assert_locals={
353
+ "c9": 0xFFFF,
354
+ "c14": 0x0000,
355
+ "b5": 0x0000007F,
356
+ "b10": 0xFFFFFF80,
357
+ "s6": 0x00007FFF,
358
+ "s11": 0xFFFF8000,
359
+ "i7": 0x7FFFFFFF,
360
+ "i12": 0x80000000,
361
+ "l8": 0x7FFFFFFFFFFFFFFF,
362
+ "l13": 0x8000000000000000,
363
+ },
364
+ )
365
+
366
+ # test_jni_getarraylength
367
+ state = self.run_method(project=project, method="MixedJava.test_jni_getarraylength")
368
+ a = state.memory.stack.load("i3")
369
+ assert state.solver.eval(a) == 10
370
+ b = state.memory.stack.load("i4")
371
+ assert state.solver.min(b) == 0
372
+ assert state.solver.max(b) == 255
203
373
 
204
- run_method(
205
- project=project,
206
- method="MixedJava.test_instance_field_access_1",
207
- assert_locals={"i0": 0, "i1": 1, "i2": 10, "i3": 4, "i4": 4, "i5": 1},
208
- )
374
+ #
375
+ # Method Calls
376
+ #
209
377
 
378
+ @unittest.skipUnless(pysoot, "pysoot not available")
379
+ def test_method_calls(self):
380
+ project = self.create_project("method_calls", load_native_libs=False)
210
381
 
211
- #
212
- # JNI Method Calls
213
- #
382
+ self.run_method(
383
+ project=project,
384
+ method="MixedJava.test_instance_method_calls",
385
+ assert_locals={"i0": 0, "i1": 1, "i2": 1, "i3": 2, "i4": 2, "i5": 2},
386
+ )
214
387
 
388
+ self.run_method(
389
+ project=project,
390
+ method="MixedJava.test_static_method_calls_0",
391
+ assert_locals={"i0": 0, "i1": 1, "i2": 2, "i3": 2},
392
+ )
215
393
 
216
- @unittest.skipUnless(pysoot, "pysoot not available")
217
- def test_jni_method_calls():
218
- project = create_project("jni_method_calls")
394
+ self.run_method(
395
+ project=project,
396
+ method="MixedJava.test_static_method_calls_1",
397
+ assert_locals={"i0": 0, "i1": 0, "i2": 1, "i3": 2, "i4": 2, "i5": 2},
398
+ )
219
399
 
220
- run_method(project=project, method="MixedJava.test_jni_non_virtual_instance_method_call", assert_locals={"i0": 5})
400
+ self.run_method(project=project, method="MixedJava.test_special_invoke_0", assert_locals={"i0": 3})
221
401
 
222
- run_method(
223
- project=project, method="MixedJava.test_jni_instance_method_calls_basic", assert_locals={"i0": 7, "i1": 7}
224
- )
402
+ self.run_method(project=project, method="MixedJava.test_special_invoke_1", assert_locals={"i0": 4})
225
403
 
226
- run_method(
227
- project=project, method="MixedJava.test_jni_instance_method_calls_subclass", assert_locals={"i0": 2, "i1": 2}
228
- )
404
+ #
405
+ # Array Operations
406
+ #
229
407
 
230
- run_method(
231
- project=project,
232
- method="MixedJava.test_jni_instance_method_calls_shared_method_id",
233
- assert_locals={"i0": 8, "i1": 2},
234
- )
408
+ @unittest.skipUnless(pysoot, "pysoot not available")
409
+ def test_array_operations(self):
410
+ project = self.create_project("array_operations", load_native_libs=False)
411
+
412
+ # test_basic_array_operations
413
+ self.run_method(
414
+ project=project,
415
+ method="MixedJava.test_basic_array_operations",
416
+ assert_locals={"i1": 0, "i2": 1, "i3": 2, "i4": 3, "i5": 4, "i6": 5, "i7": 2, "i8": 0},
417
+ )
418
+
419
+ # test_symbolic_array_read
420
+ winning_path = self.get_winning_path(project=project, method_fullname="MixedJava.test_symbolic_array_read")
421
+ stdin_packets = winning_path.posix.stdin.content
422
+ input_char, _ = stdin_packets[0]
423
+ solutions = winning_path.solver.eval_upto(input_char, 2)
424
+ assert ord("A") in solutions
425
+ assert ord("C") in solutions
426
+
427
+ # test_symbolic_array_write
428
+ winning_path = self.get_winning_path(project=project, method_fullname="MixedJava.test_symbolic_array_write")
429
+ stdin_packets = winning_path.posix.stdin.content
430
+ idx_symbol, _ = stdin_packets[0]
431
+ val_symbol, _ = stdin_packets[1]
432
+ winning_path.solver.add(val_symbol != 0) # exclude trivial solution
433
+ idx = winning_path.solver.eval(idx_symbol)
434
+ val = winning_path.solver.eval(val_symbol)
435
+ assert idx == 73
436
+ assert val == 53
437
+
438
+ # test_symbolic_array_length
439
+ winning_path = self.get_winning_path(project=project, method_fullname="MixedJava.test_symbolic_array_length")
440
+ stdin_packets = winning_path.posix.stdin.content
441
+ input_char, _ = stdin_packets[0]
442
+ solution = winning_path.solver.eval(input_char)
443
+ assert solution == ord("F")
444
+
445
+ # test_index_of_of_bound0
446
+ state = self.run_method(project=project, method="MixedJava.test_index_of_of_bound0")
447
+ array_len = self.load_value_from_stack(state, "i1")
448
+ assert state.solver.min(array_len) == 0
449
+ assert state.solver.max(array_len) == 255
450
+
451
+ # test_index_of_of_bound1
452
+ state = self.run_method(project=project, method="MixedJava.test_index_of_of_bound1")
453
+ array_len = self.load_value_from_stack(state, "i1")
454
+ assert state.solver.min(array_len) == 101
455
+ assert state.solver.max(array_len) == 255
456
+
457
+ # test_index_of_of_bound2
458
+ state = self.run_method(project=project, method="MixedJava.test_index_of_of_bound2")
459
+ assert self.load_value_from_stack(state, "i1") is not None
460
+ assert self.load_value_from_stack(state, "i2") is None
461
+ assert self.load_value_from_stack(state, "i3") is None
462
+ assert self.load_value_from_stack(state, "i4") is not None
463
+ assert self.load_value_from_stack(state, "i5") is None
464
+
465
+ # test_index_of_of_bound3
466
+ state = self.run_method(project=project, method="MixedJava.test_index_of_of_bound3")
467
+ assert self.load_value_from_stack(state, "i1") is not None
468
+ assert self.load_value_from_stack(state, "i2") is not None
469
+ assert self.load_value_from_stack(state, "i3") is None
470
+ assert self.load_value_from_stack(state, "i4") is not None
471
+ assert self.load_value_from_stack(state, "i5") is None
472
+
473
+ # test_index_of_of_bound4
474
+ state = self.run_method(project=project, method="MixedJava.test_index_of_of_bound4")
475
+ assert self.load_value_from_stack(state, "i1") is not None
476
+ assert self.load_value_from_stack(state, "i2") is not None
477
+ assert self.load_value_from_stack(state, "i3") is None
478
+
479
+ # test_index_of_of_bound5
480
+ state = self.run_method(project=project, method="MixedJava.test_index_of_of_bound5")
481
+ assert self.load_value_from_stack(state, "i1") is not None
482
+ assert self.load_value_from_stack(state, "i2") is not None
483
+ assert self.load_value_from_stack(state, "i3") is None
235
484
 
236
- run_method(project=project, method="MixedJava.test_jni_instance_method_calls_args", assert_locals={"i0": 11})
485
+ #
486
+ # MultiArray Operations
487
+ #
237
488
 
238
- run_method(project=project, method="MixedJava.test_jni_static_method_call", assert_locals={"i0": 10})
489
+ @unittest.skipUnless(pysoot, "pysoot not available")
490
+ def test_multiarray_operations(self):
491
+ project = self.create_project("multiarray_operations", load_native_libs=False)
239
492
 
240
- run_method(project=project, method="MixedJava.test_jni_static_method_call_return_obj", assert_locals={"i0": 7})
493
+ self.run_method(project=project, method="MixedJava.basic_multiarray_ops", assert_locals={"d1": 4})
241
494
 
495
+ #
496
+ # Loading
497
+ #
242
498
 
243
- #
244
- # JNI Primitive Datatypes
245
- #
499
+ @unittest.skipUnless(pysoot, "pysoot not available")
500
+ def test_loading(self):
501
+ # Test1: test loading with load path
502
+ native_libs_ld_path = os.path.join(self.test_location, "misc", "loading1", "libs")
503
+ jar_path = os.path.join(self.test_location, "misc", "loading1", "mixedjava.jar")
504
+ # define which libraries to load (+ the load path)
505
+ jni_options = {"jni_libs": ["libmixedjava.so"], "jni_libs_ld_path": native_libs_ld_path}
506
+ project = angr.Project(jar_path, main_opts=jni_options, auto_load_libs=True)
507
+ # check if libmixedjava.so was loaded
508
+ loaded_libs = [lib.provides for lib in project.loader.all_elf_objects]
509
+ assert "libmixedjava.so" in loaded_libs
510
+
511
+ # Test 2: test loading without load path
512
+ # => the folder of the JAR is implicitly used as an additional load path
513
+ binary_dir = os.path.join(self.test_location, "misc", "loading2")
514
+ project = self.create_project(binary_dir)
515
+ # check if libmixedjava.so was loaded
516
+ loaded_libs = [lib.provides for lib in project.loader.all_elf_objects]
517
+ assert "libmixedjava.so" in loaded_libs
246
518
 
519
+ #
520
+ # SimStates
521
+ #
247
522
 
248
- @unittest.skipUnless(pysoot, "pysoot not available")
249
- def test_jni_primitive_datatypes():
250
- project = create_project("jni_primitive_datatypes")
523
+ @unittest.skipUnless(pysoot, "pysoot not available")
524
+ def test_toggling_of_simstate(self):
525
+ binary_dir = os.path.join(self.test_location, "misc", "simstates")
526
+ project = self.create_project(binary_dir)
527
+
528
+ state = project.factory.entry_state()
529
+ assert state.ip_is_soot_addr
530
+ assert isinstance(state.arch, ArchSoot)
531
+ assert isinstance(state.memory, JavaVmMemory)
532
+ assert isinstance(state.registers, KeyValueMemory)
533
+
534
+ state.regs.ip = 1
535
+ assert not state.ip_is_soot_addr
536
+ assert isinstance(state.arch, ArchAMD64)
537
+ assert isinstance(state.memory, DefaultMemory)
538
+ assert isinstance(state.registers, DefaultMemory)
539
+
540
+ state.regs._ip = project.entry
541
+
542
+ assert state.ip_is_soot_addr
543
+ assert isinstance(state.arch, ArchSoot)
544
+ assert isinstance(state.memory, JavaVmMemory)
545
+ assert isinstance(state.registers, KeyValueMemory)
546
+
547
+ state.ip = 1
548
+ assert not state.ip_is_soot_addr
549
+ assert isinstance(state.arch, ArchAMD64)
550
+ assert isinstance(state.memory, DefaultMemory)
551
+ assert isinstance(state.registers, DefaultMemory)
552
+
553
+ state_copy = state.copy()
554
+ assert not state_copy.ip_is_soot_addr
555
+ assert isinstance(state_copy.arch, ArchAMD64)
556
+ assert isinstance(state_copy.memory, DefaultMemory)
557
+ assert isinstance(state_copy.registers, DefaultMemory)
558
+
559
+ @unittest.skipUnless(pysoot, "pysoot not available")
560
+ def test_object_tracking(self):
561
+ binary_dir = os.path.join(self.test_location, "object_tracking")
562
+ project = self.create_project(binary_dir, load_native_libs=False)
563
+ bootstrap_state = project.factory.blank_state(addr=SootAddressTerminator())
564
+ mylib_object = SimSootValue_ThisRef.new_object(bootstrap_state, "MyLib", symbolic=True, init_object=False)
565
+
566
+ soot_method = resolve_method(
567
+ bootstrap_state, "testGetterAndSetterConcrete", "MixedJava", ("mylib.MyLib",), init_class=False
568
+ ).address()
569
+
570
+ call_state = project.factory.call_state(
571
+ soot_method,
572
+ SootArgument(mylib_object, mylib_object.type, is_this_ref=False),
573
+ base_state=bootstrap_state,
574
+ ret_addr=SootAddressTerminator(),
575
+ )
576
+
577
+ call_state.options.add(angr.options.JAVA_IDENTIFY_GETTER_SETTER)
578
+ call_state.options.add(angr.options.JAVA_TRACK_ATTRIBUTES)
579
+
580
+ simgr = project.factory.simgr(call_state)
581
+ simgr.run()
582
+
583
+ assert len(simgr.deadended) == 1
584
+
585
+ final_state = simgr.deadended[0]
586
+
587
+ assert final_state.solver.eval(mylib_object.get_field(final_state, "myInt", "int")) == 1
588
+ assert final_state.solver.eval(mylib_object.get_field(final_state, "myShort", "short")) == 1
589
+ assert final_state.solver.eval(mylib_object.get_field(final_state, "myChar", "char")) == ord("c")
590
+ assert final_state.solver.eval(mylib_object.get_field(final_state, "myLong", "long")) == 2
591
+ assert final_state.solver.eval(mylib_object.get_field(final_state, "myFloat", "float")) == 1.5
592
+ assert final_state.solver.eval(mylib_object.get_field(final_state, "myDouble", "double")) == 1.5
593
+ string_ref = mylib_object.get_field(final_state, "myString", "java.lang.String")
594
+ assert final_state.solver.eval(final_state.memory.load(string_ref)) == "Hello!"
595
+ array_ref = mylib_object.get_field(final_state, "myArray", "int[]")
596
+ assert final_state.solver.eval(array_ref.size) == 3
597
+ object_ref = mylib_object.get_field(final_state, "myObject", "java.lang.Object")
598
+ assert final_state.solver.eval(object_ref.get_field(final_state, "a", "int")) == 1
599
+
600
+ assert ("myInt", "int") in mylib_object.attributes
601
+ assert ("myChar", "char") in mylib_object.attributes
602
+ assert ("myShort", "short") in mylib_object.attributes
603
+ assert ("myLong", "long") in mylib_object.attributes
604
+ assert ("myFloat", "float") in mylib_object.attributes
605
+ assert ("myDouble", "double") in mylib_object.attributes
606
+ assert ("myString", "java.lang.String") in mylib_object.attributes
607
+ assert ("myArray", "int[]") in mylib_object.attributes
608
+ assert ("myObject", "java.lang.Object") in mylib_object.attributes
251
609
 
252
- run_method(
253
- project=project, method="MixedJava.test_boolean", assert_locals={"z0": 1, "z1": 0, "z2": 1, "z3": 0, "z4": 1}
254
- )
610
+ #
611
+ # Helper
612
+ #
255
613
 
256
- run_method(project=project, method="MixedJava.test_byte", assert_locals={"b5": 30, "b8": 0xFFFFFF80, "b11": 0})
257
-
258
- run_method(project=project, method="MixedJava.test_char", assert_locals={"c4": 21, "c6": 0, "c9": 1})
259
-
260
- run_method(
261
- project=project,
262
- method="MixedJava.test_short",
263
- assert_locals={"s3": 0x1000, "s5": 0xFFFFF000, "s0": 11, "s9": 0},
264
- )
265
-
266
- run_method(
267
- project=project,
268
- method="MixedJava.test_int",
269
- assert_locals={"i1": 0xFFFFFFF6, "i3": 0, "i5": 0x80000001, "i7": 0x7FFFFFFF},
270
- )
271
-
272
- run_method(project=project, method="MixedJava.test_long", assert_locals={"l1": 0xFFFFFFFFFFFFFFFF, "l3": 1})
273
-
274
-
275
- @unittest.skipUnless(pysoot, "pysoot not available")
276
- def test_jni_object_arrays():
277
- project = create_project("jni_object_array_operations")
278
-
279
- run_method(project=project, method="MixedJava.test_jni_access_object_array", assert_locals={"i0": 7})
280
-
281
- run_method(project=project, method="MixedJava.test_jni_new_object_array", assert_locals={"i0": 10})
282
-
283
-
284
- #
285
- # JNI Array Operations
286
- #
287
-
288
-
289
- @unittest.skipUnless(pysoot, "pysoot not available")
290
- def test_jni_array_operations():
291
- project = create_project("jni_array_operations")
292
-
293
- # test_jni_newarray
294
- run_method(
295
- project=project,
296
- method="MixedJava.test_jni_newarray",
297
- assert_locals={"i0": 0, "i1": 1, "i2": 2, "i3": 3, "i4": 4},
298
- )
299
-
300
- # test_jni_getarrayregion
301
- state = run_method(project=project, method="MixedJava.test_jni_getarrayregion")
302
- a = load_value_from_stack(state, "i1")
303
- state.solver.add(a == 15)
304
- idx = state.posix.stdin.content[0][0]
305
- assert state.solver.eval_one(idx) == 7
306
-
307
- # test_jni_setarrayregion1
308
- run_method(
309
- project=project,
310
- method="MixedJava.test_jni_setarrayregion1",
311
- assert_locals={"i0": 0, "i1": 3, "i2": 2, "i3": 1, "i4": 4},
312
- )
313
-
314
- # test_jni_setarrayregion2
315
- state = run_method(project=project, method="MixedJava.test_jni_setarrayregion2")
316
- a = load_value_from_stack(state, "i1")
317
- state.solver.add(a == 2)
318
- idx = state.posix.stdin.content[0][0]
319
- idx_value = state.solver.eval_one(idx)
320
- assert idx_value == 0
321
-
322
- # test_jni_setarrayregion2
323
- state = run_method(project=project, method="MixedJava.test_jni_setarrayregion2")
324
- a = load_value_from_stack(state, "i1")
325
- state.solver.add(a == 0)
326
- idx = state.posix.stdin.content[0][0]
327
- idx_value = state.solver.eval_exact(idx, 2)
328
- assert 1 in idx_value
329
- assert 2 in idx_value
330
- assert 3 not in idx_value
331
-
332
- # test_jni_getarrayelements_symbolic
333
- winning_path = get_winning_path(project=project, method_fullname="MixedJava.test_jni_getarrayelements_symbolic")
334
- stdin_packets = winning_path.posix.stdin.content
335
- idx = winning_path.solver.eval_one(stdin_packets[0][0])
336
- min_length = winning_path.solver.min(stdin_packets[1][0])
337
- assert idx == 223
338
- assert min_length == 224
339
-
340
- # test_jni_releasearrayelements
341
- run_method(
342
- project=project,
343
- method="MixedJava.test_jni_releasearrayelments",
344
- assert_locals={"i0": 4, "i1": 3, "i2": 2, "i3": 1, "i4": 0},
345
- )
346
-
347
- # test_jni_getarrayelements_and_releasearrayelements
348
- run_method(
349
- project=project,
350
- method="MixedJava.test_jni_getarrayelements_and_releasearrayelements",
351
- assert_locals={
352
- "c9": 0xFFFF,
353
- "c14": 0x0000,
354
- "b5": 0x0000007F,
355
- "b10": 0xFFFFFF80,
356
- "s6": 0x00007FFF,
357
- "s11": 0xFFFF8000,
358
- "i7": 0x7FFFFFFF,
359
- "i12": 0x80000000,
360
- "l8": 0x7FFFFFFFFFFFFFFF,
361
- "l13": 0x8000000000000000,
362
- },
363
- )
364
-
365
- # test_jni_getarraylength
366
- state = run_method(project=project, method="MixedJava.test_jni_getarraylength")
367
- a = state.memory.stack.load("i3")
368
- assert state.solver.eval(a) == 10
369
- b = state.memory.stack.load("i4")
370
- assert state.solver.min(b) == 0
371
- assert state.solver.max(b) == 255
372
-
373
-
374
- #
375
- # Method Calls
376
- #
377
-
378
-
379
- @unittest.skipUnless(pysoot, "pysoot not available")
380
- def test_method_calls():
381
- project = create_project("method_calls", load_native_libs=False)
382
-
383
- run_method(
384
- project=project,
385
- method="MixedJava.test_instance_method_calls",
386
- assert_locals={"i0": 0, "i1": 1, "i2": 1, "i3": 2, "i4": 2, "i5": 2},
387
- )
388
-
389
- run_method(
390
- project=project,
391
- method="MixedJava.test_static_method_calls_0",
392
- assert_locals={"i0": 0, "i1": 1, "i2": 2, "i3": 2},
393
- )
394
-
395
- run_method(
396
- project=project,
397
- method="MixedJava.test_static_method_calls_1",
398
- assert_locals={"i0": 0, "i1": 0, "i2": 1, "i3": 2, "i4": 2, "i5": 2},
399
- )
400
-
401
- run_method(project=project, method="MixedJava.test_special_invoke_0", assert_locals={"i0": 3})
402
-
403
- run_method(project=project, method="MixedJava.test_special_invoke_1", assert_locals={"i0": 4})
404
-
405
-
406
- #
407
- # Array Operations
408
- #
409
-
410
-
411
- @unittest.skipUnless(pysoot, "pysoot not available")
412
- def test_array_operations():
413
- project = create_project("array_operations", load_native_libs=False)
414
-
415
- # test_basic_array_operations
416
- run_method(
417
- project=project,
418
- method="MixedJava.test_basic_array_operations",
419
- assert_locals={"i1": 0, "i2": 1, "i3": 2, "i4": 3, "i5": 4, "i6": 5, "i7": 2, "i8": 0},
420
- )
421
-
422
- # test_symbolic_array_read
423
- winning_path = get_winning_path(project=project, method_fullname="MixedJava.test_symbolic_array_read")
424
- stdin_packets = winning_path.posix.stdin.content
425
- input_char, _ = stdin_packets[0]
426
- solutions = winning_path.solver.eval_upto(input_char, 2)
427
- assert ord("A") in solutions
428
- assert ord("C") in solutions
429
-
430
- # test_symbolic_array_write
431
- winning_path = get_winning_path(project=project, method_fullname="MixedJava.test_symbolic_array_write")
432
- stdin_packets = winning_path.posix.stdin.content
433
- idx_symbol, _ = stdin_packets[0]
434
- val_symbol, _ = stdin_packets[1]
435
- winning_path.solver.add(val_symbol != 0) # exclude trivial solution
436
- idx = winning_path.solver.eval(idx_symbol)
437
- val = winning_path.solver.eval(val_symbol)
438
- assert idx == 73
439
- assert val == 53
440
-
441
- # test_symbolic_array_length
442
- winning_path = get_winning_path(project=project, method_fullname="MixedJava.test_symbolic_array_length")
443
- stdin_packets = winning_path.posix.stdin.content
444
- input_char, _ = stdin_packets[0]
445
- solution = winning_path.solver.eval(input_char)
446
- assert solution == ord("F")
447
-
448
- # test_index_of_of_bound0
449
- state = run_method(project=project, method="MixedJava.test_index_of_of_bound0")
450
- array_len = load_value_from_stack(state, "i1")
451
- assert state.solver.min(array_len) == 0
452
- assert state.solver.max(array_len) == 255
453
-
454
- # test_index_of_of_bound1
455
- state = run_method(project=project, method="MixedJava.test_index_of_of_bound1")
456
- array_len = load_value_from_stack(state, "i1")
457
- assert state.solver.min(array_len) == 101
458
- assert state.solver.max(array_len) == 255
459
-
460
- # test_index_of_of_bound2
461
- state = run_method(project=project, method="MixedJava.test_index_of_of_bound2")
462
- assert load_value_from_stack(state, "i1") is not None
463
- assert load_value_from_stack(state, "i2") is None
464
- assert load_value_from_stack(state, "i3") is None
465
- assert load_value_from_stack(state, "i4") is not None
466
- assert load_value_from_stack(state, "i5") is None
467
-
468
- # test_index_of_of_bound3
469
- state = run_method(project=project, method="MixedJava.test_index_of_of_bound3")
470
- assert load_value_from_stack(state, "i1") is not None
471
- assert load_value_from_stack(state, "i2") is not None
472
- assert load_value_from_stack(state, "i3") is None
473
- assert load_value_from_stack(state, "i4") is not None
474
- assert load_value_from_stack(state, "i5") is None
475
-
476
- # test_index_of_of_bound4
477
- state = run_method(project=project, method="MixedJava.test_index_of_of_bound4")
478
- assert load_value_from_stack(state, "i1") is not None
479
- assert load_value_from_stack(state, "i2") is not None
480
- assert load_value_from_stack(state, "i3") is None
481
-
482
- # test_index_of_of_bound5
483
- state = run_method(project=project, method="MixedJava.test_index_of_of_bound5")
484
- assert load_value_from_stack(state, "i1") is not None
485
- assert load_value_from_stack(state, "i2") is not None
486
- assert load_value_from_stack(state, "i3") is None
487
-
488
-
489
- #
490
- # MultiArray Operations
491
- #
492
-
493
-
494
- @unittest.skipUnless(pysoot, "pysoot not available")
495
- def test_multiarray_operations():
496
- project = create_project("multiarray_operations", load_native_libs=False)
497
-
498
- run_method(project=project, method="MixedJava.basic_multiarray_ops", assert_locals={"d1": 4})
499
-
500
-
501
- #
502
- # Loading
503
- #
504
-
505
-
506
- @unittest.skipUnless(pysoot, "pysoot not available")
507
- def test_loading():
508
- # Test1: test loading with load path
509
- native_libs_ld_path = os.path.join(test_location, "misc", "loading1", "libs")
510
- jar_path = os.path.join(test_location, "misc", "loading1", "mixedjava.jar")
511
- # define which libraries to load (+ the load path)
512
- jni_options = {"jni_libs": ["libmixedjava.so"], "jni_libs_ld_path": native_libs_ld_path}
513
- project = angr.Project(jar_path, main_opts=jni_options, auto_load_libs=True)
514
- # check if libmixedjava.so was loaded
515
- loaded_libs = [lib.provides for lib in project.loader.all_elf_objects]
516
- assert "libmixedjava.so" in loaded_libs
517
-
518
- # Test 2: test loading without load path
519
- # => the folder of the JAR is implicitly used as an additional load path
520
- binary_dir = os.path.join(test_location, "misc", "loading2")
521
- project = create_project(binary_dir)
522
- # check if libmixedjava.so was loaded
523
- loaded_libs = [lib.provides for lib in project.loader.all_elf_objects]
524
- assert "libmixedjava.so" in loaded_libs
525
-
526
-
527
- #
528
- # SimStates
529
- #
530
-
531
-
532
- @unittest.skipUnless(pysoot, "pysoot not available")
533
- def test_toggling_of_simstate():
534
- binary_dir = os.path.join(test_location, "misc", "simstates")
535
- project = create_project(binary_dir)
536
-
537
- state = project.factory.entry_state()
538
- assert state.ip_is_soot_addr
539
- assert isinstance(state.arch, ArchSoot)
540
- assert isinstance(state.memory, JavaVmMemory)
541
- assert isinstance(state.registers, KeyValueMemory)
542
-
543
- state.regs.ip = 1
544
- assert not state.ip_is_soot_addr
545
- assert isinstance(state.arch, ArchAMD64)
546
- assert isinstance(state.memory, DefaultMemory)
547
- assert isinstance(state.registers, DefaultMemory)
548
-
549
- state.regs._ip = project.entry
550
-
551
- assert state.ip_is_soot_addr
552
- assert isinstance(state.arch, ArchSoot)
553
- assert isinstance(state.memory, JavaVmMemory)
554
- assert isinstance(state.registers, KeyValueMemory)
555
-
556
- state.ip = 1
557
- assert not state.ip_is_soot_addr
558
- assert isinstance(state.arch, ArchAMD64)
559
- assert isinstance(state.memory, DefaultMemory)
560
- assert isinstance(state.registers, DefaultMemory)
561
-
562
- state_copy = state.copy()
563
- assert not state_copy.ip_is_soot_addr
564
- assert isinstance(state_copy.arch, ArchAMD64)
565
- assert isinstance(state_copy.memory, DefaultMemory)
566
- assert isinstance(state_copy.registers, DefaultMemory)
567
-
568
-
569
- @unittest.skipUnless(pysoot, "pysoot not available")
570
- def test_object_tracking():
571
- binary_dir = os.path.join(test_location, "object_tracking")
572
- project = create_project(binary_dir, load_native_libs=False)
573
- bootstrap_state = project.factory.blank_state(addr=SootAddressTerminator())
574
- mylib_object = SimSootValue_ThisRef.new_object(bootstrap_state, "MyLib", symbolic=True, init_object=False)
575
-
576
- soot_method = resolve_method(
577
- bootstrap_state, "testGetterAndSetterConcrete", "MixedJava", ("mylib.MyLib",), init_class=False
578
- ).address()
579
-
580
- call_state = project.factory.call_state(
581
- soot_method,
582
- SootArgument(mylib_object, mylib_object.type, is_this_ref=False),
583
- base_state=bootstrap_state,
584
- ret_addr=SootAddressTerminator(),
585
- )
586
-
587
- call_state.options.add(angr.options.JAVA_IDENTIFY_GETTER_SETTER)
588
- call_state.options.add(angr.options.JAVA_TRACK_ATTRIBUTES)
589
-
590
- simgr = project.factory.simgr(call_state)
591
- simgr.run()
592
-
593
- assert len(simgr.deadended) == 1
594
-
595
- final_state = simgr.deadended[0]
596
-
597
- assert final_state.solver.eval(mylib_object.get_field(final_state, "myInt", "int")) == 1
598
- assert final_state.solver.eval(mylib_object.get_field(final_state, "myShort", "short")) == 1
599
- assert final_state.solver.eval(mylib_object.get_field(final_state, "myChar", "char")) == ord("c")
600
- assert final_state.solver.eval(mylib_object.get_field(final_state, "myLong", "long")) == 2
601
- assert final_state.solver.eval(mylib_object.get_field(final_state, "myFloat", "float")) == 1.5
602
- assert final_state.solver.eval(mylib_object.get_field(final_state, "myDouble", "double")) == 1.5
603
- string_ref = mylib_object.get_field(final_state, "myString", "java.lang.String")
604
- assert final_state.solver.eval(final_state.memory.load(string_ref)) == "Hello!"
605
- array_ref = mylib_object.get_field(final_state, "myArray", "int[]")
606
- assert final_state.solver.eval(array_ref.size) == 3
607
- object_ref = mylib_object.get_field(final_state, "myObject", "java.lang.Object")
608
- assert final_state.solver.eval(object_ref.get_field(final_state, "a", "int")) == 1
609
-
610
- assert ("myInt", "int") in mylib_object.attributes
611
- assert ("myChar", "char") in mylib_object.attributes
612
- assert ("myShort", "short") in mylib_object.attributes
613
- assert ("myLong", "long") in mylib_object.attributes
614
- assert ("myFloat", "float") in mylib_object.attributes
615
- assert ("myDouble", "double") in mylib_object.attributes
616
- assert ("myString", "java.lang.String") in mylib_object.attributes
617
- assert ("myArray", "int[]") in mylib_object.attributes
618
- assert ("myObject", "java.lang.Object") in mylib_object.attributes
619
-
620
-
621
- #
622
- # Helper
623
- #
624
-
625
-
626
- def run_method(project, method, assert_locals=None, assertions=None):
627
- end_state = get_last_state_of_method(project, method)
628
- # print_java_memory(end_state)
629
-
630
- if assert_locals:
631
- for symbol_name, assert_value in assert_locals.items():
632
- symbol = load_value_from_stack(end_state, symbol_name)
633
- val = end_state.solver.eval(symbol)
634
- assert val == assert_value
635
-
636
- if assertions:
637
- for _, test in assertions.items():
638
- assert test(end_state)
639
-
640
- return end_state
641
-
642
-
643
- # def print_java_memory(state):
644
- # print "\n##### STACK ##########" + "#"*60
645
- # print state.memory.stack
646
- # print "\n##### HEAP ###########" + "#"*60
647
- # print state.memory.heap
648
- # print "\n##### VM STATIC TABLE " + "#"*60
649
- # print state.memory.vm_static_table
650
- # print
651
-
652
-
653
- @unittest.skipUnless(pysoot, "pysoot not available")
654
- def create_project(binary_dir, load_native_libs=True):
655
- jar_path = os.path.join(test_location, binary_dir, "mixedjava.jar")
656
- if load_native_libs:
657
- jni_options = {"jni_libs": ["libmixedjava.so"]}
658
- project = angr.Project(jar_path, main_opts=jni_options)
659
- else:
660
- project = angr.Project(jar_path)
661
- return project
662
-
663
-
664
- def load_string(state, local_name):
665
- str_ref = load_value_from_stack(state, local_name)
666
- return state.memory.load(str_ref)
667
-
668
-
669
- def load_value_from_stack(state, symbol_name):
670
- try:
671
- return state.memory.stack.load(symbol_name)
672
- except KeyError:
673
- return None
674
-
675
-
676
- def get_entry_state_of_method(project, method_fullname):
677
- # get SootAddressDescriptor of method entry
678
- soot_method = project.loader.main_object.get_soot_method(method_fullname)
679
- method = SootMethodDescriptor.from_soot_method(soot_method)
680
- addr = SootAddressDescriptor(method, 0, 0)
681
- # create call state
682
- return project.factory.blank_state(addr=addr, add_options={angr.options.ZERO_FILL_UNCONSTRAINED_MEMORY})
683
-
684
-
685
- def get_last_state_of_method(project, method_fullname):
686
- state = get_entry_state_of_method(project, method_fullname)
687
- # run until no successors exists
688
- # Note: this does not work if conditional branches are present
689
- states = [state]
690
- succ = states[-1].step()
691
- while len(succ.successors) == 1:
692
- states += succ
614
+ def run_method(self, project, method, assert_locals=None, assertions=None):
615
+ end_state = self.get_last_state_of_method(project, method)
616
+ # print_java_memory(end_state)
617
+
618
+ if assert_locals:
619
+ for symbol_name, assert_value in assert_locals.items():
620
+ symbol = self.load_value_from_stack(end_state, symbol_name)
621
+ val = end_state.solver.eval(symbol)
622
+ assert val == assert_value
623
+
624
+ if assertions:
625
+ for _, test in assertions.items():
626
+ assert test(end_state)
627
+
628
+ return end_state
629
+
630
+ @unittest.skipUnless(pysoot, "pysoot not available")
631
+ def create_project(self, binary_dir, load_native_libs=True):
632
+ jar_path = os.path.join(self.test_location, binary_dir, "mixedjava.jar")
633
+ if load_native_libs:
634
+ jni_options = {"jni_libs": ["libmixedjava.so"]}
635
+ project = angr.Project(jar_path, main_opts=jni_options)
636
+ else:
637
+ project = angr.Project(jar_path)
638
+ return project
639
+
640
+ def load_string(self, state, local_name):
641
+ str_ref = self.load_value_from_stack(state, local_name)
642
+ return state.memory.load(str_ref)
643
+
644
+ def load_value_from_stack(self, state, symbol_name):
645
+ try:
646
+ return state.memory.stack.load(symbol_name)
647
+ except KeyError:
648
+ return None
649
+
650
+ def get_entry_state_of_method(self, project, method_fullname):
651
+ # get SootAddressDescriptor of method entry
652
+ soot_method = project.loader.main_object.get_soot_method(method_fullname)
653
+ method = SootMethodDescriptor.from_soot_method(soot_method)
654
+ addr = SootAddressDescriptor(method, 0, 0)
655
+ # create call state
656
+ return project.factory.blank_state(addr=addr, add_options={angr.options.ZERO_FILL_UNCONSTRAINED_MEMORY})
657
+
658
+ def get_last_state_of_method(self, project, method_fullname):
659
+ state = self.get_entry_state_of_method(project, method_fullname)
660
+ # run until no successors exists
661
+ # Note: this does not work if conditional branches are present
662
+ states = [state]
693
663
  succ = states[-1].step()
694
- # last state is the 'Terminator' state
695
- # => return the state before
696
- return states[-2]
697
-
698
-
699
- def get_winning_paths(project, method_fullname):
700
- state = get_entry_state_of_method(project, method_fullname)
701
- simgr = project.factory.simgr(state)
702
- simgr.run()
703
- paths = simgr.deadended
704
-
705
- # winning paths output a single 'W' on stdout
706
- winnning_paths = []
707
- for pp in paths:
708
- stdout_packets = pp.posix.stdout.content
709
- read_byte, _ = stdout_packets[0]
710
- # a winning path is printing 'W'
711
- pp.solver.add(read_byte == pp.solver.BVV(ord("W"), 8))
712
- if pp.satisfiable():
713
- winnning_paths.append(pp)
714
-
715
- return winnning_paths
716
-
717
-
718
- def get_winning_path(project, method_fullname):
719
- winning_paths = get_winning_paths(project, method_fullname)
720
- assert len(winning_paths) != 0
721
- assert len(winning_paths) == 1
722
- return winning_paths[0]
723
-
724
-
725
- def main():
726
- for k, v in list(globals().items()):
727
- if k.startswith("test_") and callable(v):
728
- v()
664
+ while len(succ.successors) == 1:
665
+ states += succ
666
+ succ = states[-1].step()
667
+ # last state is the 'Terminator' state
668
+ # => return the state before
669
+ return states[-2]
670
+
671
+ def get_winning_paths(self, project, method_fullname):
672
+ state = self.get_entry_state_of_method(project, method_fullname)
673
+ simgr = project.factory.simgr(state)
674
+ simgr.run()
675
+ paths = simgr.deadended
676
+
677
+ # winning paths output a single 'W' on stdout
678
+ winnning_paths = []
679
+ for pp in paths:
680
+ stdout_packets = pp.posix.stdout.content
681
+ read_byte, _ = stdout_packets[0]
682
+ # a winning path is printing 'W'
683
+ pp.solver.add(read_byte == pp.solver.BVV(ord("W"), 8))
684
+ if pp.satisfiable():
685
+ winnning_paths.append(pp)
686
+
687
+ return winnning_paths
688
+
689
+ def get_winning_path(self, project, method_fullname):
690
+ winning_paths = self.get_winning_paths(project, method_fullname)
691
+ assert len(winning_paths) != 0
692
+ assert len(winning_paths) == 1
693
+ return winning_paths[0]
729
694
 
730
695
 
731
696
  if __name__ == "__main__":
732
- # import logging
733
- # logging.getLogger('cle.backends.soot').setLevel('DEBUG')
734
- # logging.getLogger('cle.backends.apk').setLevel('DEBUG')
735
- # logging.getLogger('cle.backends.jar').setLevel('DEBUG')
736
-
737
- # logging.getLogger("angr").setLevel("DEBUG")
738
-
739
- # logging.getLogger("angr.state_plugins").setLevel("INFO")
740
- # logging.getLogger('angr.state_plugins.javavm_memory').setLevel("DEBUG")
741
- # logging.getLogger('angr.state_plugins.jni_references').setLevel("DEBUG")
742
- # logging.getLogger("angr.state_plugins.javavm_classloader").setLevel("DEBUG")
743
-
744
- # logging.getLogger('archinfo.arch_soot').setLevel("DEBUG")
745
- # logging.getLogger('angr.procedures.java_jni').setLevel("DEBUG")
746
- # logging.getLogger("angr.sim_procedure").setLevel("DEBUG")
747
- # logging.getLogger("angr.engines").setLevel("DEBUG")
748
- # logging.getLogger('angr.simos.JavaVM').setLevel("DEBUG")
749
- # logging.getLogger('angr.engines.vex').setLevel("DEBUG")
750
- #
751
- main()
697
+ unittest.main()