1
2import logging
3
4from archinfo.arch_soot import (ArchSoot, SootAddressDescriptor, SootArgument,
5                                SootMethodDescriptor)
6
7from . import JNISimProcedure
8from ...calling_conventions import SimCCSoot
9from ...engines.soot.method_dispatcher import resolve_method
10
11l = logging.getLogger('angr.procedures.java_jni.callmethod')
12
13# pylint: disable=arguments-differ,unused-argument
14
15#
16# GetMethodID / GetStaticMethodID
17#
18
19class GetMethodID(JNISimProcedure):
20
21    return_ty = 'reference'
22
23    def run(self, ptr_env, class_, ptr_method_name, ptr_method_sig):
24
25        method_class = self.state.jni_references.lookup(class_)
26        method_name = self._load_string_from_native_memory(ptr_method_name)
27        method_sig = self._load_string_from_native_memory(ptr_method_sig)
28
29        # derive parameter type from signature
30        params, _ = ArchSoot.decode_method_signature(method_sig)
31
32        # create method ID and return reference to it
33        method_id = SootMethodDescriptor(method_class.name, method_name, params)
34        return self.state.jni_references.create_new_reference(method_id)
35
36#
37# Call<Type>Method / CallNonvirtual<Type>Method / CallStatic<Type>Method
38#
39
40class CallMethodBase(JNISimProcedure):
41
42    return_ty = None
43
44    def _invoke(self, method_id, obj=None, dynamic_dispatch=True, args_in_array=None):
45        # get invoke target
46        class_name = obj.type if dynamic_dispatch else method_id.class_name
47        invoke_target = resolve_method(self.state, method_id.name, class_name, method_id.params)
48        invoke_addr = SootAddressDescriptor(invoke_target, 0, 0)
49
50        # get args
51        no_of_args = len(invoke_target.params)
52        if args_in_array is not None:
53            arg_values = self._get_arg_values_from_array(args_in_array, no_of_args)
54        else:
55            arg_values = self._get_arg_values(no_of_args)
56
57        # setup java args
58        java_args = self._setup_java_args(arg_values, invoke_target, this_ref=obj)
59
60        # call java method
61        # => after returning, the execution will be continued in _return_result_of_computation
62        self.call(invoke_addr, java_args, "return_from_invocation", cc=SimCCSoot(ArchSoot()))
63
64    def _get_arg_values(self, no_of_args):
65        return [ self.arg(self.num_args+idx).to_claripy() for idx in range(no_of_args) ]
66
67    def _get_arg_values_from_array(self, array, no_of_args):
68        return self._load_from_native_memory(addr=array, data_size=self.arch.bytes,
69                                             no_of_elements=no_of_args, return_as_list=True)
70
71    def _setup_java_args(self, arg_values, method_id, this_ref=None):
72        args = []
73
74        # if available, add 'this' reference
75        if this_ref:
76            args += [ SootArgument(this_ref, this_ref.type, is_this_ref=True) ]
77
78        # function arguments
79        for arg_value_, arg_type in zip(arg_values, method_id.params):
80
81            if arg_type in ArchSoot.primitive_types:
82                # argument has a primitive integral type
83                # => cast native value to java type
84                arg_value = self.project.simos.cast_primitive(self.state,
85                                                              value=arg_value_,
86                                                              to_type=arg_type)
87
88            else:
89                # argument has a relative type
90                # => lookup java object
91                arg_value = self.state.jni_references.lookup(arg_value_)
92
93            args += [ SootArgument(arg_value, arg_type) ]
94
95        return args
96
97    def _return_from_invocation(self):
98        if self.return_ty != 'void':
99            ret_value = self.state.javavm_registers.load('invoke_return_value')
100            if self.return_ty == 'reference':
101                return self.state.jni_references.create_new_reference(ret_value)
102            else:
103                return ret_value
104
105#
106# Call<Type>Method
107#
108
109class CallMethod(CallMethodBase):
110    def run(self, ptr_env, obj_, method_id_):
111        method_id = self.state.jni_references.lookup(method_id_)
112        obj = self.state.jni_references.lookup(obj_)
113        self._invoke(method_id, obj, dynamic_dispatch=True)
114
115    def return_from_invocation(self, ptr_env, obj_, method_id_):
116        return self._return_from_invocation()
117
118class CallMethodA(CallMethodBase):
119    def run(self, ptr_env, obj_, method_id_, ptr_args):
120        method_id = self.state.jni_references.lookup(method_id_)
121        obj = self.state.jni_references.lookup(obj_)
122        self._invoke(method_id, obj, dynamic_dispatch=True, args_in_array=ptr_args)
123
124    def return_from_invocation(self, ptr_env, obj_, method_id_, ptr_args):
125        return self._return_from_invocation()
126
127class CallObjectMethod(CallMethod):
128    return_ty = 'reference'
129class CallBooleanMethod(CallMethod):
130    return_ty = 'boolean'
131class CallByteMethod(CallMethod):
132    return_ty = 'byte'
133class CallCharMethod(CallMethod):
134    return_ty = 'char'
135class CallShortMethod(CallMethod):
136    return_ty = 'short'
137class CallIntMethod(CallMethod):
138    return_ty = 'int'
139class CallLongMethod(CallMethod):
140    return_ty = 'long'
141class CallVoidMethod(CallMethod):
142    return_ty = 'void'
143class CallObjectMethodA(CallMethodA):
144    return_ty = 'reference'
145class CallBooleanMethodA(CallMethodA):
146    return_ty = 'boolean'
147class CallByteMethodA(CallMethodA):
148    return_ty = 'byte'
149class CallCharMethodA(CallMethodA):
150    return_ty = 'char'
151class CallShortMethodA(CallMethodA):
152    return_ty = 'short'
153class CallIntMethodA(CallMethodA):
154    return_ty = 'int'
155class CallLongMethodA(CallMethodA):
156    return_ty = 'long'
157class CallVoidMethodA(CallMethodA):
158    return_ty = 'void'
159
160#
161# CallNonVirtual<Type>Method
162#
163
164class CallNonvirtualMethod(CallMethodBase):
165    def run(self, ptr_env, obj_, class_, method_id_):
166        method_id = self.state.jni_references.lookup(method_id_)
167        obj = self.state.jni_references.lookup(obj_)
168        self._invoke(method_id, obj, dynamic_dispatch=False)
169
170    def return_from_invocation(self, ptr_env, obj_, class_, method_id_):
171        return self._return_from_invocation()
172
173class CallNonvirtualMethodA(CallMethodBase):
174    def run(self, ptr_env, obj_, method_id_, ptr_args):
175        method_id = self.state.jni_references.lookup(method_id_)
176        obj = self.state.jni_references.lookup(obj_)
177        self._invoke(method_id, obj, dynamic_dispatch=False, args_in_array=ptr_args)
178
179    def return_from_invocation(self, ptr_env, obj_, method_id_, ptr_args):
180        return self._return_from_invocation()
181
182class CallNonvirtualObjectMethod(CallNonvirtualMethod):
183    return_ty = 'reference'
184class CallNonvirtualBooleanMethod(CallNonvirtualMethod):
185    return_ty = 'boolean'
186class CallNonvirtualByteMethod(CallNonvirtualMethod):
187    return_ty = 'byte'
188class CallNonvirtualCharMethod(CallNonvirtualMethod):
189    return_ty = 'char'
190class CallNonvirtualShortMethod(CallNonvirtualMethod):
191    return_ty = 'short'
192class CallNonvirtualIntMethod(CallNonvirtualMethod):
193    return_ty = 'int'
194class CallNonvirtualLongMethod(CallNonvirtualMethod):
195    return_ty = 'long'
196class CallNonvirtualVoidMethod(CallNonvirtualMethod):
197    return_ty = 'void'
198class CallNonvirtualObjectMethodA(CallNonvirtualMethodA):
199    return_ty = 'reference'
200class CallNonvirtualBooleanMethodA(CallNonvirtualMethodA):
201    return_ty = 'boolean'
202class CallNonvirtualByteMethodA(CallNonvirtualMethodA):
203    return_ty = 'byte'
204class CallNonvirtualCharMethodA(CallNonvirtualMethodA):
205    return_ty = 'char'
206class CallNonvirtualShortMethodA(CallNonvirtualMethodA):
207    return_ty = 'short'
208class CallNonvirtualIntMethodA(CallNonvirtualMethodA):
209    return_ty = 'int'
210class CallNonvirtualLongMethodA(CallNonvirtualMethodA):
211    return_ty = 'long'
212class CallNonvirtualVoidMethodA(CallNonvirtualMethodA):
213    return_ty = 'void'
214
215#
216# CallStatic<Type>Method
217#
218
219class CallStaticMethod(CallMethodBase):
220    def run(self, ptr_env, class_, method_id_):
221        method_id = self.state.jni_references.lookup(method_id_)
222        self._invoke(method_id, dynamic_dispatch=False)
223
224    def return_from_invocation(self, ptr_env, class_, method_id_):
225        return self._return_from_invocation()
226
227class CallStaticMethodA(CallMethodBase):
228    def run(self, ptr_env, obj_, method_id_, ptr_args):
229        method_id = self.state.jni_references.lookup(method_id_)
230        self._invoke(method_id, dynamic_dispatch=False, args_in_array=ptr_args)
231
232    def return_from_invocation(self, ptr_env, class_, method_id_, ptr_args):
233        return self._return_from_invocation()
234
235class CallStaticObjectMethod(CallStaticMethod):
236    return_ty = 'reference'
237class CallStaticBooleanMethod(CallStaticMethod):
238    return_ty = 'boolean'
239class CallStaticByteMethod(CallStaticMethod):
240    return_ty = 'byte'
241class CallStaticCharMethod(CallStaticMethod):
242    return_ty = 'char'
243class CallStaticShortMethod(CallStaticMethod):
244    return_ty = 'short'
245class CallStaticIntMethod(CallStaticMethod):
246    return_ty = 'int'
247class CallStaticLongMethod(CallStaticMethod):
248    return_ty = 'long'
249class CallStaticVoidMethod(CallStaticMethod):
250    return_ty = 'void'
251class CallStaticObjectMethodA(CallStaticMethodA):
252    return_ty = 'reference'
253class CallStaticBooleanMethodA(CallStaticMethodA):
254    return_ty = 'boolean'
255class CallStaticByteMethodA(CallStaticMethodA):
256    return_ty = 'byte'
257class CallStaticCharMethodA(CallStaticMethodA):
258    return_ty = 'char'
259class CallStaticShortMethodA(CallStaticMethodA):
260    return_ty = 'short'
261class CallStaticIntMethodA(CallStaticMethodA):
262    return_ty = 'int'
263class CallStaticLongMethodA(CallStaticMethodA):
264    return_ty = 'long'
265class CallStaticVoidMethodA(CallStaticMethodA):
266    return_ty = 'void'
267