def get_instruction_low_level_il(self, data, addr, il):
        opcode, length = self.parse_instruction(data, addr)

        op = opcodes[opcode]

        if addr == 0x10000:
            il.append(
                il.set_reg(4, 'ptr', il.const(1, 0))
            )

        if op == "Right":
            il.append(
                il.set_reg(4, 'ptr', il.add(
                    4, il.reg(4, 'ptr'), il.const(1, 1)), None)
            )
        elif op == "Left":
            il.append(
                il.set_reg(4, 'ptr', il.sub(
                    4, il.reg(4, 'ptr'), il.const(1, 1)), None)
            )
        elif op == "Add":
            il.append(
                il.store(1, il.reg(4, 'ptr'), il.add(
                    1, il.load(1, il.reg(4, 'ptr')), il.const(1, 1)), None)
            )
        elif op == "Subtract":
            il.append(
                il.store(1, il.reg(4, 'ptr'), il.sub(
                    1, il.load(1, il.reg(4, 'ptr')), il.const(1, 1)), None)
            )
        elif op == "In":
            il.append(
                il.unimplemented()
            )
        elif op == "Out":
            il.append(
                il.unimplemented()
            )
        elif op == "Open":
            true_label = il.get_label_for_address(
                Architecture['Brainfuck'], addr + 1)

            br = BinaryReader(il._source_function._view)
            br.seek(addr+1)
            # print("Found Open at : ", br.offset-1)
            counter = 1
            while counter != 0:
                instr = opcodes[br.read8()]
                if instr == "Open":
                    counter += 1
                elif instr == "Close":
                    counter -= 1
                    if counter == 0:
                        false_label = il.get_label_for_address(
                            Architecture['Brainfuck'], br.offset)
                        # print("Found loop close at offset : ", br.offset-1)
                        break
                elif br.offset == il._source_function._view.end:
                    print("Unfinished loop! This should never happen!")
                    return

            il.append(
                il.if_expr(il.compare_not_equal(1, il.load(
                    1, il.reg(4, 'ptr')), il.const(1, 0)), true_label, false_label)
            )
        elif op == "Close":
            false_label = il.get_label_for_address(
                Architecture['Brainfuck'], addr + 1)

            br = BinaryReader(il._source_function._view)
            br.seek(addr)
            # print("Found Close at : ", br.offset)
            counter = 1
            while counter != 0:
                br.seek_relative(-2)
                instr = opcodes[br.read8()]
                if instr == "Close":
                    counter += 1
                elif instr == "Open":
                    counter -= 1
                    if counter == 0:
                        true_label = il.get_label_for_address(
                            Architecture['Brainfuck'], br.offset)
                        # print("Found loop Open at offset : ", br.offset-1)
                        break
                elif br.offset == il._source_function._view.end:
                    print("Unfinished loop! This should never happen!")
                    return

            il.append(
                il.if_expr(il.compare_not_equal(1, il.load(
                    1, il.reg(4, 'ptr')), il.const(1, 0)), true_label, false_label)
            )
        else:
            il.append(
                il.nop()
            )

        return length
Exemple #2
0
class DelphiAnalyzer(object):
    '''
    TODO: Doc
    '''
    def __init__(self,
                 bv: BinaryView,
                 delphi_version: int,
                 offset_ptr_size=-1,
                 start=-1,
                 end=-1):
        self._offset_ptr_size = offset_ptr_size if offset_ptr_size > 0 else bv.address_size
        self._start = start if start >= 0 else bv.start
        self._end = end if end > 0 else bv.end
        self._vmt_list: List[DelphiVMT] = []
        self._bv = bv
        self._br = BinaryReader(bv)
        self._delphi_version = delphi_version
        self._vmt_offsets = VMTOffsets(delphi_version, self._offset_ptr_size)

        # Not really sure about this but it's working on my test binary (Win64 Delphi v10.3)
        # Need to check offsets for macOS
        # I'll clean that later
        if self._bv.view_type == 'PE' and self._offset_ptr_size == 8:
            for x, y in self._vmt_offsets.__dict__.items():
                setattr(self._vmt_offsets, x, y + -24)

    ## Properties

    @property
    def start(self) -> int:
        return self._start

    @property
    def end(self) -> int:
        return self._end

    @property
    def delphi_version(self) -> int:
        return self._delphi_version

    @property
    def vmt_list(self) -> List[DelphiVMT]:
        return self._vmt_list

    @property
    def vmt_offsets(self) -> VMTOffsets:
        return copy.copy(self._vmt_offsets)

    ## Public API

    def update_analysis_and_wait(self,
                                 callback: Callable[[DelphiVMT], None] = None):
        self._vmt_list = []
        self._seek_to_offset(0)

        while True:
            addy = self._get_possible_vmt()

            if addy is None:
                break

            delphi_vmt = DelphiVMT(self._bv, self._delphi_version, addy, self,
                                   self._offset_ptr_size)

            if not delphi_vmt.is_valid:
                continue

            self._vmt_list.append(delphi_vmt)

            if callback is not None:
                callback(delphi_vmt)

    ## Protected methods

    def _seek_to_offset(self, offset: int):
        self._br.seek(self._start + offset)

    def _read_ptr(self) -> Union[None, int]:
        if self._offset_ptr_size == 4:
            return self._br.read32()
        elif self._offset_ptr_size == 8:
            return self._br.read64()

    def _get_possible_vmt(self) -> int:
        while self._br.offset <= self._end - self._offset_ptr_size - 1:
            begin = self._br.offset

            if not self._bv.is_valid_offset(begin):
                self._br.seek_relative(self._offset_ptr_size)
                continue

            class_vmt = self._read_ptr()

            if class_vmt is None:
                # If BinaryReader can't read, it will not update the offset
                self._br.seek_relative(self._offset_ptr_size)
                continue

            if begin == class_vmt + self._vmt_offsets.cVmtSelfPtr:
                return class_vmt