Пример #1
0
def _extract_messagetable(dll: pefile.PE, locale_id: LocaleID) -> Mapping[int, str]:
    mmap = dll.get_memory_mapped_image()
    entries = dll.DIRECTORY_ENTRY_RESOURCE.entries
    offset, size = _traverse_resources(entries, (RT_MESSAGETABLE, 1, locale_id.value))

    data = mmap[offset : offset + size]
    return dict(_read_messagetable_resource(data))
Пример #2
0
def get_icon_group(pe_file: pefile.PE,
                   data_entry: pefile.Structure) -> Optional[list]:
    try:
        data_rva = data_entry.OffsetToData
        size = data_entry.Size
        data = pe_file.get_memory_mapped_image()[data_rva:data_rva + size]
        file_offset = pe_file.get_offset_from_rva(data_rva)

        grp_icon_dir = pefile.Structure(GRPICONDIR_format,
                                        file_offset=file_offset)
        grp_icon_dir.__unpack__(data)

        if grp_icon_dir.Reserved == 0 or grp_icon_dir.Type == 1:
            offset = grp_icon_dir.sizeof()
            entries = list()
            for idx in range(0, grp_icon_dir.Count):
                grp_icon = pefile.Structure(GRPICONDIRENTRY_format,
                                            file_offset=file_offset + offset)
                grp_icon.__unpack__(data[offset:])
                offset += grp_icon.sizeof()
                entries.append(grp_icon)
            return entries
    except pefile.PEFormatError:
        pass
    return None
Пример #3
0
    def map_and_load(self, path, execute_now=False):
        ql = self.ql
        pe = PE(path, fast_load=True)

        # Make sure no module will occupy the NULL page
        if self.next_image_base > pe.OPTIONAL_HEADER.ImageBase:
            IMAGE_BASE = self.next_image_base
            pe.relocate_image(IMAGE_BASE)
        else:
            IMAGE_BASE = pe.OPTIONAL_HEADER.ImageBase
        IMAGE_SIZE = ql.mem.align(pe.OPTIONAL_HEADER.SizeOfImage, 0x1000)

        while IMAGE_BASE + IMAGE_SIZE < self.heap_base_address:
            if not ql.mem.is_mapped(IMAGE_BASE, 1):
                self.next_image_base = IMAGE_BASE + 0x10000
                ql.mem.map(IMAGE_BASE, IMAGE_SIZE)
                pe.parse_data_directories()
                data = bytearray(pe.get_memory_mapped_image())
                ql.mem.write(IMAGE_BASE, bytes(data))
                logging.info("[+] Loading %s to 0x%x" % (path, IMAGE_BASE))
                entry_point = IMAGE_BASE + pe.OPTIONAL_HEADER.AddressOfEntryPoint
                if self.entry_point == 0:
                    # Setting entry point to the first loaded module entry point, so the debugger can break.
                    self.entry_point = entry_point
                logging.info("[+] PE entry point at 0x%x" % entry_point)
                self.install_loaded_image_protocol(IMAGE_BASE, IMAGE_SIZE)
                self.images.append(
                    self.coverage_image(
                        IMAGE_BASE,
                        IMAGE_BASE + pe.NT_HEADERS.OPTIONAL_HEADER.SizeOfImage,
                        path))
                if execute_now:
                    logging.info(
                        f'[+] Running from 0x{entry_point:x} of {path}')
                    assembler = self.ql.create_assembler()
                    code = f"""
                        mov rcx, {IMAGE_BASE}
                        mov rdx, {self.gST}
                        mov rax, {entry_point}
                        call rax
                    """
                    runcode, _ = assembler.asm(code)
                    ptr = ql.os.heap.alloc(len(runcode))
                    ql.mem.write(ptr, bytes(runcode))
                    ql.os.exec_arbitrary(ptr, ptr + len(runcode))

                else:
                    self.modules.append((path, IMAGE_BASE, entry_point, pe))
                return True
            else:
                IMAGE_BASE += 0x10000
                pe.relocate_image(IMAGE_BASE)
        return False
Пример #4
0
    def configExtract(rawData):
        pe = PE(data=rawData)

        try:
            rt_string_idx = [
                entry.id for entry in
                pe.DIRECTORY_ENTRY_RESOURCE.entries].index(RESOURCE_TYPE['RT_RCDATA'])
        except ValueError as e:
            return None
        except AttributeError as e:
            return None

        rt_string_directory = pe.DIRECTORY_ENTRY_RESOURCE.entries[rt_string_idx]

        for entry in rt_string_directory.directory.entries:
            if str(entry.name) == "CFG":
                data_rva = entry.directory.entries[0].data.struct.OffsetToData
                size = entry.directory.entries[0].data.struct.Size
                data = pe.get_memory_mapped_image()[data_rva:data_rva + size]
                return data
Пример #5
0
    def config_extract(raw_data):
        try:
            pe = PE(data=raw_data)

            try:
                rt_string_idx = [
                    entry.id for entry in
                    pe.DIRECTORY_ENTRY_RESOURCE.entries].index(RESOURCE_TYPE['RT_RCDATA'])
            except ValueError:
                return None
            except AttributeError:
                return None

            rt_string_directory = pe.DIRECTORY_ENTRY_RESOURCE.entries[rt_string_idx]

            for entry in rt_string_directory.directory.entries:
                if str(entry.name) == "XX-XX-XX-XX" or str(entry.name) == "CG-CG-CG-CG":
                    data_rva = entry.directory.entries[0].data.struct.OffsetToData
                    size = entry.directory.entries[0].data.struct.Size
                    data = pe.get_memory_mapped_image()[data_rva:data_rva + size]
                    config = data.split('####@####')
                    return config
        except:
            return None
Пример #6
0
def get_icon(pe_file: pefile.PE, icon_rsrcs: pefile.ResourceDirEntryData,
             idx: int) -> Optional[bytearray]:
    if idx < 0:
        try:
            idx = [entry.id
                   for entry in icon_rsrcs.directory.entries].index(-idx)
        except ValueError:
            return None
    else:
        idx = idx if idx < len(icon_rsrcs.directory.entries) else None

    if idx is None:
        return None

    icon_id = icon_rsrcs.directory.entries[idx]
    icon_entry = icon_id.directory.entries[0]

    if icon_entry.struct.DataIsDirectory:
        return None

    data_rva = icon_entry.data.struct.OffsetToData
    size = icon_entry.data.struct.Size
    data = pe_file.get_memory_mapped_image()[data_rva:data_rva + size]
    return data
Пример #7
0
    def map_and_load(self, path: str, exec_now: bool = False):
        """Map and load a module into memory.

        The specified module would be mapped and loaded into the address set
        in the `next_image_base` member. It is the caller's responsibility to
        make sure that the memory is available.

        On success, `next_image_base` will be updated accordingly.

        Args:
            path     : path of the module binary to load
            exec_now : execute module right away; will be enququed if not

        Raises:
            QlMemoryMappedError : when `next_image_base` is not available
        """

        ql = self.ql
        pe = PE(path, fast_load=True)

        # use image base only if it does not point to NULL
        image_base = pe.OPTIONAL_HEADER.ImageBase or self.next_image_base
        image_size = ql.mem.align(pe.OPTIONAL_HEADER.SizeOfImage, 0x1000)

        assert (image_base %
                0x1000) == 0, 'image base is expected to be page-aligned'

        if image_base != pe.OPTIONAL_HEADER.ImageBase:
            pe.relocate_image(image_base)

        pe.parse_data_directories()
        data = bytes(pe.get_memory_mapped_image())

        ql.mem.map(image_base, image_size, info="[module]")
        ql.mem.write(image_base, data)
        ql.log.info(f'Module {path} loaded to {image_base:#x}')

        entry_point = image_base + pe.OPTIONAL_HEADER.AddressOfEntryPoint
        ql.log.info(f'Module entry point at {entry_point:#x}')

        # the 'entry_point' member is used by the debugger. if not set, set it
        # to the first loaded module entry point so the debugger can break
        if self.entry_point == 0:
            self.entry_point = entry_point

        self.install_loaded_image_protocol(image_base, image_size)

        # this would be used later be os.find_containing_image
        self.images.append(
            self.coverage_image(image_base, image_base + image_size, path))

        # update next memory slot to allow sequencial loading. its availability
        # is unknown though
        self.next_image_base = image_base + image_size

        module_info = (path, image_base, entry_point)

        # execute the module right away or enqueue it
        if exec_now:
            # call entry point while retaining the current return address
            self.execute_module(*module_info, eoe_trap=None)
        else:
            self.modules.append(module_info)
Пример #8
0
    def get_icon_info(self, pe: pefile.PE) -> Tuple[str, str, str, str]:
        """Get icon in PNG format and information for searching for similar icons
        @return: tuple of (image data in PNG format encoded as base64, md5 hash of image data, md5 hash of "simplified"
         image for fuzzy matching)
        """
        if not pe or not hasattr(pe, "DIRECTORY_ENTRY_RESOURCE"):
            return None, None, None, None

        try:
            idx = [entry.id for entry in pe.DIRECTORY_ENTRY_RESOURCE.entries]
            if pefile.RESOURCE_TYPE["RT_GROUP_ICON"] not in idx:
                return None, None, None, None

            rt_group_icon_idx = idx.index(
                pefile.RESOURCE_TYPE["RT_GROUP_ICON"])
            rt_group_icon_dir = pe.DIRECTORY_ENTRY_RESOURCE.entries[
                rt_group_icon_idx]
            entry = rt_group_icon_dir.directory.entries[0]
            offset = entry.directory.entries[0].data.struct.OffsetToData
            size = entry.directory.entries[0].data.struct.Size
            peicon = PEGroupIconDir(
                pe.get_memory_mapped_image()[offset:offset + size])
            bigwidth = 0
            bigheight = 0
            bigbpp = 0
            bigidx = -1
            iconidx = 0
            if hasattr(peicon, "icons") and peicon.icons:
                for idx, icon in enumerate(peicon.icons):
                    if icon.bWidth >= bigwidth and icon.bHeight >= bigheight and icon.wBitCount >= bigbpp:
                        bigwidth = icon.bWidth
                        bigheight = icon.bHeight
                        bigbpp = icon.wBitCount
                        bigidx = icon.nID
                        iconidx = idx

            rt_icon_idx = False
            rt_icon_idx_tmp = [
                entry.id for entry in pe.DIRECTORY_ENTRY_RESOURCE.entries
            ]
            if pefile.RESOURCE_TYPE["RT_ICON"] in rt_icon_idx_tmp:
                rt_icon_idx = rt_icon_idx_tmp.index(
                    pefile.RESOURCE_TYPE["RT_ICON"])
            if not isinstance(rt_icon_idx, int):
                return None, None, None, None
            rt_icon_dir = pe.DIRECTORY_ENTRY_RESOURCE.entries[rt_icon_idx]
            for entry in rt_icon_dir.directory.entries:
                if entry.id == bigidx:
                    offset = entry.directory.entries[
                        0].data.struct.OffsetToData
                    size = entry.directory.entries[0].data.struct.Size
                    icon = peicon.get_icon_file(
                        iconidx,
                        pe.get_memory_mapped_image()[offset:offset + size])

                    with BytesIO() as byteio:
                        byteio.write(icon)
                        byteio.seek(0)
                        try:
                            with Image.open(
                                    byteio) as img, BytesIO() as output:
                                img.save(output, format="PNG")

                                dhash = self.generate_icon_dhash(img)

                                img = (img.resize(
                                    (8, 8),
                                    Image.BILINEAR).convert("RGB").convert(
                                        "P", palette=Image.ADAPTIVE,
                                        colors=2).convert("L"))
                                lowval = img.getextrema()[0]
                                img = img.point(lambda i: 255 if i > lowval
                                                else 0).convert("1")
                                simplified = bytearray(img.getdata())

                                m = hashlib.md5()
                                m.update(output.getvalue())
                                fullhash = m.hexdigest()

                                m = hashlib.md5()
                                m.update(simplified)
                                simphash = m.hexdigest()
                                icon = base64.b64encode(
                                    output.getvalue()).decode()
                        except ValueError:
                            log.error(
                                "parse_pe.py -> get_incon_info -> buffer is not large enough"
                            )
                            return None, None, None, None
                        except OSError as e:
                            log.error(e)
                            return None, None, None, None
                    return icon, fullhash, simphash, dhash
        except Exception as e:
            log.error(e, exc_info=True)

        return None, None, None, None