コード例 #1
0
    def __init__(self):
        # Main switch for executing the bytecode instruction.
        self.eval = {
            # invoke-kind
            "invoke-virtual": self.INVOKE_VIRTUAL,
            "invoke-direct": self.INVOKE_DIRECT,
            "invoke-static": self.INVOKE_STATIC,
            "invoke-virtual/range": self.INVOKE_VIRTUAL_RANGE,
            "invoke-interface": self.INVOKE_INTERFACE,
            # move-result-kind
            "move-result": self.MOVE_RESULT,
            "move-result-wide": self.MOVE_RESULT_WIDE,
            "move-result-object": self.MOVE_RESULT_OBJECT,
            # instance-kind
            "new-instance": self.NEW_INSTANCE,
            # const-kind
            "const-string": self.CONST_STRING,
            "const": self.CONST,
            "const/4": self.CONST_FOUR,
            "const/16": self.CONST_SIXTEEN,
            "const/high16": self.CONST_HIGHSIXTEEN,
            "const-wide": self.CONST_WIDE,
            "const-wide/16": self.CONST_WIDE_SIXTEEN,
            "const-wide/32": self.CONST_WIDE_THIRTY_TWO,
            "const-wide/high16": self.CONST_WIDE_HIGHSIXTEEN,
            # array
            "aget-object": self.AGET_OBJECT,
        }

        self.table_obj = TableObject(MAX_REG_COUNT)
        self.ret_stack = []
コード例 #2
0
    def test_init(self, table_obj):
        with pytest.raises(TypeError):
            table_obj_with_no_argu = TableObject()

        assert isinstance(table_obj, TableObject)
        assert table_obj.hash_table == [[], [], [], [], []]
        assert len(table_obj.hash_table) == 5
コード例 #3
0
class PyEval:
    def __init__(self):
        # Main switch for executing the bytecode instruction.
        self.eval = {
            # invoke-kind
            "invoke-virtual": self.INVOKE_VIRTUAL,
            "invoke-direct": self.INVOKE_DIRECT,
            "invoke-static": self.INVOKE_STATIC,
            "invoke-virtual/range": self.INVOKE_VIRTUAL_RANGE,
            "invoke-interface": self.INVOKE_INTERFACE,
            # move-result-kind
            "move-result": self.MOVE_RESULT,
            "move-result-wide": self.MOVE_RESULT_WIDE,
            "move-result-object": self.MOVE_RESULT_OBJECT,
            # instance-kind
            "new-instance": self.NEW_INSTANCE,
            # const-kind
            "const-string": self.CONST_STRING,
            "const": self.CONST,
            "const/4": self.CONST_FOUR,
            "const/16": self.CONST_SIXTEEN,
            "const/high16": self.CONST_HIGHSIXTEEN,
            "const-wide": self.CONST_WIDE,
            "const-wide/16": self.CONST_WIDE_SIXTEEN,
            "const-wide/32": self.CONST_WIDE_THIRTY_TWO,
            "const-wide/high16": self.CONST_WIDE_HIGHSIXTEEN,
            # array
            "aget-object": self.AGET_OBJECT,
        }

        self.table_obj = TableObject(MAX_REG_COUNT)
        self.ret_stack = []

    def _invoke(self, instruction):
        """
        Function call in Android smali code. It will check if the corresponding table field has a value, if it does,
        inserts its own function name into called_by_func column.
        """

        executed_fuc = instruction[-1]
        reg_list = instruction[1:len(instruction) - 1]
        value_of_reg_list = []

        # query the value from hash table based on register index.
        for reg in reg_list:
            index = int(reg[1:])
            obj_stack = self.table_obj.get_obj_list(index)
            if obj_stack:
                var_obj = self.table_obj.pop(index)
                value_of_reg_list.append(var_obj.value)

        # 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 = f"{executed_fuc}({','.join(value_of_reg_list)})"

        # push the return value into ret_stack
        self.ret_stack.append(f"{executed_fuc}({','.join(value_of_reg_list)})")

    def _move(self, instruction):

        reg = instruction[1]
        index = int(reg[1:])
        try:
            pre_ret = self.ret_stack.pop()
            variable_object = RegisterObject(reg, pre_ret)
            self.table_obj.insert(index, variable_object)
        except IndexError as e:

            log.exception(f"{e} in _move")

    def _assign_value(self, instruction):

        reg = instruction[1]
        value = instruction[2]
        index = int(reg[1:])

        variable_object = RegisterObject(reg, value)
        self.table_obj.insert(index, variable_object)

    def _assign_value_wide(self, instruction):
        """
        For 64 bit, it has two register, which is vx and vx+1
        """
        reg = instruction[1]
        value = instruction[2]
        index = int(reg[1:])
        reg_plus_one = f"v{index + 1}"

        variable_object = RegisterObject(reg, value)
        variable_object2 = RegisterObject(reg_plus_one, value)
        self.table_obj.insert(index, variable_object)
        self.table_obj.insert(index + 1, variable_object2)

    @logger
    def INVOKE_VIRTUAL(self, instruction):
        """
        invoke-virtual { parameters }, methodtocall

        Invokes a virtual method with parameters.
        """
        self._invoke(instruction)

    @logger
    def INVOKE_DIRECT(self, instruction):
        """
        invoke-direct { parameters }, methodtocall

        Invokes a method with parameters without the virtual method resolution. (first parameter is "this")
        """
        self._invoke(instruction)

    @logger
    def INVOKE_STATIC(self, instruction):
        """
        invoke-static {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)

    @logger
    def INVOKE_INTERFACE(self, instruction):
        """
        invoke-interface { parameters }, methodtocall
        Invokes a interface method with parameters.
        """
        self._invoke(instruction)

    @logger
    def MOVE_RESULT(self, instruction):
        """
        move-result vx

        Move the result value of the previous method invocation into vx.

        Save the value returned by the previous function call to the vx register,and then insert the VariableObject
        into table.
        """
        self._move(instruction)

    @logger
    def MOVE_RESULT_WIDE(self, instruction):
        """
        move-result-wide vx

        Move the long/double result value of the previous method invocation into vx,vx+1.
        """
        reg = instruction[1]
        index = int(reg[1:])
        try:
            pre_ret = self.ret_stack.pop()
            variable_object = RegisterObject(reg, pre_ret)
            variable_object2 = RegisterObject(f"v{index + 1}", pre_ret)
            self.table_obj.insert(index, variable_object)
            self.table_obj.insert(index + 1, variable_object2)
        except IndexError as e:
            log.exception(f"{e} in MOVE_RESULT_WIDE")

    @logger
    def MOVE_RESULT_OBJECT(self, instruction):
        """
        move-result-object vx

        Move the result object reference of the previous method invocation into vx.

        Save the value returned by the previous function call to the vx register,and then insert the VariableObject
        into table.
        """

        self._move(instruction)

    @logger
    def NEW_INSTANCE(self, instruction):
        """
        new-instance vx,type

        Instantiates an object type and puts the reference of the newly created instance into vx.

        Store variables to vx, and then insert the VariableObject into table.
        """

        self._assign_value(instruction)

    @logger
    def CONST_STRING(self, instruction):
        """
        const-string vx,string_id

        Puts reference to a string constant identified by string_id into vx.

        Store string variable to vx, and then insert the VariableObject into table.
        """

        self._assign_value(instruction)

    @logger
    def CONST(self, instruction):
        """
        const vx, lit32

        Puts the integer constant into vx.
        """
        self._assign_value(instruction)

    @logger
    def CONST_FOUR(self, instruction):
        """
        const/4 vx,lit4

        Puts the 4 bit constant into vx.

        Store 4 bit constant into vx, and then insert the VariableObject into table.
        """

        self._assign_value(instruction)

    @logger
    def CONST_SIXTEEN(self, instruction):
        """
        const/16 vx,lit16

        Puts the 4 bit constant into vx.
        """
        self._assign_value(instruction)

    @logger
    def CONST_HIGHSIXTEEN(self, instruction):
        """
        const/high16 v0, lit16

        Puts the 16 bit constant into the topmost bits of the register. Used to initialize float values.
        """

        self._assign_value(instruction)

    @logger
    def CONST_WIDE(self, instruction):
        """
        const-wide vx, lit64

        Puts the 64 bit constant into vx and vx+1 registers.
        """
        self._assign_value_wide(instruction)

    @logger
    def CONST_WIDE_SIXTEEN(self, instruction):
        """
        const-wide/16 vx, lit16

        Puts the integer constant into vx and vx+1 registers, expanding the integer constant into a long constant.
        """
        self._assign_value_wide(instruction)

    @logger
    def CONST_WIDE_THIRTY_TWO(self, instruction):
        """
        const-wide/32 vx, lit32

        Puts the 32 bit constant into vx and vx+1 registers, expanding the integer constant into a long constant.
        """
        self._assign_value_wide(instruction)

    @logger
    def CONST_WIDE_HIGHSIXTEEN(self, instruction):
        """
        const-wide/high16 vx,lit16

        Puts the 16 bit constant into the highest 16 bit of vx and vx+1 registers. Used to initialize double values.
        """
        self._assign_value_wide(instruction)

    @logger
    def AGET_OBJECT(self, instruction):
        """
        aget-object vx,vy,vz

        Gets an object reference value of an object reference array into vx. The array is referenced by vy and is
        indexed by vz.

        It means vx = vy[vz].
        """

        reg = instruction[1]
        index = int(reg[1:])

        try:

            array_obj = self.table_obj.get_obj_list(
                int(re.sub("[^0-9]", "", instruction[2][1:])), ).pop()
            array_index = self.table_obj.get_obj_list(
                int(re.sub("[^0-9]", "", instruction[3])), ).pop()

            variable_object = RegisterObject(
                reg,
                f"{array_obj.value}[{array_index.value}]",
            )
            self.table_obj.insert(index, variable_object)

        except IndexError as e:
            log.exception(f"{e} in AGET_OBJECT")

    def show_table(self):
        return self.table_obj.get_table()
コード例 #4
0
def table_obj():
    table_obj = TableObject(5)

    yield table_obj

    del table_obj