Beispiel #1
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)
Beispiel #2
0
    def dump_image(self,
                   uc,
                   base_addr,
                   virtualmemorysize,
                   apicall_handler,
                   sample,
                   path="unpacked.exe"):
        ntp = apicall_handler.ntp
        dllname_to_functionlist = sample.dllname_to_functionlist
        if len(sample.allocated_chunks) == 0:
            total_size = virtualmemorysize
        else:
            total_size = sorted(sample.allocated_chunks)[-1][1] - base_addr
            virtualmemorysize = total_size

        print(f"Totalsize:{hex(total_size)}, "
              f"VirtualMemorySize:{hex(virtualmemorysize)}")

        print_chunks(sample.allocated_chunks)

        try:
            hdr = PE(uc, base_addr)
        except InvalidPEFile as i:
            print("Invalid PE File... Cannot dump")
            return

        old_number_of_sections = hdr.pe_header.NumberOfSections

        print("Setting unpacked Entry Point")
        print(f"OEP:{hex(uc.reg_read(UC_X86_REG_EIP) - base_addr)}")
        hdr.opt_header.AddressOfEntryPoint = uc.reg_read(
            UC_X86_REG_EIP) - base_addr

        print("Fixing Imports...")
        hdr = self.fix_imports(uc, hdr, virtualmemorysize, total_size,
                               dllname_to_functionlist,
                               sample.original_imports)

        print("Fixing sections")
        self.fix_sections(hdr, old_number_of_sections, virtualmemorysize)

        print("Set IAT-Directory to 0 (VA and Size)")
        hdr.data_directories[12].VirtualAddress = 0
        hdr.data_directories[12].Size = 0

        print(
            f"RVA to import table: {hex(hdr.data_directories[1].VirtualAddress)}"
        )

        if (virtualmemorysize - 0xE000) <= hdr.data_directories[
                1].VirtualAddress <= virtualmemorysize or len(
                    sample.allocated_chunks) != 0 or True:
            print(f"Totalsize:{hex(total_size)}, "
                  f"VirtualMemorySize:{hex(virtualmemorysize)}, "
                  f"Allocated chunks: {sample.allocated_chunks}")
            # print("Relocating Headers to End of Image")
            # hdr.dos_header.e_lfanew = virtualmemorysize - 0x10000
            # hdr = self.add_section(hdr, '.newhdr', 0x10000, virtualmemorysize-0x10000)
            # print("Adding new import section")
            # hdr = self.add_section(hdr, '.nimdata', 0xe000, (virtualmemorysize - 0x10000) + 0x2000)
            # print("Appending allocated chunks at the end of the image")
            # hdr = self.chunk_to_image_section_hdr(hdr, base_addr, sample.allocated_chunks)
            # TODO Fix chunk unmapped space with 0
        else:
            virtualmemorysize -= 0x10000
            total_size = virtualmemorysize

        hdr.sync(uc)

        print("Fixing SizeOfImage...")
        hdr.opt_header.SizeOfImage = alignments(
            total_size, hdr.opt_header.SectionAlignment)

        print("Fixing Memory Protection of Sections")
        hdr = self.fix_section_mem_protections(hdr, ntp)

        hdr.sync(uc)

        print("Fixing Checksum")
        hdr = self.fix_checksum(uc, hdr, base_addr, total_size)
        hdr.sync(uc)

        dllcharacteristics = hdr.opt_header.DllCharacteristics & 0xFFBF
        hdr.opt_header.DllCharacteristics = dllcharacteristics  # Remove Dynamic Base
        hdr.sync(uc)

        print(f"Dumping state to {path}")
        pe_write(uc, base_addr, total_size, path)