예제 #1
0
    def VirtualFree(self, uc, esp, log, address, size, free_type):
        log and print(f"VirtualFree: chunk to free: 0x{address:02x}, size 0x{size:02x}, type 0x{free_type:02x}")
        new_chunks = []
        success = False
        for start, end in sorted(self.sample.allocated_chunks):
            if start <= address <= end:
                if free_type & 0x8000 and size == 0:  # MEM_RELEASE, clear whole allocated range
                    if address in self.alloc_sizes:
                        size = self.alloc_sizes[address]
                        end_addr = address + size
                        uc.mem_unmap(address, size)
                        new_chunks += remove_range((start, end), (address, end_addr))
                        success = True
                    else:
                        log and print(f"\t0x{address} is not an alloc base address!")
                        new_chunks += [(start, end)]
                elif free_type & 0x4000 and size > 0:  # MEM_DECOMMIT, free requested size
                    end_addr = address + align(size)
                    uc.mem_unmap(address, align(size))
                    new_chunks += remove_range((start, end), (address, end_addr))
                    success = True
                else:
                    log and print("\tIncorrect size + type combination!")
                    new_chunks += [(start, end)]
            else:
                new_chunks += [(start, end)]

        self.sample.allocated_chunks = list(merge(new_chunks))
        log and self.print_allocs()
        if success:
            return 1
        log and print("\tAddress range not allocated!")
        return 0
예제 #2
0
파일: core.py 프로젝트: snemes/unipacker
 def load_dll(self, path_dll, start_addr):
     filename = os.path.splitext(os.path.basename(path_dll))[0]
     if not os.path.exists(f"{os.path.dirname(unipacker.__file__)}/DLLs/{filename}.ldll"):
         dll = pefile.PE(path_dll)
         loaded_dll = dll.get_memory_mapped_image(ImageBase=start_addr)
         with open(f"{os.path.dirname(unipacker.__file__)}/DLLs/{filename}.ldll", 'wb') as f:
             f.write(loaded_dll)
         self.uc.mem_map(start_addr, align(len(loaded_dll) + 0x1000))
         self.uc.mem_write(start_addr, loaded_dll)
     else:
         with open(f"{os.path.dirname(unipacker.__file__)}/DLLs/{filename}.ldll", 'rb') as dll:
             loaded_dll = dll.read()
             self.uc.mem_map(start_addr, align((len(loaded_dll) + 0x1000)))
             self.uc.mem_write(start_addr, loaded_dll)
예제 #3
0
    def alloc(self, log, size, uc, offset=None):
        page_size = 4 * 1024
        aligned_size = align(size, page_size)
        log and print(
            f"\tUnaligned size: 0x{size:02x}, aligned size: 0x{aligned_size:02x}"
        )
        if offset is None:
            for chunk_start, chunk_end in self.sample.allocated_chunks:
                if chunk_start <= self.dynamic_mem_offset <= chunk_end:
                    # we have to push back the dynamic mem offset as it is inside an already allocated chunk!
                    self.dynamic_mem_offset = chunk_end + 1
            offset = self.dynamic_mem_offset
            self.dynamic_mem_offset += aligned_size
        new_offset_m = offset % page_size
        aligned_address = offset  # TODO Remove hacky fix, chunks are not merged
        if (aligned_address % page_size) != 0:
            aligned_address = align(offset)

        # check if we have mapped parts of it already
        mapped_partial = False
        for chunk_start, chunk_end in self.sample.allocated_chunks:
            if chunk_start <= aligned_address < chunk_end:
                if aligned_address + aligned_size <= chunk_end:
                    log and print(f"\tAlready fully mapped")
                else:
                    log and print(
                        f"\tMapping missing piece 0x{chunk_end + 1:02x} to 0x{aligned_address + aligned_size:02x}"
                    )
                    uc.mem_map(chunk_end,
                               aligned_address + aligned_size - chunk_end)
                mapped_partial = True
                break

        if not mapped_partial:
            uc.mem_map(aligned_address, aligned_size)
        log and print(
            f"\tfrom 0x{aligned_address:02x} to 0x{(aligned_address + aligned_size):02x}"
        )
        self.sample.allocated_chunks = list(
            merge(self.sample.allocated_chunks +
                  [(aligned_address, aligned_address + aligned_size)]))
        log and self.print_allocs()
        self.alloc_sizes[aligned_address] = aligned_size
        return aligned_address
예제 #4
0
파일: core.py 프로젝트: snemes/unipacker
    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)
예제 #5
0
파일: core.py 프로젝트: snemes/unipacker
    def setup_processinfo(self):
        self.TEB_BASE = 0x200000
        self.PEB_BASE = self.TEB_BASE + 0x1000
        LDR_PTR = self.PEB_BASE + 0x1000
        LIST_ENTRY_BASE = LDR_PTR + 0x1000

        teb = TEB(
            -1,  # fs:00h
            self.STACK_ADDR + self.STACK_SIZE,  # fs:04h
            self.STACK_ADDR,  # fs:08h
            0,  # fs:0ch
            0,  # fs:10h
            0,  # fs:14h
            self.TEB_BASE,  # fs:18h (teb base)
            0,  # fs:1ch
            0xdeadbeef,  # fs:20h (process id)
            0xdeadbeef,  # fs:24h (current thread id)
            0,  # fs:28h
            0,  # fs:2ch
            self.PEB_BASE,  # fs:3ch (peb base)
        )

        peb = PEB(
            0,
            0,
            0,
            0,
            0xffffffff,
            self.sample.BASE_ADDR,
            LDR_PTR,
        )

        ntdll_entry = LIST_ENTRY(
            LIST_ENTRY_BASE + 12,
            LIST_ENTRY_BASE + 24,
            0x77400000,
        )

        kernelbase_entry = LIST_ENTRY(
            LIST_ENTRY_BASE + 24,
            LIST_ENTRY_BASE + 0,
            0x73D00000,

        )

        kernel32_entry = LIST_ENTRY(
            LIST_ENTRY_BASE + 0,
            LIST_ENTRY_BASE + 12,
            0x755D0000,
        )

        ldr = PEB_LDR_DATA(
            0x30,
            0x1,
            0x0,
            LIST_ENTRY_BASE,
            LIST_ENTRY_BASE + 24,
            LIST_ENTRY_BASE,
            LIST_ENTRY_BASE + 24,
            LIST_ENTRY_BASE,
            LIST_ENTRY_BASE + 24,
        )

        teb_payload = bytes(teb)
        peb_payload = bytes(peb)

        ldr_payload = bytes(ldr)

        ntdll_payload = bytes(ntdll_entry)
        kernelbase_payload = bytes(kernelbase_entry)
        kernel32_payload = bytes(kernel32_entry)

        self.uc.mem_map(self.TEB_BASE, align(0x5000))
        self.uc.mem_write(self.TEB_BASE, teb_payload)
        self.uc.mem_write(self.PEB_BASE, peb_payload)
        self.uc.mem_write(LDR_PTR, ldr_payload)
        self.uc.mem_write(LIST_ENTRY_BASE, ntdll_payload)
        self.uc.mem_write(LIST_ENTRY_BASE + 12, kernelbase_payload)
        self.uc.mem_write(LIST_ENTRY_BASE + 24, kernel32_payload)
        self.uc.windows_tib = self.TEB_BASE