Exemple #1
0
    def add_section(self,
                    hdr,
                    name,
                    VirtualSize,
                    VirtualAddress,
                    Characteristics=0xe0000020):
        if len(name) > 8:
            print("Error section name too long")
            return
        import_section_hdr = IMAGE_SECTION_HEADER(
            bytes(name, 'ascii'),  # Name
            VirtualSize,  # VirtualSize
            VirtualAddress,  # VirtualAddress
            VirtualSize,  # SizeOfRawData
            VirtualAddress,  # PointerToRawData
            0,  # PointerToRelocations
            0,  # PointerToLinenumbers
            0,  # NumberOfRelocations
            0,  # NumberOfLinenumbers
            Characteristics,  # Characteristics
        )

        hdr.section_list.append(import_section_hdr)

        # Correct Value of Number of Sections
        hdr.pe_header.NumberOfSections += 1

        # Fix SizeOfHeaders
        hdr.opt_header.SizeOfHeaders = alignments(
            hdr.opt_header.SizeOfHeaders + len(bytes(IMAGE_SECTION_HEADER())),
            hdr.opt_header.FileAlignment)

        return hdr
Exemple #2
0
    def add_import_section_api(self,
                               hdr,
                               virtualmemorysize,
                               totalsize,
                               check_space=True):
        # Set check_space to false if the pe-header was relocated

        if check_space:
            rva_to_section_table = hdr.dos_header.e_lfanew + len(
                bytes(_IMAGE_FILE_HEADER())) + len(
                    bytes(_IMAGE_OPTIONAL_HEADER()))
            number_of_sections = hdr.pe_header.NumberOfSections
            end_of_section_table = rva_to_section_table + len(
                bytes(IMAGE_SECTION_HEADER())) * number_of_sections

            beginning_of_first_section = sys.maxsize

            for section in hdr.section_list:
                if section.VirtualAddress < beginning_of_first_section:
                    beginning_of_first_section = section.VirtualAddress

            if end_of_section_table + len(bytes(
                    IMAGE_SECTION_HEADER())) >= beginning_of_first_section:
                print("Not enough space for additional section")
                return

        import_section = IMAGE_SECTION_HEADER(
            bytes(".impdata", 'ascii'),  # Name
            0x10000,  # VirtualSize
            virtualmemorysize - 0x10000,  # VirtualAddress
            0x10000,  # SizeOfRawData
            virtualmemorysize - 0x10000,  # PointerToRawData
            0,  # PointerToRelocations
            0,  # PointerToLinenumbers
            0,  # NumberOfRelocations
            0,  # NumberOfLinenumbers
            0xe0000020,  # Characteristics
        )

        hdr.section_list.append(import_section)

        # Correct Value of Number of Sections
        hdr.pe_header.NumberOfSections += 1

        # Fix SizeOfHeaders
        hdr.opt_header.SizeOfHeaders = alignments(
            hdr.opt_header.SizeOfHeaders + len(bytes(IMAGE_SECTION_HEADER())),
            hdr.opt_header.FileAlignment)

        return hdr
Exemple #3
0
    def init_uc(self):
        # Calculate required memory
        pe = pefile.PE(self.sample.path)
        self.sample.BASE_ADDR = pe.OPTIONAL_HEADER.ImageBase  # 0x400000
        self.sample.unpacker.BASE_ADDR = self.sample.BASE_ADDR
        self.sample.virtualmemorysize = self.getVirtualMemorySize()
        self.STACK_ADDR = 0x0
        self.STACK_SIZE = 1024 * 1024
        STACK_START = self.STACK_ADDR + self.STACK_SIZE
        # self.sample.unpacker.secs += [{"name": "stack", "vaddr": self.STACK_ADDR, "vsize": self.STACK_SIZE}]
        stack_sec_header = IMAGE_SECTION_HEADER(
            "stack".encode('ascii'),
            self.STACK_SIZE,
            self.STACK_ADDR,
            self.STACK_SIZE,
            0,
            0,
            0,
            0,
            0,
            0,
        )
        self.sample.unpacker.secs.append(SectionHeader(stack_sec_header))
        self.HOOK_ADDR = STACK_START + 0x3000 + 0x1000

        # Start unicorn emulator with x86-32bit architecture
        self.uc = Uc(UC_ARCH_X86, UC_MODE_32)
        if self.sample.unpacker.startaddr is None:
            self.sample.unpacker.startaddr = self.entrypoint(pe)
        self.sample.loaded_image = pe.get_memory_mapped_image(ImageBase=self.sample.BASE_ADDR)
        self.sample.virtualmemorysize = align(self.sample.virtualmemorysize + 0x10000,
                                              page_size=4096)  # Space possible IAT rebuilding
        self.sample.unpacker.virtualmemorysize = self.sample.virtualmemorysize
        self.uc.mem_map(self.sample.BASE_ADDR, self.sample.virtualmemorysize)
        self.uc.mem_write(self.sample.BASE_ADDR, self.sample.loaded_image)

        self.setup_processinfo()

        # Load DLLs
        self.load_dll(f"{os.path.dirname(unipacker.__file__)}/DLLs/KernelBase.dll", 0x73D00000)
        self.load_dll(f"{os.path.dirname(unipacker.__file__)}/DLLs/kernel32.dll", 0x755D0000)
        self.load_dll(f"{os.path.dirname(unipacker.__file__)}/DLLs/ntdll.dll", 0x77400000)

        # initialize machine registers
        self.uc.mem_map(self.STACK_ADDR, self.STACK_SIZE)
        self.uc.reg_write(UC_X86_REG_ESP, self.STACK_ADDR + int(self.STACK_SIZE / 2))
        self.uc.reg_write(UC_X86_REG_EBP, self.STACK_ADDR + int(self.STACK_SIZE / 2))
        self.uc.mem_write(self.uc.reg_read(UC_X86_REG_ESP) + 0x8, bytes([1]))  # -> PEtite Stack Operations?
        self.uc.reg_write(UC_X86_REG_EAX, self.sample.unpacker.startaddr)
        self.uc.reg_write(UC_X86_REG_EBX, self.PEB_BASE)
        self.uc.reg_write(UC_X86_REG_ECX, self.sample.unpacker.startaddr)
        self.uc.reg_write(UC_X86_REG_EDX, self.sample.unpacker.startaddr)
        self.uc.reg_write(UC_X86_REG_ESI, self.sample.unpacker.startaddr)
        self.uc.reg_write(UC_X86_REG_EDI, self.sample.unpacker.startaddr)
        self.uc.reg_write(UC_X86_REG_EFLAGS, 0x244)

        new_pe = PE(self.uc, self.sample.BASE_ADDR)
        prot_val = lambda x, y: True if x & y != 0 else False
        for s in new_pe.section_list:
            self.sample.atn[(
                s.VirtualAddress + self.sample.BASE_ADDR,
                s.VirtualAddress + self.sample.BASE_ADDR + s.VirtualSize)] = convert_to_string(
                s.Name)
            self.sample.ntp[convert_to_string(s.Name)] = (
                prot_val(s.Characteristics, 0x20000000), prot_val(s.Characteristics, 0x40000000),
                prot_val(s.Characteristics, 0x80000000))

        # for s in pe.sections:
        #    atn[(s.VirtualAddress + self.sample.BASE_ADDR, s.VirtualAddress + self.sample.BASE_ADDR + s.Misc_VirtualSize)] = s.Name
        #    ntp[s.Name] = (s.IMAGE_SCN_MEM_EXECUTE, s.IMAGE_SCN_MEM_READ, s.IMAGE_SCN_MEM_WRITE)

        # init syscall handling and prepare hook memory for return values
        self.apicall_handler = WinApiCalls(self)
        self.uc.mem_map(self.HOOK_ADDR, 0x1000)
        # self.sample.unpacker.secs += [{"name": "hooks", "vaddr": self.HOOK_ADDR, "vsize": 0x1000}]
        hook_sec_header = IMAGE_SECTION_HEADER(
            "hooks".encode('ascii'),
            0x1000,
            self.HOOK_ADDR,
            0x1000,
            0,
            0,
            0,
            0,
            0,
            0,
        )
        self.sample.unpacker.secs.append(SectionHeader(stack_sec_header))

        hexstr = bytes.fromhex('000000008b0425') + struct.pack('<I', self.HOOK_ADDR) + bytes.fromhex(
            'c3')  # mov eax, [HOOK]; ret -> values of syscall are stored in eax
        self.uc.mem_write(self.HOOK_ADDR, hexstr)

        # handle imports
        # TODO Update when custom loader available
        for lib in pe.DIRECTORY_ENTRY_IMPORT:
            descriptor = ImportDescriptor(None, lib.struct.Characteristics, lib.struct.TimeDateStamp,
                                          lib.struct.ForwarderChain, lib.struct.Name, lib.struct.FirstThunk)
            fct_list = []
            for i in lib.imports:
                fct_list.append(i.name)
            imp = Import(descriptor, lib.dll.decode('ascii'), fct_list)
            self.sample.original_imports.append(imp)
            for func in lib.imports:
                func_name = func.name.decode() if func.name is not None else f"no name: 0x{func.address:02x}"
                dll_name = lib.dll.decode() if lib.dll is not None else "-- unknown --"
                self.sample.imports.add(func_name)
                curr_hook_addr = self.apicall_handler.add_hook(self.uc, func_name, dll_name)
                self.uc.mem_write(func.address, struct.pack('<I', curr_hook_addr))

        hdr = PE(self.uc, self.sample.BASE_ADDR)

        # Patch DLLs with hook
        # Hardcoded values used for speed improvement -> Offsets can be calculated with utils.calc_export_offset_of_dll
        self.apicall_handler.add_hook(self.uc, "VirtualProtect", "KernelBase.dll", 0x73D00000 + 0x1089f0)
        self.apicall_handler.add_hook(self.uc, "VirtualAlloc", "KernelBase.dll", 0x73D00000 + 0xd4600)
        self.apicall_handler.add_hook(self.uc, "VirtualFree", "KernelBase.dll", 0x73D00000 + 0xd4ae0)
        self.apicall_handler.add_hook(self.uc, "LoadLibraryA", "KernelBase.dll", 0x73D00000 + 0xf20d0)
        self.apicall_handler.add_hook(self.uc, "GetProcAddress", "KernelBase.dll", 0x73D00000 + 0x102870)

        self.apicall_handler.add_hook(self.uc, "VirtualProtect", "kernel32.dll", 0x755D0000 + 0x16760)
        self.apicall_handler.add_hook(self.uc, "VirtualAlloc", "kernel32.dll", 0x755D0000 + 0x166a0)
        self.apicall_handler.add_hook(self.uc, "VirtualFree", "kernel32.dll", 0x755D0000 + 0x16700)
        self.apicall_handler.add_hook(self.uc, "LoadLibraryA", "kernel32.dll", 0x755D0000 + 0x157b0)
        self.apicall_handler.add_hook(self.uc, "GetProcAddress", "kernel32.dll", 0x755D0000 + 0x14ee0)

        # Add hooks
        self.uc.hook_add(UC_HOOK_CODE, self.hook_code)
        self.uc.hook_add(UC_HOOK_MEM_READ | UC_HOOK_MEM_WRITE | UC_HOOK_MEM_FETCH, self.hook_mem_access)
        self.uc.hook_add(UC_HOOK_MEM_READ_UNMAPPED | UC_HOOK_MEM_WRITE_UNMAPPED, self.hook_mem_invalid)
Exemple #4
0
def parse_disk_to_header(sample, query_header=None):
    offsets = {}
    # Read DOS Header
    with open(sample, 'rb') as f:
        dos_read = bytearray(f.read(header_sizes["_IMAGE_DOS_HEADER"]))
        dos_header = _IMAGE_DOS_HEADER.from_buffer(dos_read)

        if getattr(dos_header, "e_magic") != 0x5A4D:
            print(f"e_magic = {getattr(dos_header, 'e_magic')}")
            print("Wrong DOS Magic Value (MZ). Aborting...")
            raise InvalidPEFile

        e_lfanew = getattr(dos_header, "e_lfanew")

        if query_header == "e_lfanew":
            return e_lfanew

        if query_header == "_IMAGE_DOS_HEADER":
            return dos_header

        offsets["_IMAGE_DOS_HEADER"] = 0

        # Read PE Header
        pe_hdr_offset = e_lfanew
        f.seek(pe_hdr_offset)
        offsets["_IMAGE_FILE_HEADER"] = pe_hdr_offset
        pe_read = bytearray(f.read(header_sizes["_IMAGE_FILE_HEADER"]))
        pe_header = _IMAGE_FILE_HEADER.from_buffer(pe_read)

        if getattr(pe_header, "Signature") != 0x4550:
            print(f"Signature: {getattr(pe_header, 'Signature')}")
            print("Wrong PE Header Signature. Aborting...")
            raise InvalidPEFile

        number_of_sections = getattr(pe_header, "NumberOfSections")

        if query_header == "NumberOfSections":
            return number_of_sections

        if query_header == "_IMAGE_FILE_HEADER":
            return pe_header

        # Read Optional Header
        opt_hdr_offset = pe_hdr_offset + header_sizes["_IMAGE_FILE_HEADER"]
        f.seek(opt_hdr_offset)
        offsets["_IMAGE_OPTIONAL_HEADER"] = opt_hdr_offset
        opt_read = bytearray(f.read(header_sizes["_IMAGE_OPTIONAL_HEADER"]))
        opt_header = _IMAGE_OPTIONAL_HEADER.from_buffer(opt_read)

        if getattr(opt_header, "Magic") != 0x10B:
            print(f"OPT Magic: {getattr(opt_header, 'Magic')}")
            print("Wrong Optional Header Magic. Aborting...")
            raise InvalidPEFile

        if query_header == "_IMAGE_OPTIONAL_HEADER":
            return opt_header

        if query_header == "_IMAGE_DATA_DIRECTORY":
            return getattr(opt_header, "DataDirectory")

        rva_to_IMAGE_IMPORT_DESCRIPTOR = getattr(
            getattr(opt_header, "DataDirectory")[1], "VirtualAddress")
        size_import_table = getattr(
            getattr(opt_header, "DataDirectory")[1], "Size")
        #import_table = get_imp(uc, rva_to_IMAGE_IMPORT_DESCRIPTOR, base_addr, size_import_table)
        import_descriptor_table = []
        # TODO Use this when custom loader finished
        #for x in range(int((size_import_table / header_sizes["IMAGE_IMPORT_DESCRIPTOR"]))):
        #    f.seek(rva_to_IMAGE_IMPORT_DESCRIPTOR)
        #    imp_descriptor_read = bytearray(f.read(header_sizes["IMAGE_IMPORT_DESCRIPTOR"]))
        #    imp_descriptor = IMAGE_IMPORT_DESCRIPTOR.from_buffer(imp_descriptor_read)
        #    if getattr(imp_descriptor, "Characteristics") != 0 or getattr(imp_descriptor, "FirstThunk") != 0:
        #        import_descriptor_table.append(imp_descriptor)
        #        rva_to_IMAGE_IMPORT_DESCRIPTOR += header_sizes["IMAGE_IMPORT_DESCRIPTOR"]
        #    else:
        #        break
        if query_header == "IMPORTS":
            return import_descriptor_table

        # Read Section Header
        section_hdr_offset = opt_hdr_offset + header_sizes[
            "_IMAGE_OPTIONAL_HEADER"]
        offsets["IMAGE_SECTION_HEADER"] = section_hdr_offset
        section_headers = []
        for i in range(number_of_sections):
            f.seek(section_hdr_offset)
            sec_read = bytearray(f.read(header_sizes["IMAGE_SECTION_HEADER"]))
            sec_header = IMAGE_SECTION_HEADER.from_buffer(sec_read)
            section_headers.append(sec_header)
            section_hdr_offset += header_sizes["IMAGE_SECTION_HEADER"]

        if query_header == "IMAGE_SECTION_HEADER":
            return section_headers

        if query_header == "Offsets":
            return offsets

        headers = {
            "_IMAGE_DOS_HEADER": dos_header,
            "_IMAGE_FILE_HEADER": pe_header,
            "_IMAGE_OPTIONAL_HEADER": opt_header,
            "IMAGE_SECTION_HEADER": section_headers,
            "IMPORTS": import_descriptor_table,
        }

        return headers
Exemple #5
0
def parse_memory_to_header(uc, base_addr, query_header=None):
    # Read DOS Header
    uc_dos = uc.mem_read(base_addr, header_sizes["_IMAGE_DOS_HEADER"])
    dos_header = _IMAGE_DOS_HEADER.from_buffer(uc_dos)

    if getattr(dos_header, "e_magic") != 0x5A4D:
        print(f"e_magic = {getattr(dos_header, 'e_magic')}")
        print("Wrong DOS Magic Value (MZ). Aborting...")
        raise InvalidPEFile

    e_lfanew = getattr(dos_header, "e_lfanew")

    if query_header == "e_lfanew":
        return e_lfanew

    if query_header == "_IMAGE_DOS_HEADER":
        return dos_header

    # Read PE Header
    pe_hdr_offset = base_addr + e_lfanew
    uc_pe = uc.mem_read(pe_hdr_offset, header_sizes["_IMAGE_FILE_HEADER"])
    pe_header = _IMAGE_FILE_HEADER.from_buffer(uc_pe)

    if getattr(pe_header, "Signature") != 0x4550:
        print(f"Signature: {getattr(pe_header, 'Signature')}")
        print("Wrong PE Header Signature. Aborting...")
        raise InvalidPEFile

    number_of_sections = getattr(pe_header, "NumberOfSections")

    if query_header == "NumberOfSections":
        return number_of_sections

    if query_header == "_IMAGE_FILE_HEADER":
        return pe_header

    # Read Optional Header
    opt_hdr_offset = pe_hdr_offset + header_sizes["_IMAGE_FILE_HEADER"]
    uc_opt = uc.mem_read(opt_hdr_offset,
                         header_sizes["_IMAGE_OPTIONAL_HEADER"])
    opt_header = _IMAGE_OPTIONAL_HEADER.from_buffer(uc_opt)

    if getattr(opt_header, "Magic") != 0x10B:
        print(f"OPT Magic: {getattr(opt_header, 'Magic')}")
        print("Wrong Optional Header Magic. Aborting...")
        raise InvalidPEFile

    if query_header == "_IMAGE_OPTIONAL_HEADER":
        return opt_header

    if query_header == "_IMAGE_DATA_DIRECTORY":
        return getattr(opt_header, "DataDirectory")

    rva_to_IMAGE_IMPORT_DESCRIPTOR = getattr(
        getattr(opt_header, "DataDirectory")[1], "VirtualAddress")
    size_import_table = getattr(
        getattr(opt_header, "DataDirectory")[1], "Size")
    import_table = get_imp(uc, rva_to_IMAGE_IMPORT_DESCRIPTOR, base_addr,
                           size_import_table)

    if query_header == "IMPORTS":
        return import_table

    # Read Section Header
    section_hdr_offset = opt_hdr_offset + header_sizes["_IMAGE_OPTIONAL_HEADER"]
    section_headers = []
    for i in range(number_of_sections):
        uc_sec = uc.mem_read(section_hdr_offset,
                             header_sizes["IMAGE_SECTION_HEADER"])
        sec_header = IMAGE_SECTION_HEADER.from_buffer(uc_sec)
        section_headers.append(sec_header)
        section_hdr_offset += header_sizes["IMAGE_SECTION_HEADER"]

    if query_header == "IMAGE_SECTION_HEADER":
        return section_headers

    headers = {
        "_IMAGE_DOS_HEADER": dos_header,
        "_IMAGE_FILE_HEADER": pe_header,
        "_IMAGE_OPTIONAL_HEADER": opt_header,
        "IMAGE_SECTION_HEADER": section_headers,
        "IMPORTS": import_table,
    }

    return headers
Exemple #6
0
import struct
from ctypes import *
from datetime import datetime

from unicorn import UcError

from unipacker.pe_structs import _IMAGE_DOS_HEADER, _IMAGE_FILE_HEADER, _IMAGE_OPTIONAL_HEADER, IMAGE_SECTION_HEADER, \
    _IMAGE_DATA_DIRECTORY, IMAGE_IMPORT_DESCRIPTOR, SectionHeader, DosHeader, PEHeader, OptionalHeader, \
    ImportDescriptor, DataDirectory
from unipacker.utils import InvalidPEFile, ImportValues, get_string

header_sizes = {
    "_IMAGE_DOS_HEADER": len(bytes(_IMAGE_DOS_HEADER())),  # 0x40
    "_IMAGE_FILE_HEADER": len(bytes(_IMAGE_FILE_HEADER())),  # 0x18
    "_IMAGE_OPTIONAL_HEADER": len(bytes(_IMAGE_OPTIONAL_HEADER())),  # 0xE0
    "IMAGE_SECTION_HEADER": len(bytes(IMAGE_SECTION_HEADER())),  # 0x28
    "_IMAGE_DATA_DIRECTORY": len(bytes(_IMAGE_DATA_DIRECTORY())),  # 0x8
    "IMAGE_IMPORT_DESCRIPTOR": len(bytes(IMAGE_IMPORT_DESCRIPTOR())),
}

short_hdr_names = {
    "DOS": "_IMAGE_DOS_HEADER",
    "DOS_HEADER": "_IMAGE_DOS_HEADER",
    "DOS_HDR": "_IMAGE_DOS_HEADER",
    "IMAGE_DOS_HEADER": "_IMAGE_DOS_HEADER",
    "PE": "_IMAGE_FILE_HEADER",
    "PE_HEADER": "_IMAGE_FILE_HEADER",
    "PE_HDR": "_IMAGE_FILE_HEADER",
    "FILE_HEADER": "_IMAGE_FILE_HEADER",
    "FILE_HDR": "_IMAGE_FILE_HEADER",
    "IMAGE_FILE_HEADER": "_IMAGE_FILE_HEADER",