Exemple #1
0
def ql_create_assembler(archtype: QL_ARCH,
                        archendian: QL_ENDIAN,
                        reg_cpsr=None) -> Ks:
    if archtype == QL_ARCH.X86:
        ks = Ks(KS_ARCH_X86, KS_MODE_32)

    elif archtype == QL_ARCH.X8664:
        ks = Ks(KS_ARCH_X86, KS_MODE_64)

    elif archtype == QL_ARCH.ARM:
        mode = KS_MODE_THUMB if reg_cpsr & __reg_cpsr_v[
            archendian] else KS_MODE_ARM

        ks = Ks(KS_ARCH_ARM,
                mode)  # FIXME: should be: mode + __ks_endian[archendian]

    elif archtype == QL_ARCH.ARM_THUMB:
        ks = Ks(KS_ARCH_ARM, KS_MODE_THUMB)

    elif archtype == QL_ARCH.ARM64:
        ks = Ks(KS_ARCH_ARM64, KS_MODE_LITTLE_ENDIAN)

    elif archtype == QL_ARCH.MIPS:
        ks = Ks(KS_ARCH_MIPS, KS_MODE_MIPS32 + __ks_endian[archendian])

    elif archtype == QL_ARCH.A8086:
        ks = Ks(KS_ARCH_X86, KS_MODE_16)

    elif archtype == QL_ARCH.EVM:
        raise NotImplementedError('evm')

    else:
        raise QlErrorArch(f'{archtype:d}')

    return ks
Exemple #2
0
def ql_create_disassembler(archtype: QL_ARCH,
                           archendian: QL_ENDIAN,
                           reg_cpsr=None) -> Cs:
    if archtype == QL_ARCH.X86:
        md = Cs(CS_ARCH_X86, CS_MODE_32)

    elif archtype == QL_ARCH.X8664:
        md = Cs(CS_ARCH_X86, CS_MODE_64)

    elif archtype == QL_ARCH.ARM:
        mode = CS_MODE_THUMB if reg_cpsr & __reg_cpsr_v[
            archendian] else CS_MODE_ARM

        md = Cs(CS_ARCH_ARM,
                mode)  # FIXME: should be: mode + __cs_endian[archendian]

    elif archtype == QL_ARCH.ARM_THUMB:
        md = Cs(CS_ARCH_ARM, CS_MODE_THUMB)

    elif archtype == QL_ARCH.ARM64:
        md = Cs(CS_ARCH_ARM64, CS_MODE_ARM)

    elif archtype == QL_ARCH.MIPS:
        md = Cs(CS_ARCH_MIPS, CS_MODE_MIPS32 + __cs_endian[archendian])

    elif archtype == QL_ARCH.A8086:
        md = Cs(CS_ARCH_X86, CS_MODE_16)

    elif archtype == QL_ARCH.EVM:
        raise NotImplementedError('evm')

    else:
        raise QlErrorArch(f'{archtype:d}')

    return md
Exemple #3
0
    def run(self):
        ql = self.ql

        # intel architecture uefi implementation only
        if ql.arch.type not in (QL_ARCH.X86, QL_ARCH.X8664):
            raise QlErrorArch("Unsupported architecture")

        # x86-64 arch only
        if ql.arch.type != QL_ARCH.X8664:
            raise QlErrorArch(
                "Only 64-bit modules are supported at the moment")

        self.loaded_image_protocol_guid = ql.os.profile[
            "LOADED_IMAGE_PROTOCOL"]["Guid"]
        self.tpl = 4  # TPL_APPLICATION

        # TODO: assign context to os rather than loader
        self.dxe_context = self.__init_dxe_environment(ql)
        self.smm_context = self.__init_smm_environment(ql)

        self.entry_point = 0
        self.load_address = 0

        try:
            for dependency in ql.argv:

                # TODO: determine whether this is an smm or dxe module
                is_smm_module = 'Smm' in dependency

                if is_smm_module:
                    self.context = self.smm_context
                else:
                    self.context = self.dxe_context

                self.map_and_load(dependency, self.context)

            ql.log.info(f"Done loading modules")

        except QlMemoryMappedError:
            ql.log.critical("Could not map dependency")

        self.set_exit_hook(self.dxe_context.end_of_execution_ptr)
        self.set_exit_hook(self.smm_context.end_of_execution_ptr)

        self.execute_next_module()
Exemple #4
0
    def get_init_uc(self) -> Uc:
        if self.ql.archendian == QL_ENDIAN.EB:
            mode = UC_MODE_ARM + UC_MODE_BIG_ENDIAN

        elif self.ql.archtype == QL_ARCH.ARM_THUMB:
            mode = UC_MODE_THUMB

        elif self.ql.archtype == QL_ARCH.ARM:
            mode = UC_MODE_ARM

        else:
            raise QlErrorArch(f'unsupported arch type {self.ql.archtype}')

        return Uc(UC_ARCH_ARM, mode)
Exemple #5
0
    def create_assembler(self) -> Ks:
        # note: we do not cache the assembler instance; rather we refresh it
        # each time to make sure thumb mode is taken into account

        if self.ql.archtype == QL_ARCH.ARM:
            # FIXME: mode should take endianess into account
            mode = KS_MODE_THUMB if self.__is_thumb() else KS_MODE_ARM

        elif self.ql.archtype == QL_ARCH.ARM_THUMB:
            mode = KS_MODE_THUMB

        else:
            raise QlErrorArch(f'unexpected arch type {self.ql.archtype}')

        return Ks(KS_ARCH_ARM, mode)
def create_disassembler(ql: Qiling):
    if ql.archtype == QL_ARCH.ARM:  # QL_ARM
        reg_cpsr = ql.reg.cpsr
        mode = CS_MODE_ARM
        if ql.archendian == QL_ENDIAN.EB:
            reg_cpsr_v = 0b100000
            # reg_cpsr_v = 0b000000
        else:
            reg_cpsr_v = 0b100000

        if reg_cpsr & reg_cpsr_v != 0:
            mode = CS_MODE_THUMB

        if ql.archendian == QL_ENDIAN.EB:
            md = Cs(CS_ARCH_ARM, mode)
            # md = Cs(CS_ARCH_ARM, mode + CS_MODE_BIG_ENDIAN)
        else:
            md = Cs(CS_ARCH_ARM, mode)

    elif ql.archtype == QL_ARCH.ARM_THUMB:
        md = Cs(CS_ARCH_ARM, CS_MODE_THUMB)

    elif ql.archtype == QL_ARCH.X86:  # QL_X86
        md = Cs(CS_ARCH_X86, CS_MODE_32)

    elif ql.archtype == QL_ARCH.X8664:  # QL_X86_64
        md = Cs(CS_ARCH_X86, CS_MODE_64)

    elif ql.archtype == QL_ARCH.ARM64:  # QL_ARM64
        md = Cs(CS_ARCH_ARM64, CS_MODE_ARM)

    elif ql.archtype == QL_ARCH.A8086:  # QL_A8086
        md = Cs(CS_ARCH_X86, CS_MODE_16)

    elif ql.archtype == QL_ARCH.MIPS:  # QL_MIPS32
        if ql.archendian == QL_ENDIAN.EB:
            md = Cs(CS_ARCH_MIPS, CS_MODE_MIPS32 + CS_MODE_BIG_ENDIAN)
        else:
            md = Cs(CS_ARCH_MIPS, CS_MODE_MIPS32 + CS_MODE_LITTLE_ENDIAN)

    else:
        raise QlErrorArch(
            "[!] Unknown arch defined in utils.py (debug output mode)")

    return md
Exemple #7
0
    def run(self):
        # intel architecture uefi implementation only
        if self.ql.archtype not in (QL_ARCH.X86, QL_ARCH.X8664):
            raise QlErrorArch("Unsupported architecture")

        # x86-64 arch only
        if self.ql.archtype != QL_ARCH.X8664:
            raise QlErrorArch("Only 64 bit arch is supported at the moment")

        self.loaded_image_protocol_guid = self.ql.os.profile[
            "LOADED_IMAGE_PROTOCOL"]["Guid"]
        self.loaded_image_protocol_modules = []
        self.tpl = 4  # TPL_APPLICATION

        self.user_defined_api = self.ql.os.user_defined_api
        self.user_defined_api_onenter = self.ql.os.user_defined_api_onenter
        self.user_defined_api_onexit = self.ql.os.user_defined_api_onexit

        arch_key = {
            QL_ARCH.X86: "OS32",
            QL_ARCH.X8664: "OS64"
        }[self.ql.archtype]

        # -------- init BS / RT / DXE data structures and protocols --------

        os_profile = self.ql.os.profile[arch_key]
        self.dxe_context = context.DxeContext(self.ql)

        # initialize and locate heap
        heap_base = int(os_profile["heap_address"], 0)
        heap_size = int(os_profile["heap_size"], 0)
        self.dxe_context.init_heap(heap_base, heap_size)
        self.heap_base_address = heap_base
        self.ql.log.info(f"Located heap at {heap_base:#010x}")

        # initialize and locate stack
        stack_base = int(os_profile["stack_address"], 0)
        stack_size = int(os_profile["stack_size"], 0)
        self.dxe_context.init_stack(stack_base, stack_size)
        sp = stack_base + stack_size - CPU_STACK_ALIGNMENT
        self.ql.log.info(f"Located stack at {sp:#010x}")

        # TODO: statically allocating 256 KiB for ST, RT, BS, DS and Configuration Tables.
        # however, this amount of memory is rather arbitrary
        gST = self.dxe_context.heap.alloc(256 * 1024)
        st.initialize(self.ql, gST)

        protocols = (
            EfiSmmAccess2Protocol,
            EfiSmmBase2Protocol,
        )

        for proto in protocols:
            self.dxe_context.install_protocol(proto.descriptor, 1)

        # workaround
        self.ql.os.heap = self.dxe_context.heap

        # -------- init SMM data structures and protocols --------

        smm_profile = self.ql.os.profile['SMRAM']
        self.smm_context = context.SmmContext(self.ql)

        # initialize and locate SMM heap
        heap_base = int(smm_profile["heap_address"], 0)
        heap_size = int(smm_profile["heap_size"], 0)
        self.smm_context.init_heap(heap_base, heap_size)
        self.ql.log.info(f"Located SMM heap at {heap_base:#010x}")

        # TODO: statically allocating 256 KiB for SMM ST.
        # however, this amount of memory is rather arbitrary
        gSmst = self.smm_context.heap.alloc(256 * 1024)
        smst.initialize(self.ql, gSmst)

        self.in_smm = False

        protocols = (EfiSmmCpuProtocol, EfiSmmSwDispatch2Protocol)

        for proto in protocols:
            self.smm_context.install_protocol(proto.descriptor, 1)

        # map mmio ranges
        # TODO: move to somehwere more appropriate (+ hook accesses?)
        mmio_map = self.ql.os.profile["MMIO"]
        self.ql.mem.map(int(mmio_map['sbreg_base'], 0),
                        int(mmio_map['sbreg_size'], 0))

        # set stack and frame pointers
        self.ql.reg.rsp = sp
        self.ql.reg.rbp = sp

        self.entry_point = 0
        self.load_address = 0
        self.next_image_base = int(os_profile["image_address"], 0)

        try:
            for dependency in self.ql.argv:
                self.map_and_load(dependency)
        except QlMemoryMappedError:
            self.ql.log.critical("Couldn't map dependency")

        self.ql.log.info(f"Done with loading {self.ql.path}")

        # set up an end-of-execution hook to regain control when module is done
        # executing (i.e. when the entry point function returns). that should be
        # set on a non-executable address, so SystemTable's address was picked
        self.end_of_execution_ptr = gST
        self.ql.hook_address(hook_EndOfExecution, self.end_of_execution_ptr)

        self.execute_next_module()
Exemple #8
0
    def load(self, pe: Optional[pefile.PE]):
        # set stack pointer
        self.ql.log.info("Initiate stack address at 0x%x " %
                         self.stack_address)
        self.ql.mem.map(self.stack_address, self.stack_size, info="[stack]")

        if pe is not None:
            image_name = os.path.basename(self.path)
            image_base = pe.OPTIONAL_HEADER.ImageBase
            image_size = self.ql.mem.align_up(pe.OPTIONAL_HEADER.SizeOfImage)

            # if default base address is taken, use the one specified in profile
            if not self.ql.mem.is_available(image_base, image_size):
                image_base = self.image_address
                pe.relocate_image(image_base)

            self.entry_point = image_base + pe.OPTIONAL_HEADER.AddressOfEntryPoint
            self.pe_image_address = image_base
            self.pe_image_size = image_size

            self.ql.log.info(f'Loading {self.path} to {image_base:#x}')
            self.ql.log.info(f'PE entry point at {self.entry_point:#x}')

            self.ql.mem.map(image_base, image_size, info=f'[{image_name}]')
            self.images.append(
                Image(image_base,
                      image_base + pe.NT_HEADERS.OPTIONAL_HEADER.SizeOfImage,
                      os.path.abspath(self.path)))

            if self.is_driver:
                self.init_driver_object()
                self.init_registry_path()
                self.init_eprocess()
                self.init_ki_user_shared_data()

                # set IRQ Level in CR8 to PASSIVE_LEVEL
                self.ql.arch.regs.write(UC_X86_REG_CR8, 0)

                # setup CR4, enabling: DE, PSE, PAE, MCE, PGE, OSFXSR and OSXMMEXCPT.
                # some drivers may check this at initialized
                self.ql.arch.regs.write(UC_X86_REG_CR4, 0b0000011011111000)

            else:
                # initialize thread information block
                self.init_teb()
                self.init_peb()
                self.init_ldr_data()
                self.init_exports(pe)

                # add image to ldr table
                self.add_ldr_data_table_entry(image_name)

            pe.parse_data_directories()

            # done manipulating pe file; write its contents into memory
            self.ql.mem.write(image_base, bytes(pe.get_memory_mapped_image()))

            if self.is_driver:
                # security cookie can be written only after image has been loaded to memory
                self.init_security_cookie(pe, image_base)

            # Stack should not init at the very bottom. Will cause errors with Dlls
            top_of_stack = self.stack_address + self.stack_size - 0x1000

            if self.ql.arch.type == QL_ARCH.X86:
                bp_reg = 'ebp'
                sp_reg = 'esp'
            elif self.ql.arch.type == QL_ARCH.X8664:
                bp_reg = 'rbp'
                sp_reg = 'rsp'
            else:
                raise QlErrorArch(f'unexpected arch type: {self.ql.arch.type}')

            # we are about to load some dlls and call their DllMain functions.
            # the stack should be set first
            self.ql.arch.regs.write(bp_reg, top_of_stack)
            self.ql.arch.regs.write(sp_reg, top_of_stack)

            # load system dlls
            for each in self.sys_dlls:
                super().load_dll(each, self.is_driver)

            # parse directory entry import
            self.ql.log.debug(f'Init imports for {self.path}')
            super().init_imports(pe, self.is_driver)

            self.ql.log.debug(f'Done loading {self.path}')

            if pe.is_driver():
                args = ((POINTER, self.driver_object_address),
                        (POINTER, self.regitry_path_address))

                self.ql.log.debug('Setting up call frame for DriverEntry:')
                self.ql.log.debug(
                    f'  PDRIVER_OBJECT   DriverObject : {args[0][1]:#010x}')
                self.ql.log.debug(
                    f'  PUNICODE_STRING  RegistryPath : {args[1][1]:#010x}')

                # We know that a driver will return, so if the user did not configure stop
                # options, write a sentinel return value
                ret = None if self.ql.stop_options else self.ql.stack_write(
                    0, 0xdeadc0de)

                # set up call frame for DriverEntry
                self.ql.os.fcall.call_native(self.entry_point, args, ret)

            elif pe.is_dll():
                args = (
                    (POINTER, image_base),
                    (DWORD, 1),  # DLL_PROCESS_ATTACH
                    (POINTER, 0))

                self.ql.log.debug('Setting up call frame for DllMain:')
                self.ql.log.debug(
                    f'  HINSTANCE hinstDLL   : {args[0][1]:#010x}')
                self.ql.log.debug(
                    f'  DWORD     fdwReason  : {args[1][1]:#010x}')
                self.ql.log.debug(
                    f'  LPVOID    lpReserved : {args[2][1]:#010x}')

                # set up call frame for DllMain
                self.ql.os.fcall.call_native(self.entry_point, args, None)

        elif pe is None:
            self.filepath = b""

            self.ql.mem.map(self.entry_point,
                            self.ql.os.code_ram_size,
                            info="[shellcode]")

            self.init_teb()
            self.init_peb()
            self.init_ldr_data()

            # write shellcode to memory
            self.ql.mem.write(self.entry_point, self.ql.code)

            top_of_stack = self.stack_address + self.stack_size

            if self.ql.arch.type == QL_ARCH.X86:
                bp_reg = 'ebp'
                sp_reg = 'esp'
            elif self.ql.arch.type == QL_ARCH.X8664:
                bp_reg = 'rbp'
                sp_reg = 'rsp'
            else:
                raise QlErrorArch(f'unexpected arch type: {self.ql.arch.type}')

            self.ql.arch.regs.write(bp_reg, top_of_stack)
            self.ql.arch.regs.write(sp_reg, top_of_stack)

            # load dlls
            for each in self.init_dlls:
                super().load_dll(each, self.is_driver)

        # move entry_point to ql.os
        self.ql.os.entry_point = self.entry_point
        self.init_sp = self.ql.arch.regs.arch_sp