diff --git a/.github/workflows/smoke_test.yml b/.github/workflows/smoke_test.yml index 58b55500b..f29bbce2b 100644 --- a/.github/workflows/smoke_test.yml +++ b/.github/workflows/smoke_test.yml @@ -95,7 +95,7 @@ jobs: shell: bash # This sample should have 16 behaviors with 100% confidence run: | - if [ "${{ env.Ahmyth_RESULT }}" == "37" ]; then + if [ "${{ env.Ahmyth_RESULT }}" == "40" ]; then exit 0 else exit 1 @@ -115,7 +115,7 @@ jobs: shell: bash # This sample should have 15 behaviors with 100% confidence run: | - if [ "${{ env.e273e_RESULT }}" == "41" ]; then + if [ "${{ env.e273e_RESULT }}" == "42" ]; then exit 0 else exit 1 diff --git a/docs/source/quark_inside_objects.rst b/docs/source/quark_inside_objects.rst index 5c3624f18..259a64803 100644 --- a/docs/source/quark_inside_objects.rst +++ b/docs/source/quark_inside_objects.rst @@ -254,28 +254,17 @@ RegisterObject(quark.Objects.registerobject) ============================================ RegisterObject is used to record the state of each register. Each initialized -registerobject will have register_name, value, called_by_func in a single -instance. +registerobject will have value and called_by_func in a single instance. .. image:: https://i.imgur.com/k5nHprC.png -============== ========== ================================================= -register_name value called_by_func -============== ========== ================================================= -"v3" "GPS" Lcom/google/progress/APNOperator;->deleteAPN()Z -============== ========== ================================================= - -**register_name**: register name, such as "v3", "v4". +========== ================================================= + value called_by_func +========== ================================================= + "GPS" Lcom/google/progress/APNOperator;->deleteAPN()Z +========== ================================================= **value**: the value stored in the register. **called_by_func**: what functions are called with this register as a parameter. - - -Explanation of each function ----------------------------- - - * **hash_index**: - - - Get the index number from given VarabileObject, given "v34" will return 34. diff --git a/quark/core/struct/registerobject.py b/quark/core/struct/registerobject.py index dd77f1d86..e68632544 100644 --- a/quark/core/struct/registerobject.py +++ b/quark/core/struct/registerobject.py @@ -7,27 +7,24 @@ class RegisterObject: """The RegisterObject is used to record the state of each register""" __slots__ = [ - "_register_name", "_value", "_called_by_func", "_current_type", "_type_history", ] - def __init__(self, register_name, value, called_by_func=None, value_type=None): + def __init__(self, value, called_by_func=None, value_type=None): """ A data structure for creating the bytecode variable object, which used to record the state of each register. - +================+========+==================+ - | register_name | value | called_by_func | - +================+========+==================+ + +========+==================+ + | value | called_by_func | + +========+==================+ - :param register_name: :param value: :param called_by_func: """ - self._register_name = register_name self._value = value self._current_type = value_type self._type_history = [] @@ -36,13 +33,12 @@ def __init__(self, register_name, value, called_by_func=None, value_type=None): self._called_by_func.append(called_by_func) def __repr__(self): - return f"" + return f"" def __eq__(self, obj): return ( isinstance(obj, RegisterObject) and obj.called_by_func == self.called_by_func - and obj.register_name == self.register_name and obj.value == self.value and obj.current_type == self.current_type ) @@ -67,25 +63,6 @@ def called_by_func(self, called_by_func): self._called_by_func.append(called_by_func) self._type_history.append(self._current_type) - @property - def register_name(self): - """ - Individual register name, for example 'v3'. - - :return: a string of register name - """ - return self._register_name - - @register_name.setter - def register_name(self, reg_name): - """ - Setter of register_name. - - :param reg_name: - :return: None - """ - self._register_name = reg_name - @property def value(self): """ @@ -123,15 +100,14 @@ def current_type(self, value): def type_histroy(self): return self._type_history - @property - def hash_index(self): + def bears_object(self) -> bool: """ - Get the index number from given VarabileObject. + Check whether the register bears an object. - :return: an integer corresponding to the register index + :return: True if the register bears an object, False otherwise + :rtype: bool """ - return int(self.register_name[1:]) - + return self.current_type is not None and self.current_type.startswith("L") if __name__ == "__main__": pass diff --git a/quark/evaluator/pyeval.py b/quark/evaluator/pyeval.py index cf0b3d1a6..b4638d6f4 100644 --- a/quark/evaluator/pyeval.py +++ b/quark/evaluator/pyeval.py @@ -42,13 +42,19 @@ def __init__(self, apkinfo): self.eval = { # invoke-kind "invoke-virtual": self.INVOKE_VIRTUAL, + "invoke-virtual/range": self.INVOKE_VIRTUAL, "invoke-direct": self.INVOKE_DIRECT, + "invoke-direct/range": self.INVOKE_DIRECT, "invoke-static": self.INVOKE_STATIC, - "invoke-virtual/range": self.INVOKE_VIRTUAL_RANGE, + "invoke-static/range": self.INVOKE_STATIC, "invoke-interface": self.INVOKE_INTERFACE, + "invoke-interface/range": self.INVOKE_INTERFACE, "invoke-super": self.INVOKE_SUPER, + "invoke-super/range": self.INVOKE_SUPER, "invoke-polymorphic": self.INVOKE_POLYMORPHIC, + "invoke-polymorphic/range": self.INVOKE_POLYMORPHIC, "invoke-custom": self.INVOKE_CUSTOM, + "invoke-custom/range": self.INVOKE_CUSTOM, # move-result-kind "move-result": self.MOVE_RESULT, "move-result-wide": self.MOVE_RESULT_WIDE, @@ -177,24 +183,31 @@ def _invoke(self, instruction, look_up=False, skip_self=False): var_obj = self.table_obj.pop(index) value_of_reg_list.append(var_obj.value) + # Remove duplicate parameter values to save memory + seen = {} + for idx, val in enumerate(value_of_reg_list): + if val in seen: + value_of_reg_list[idx] = f"" + else: + seen[val] = idx + invoked_state = f"{executed_fuc}({','.join(value_of_reg_list)})" # insert the function and the parameter into called_by_func for reg in reg_list: index = int(reg[1:]) - obj_stack = self.table_obj.get_obj_list(index) - if obj_stack: - # add the function name into each parameter table - var_obj = self.table_obj.pop(index) - var_obj.called_by_func = invoked_state - if instruction[0].startswith('invoke') and not instruction[0].endswith("static"): - # push the return value into the instance - reg_idx_to_object = int(reg_list[0][1:]) + if not self.table_obj.get_obj_list(index): + continue - obj_stack = self.table_obj.get_obj_list(reg_idx_to_object) - if obj_stack: - var_obj = self.table_obj.pop(reg_idx_to_object) + # add the function name into each parameter table + var_obj = self.table_obj.pop(index) + var_obj.called_by_func = invoked_state + + if var_obj.bears_object(): + # If the register bears an object, update its value to reflect + # the method invocation since the method may modify the + # internal state of the object. var_obj.value = invoked_state if not executed_fuc.endswith(")V"): @@ -210,20 +223,33 @@ def _move_result(self, instruction): index = int(reg[1:]) try: pre_ret = self.ret_stack.pop() - variable_object = RegisterObject(reg, pre_ret, value_type=self.ret_type) + variable_object = RegisterObject( + value=pre_ret, value_type=self.ret_type + ) self.table_obj.insert(index, variable_object) self.ret_type = "" except IndexError as e: log.exception(f"{e} in _move_result") + def _move_object(self, src_reg_idx: int, dest_reg_idx: int): + """ + Move object from src_reg_idx to dest_reg_idx without creating new + RegisterObject. This allow both registers to point to the same object. + """ + # Get the source object from the table + src_obj = self.table_obj.pop(src_reg_idx) + + # Insert the source object to the destination register. + self.table_obj.insert(dest_reg_idx, src_obj) + def _assign_value(self, instruction, value_type=""): reg = instruction[1] value = instruction[2] index = int(reg[1:]) - variable_object = RegisterObject(reg, value, value_type=value_type) + variable_object = RegisterObject(value=value, value_type=value_type) self.table_obj.insert(index, variable_object) def _assign_value_wide(self, instruction, value_type=""): @@ -233,10 +259,9 @@ def _assign_value_wide(self, instruction, value_type=""): reg = instruction[1] value = instruction[2] index = int(reg[1:]) - reg_plus_one = f"v{index + 1}" - variable_object = RegisterObject(reg, value, value_type=value_type) - variable_object2 = RegisterObject(reg_plus_one, value, value_type=value_type) + variable_object = RegisterObject(value=value, value_type=value_type) + variable_object2 = RegisterObject(value=value, value_type=value_type) self.table_obj.insert(index, variable_object) self.table_obj.insert(index + 1, variable_object2) @@ -244,6 +269,7 @@ def _assign_value_wide(self, instruction, value_type=""): def INVOKE_VIRTUAL(self, instruction): """ invoke-virtual { parameters }, methodtocall + invoke-virtual/range { parameters }, methodtocall Invokes a virtual method with parameters. """ @@ -253,6 +279,7 @@ def INVOKE_VIRTUAL(self, instruction): def INVOKE_DIRECT(self, instruction): """ invoke-direct { parameters }, methodtocall + invoke-direct/range { parameters }, methodtocall Invokes a method with parameters without the virtual method resolution. (first parameter is "this") """ @@ -262,23 +289,18 @@ def INVOKE_DIRECT(self, instruction): def INVOKE_STATIC(self, instruction): """ invoke-static {parameters}, methodtocall + invoke-static/range {parameters}, methodtocall Invokes a static method with parameters. """ self._invoke(instruction) - @logger - def INVOKE_VIRTUAL_RANGE(self, instruction): - """ - invoke-virtual/range { parameters }, methodtocall - Invokes a virtual-range method with parameters. - """ - self._invoke(instruction, look_up=True) - @logger def INVOKE_INTERFACE(self, instruction): """ invoke-interface { parameters }, methodtocall + invoke-interface/range { parameters }, methodtocall + Invokes a interface method with parameters. """ self._invoke(instruction, look_up=True) @@ -286,15 +308,29 @@ def INVOKE_INTERFACE(self, instruction): @logger def INVOKE_SUPER(self, instruction): """ - invoke-interface { parameters }, methodtocall - Invokes a interface method with parameters. + invoke-super { parameters }, methodtocall + invoke-super/range { parameters }, methodtocall + + Invokes a super method with parameters. """ self._invoke(instruction, look_up=True, skip_self=True) def INVOKE_POLYMORPHIC(self, instruction): + """ + invoke-polymorphic { parameters }, methodtocall + invoke-polymorphic/range { parameters }, methodtocall + + Invokes a polymorphic method with parameters. + """ self._invoke(instruction) def INVOKE_CUSTOM(self, instruction): + """ + invoke-custom { parameters }, callsite + invoke-custom/range { parameters }, callsite + + Invokes a call site with parameters. + """ self._invoke(instruction) @logger @@ -320,9 +356,9 @@ def MOVE_RESULT_WIDE(self, instruction): index = int(reg[1:]) try: pre_ret = self.ret_stack.pop() - variable_object = RegisterObject(reg, pre_ret, value_type=self.ret_type) + variable_object = RegisterObject(value=pre_ret, value_type=self.ret_type) variable_object2 = RegisterObject( - f"v{index + 1}", pre_ret, value_type=self.ret_type + value=pre_ret, value_type=self.ret_type ) self.table_obj.insert(index, variable_object) self.table_obj.insert(index + 1, variable_object2) @@ -488,6 +524,13 @@ def AGET_KIND(self, instruction): @logger def MOVE_KIND(self, instruction): try: + if instruction[0].startswith("move-object"): + self._move_object( + src_reg_idx=int(instruction[2][1:]), + dest_reg_idx=int(instruction[1][1:]), + ) + return + wide = "wide" in instruction[0] self._move_value_to_register(instruction, "{src0}", wide=wide) except IndexError as e: @@ -714,8 +757,7 @@ def _move_value_and_data_to_register( value_dict["data"] = data new_register = RegisterObject( - f"v{source}", - str_format.format(**value_dict), + value=str_format.format(**value_dict), value_type=value_type, ) self.table_obj.insert(source, new_register) @@ -765,8 +807,7 @@ def _transfer_register( value_dict["data"] = data new_register = RegisterObject( - f"v{destination}", - str_format.format(**value_dict), + value=str_format.format(**value_dict), value_type=value_type, ) diff --git a/tests/core/struct/test_registerobject.py b/tests/core/struct/test_registerobject.py index b106e2643..05d6f07e9 100644 --- a/tests/core/struct/test_registerobject.py +++ b/tests/core/struct/test_registerobject.py @@ -5,7 +5,7 @@ @pytest.fixture() def standard_register_obj(): - register_obj = RegisterObject("v1", "value", "func") + register_obj = RegisterObject("value", "func") yield register_obj del register_obj @@ -13,16 +13,14 @@ def standard_register_obj(): class TestRegisterObject: def test_init_without_called_by_func(self): - register_obj = RegisterObject("v1", "value") + register_obj = RegisterObject("value") - assert register_obj._register_name == "v1" assert register_obj._value == "value" assert register_obj._called_by_func == [] def test_init_with_called_by_func(self): - register_obj = RegisterObject("v1", "value", "func") + register_obj = RegisterObject("value", "func") - assert register_obj._register_name == "v1" assert register_obj._value == "value" assert register_obj._called_by_func == ["func"] @@ -34,21 +32,18 @@ def test_called_by_func(self, standard_register_obj): assert len(standard_register_obj.called_by_func) == 2 assert standard_register_obj.called_by_func[-1] == value - def test_register_name(self): - value = "v1" - - standard_register_obj.register_name = value - - assert standard_register_obj.register_name == value - - def test_value(self): + def test_value(self, standard_register_obj): value = "value" standard_register_obj.value = value assert standard_register_obj.value == value - def test_hash_index(self, standard_register_obj): - standard_register_obj._register_name = "v5" + def test_bears_object(self): + reg_with_object = RegisterObject("value", value_type="Ljava/lang/String;") + reg_with_primitive = RegisterObject("value", value_type="I") + reg_with_none = RegisterObject("value", value_type=None) - assert standard_register_obj.hash_index == 5 + assert reg_with_object.bears_object() is True + assert reg_with_primitive.bears_object() is False + assert reg_with_none.bears_object() is False diff --git a/tests/evaluator/test_pyeval.py b/tests/evaluator/test_pyeval.py index 73aa7cb6f..27ba77fcc 100644 --- a/tests/evaluator/test_pyeval.py +++ b/tests/evaluator/test_pyeval.py @@ -27,21 +27,9 @@ def instructions(): del ins -APK_SOURCE = ( - "https://github.com/quark-engine/apk-samples" - "/raw/master/malware-samples/13667fe3b0ad496a0cd157f34b7e0c991d72a4db.apk" -) -APK_FILENAME = "13667fe3b0ad496a0cd157f34b7e0c991d72a4db.apk" - - @pytest.fixture(scope="module") -def apkinfo(): - r = requests.get(APK_SOURCE, allow_redirects=True) - file = open(APK_FILENAME, "wb") - file.write(r.content) - - apkinfo = AndroguardImp(APK_FILENAME) - +def apkinfo(SAMPLE_PATH_13667): + apkinfo = AndroguardImp(SAMPLE_PATH_13667) yield apkinfo @@ -52,24 +40,21 @@ def pyeval(apkinfo): # mock_hash_table = [...[], [v4_mock_variable_obj], [], [], # [v9_mock_variable_obj]....] v4_mock_variable_obj = RegisterObject( - "v4", "Lcom/google/progress/SMSHelper;", value_type="Lcom/google/progress/SMSHelper;", ) v5_mock_variable_obj = RegisterObject( - "v5", "some_number", "java.lang.String.toString()", value_type="I" + "some_number", "java.lang.String.toString()", value_type="I" ) v6_mock_variable_obj = RegisterObject( - "v6", "an_array", "java.lang.Collection.toArray()", value_type="[I" + "an_array", "java.lang.Collection.toArray()", value_type="[I" ) - v7_mock_variable_obj = RegisterObject("v7", "a_float", value_type="F") + v7_mock_variable_obj = RegisterObject("a_float", value_type="F") v8_mock_variable_obj = RegisterObject( - "v8", "ArrayMap object", value_type="Landroid/support/v4/util/ArrayMap;", ) v9_mock_variable_obj = RegisterObject( - "v9", "some_string", "java.io.file.close()", value_type="Ljava/lang/String;", @@ -376,6 +361,21 @@ def test_invoke_virtual_with_class_inheritance(self, pyeval): ] assert pyeval.ret_type == "Z" + def test_invoke_virtual_range_with_valid_mnemonic(self, pyeval): + instruction = [ + "invoke-virtual/range", + "v4", + "v9", + ( + "Landroid/support/v4/util/ArrayMap;" + "->entrySet()Ljava/util/Set;(ArrayMap object)" + ), + ] + + with patch("quark.evaluator.pyeval.PyEval._invoke") as mock: + pyeval.INVOKE_VIRTUAL(instruction) + mock.assert_called_once_with(instruction, look_up=True) + # Tests for invoke_direct def test_invoke_direct_with_valid_mnemonic(self, pyeval): instruction = [ @@ -392,6 +392,21 @@ def test_invoke_direct_with_valid_mnemonic(self, pyeval): pyeval.INVOKE_DIRECT(instruction) mock.assert_called_once_with(instruction) + def test_invoke_direct_range_with_valid_mnemonic(self, pyeval): + instruction = [ + "invoke-direct/range", + "v4", + "v9", + ( + "Landroid/support/v4/util/ArrayMap;" + "->entrySet()Ljava/util/Set;(ArrayMap object)" + ), + ] + + with patch("quark.evaluator.pyeval.PyEval._invoke") as mock: + pyeval.INVOKE_DIRECT(instruction) + mock.assert_called_once_with(instruction) + # Tests for invoke_static def test_invoke_static_with_valid_mnemonic(self, pyeval): instruction = [ @@ -408,6 +423,21 @@ def test_invoke_static_with_valid_mnemonic(self, pyeval): pyeval.INVOKE_STATIC(instruction) mock.assert_called_once_with(instruction) + def test_invoke_static_range_with_valid_mnemonic(self, pyeval): + instruction = [ + "invoke-static/range", + "v4", + "v9", + ( + "Landroid/support/v4/util/ArrayMap;" + "->entrySet()Ljava/util/Set;(ArrayMap object)" + ), + ] + + with patch("quark.evaluator.pyeval.PyEval._invoke") as mock: + pyeval.INVOKE_STATIC(instruction) + mock.assert_called_once_with(instruction) + # Tests for invoke-interface def test_invoke_interface_with_valid_mnemonic(self, pyeval): instruction = [ @@ -441,6 +471,21 @@ def test_invoke_interface_with_class_inheritance(self, pyeval): ] assert pyeval.ret_type == "Ljava/util/Set;" + def test_invoke_interface_range_with_valid_mnemonic(self, pyeval): + instruction = [ + "invoke-interface/range", + "v4", + "v9", + ( + "Landroid/support/v4/util/ArrayMap;" + "->entrySet()Ljava/util/Set;(ArrayMap object)" + ), + ] + + with patch("quark.evaluator.pyeval.PyEval._invoke") as mock: + pyeval.INVOKE_INTERFACE(instruction) + mock.assert_called_once_with(instruction, look_up=True) + # Tests for invoke-super def test_invoke_super_with_valid_mnemonic(self, pyeval): instruction = ["invoke-super", "v4", "v9", "some_function()V"] @@ -468,6 +513,15 @@ def test_invoke_super_with_class_inheritance(self, pyeval): ] assert pyeval.ret_type == "Ljava/lang/String;" + def test_invoke_super_range_with_valid_mnemonic(self, pyeval): + instruction = ["invoke-super/range", "v4", "v9", "some_function()V"] + + with patch("quark.evaluator.pyeval.PyEval._invoke") as mock: + pyeval.INVOKE_SUPER(instruction) + mock.assert_called_once_with( + instruction, look_up=True, skip_self=True + ) + # Tests for invoke polymorphic def test_invoke_polymorphic_with_valid_mnemonic(self, pyeval): instruction = [ @@ -482,6 +536,19 @@ def test_invoke_polymorphic_with_valid_mnemonic(self, pyeval): pyeval.INVOKE_POLYMORPHIC(instruction) mock.assert_called_once_with(instruction) + def test_invoke_polymorphic_range_with_valid_mnemonic(self, pyeval): + instruction = [ + "invoke-polymorphic/range", + "v4", + "v9", + "some_function()V", + "prototype_idx", + ] + + with patch("quark.evaluator.pyeval.PyEval._invoke") as mock: + pyeval.INVOKE_POLYMORPHIC(instruction) + mock.assert_called_once_with(instruction) + # Tests for invoke-custom def test_invoke_custom_with_valid_mnemonic(self, pyeval): instruction = ["invoke-custom", "v4", "v9", "method"] @@ -489,6 +556,12 @@ def test_invoke_custom_with_valid_mnemonic(self, pyeval): pyeval.INVOKE_CUSTOM(instruction) mock.assert_called_once_with(instruction) + def test_invoke_custom_range_with_valid_mnemonic(self, pyeval): + instruction = ["invoke-custom/range", "v4", "v9", "method"] + with patch("quark.evaluator.pyeval.PyEval._invoke") as mock: + pyeval.INVOKE_CUSTOM(instruction) + mock.assert_called_once_with(instruction) + # Tests for _move_result def test_move_with_non_list_object(self, pyeval): instruction = None @@ -520,7 +593,7 @@ def test_move_with_valid_instrcution(self, pyeval): pyeval._move_result(instruction) assert pyeval.table_obj.pop(1) == RegisterObject( - "v1", expected_return_value, None, value_type=expected_return_type + expected_return_value, None, value_type=expected_return_type ) # Tests for move_result @@ -563,12 +636,10 @@ def test_new_instance(self, pyeval): pyeval.NEW_INSTANCE(instruction) assert pyeval.table_obj.pop(3) == RegisterObject( - "v3", "Lcom/google/progress/SMSHelper;", value_type="Lcom/google/progress/SMSHelper;", ) assert pyeval.table_obj.pop(4) == RegisterObject( - "v4", "Lcom/google/progress/SMSHelper;", value_type="Lcom/google/progress/SMSHelper;", ) @@ -576,7 +647,7 @@ def test_new_instance(self, pyeval): pyeval.NEW_INSTANCE(override_original_instruction) assert pyeval.table_obj.pop(4) == RegisterObject( - "v4", "Ljava/lang/Object;", value_type="Ljava/lang/Object;" + "Ljava/lang/Object;", value_type="Ljava/lang/Object;" ) # Tests for const_string @@ -590,7 +661,6 @@ def test_const_string(self, pyeval): pyeval.CONST_STRING(instruction) assert pyeval.table_obj.pop(8) == RegisterObject( - "v8", "https://github.com/quark-engine/quark-engine", value_type="Ljava/lang/String;", ) @@ -605,7 +675,6 @@ def test_const_string_jumbo(self, pyeval): pyeval.eval[instruction[0]](instruction) assert pyeval.table_obj.pop(8) == RegisterObject( - "v8", "https://github.com/quark-engine/quark-engine", value_type="Ljava/lang/String;", ) @@ -620,7 +689,6 @@ def test_const_class(self, pyeval): pyeval.eval[instruction[0]](instruction) assert pyeval.table_obj.pop(8) == RegisterObject( - "v8", "Landroid/telephony/SmsMessage;", value_type="Ljava/lang/Class;", ) @@ -668,23 +736,28 @@ def test_move_kind(self, pyeval, move_kind): pyeval.eval[instruction[0]](instruction) assert pyeval.table_obj.pop(1) == RegisterObject( - "v1", "Lcom/google/progress/SMSHelper;", value_type="Lcom/google/progress/SMSHelper;", ) + def test_move_object(self, pyeval): + instruction = ["move-object", "v1", "v4"] + + pyeval.eval[instruction[0]](instruction) + + assert id(pyeval.table_obj.pop(1)) == id(pyeval.table_obj.pop(4)) + def test_move_wide_kind(self, pyeval, move_wide_kind): instruction = [move_wide_kind, "v1", "v4"] pyeval.eval[instruction[0]](instruction) assert pyeval.table_obj.pop(1) == RegisterObject( - "v1", "Lcom/google/progress/SMSHelper;", value_type="Lcom/google/progress/SMSHelper;", ) assert pyeval.table_obj.pop(2) == RegisterObject( - "v2", "some_number", value_type="I" + "some_number", value_type="I" ) def test_new_array(self, pyeval): @@ -693,7 +766,6 @@ def test_new_array(self, pyeval): pyeval.eval[instruction[0]](instruction) assert pyeval.table_obj.pop(1) == RegisterObject( - "v1", "new-array()[(some_number)", value_type="[java/lang/String;", ) @@ -721,12 +793,11 @@ def test_filled_array_kind_with_primitive_type( # Tests for aget-kind def test_aget_kind(self, pyeval, aget_kind): v2_mock_variable_obj = RegisterObject( - "v2", "some_list_like[1,2,3,4]", "java.io.file.close()", value_type="[Ljava/lang/Integer;", ) - v3_mock_variable_obj = RegisterObject("v3", "2", None, value_type="I") + v3_mock_variable_obj = RegisterObject("2", None, value_type="I") pyeval.table_obj.insert(2, v2_mock_variable_obj) pyeval.table_obj.insert(3, v3_mock_variable_obj) @@ -745,7 +816,7 @@ def test_aget_kind(self, pyeval, aget_kind): pyeval.eval[instruction[0]](instruction) assert pyeval.table_obj.pop(1) == RegisterObject( - "v1", "some_list_like[1,2,3,4][2]", value_type=expected_value_type + "some_list_like[1,2,3,4][2]", value_type=expected_value_type ) def test_aget_wide_kind(self, pyeval, aget_wide_kind): @@ -754,7 +825,7 @@ def test_aget_wide_kind(self, pyeval, aget_wide_kind): pyeval.eval[instruction[0]](instruction) assert pyeval.table_obj.pop(1) == RegisterObject( - "v1", "an_array[some_number]", value_type="I" + "an_array[some_number]", value_type="I" ) # Tests for aput-kind @@ -764,7 +835,6 @@ def test_aput_kind(self, pyeval, aput_kind): pyeval.eval[instruction[0]](instruction) assert pyeval.table_obj.pop(6) == RegisterObject( - "v6", "an_array[some_number]:Lcom/google/progress/SMSHelper;", value_type="[I", ) @@ -775,7 +845,6 @@ def test_aput_wide_kind(self, pyeval, aput_wide_kind): pyeval.eval[instruction[0]](instruction) assert pyeval.table_obj.pop(6) == RegisterObject( - "v6", ( "an_array[some_number]:" "(Lcom/google/progress/SMSHelper;, some_number)" @@ -790,7 +859,7 @@ def test_neg_and_not_kind(self, pyeval, neg_not_kind): pyeval.eval[instruction[0]](instruction) assert pyeval.table_obj.pop(1) == RegisterObject( - "v1", "some_number", value_type="I" + "some_number", value_type="I" ) def test_neg_and_not_wide_kind(self, pyeval, neg_not_wide_kind): @@ -799,10 +868,10 @@ def test_neg_and_not_wide_kind(self, pyeval, neg_not_wide_kind): pyeval.eval[instruction[0]](instruction) assert pyeval.table_obj.pop(1) == RegisterObject( - "v1", "some_number", value_type="I" + "some_number", value_type="I" ) assert pyeval.table_obj.pop(2) == RegisterObject( - "v2", "an_array", value_type="[I" + "an_array", value_type="[I" ) # Tests for type-casting @@ -815,7 +884,6 @@ def test_type_casting_without_wide_type(self, pyeval, cast_kind): pyeval.eval[instruction[0]](instruction) assert pyeval.table_obj.pop(1) == RegisterObject( - "v1", "casting(some_number)", value_type=pyeval.type_mapping[postfix], ) @@ -831,7 +899,6 @@ def test_type_casting_with_wide_type_to_simple_type( pyeval.eval[instruction[0]](instruction) assert pyeval.table_obj.pop(1) == RegisterObject( - "v1", "casting(some_number, an_array)", value_type=pyeval.type_mapping[postfix], ) @@ -847,12 +914,10 @@ def test_type_casting_with_simple_type_to_wide_type( pyeval.eval[instruction[0]](instruction) assert pyeval.table_obj.pop(1) == RegisterObject( - "v1", "casting(some_number)", value_type=pyeval.type_mapping[postfix], ) assert pyeval.table_obj.pop(2) == RegisterObject( - "v2", "casting(some_number)", value_type=pyeval.type_mapping[postfix], ) @@ -867,7 +932,6 @@ def test_simple_binop_kind(self, pyeval, simple_binop_kind): pyeval.eval[instruction[0]](instruction) assert pyeval.table_obj.pop(1) == RegisterObject( - "v1", "binop(some_number, an_array)", value_type=pyeval.type_mapping[postfix], ) @@ -881,12 +945,10 @@ def test_binop_kind_with_wide_type(self, pyeval, binop_wide_kind): pyeval.eval[instruction[0]](instruction) assert pyeval.table_obj.pop(1) == RegisterObject( - "v1", "binop(Lcom/google/progress/SMSHelper;, an_array)", value_type=pyeval.type_mapping[postfix], ) assert pyeval.table_obj.pop(2) == RegisterObject( - "v2", "binop(some_number, a_float)", value_type=pyeval.type_mapping[postfix], ) @@ -901,7 +963,6 @@ def test_binop_kind_in_place(self, pyeval, binop_2addr_kind): pyeval.eval[instruction[0]](instruction) assert pyeval.table_obj.pop(4) == RegisterObject( - "v4", "binop(Lcom/google/progress/SMSHelper;, an_array)", value_type=pyeval.type_mapping[postfix], ) @@ -916,7 +977,6 @@ def test_binop_kind_with_literal(self, pyeval, binop_lit_kind): pyeval.eval[instruction[0]](instruction) assert pyeval.table_obj.pop(1) == RegisterObject( - "v1", "binop(some_number, literal_number)", value_type=pyeval.type_mapping[postfix], ) @@ -928,7 +988,7 @@ def test_move_exception(self, pyeval): pyeval.eval[instruction[0]](instruction) assert pyeval.table_obj.pop(1) == RegisterObject( - "v1", "Exception", value_type="Ljava/lang/Throwable;" + "Exception", value_type="Ljava/lang/Throwable;" ) # Tests for fill-array-data @@ -938,7 +998,7 @@ def test_fill_array_data(self, pyeval): pyeval.eval[instruction[0]](instruction) assert pyeval.table_obj.pop(6) == RegisterObject( - "v6", "Embedded-array-data()[", value_type="[I" + "Embedded-array-data()[", value_type="[I" ) def test_show_table(self, pyeval): @@ -951,13 +1011,13 @@ def test_show_table(self, pyeval): def test_invoke_and_move(self, pyeval): v6_mock_variable_obj = RegisterObject( - "v6", "some_string", None, value_type="Ljava/lang/String;" + "some_string", None, value_type="Ljava/lang/String;" ) pyeval.table_obj.insert(6, v6_mock_variable_obj) assert pyeval.table_obj.pop(6) == RegisterObject( - "v6", "some_string", value_type="Ljava/lang/String;" + "some_string", value_type="Ljava/lang/String;" ) first_instruction = [ @@ -972,7 +1032,6 @@ def test_invoke_and_move(self, pyeval): pyeval.MOVE_RESULT_OBJECT(second_instruction) assert pyeval.table_obj.pop(1) == RegisterObject( - "v1", ( "Lcom/google/progress/ContactsCollector;" "->getContactList()Ljava/lang/String;(some_string)" diff --git a/tests/script/test_script.py b/tests/script/test_script.py index bdd741d8b..119ea5b3e 100644 --- a/tests/script/test_script.py +++ b/tests/script/test_script.py @@ -521,7 +521,7 @@ def testCheckMethodCalls(SAMPLE_PATH_14d9f) -> None: "(Ljava/lang/String; Ljava/lang/String;)I" ])) - assert checkMethodCalls("14d9f1a92dd984d6040cc41ed06e273e.apk", targetMethod, checkMethods) is True + assert checkMethodCalls(SAMPLE_PATH_14d9f, targetMethod, checkMethods) is True def testFindMethodImpls(SAMPLE_PATH_pivaa) -> None: