예제 #1
0
    def LocalAlloc(self, proc, argv, ctx={}):
        '''
        DECLSPEC_ALLOCATOR HLOCAL LocalAlloc(
            UINT   uFlags,
            SIZE_T uBytes
        );
        '''
        flag, size = argv

        pMem = self.win_emu.mem_manager.alloc_heap(proc.proc_default_heap,
                                                   size)
        hnd = ObjectManager.create_new_object('EmLMEM', pMem, size, flag)
        if flag and 0x0:  # LMEM_FIXED
            lMem_obj = ObjectManager.get_obj_by_handle(hnd)
            lMem_obj.handle = hnd

        return hnd
예제 #2
0
 def LocalLock(self, proc, argv, ctx={}):
     '''
     LPVOID LocalLock(
         HLOCAL hMem
     );
     '''
     lmem_handle, = argv
     lMem_obj = ObjectManager.get_obj_by_handle(lmem_handle)
     return lMem_obj.base
예제 #3
0
    def create_heap(self, pid, size, max_size, option=None) -> Heap:
        block = self.find_block_from_pid(pid)
        if not block:
            return -1

        if max_size:
            size = max_size
            if size % PAGE_SIZE != 0:
                #Upperbound
                size += (PAGE_SIZE - size % PAGE_SIZE)

            page_protect = PageProtect.PAGE_READWRITE
            if option == HeapOption.HEAP_CREATE_ENABLE_EXECUTE:
                page_protect = PageProtect.PAGE_EXECUTE_READWRITE
            _p_region = self.alloc_page(
                pid,
                size=size,
                allocation_type=PageAllocationType.MEM_COMMIT,
                protect=page_protect)
            hHeap = ObjectManager.create_new_object('Heap', pid, option,
                                                    _p_region, True)

        else:
            if size % PAGE_SIZE != 0:
                #Upperbound
                size += (PAGE_SIZE - size % PAGE_SIZE)
            page_protect = PageProtect.PAGE_READWRITE
            if option == HeapOption.HEAP_CREATE_ENABLE_EXECUTE:
                page_protect = PageProtect.PAGE_EXECUTE_READWRITE
            _p_region = self.alloc_page(
                pid,
                size=size,
                allocation_type=PageAllocationType.MEM_COMMIT,
                protect=page_protect)
            hHeap = ObjectManager.create_new_object('Heap', pid, option,
                                                    _p_region, False)

        heap = ObjectManager.get_obj_by_handle(hHeap)
        heap.set_handle(hHeap)

        self.add_heap_list(block, heap)

        return heap
예제 #4
0
    def destroy_heap(self, handle):
        heap = ObjectManager.get_obj_by_handle(handle)
        block = self.find_block_from_pid(heap.pid)
        if not block:
            return -1
        for heaps in heap.heap_space:
            self.unmap_process_vas(block["proc_obj"], heaps)

        self.delete_heap_from_list(block, heap)
        pass
예제 #5
0
    def LocalSize(self, proc, argv, ctx={}):
        '''
        SIZE_T LocalSize(
            HLOCAL hMem
        );
        '''
        lmem_handle, = argv
        lMem_obj = ObjectManager.get_obj_by_handle(lmem_handle)

        return lMem_obj.size
예제 #6
0
    def LocalFlags(self, proc, argv, ctx={}):
        '''
        UINT LocalFlags(
            HLOCAL hMem
        );
        '''
        lmem_handle, = argv
        lMem_obj = ObjectManager.get_obj_by_handle(lmem_handle)

        return lMem_obj.flags
예제 #7
0
    def LocalFree(self, proc, argv, ctx={}):
        '''
        HLOCAL LocalFree(
            _Frees_ptr_opt_ HLOCAL hMem
        );
        '''
        lmem_handle, = argv
        lMem_obj = ObjectManager.get_obj_by_handle(lmem_handle)
        self.win_emu.mem_manager.free_heap(proc.proc_default_heap,
                                           lMem_obj.base)

        return 0
예제 #8
0
    def CreateProcess(self, proc, argv, ctx={}):
        '''BOOL CreateProcess(
            LPTSTR                lpApplicationName,
            LPTSTR                lpCommandLine,
            LPSECURITY_ATTRIBUTES lpProcessAttributes,
            LPSECURITY_ATTRIBUTES lpThreadAttributes,
            BOOL                  bInheritHandles,
            DWORD                 dwCreationFlags,
            LPVOID                lpEnvironment,
            LPTSTR                lpCurrentDirectory,
            LPSTARTUPINFO         lpStartupInfo,
            LPPROCESS_INFORMATION lpProcessInformation
        );'''
        app, cmd, pa, ta, inherit, flags, env, cd, si, ppi = argv

        cw = self.get_char_width(ctx)
        cmdstr = ''
        appstr = ''
        if app:
            appstr = proc.read_string(app, cw)
            argv[0] = appstr
        if cmd:
            cmdstr = proc.read_string(cmd, cw)
            argv[1] = cmdstr

        if not appstr and cmdstr:
            appstr = cmdstr
        elif appstr and cmdstr:
            appstr += " " + cmdstr  # cmdstr be param
        elif appstr and not cmdstr:
            pass
        else:
            return 0
        # child proc can't be inherited

        new_proc_obj, hProc, hThread = self.win_emu.create_process(appstr)
        main_thread = ObjectManager.get_obj_by_handle(hThread)
        EmuProcManager.push_wait_queue(new_proc_obj.pid, new_proc_obj)

        _pi = self.k32types.PROCESS_INFORMATION(proc.ptr_size)
        data = common.mem_cast(proc.uc_eng, _pi, ppi)
        _pi.hProcess = hProc
        _pi.hThread = hThread
        _pi.dwProcessId = new_proc_obj.pid
        _pi.dwThreadId = main_thread.tid

        proc.write_mem_self(ppi, common.get_bytes(data))

        rv = 1

        return rv
예제 #9
0
    def __init__(self, parent=None):
        if not parent:
            # create new virtual FileSystem
            self.emu_vfs = WinVFS()
            self.obj_manager = ObjectManager()
            self.mem_manager = mem_manager.MemoryManager()

        else:
            self.net_manager = parent.net_manager
            self.obj_manager = parent.obj_manager
        self.arch = UC_ARCH_X86
        self.mode = UC_MODE_32
        self.cur_thread = None
        self.threads = []
        self.ctx: CONTEXT = None
        self.ptr_size = 0
        self.api_handler = ApiHandler(self)

        self.set_ptr_size()
        self.emu_waiting_queue = []
        self.winapi_info_dict = {}
        self.running_process = None
        self.__set_emulation_config()
예제 #10
0
    def VirtualFreeEx(self, proc, argv, ctx={}):
        '''
        BOOL VirtualFreeEx(
            HANDLE hProcess,
            LPVOID lpAddress,
            SIZE_T dwSize,
            DWORD  dwFreeType
        );
        '''
        proc_handle, base_addr, size, ftype = argv
        targ_proc_obj = ObjectManager.get_obj_by_handle(proc_handle)
        self.win_emu.mem_manager.free_page(targ_proc_obj.pid, base_addr, size)

        return True
예제 #11
0
    def ReadProcessMemory(self, proc, argv, ctx={}):
        '''
        BOOL ReadProcessMemory(
            HANDLE  hProcess,
            LPCVOID lpBaseAddress,
            LPVOID  lpBuffer,
            SIZE_T  nSize,
            SIZE_T  *lpNumberOfBytesRead
        );
        '''
        proc_handle, base_addr, pBuf, size, pRead_sz = argv
        targ_proc_obj = ObjectManager.get_obj_by_handle(proc_handle)
        mem_raw = targ_proc_obj.read_mem_self(base_addr, size)
        proc.write_mem_self(pBuf, mem_raw)
        proc.write_mem_self(pRead_sz, len(mem_raw).to_bytes(4, "little"))

        return True
예제 #12
0
    def WriteProcessMemory(self, proc, argv, ctx={}):
        '''
        BOOL WriteProcessMemory(
            HANDLE  hProcess,
            LPVOID  lpBaseAddress,
            LPCVOID lpBuffer,
            SIZE_T  nSize,
            SIZE_T  *lpNumberOfBytesWritten
        );
        '''
        proc_handle, base_addr, pData, dwSize, pWritten_sz = argv
        targ_proc_obj = ObjectManager.get_obj_by_handle(proc_handle)

        raw_data = proc.read_mem_self(pData, dwSize)
        targ_proc_obj.write_mem_self(base_addr, bytes(raw_data))
        proc.write_mem_self(pWritten_sz, len(raw_data).to_bytes(4, 'little'))

        return 0x1
예제 #13
0
 def VirtualAllocEx(self, proc, argv, ctx={}):
     '''
     LPVOID VirtualAllocEx(
         HANDLE hProcess,
         LPVOID lpAddress,
         SIZE_T dwSize,
         DWORD  flAllocationType,
         DWORD  flProtect
     );
     '''
     proc_handle, base_addr, size, alloc_type, protection = argv
     targ_proc_obj = ObjectManager.get_obj_by_handle(proc_handle)
     page_region = self.win_emu.mem_manager.alloc_page(
         pid=targ_proc_obj.pid,
         size=size,
         allocation_type=alloc_type,
         page_type=PageType.MEM_PRIVATE,
         alloc_base=base_addr)
     return page_region.get_base_addr()
예제 #14
0
    def MapViewOfFile(self, proc, argv, ctx={}):
        '''
        LPVOID MapViewOfFile(
          HANDLE hFileMappingObject,
          DWORD  dwDesiredAccess,
          DWORD  dwFileOffsetHigh,
          DWORD  dwFileOffsetLow,
          SIZE_T dwNumberOfBytesToMap
        );
        '''
        hFileMap, access, offset_high, offset_low, bytes_to_map = argv

        fmap_obj = ObjectManager.get_obj_by_handle(hFileMap)

        if bytes_to_map > fmap_obj.maximum_size:
            return win_const.INVALID_HANDLE_VALUE  #

        map_region = self.win_emu.mem_manager.alloc_page(
            pid=proc.pid,
            size=fmap_obj.maximum_size,
            allocation_type=PageAllocationType.MEM_COMMIT,
            page_type=fmap_obj.protect)

        mf = fmap_obj.map_memory_with_file(map_region.get_base_addr(),
                                           offset_high, offset_low,
                                           bytes_to_map)
        if not mf["success"]:
            return win_const.INVALID_HANDLE_VALUE

        map_region.set_mmf_handle(hFileMap)
        proc.write_mem_self(map_region.get_base_addr(), mf["data"])

        Dispatcher.mmf_counter_tab[hFileMap] = 0
        h = proc.uc_eng.hook_add(UC_HOOK_MEM_WRITE,
                                 Dispatcher.file_map_dispatcher,
                                 (proc, fmap_obj))
        fmap_obj.set_dispatcher(h)

        return map_region.get_base_addr()
예제 #15
0
    def VirtualQueryEx(self, proc, argv, ctx={}):
        '''
        SIZE_T VirtualQueryEx(
            HANDLE                    hProcess
            LPCVOID                   lpAddress,
            PMEMORY_BASIC_INFORMATION lpBuffer,
            SIZE_T                    dwLength
        );
        '''
        proc_handle, base_addr, pMbi, size = argv
        targ_proc_obj = ObjectManager.get_obj_by_handle(proc_handle)
        mbi = k32types.MEMORY_BASIC_INFORMATION(proc.ptr_size)
        targ_pg_rg = self.win_emu.mem_manager.get_page_region_from_baseaddr(
            targ_proc_obj, base_addr)
        mbi.AllocationBase = targ_pg_rg.base_address
        mbi.AllocationProtect = PageProtect.PAGE_EXECUTE_READWRITE
        mbi.State = PageAllocationType.MEM_COMMIT
        mbi.RegionSize = targ_pg_rg.size
        mbi.Type = targ_pg_rg.page_type

        targ_proc_obj.mem_write(pMbi, mbi.get_bytes())

        return mbi.sizeof()
예제 #16
0
class WinX86Emu:
    def __init__(self, parent=None):
        if not parent:
            # create new virtual FileSystem
            self.emu_vfs = WinVFS()
            self.obj_manager = ObjectManager()
            self.mem_manager = mem_manager.MemoryManager()

        else:
            self.net_manager = parent.net_manager
            self.obj_manager = parent.obj_manager
        self.arch = UC_ARCH_X86
        self.mode = UC_MODE_32
        self.cur_thread = None
        self.threads = []
        self.ctx: CONTEXT = None
        self.ptr_size = 0
        self.api_handler = ApiHandler(self)

        self.set_ptr_size()
        self.emu_waiting_queue = []
        self.winapi_info_dict = {}
        self.running_process = None
        self.__set_emulation_config()

    def create_new_emu_engine(self):
        return Uc(UC_ARCH_X86, UC_MODE_32)

    def init_emulation_environment(self, phy_file_full_path):
        def split_path(path):
            sep = ""
            if "\\" in path:
                sep = "\\"
            else:
                sep = "/"
            return path.split(sep)

        def get_basename(file_path):
            return split_path(file_path)[-1]

        # creation emulation env
        self.emu_vfs.create_home_dir(self.emu_home_dir)
        virtual_file_full_path = emu_path_join(
            self.emu_home_dir,
            get_basename(phy_file_full_path).lower())
        self.emu_vfs.copy(phy_file_full_path, virtual_file_full_path)
        self.insert_emulation_processing_queue(virtual_file_full_path)

        pass

    def insert_emulation_processing_queue(self, argv):
        proc_obj = None
        if isinstance(argv, str):
            proc_obj, _, _ = self.create_process(argv)  # file_path

        elif isinstance(argv, bytes) or isinstance(bytearray):
            # TODO:
            # CreateProcess with SectionHandle or FileHandle
            pass

        EmuProcManager.push_wait_queue(proc_obj.pid, proc_obj)

        pass

    def launch(self):
        while not EmuProcManager.is_wait_empty():
            po = EmuProcManager.deq_wait_queue()
            self.running_process = po["obj"]
            self.resume_thread(self.running_process)
        pass

    def resume_thread(self, proc_obj: EmuProcess, tid: int = -1):
        thread_obj = None
        pid = proc_obj.pid
        wait_q = EmuThreadManager.get_wait_queue(pid)
        while wait_q:
            tid = -1
            if tid == -1:
                to = EmuThreadManager.deq_wait_queue(pid)
                thread_obj = to["obj"]
                tid = thread_obj.tid
            else:
                q = wait_q
                if not q:
                    raise Exception('Fail to resume thread tid : %d' % (tid))
                idx = 0
                for o in q:
                    if o["tid"] == tid:
                        to = EmuThreadManager.deq_wait_queue(pid, idx)
                        thread_obj = to["obj"]
                    idx += 1
                if not thread_obj:
                    raise Exception('Fail to resume thread tid : %d' % (tid))

            EmuThreadManager.set_running_thread(pid, tid, thread_obj)
            thread_obj.setup_context()
            thread_obj.setup_ldt()
            try:
                thread_obj.uc_eng.emu_start(thread_obj.ctx.Eip, 0)
            except Exception as e:
                if e.args[0] == UC_ERR_EXCEPTION:
                    thread_obj.uc_eng.emu_stop()
                elif e.args[0] == UC_ERR_OK:
                    thread_obj.uc_eng.emu_stop()
                else:
                    print(e)
            pass

    # def resume(self):
    #     while len(self.threads) != 0:
    #         em_thread_handle = self.pop_waiting_queue()
    #         em_thread = ObjectManager.get_obj_by_handle(em_thread_handle)
    #         em_thread.setup_context()
    #         em_thread.setup_ldt()
    #         self.running_thread = em_thread
    #         try:
    #             self.emu_suspend_flag = False
    #             em_thread.uc_eng.emu_start(em_thread.ctx.Eip, 0)
    #         except Exception as e:
    #             if e.args[0] == UC_ERR_EXCEPTION:
    #                 em_thread.uc_eng.emu_stop()
    #             elif e.args[1] == UC_ERR_OK:
    #                 em_thread.uc_eng.emu_stop()

    def init_vas(self, proc_obj: EmuProcess):
        # This is actually done by ntoskrnl
        self.mem_manager.alloc_page(
            pid=proc_obj.pid,
            alloc_base=0,
            size=0x10000,
            allocation_type=PageAllocationType.MEM_RESERVE)
        peb_heap = self.mem_manager.create_heap(pid=proc_obj.pid,
                                                size=0x2000,
                                                max_size=0)
        peb_base = self.mem_manager.alloc_heap(
            peb_heap,
            ntos.PEB(self.ptr_size).sizeof())
        proc_default_heap = self.mem_manager.create_heap(pid=proc_obj.pid,
                                                         size=1024 * 1024,
                                                         max_size=1024 * 1024)

        proc_obj.set_peb_heap(peb_heap)
        proc_obj.set_peb_base(peb_base)
        proc_obj.set_proc_default_heap(proc_default_heap)

        pass

    def load_target_proc(self, proc_obj: EmuProcess):
        _pe_ = proc_obj.parsed_pe

        if _pe_.DOS_HEADER.e_magic != struct.unpack("<H", b'MZ')[0]:  # pylint: disable=no-member
            raise Exception("Target file is not PE")

        image_base = _pe_.OPTIONAL_HEADER.ImageBase
        size_of_image = _pe_.OPTIONAL_HEADER.SizeOfImage
        ep = image_base + _pe_.OPTIONAL_HEADER.AddressOfEntryPoint
        image_pages = self.mem_manager.alloc_page(
            pid=proc_obj.pid,
            size=size_of_image,
            allocation_type=PageAllocationType.MEM_COMMIT
            | PageAllocationType.MEM_RESERVE,
            alloc_base=image_base,
            protect=PageProtect.PAGE_EXECUTE_READWRITE,
            page_type=PageType.MEM_IMAGE)
        image_base = image_pages.get_base_addr()

        proc_obj.set_image_base(image_base)
        proc_obj.set_ep(ep)

        pe_image = _pe_.get_memory_mapped_image(ImageBase=image_base)
        self.mem_manager.write_process_memory(proc_obj.pid, image_base,
                                              pe_image)

        del pe_image

    def load_import_mods(self, proc_obj: EmuProcess):
        # will be changed
        # cur  : load all modules that was emulated
        # todo : load specific modules which recorded in IAT
        for dll_name in pydll.EMULATED_DLL_LIST:
            self.load_library(dll_name, proc_obj)

    def load_library(self, dll_name, proc_obj: EmuProcess):
        if dll_name not in pydll.SYSTEM_DLL_BASE:
            dll_name = self.api_handler.api_set_schema(dll_name)
        if dll_name not in pydll.SYSTEM_DLL_BASE:
            return 0xFFFFFFFF  # Invalid Handle

        if dll_name not in proc_obj.imports:
            _sys_dll_init_base = pydll.SYSTEM_DLL_BASE[dll_name]
            dll_page = self.mem_manager.alloc_page(
                pid=proc_obj.pid,
                size=ALLOCATION_GRANULARITY,
                allocation_type=PageAllocationType.MEM_COMMIT
                | PageAllocationType.MEM_RESERVE,
                alloc_base=_sys_dll_init_base,
                page_type=PageType.MEM_IMAGE)
            pydll.SYSTEM_DLL_BASE[dll_name] = dll_page.get_base_addr()
            self.setup_emulated_dllobj(dll_name, proc_obj)
            # Fake load
            # overwrite RET at entire dll memory region
            self.mem_manager.write_process_memory(
                proc_obj.pid, dll_page.get_base_addr(),
                b'\xC3' * ALLOCATION_GRANULARITY)
            self.add_module_to_peb(proc_obj, dll_name)

            return pydll.SYSTEM_DLL_BASE[dll_name]
        else:
            return pydll.SYSTEM_DLL_BASE[dll_name]

    def setup_emulated_dllobj(self, mod_name, proc_obj: EmuProcess):
        def igetattr(obj, attr):
            for a in dir(obj):
                if a.lower() == attr.lower():
                    return getattr(obj, a)
            raise AttributeError

        if mod_name not in sys.modules:
            mod_obj = importlib.import_module("pydll." + mod_name)
            if mod_name not in proc_obj.e_dllobj:
                proc_obj.add_e_dll_obj(mod_name,
                                       igetattr(mod_obj, mod_name)(self))
        pass

    def setup_import_tab(self, proc_obj: EmuProcess):
        def rewrite_iat_table(uc, first_thunk_etry, addr):
            addr = struct.pack("I", addr)
            uc.mem_write(first_thunk_etry, addr)

        for dll in proc_obj.parsed_pe.DIRECTORY_ENTRY_IMPORT:  # pylint: disable=no-member
            dll_name = dll.dll.decode("ascii").lower().split(".")[0]
            proc_obj.set_imports(dll_name, [])
            if dll_name not in pydll.SYSTEM_DLL_BASE:
                dll_name = self.api_handler.api_set_schema(dll_name)
            try:
                dll_base = pydll.SYSTEM_DLL_BASE[dll_name]
            except:
                raise Exception("Unsupported DLL")

            for imp_api in dll.imports:
                api_name = imp_api.name.decode("ascii")
                if "msvcp" in dll_name:
                    # MS cpp runtime lib
                    if not proc_obj.pid in self.api_handler.cpp_procedure:
                        self.api_handler.cpp_procedure[proc_obj.pid] = {}
                    self.api_handler.cpp_procedure[proc_obj.pid][
                        imp_api.address] = api_name
                else:
                    if dll_name not in proc_obj.imports:
                        proc_obj.set_imports(
                            dll_name, [(api_name, dll_base + imp_api.hint)])
                    proc_obj.add_imports(dll_name,
                                         (api_name, dll_base + imp_api.hint))
                proc_obj.set_api_va_dict(dll_base + imp_api.hint,
                                         (dll_name, api_name))
                rewrite_iat_table(proc_obj.uc_eng, imp_api.address,
                                  dll_base + imp_api.hint)
        pass

    def init_peb(self, proc_obj: EmuProcess):
        # create new PEB & PEB_LDR & Process Image LDR_ENTRY
        peb = ntos.PEB(self.ptr_size)
        new_ldte = ntos.LDR_DATA_TABLE_ENTRY(self.ptr_size)
        peb_ldr_data = ntos.PEB_LDR_DATA(self.ptr_size)

        peb.BeingDebugged = 0
        peb.ImageBaseAddress = proc_obj.image_base
        peb.ProcessHeap = proc_obj.proc_default_heap.get_base_addr()

        # allocate memory space for PEB and PEB_LDR & Process Image LDR_ENTRY
        peb.Ldr = self.mem_manager.alloc_heap(proc_obj.peb_heap,
                                              peb_ldr_data.sizeof())
        pNew_ldte = self.mem_manager.alloc_heap(proc_obj.peb_heap,
                                                new_ldte.sizeof())

        # setup Process Image LDR_ENTRY
        new_ldte.SizeOfImage = proc_obj.parsed_pe.OPTIONAL_HEADER.SizeOfImage
        new_ldte.DllBase = proc_obj.parsed_pe.OPTIONAL_HEADER.ImageBase
        new_ldte.LoadCount = 1

        self.new_unicode_string(proc_obj, new_ldte.BaseDllName, proc_obj.name)
        self.new_unicode_string(proc_obj, new_ldte.FullDllName, proc_obj.path)

        # link PEB_LDR and Process Image LDR_ENTRY
        size_of_list_etry = ntos.LIST_ENTRY(self.ptr_size).sizeof()
        peb_ldr_data.InLoadOrderModuleList.Flink = pNew_ldte
        peb_ldr_data.InMemoryOrderModuleList.Flink = pNew_ldte + size_of_list_etry

        new_ldte.InLoadOrderLinks.Flink = peb.Ldr + 0xC
        new_ldte.InMemoryOrderLinks.Flink = peb.Ldr + 0xC + size_of_list_etry

        proc_obj.write_mem_self(pNew_ldte, new_ldte.get_bytes())
        proc_obj.write_mem_self(peb.Ldr, peb_ldr_data.get_bytes())
        proc_obj.write_mem_self(proc_obj.peb_base, peb.get_bytes())

        proc_obj.add_ldr_entry((pNew_ldte, new_ldte))
        proc_obj.set_peb_ldr(peb_ldr_data)
        proc_obj.set_peb(peb)
        pass

    def add_module_to_peb(self, proc_obj: EmuProcess, mod_name: str):
        new_ldte = ntos.LDR_DATA_TABLE_ENTRY(self.ptr_size)
        new_ldte.DllBase = pydll.SYSTEM_DLL_BASE[mod_name]
        new_ldte.Length = ntos.LDR_DATA_TABLE_ENTRY(self.ptr_size).sizeof()

        self.new_unicode_string(proc_obj, new_ldte.BaseDllName, mod_name)
        self.new_unicode_string(proc_obj, new_ldte.FullDllName,
                                "C:\\Windows\\System32\\" + mod_name + ".dll")

        pNew_ldte = self.mem_manager.alloc_heap(proc_obj.peb_heap,
                                                new_ldte.sizeof())
        list_type = ntos.LIST_ENTRY(self.ptr_size)

        # Link created list_entry to LDR_MODULE
        if not proc_obj.ldr_entries:

            pEntry, prev = proc_obj.peb.Ldr, proc_obj.peb_ldr_data

            prev.InLoadOrderModuleList.Flink = pNew_ldte
            prev.InMemoryOrderModuleList.Flink = pNew_ldte + list_type.sizeof()
            prev.InInitializationOrderModuleList.Flink = 0

        else:
            pEntry, prev = proc_obj.ldr_entries[-1]

            prev.InLoadOrderLinks.Flink = pNew_ldte
            prev.InMemoryOrderLinks.Flink = pNew_ldte + list_type.sizeof()
            prev.InInitializationOrderLinks.Flink = 0
        # Not implement Blink

        new_ldte.InLoadOrderLinks.Flink = proc_obj.peb.Ldr + 0xC
        new_ldte.InMemoryOrderLinks.Flink = proc_obj.peb.Ldr + 0xC + list_type.sizeof(
        )

        proc_obj.add_ldr_entry((pNew_ldte, new_ldte))

        proc_obj.write_mem_self(pNew_ldte, new_ldte.get_bytes())
        proc_obj.write_mem_self(pEntry, prev.get_bytes())
        proc_obj.write_mem_self(proc_obj.peb_base, proc_obj.peb.get_bytes())
        proc_obj.write_mem_self(proc_obj.peb.Ldr,
                                proc_obj.peb_ldr_data.get_bytes())

        pass

    def setup_uc_hooks(self, proc_obj: EmuProcess):
        h0 = proc_obj.uc_eng.hook_add(UC_HOOK_MEM_READ,
                                      self.api_handler.cpp_runtime_api_cb,
                                      (proc_obj, self.api_handler))
        h3 = proc_obj.uc_eng.hook_add(UC_HOOK_CODE, logger)
        h1 = proc_obj.uc_eng.hook_add(
            UC_HOOK_CODE, self.api_handler.pre_api_call_cb_wrapper,
            (self, proc_obj, self.get_arch(), self.get_ptr_size()))
        h2 = proc_obj.uc_eng.hook_add(
            UC_HOOK_MEM_READ_UNMAPPED | UC_HOOK_MEM_WRITE_UNMAPPED,
            invalid_mem_access_cb)

        #h2 = proc_obj.uc_eng.hook_add(UC_HOOK_CODE, self.code_cb_handler.logger, (proc_obj, self.get_arch(), self.get_ptr_size()))
        #h3 = self.uc_eng.hook_add(UC_HOOK_MEM_UNMAPPED, self.code_cb_handler.unmap_handler, (self, self.get_arch(), self.get_ptr_size()))
        pass

    def switch_thread_context(self,
                              proc_obj: EmuProcess,
                              thread_obj: EmuThread,
                              ret=0):
        def context_switch_cb(proc_obj: EmuProcess, thread_handle):
            proc_obj.running_thread.save_context()
            proc_obj.push_waiting_queue(proc_obj.running_thread.handle)
            proc_obj.push_waiting_queue(thread_handle)
            proc_obj.uc_eng.hook_del(proc_obj.ctx_switch_hook)
            proc_obj.running_thread.suspend_thread()

        proc_obj.ctx_switch_hook = proc_obj.uc_eng.hook_add(
            UC_HOOK_CODE, self.api_handler.post_api_call_cb_wrapper,
            (proc_obj, (proc_obj, thread_obj.handle), 1, context_switch_cb))
        pass

    def create_thread(
            self,
            proc_obj: EmuProcess,
            thread_entry,
            param=None,
            stack_size=1024 * 1024,  # 1MB default stack size
            creation=windef.CREATE_NEW):
        if stack_size == 0:
            stack_size = 1024 * 1024
        thread_stack_region = self.mem_manager.alloc_page(
            proc_obj.pid, stack_size, PageAllocationType.MEM_COMMIT)
        stack_limit, stack_base = thread_stack_region.get_page_region_range()
        hThread = self.obj_manager.create_new_object(
            'Thread', proc_obj, thread_entry, stack_base - stack_size + 0x1000,
            stack_limit, param)
        thread_obj: EmuThread = self.obj_manager.get_obj_by_handle(hThread)
        thread_obj.set_thread_stack(thread_stack_region)
        thread_obj.teb_heap = self.mem_manager.create_heap(proc_obj.pid,
                                                           size=0x10000,
                                                           max_size=0x10000)

        if creation & windef.CREATE_SUSPENDED:
            thread_obj.suspend_count += 1
        teb_base = self.mem_manager.alloc_heap(
            thread_obj.teb_heap,
            ntos.TEB(self.ptr_size).sizeof())
        gdt_page = self.mem_manager.alloc_page(proc_obj.pid, 0x1000,
                                               PageAllocationType.MEM_COMMIT)

        selectors = proc_obj.gdt.setup_selector(
            gdt_addr=gdt_page.get_base_addr(),
            fs_base=teb_base,
            fs_limit=ALLOCATION_GRANULARITY)
        thread_obj.set_selectors(selectors)
        thread_obj.init_teb(proc_obj.peb_base)
        thread_obj.init_context()
        self.mem_manager.write_process_memory(proc_obj.pid, teb_base,
                                              thread_obj.get_bytes())

        EmuThreadManager.push_wait_queue(proc_obj.pid, thread_obj.tid,
                                         thread_obj)

        return hThread

    def create_process(self, file_path):
        def parse_pe_binary(pe_bin):
            return pefile.PE(data=pe_bin)

        """
            1. 
        """
        if os.path.basename(file_path) == file_path:
            # input file_path is using alias
            # search procedure
            # 1. %home_dir%
            # 2. c:/windows/system32
            virtual_file_path = convert_winpath_to_emupath(
                emu_path_join(self.emu_home_dir, file_path))
            virtual_file_path = emu_path_join(virtual_file_path["vl"],
                                              virtual_file_path["ps"])
            if self.emu_vfs.check_file_exist(virtual_file_path):
                pass
            else:
                virtual_file_path = convert_winpath_to_emupath(
                    emu_path_join("c:/windows/system32", file_path))
                virtual_file_path = emu_path_join(virtual_file_path["vl"],
                                                  virtual_file_path["ps"])
                if self.emu_vfs.check_file_exist(virtual_file_path):
                    pass
                else:
                    """
                    *** Copy Mock Application to Start
                    """
                    mock_app_path = emu_path_join(self.emu_home_dir, file_path)
                    self.emu_vfs.vcopy(self.emu_vfs.dummpy_app, mock_app_path)
                    virtual_file_path = mock_app_path
        else:
            virtual_file_path = convert_winpath_to_emupath(file_path)
            virtual_file_path = emu_path_join(virtual_file_path["vl"],
                                              virtual_file_path["ps"])

        uc_eng = self.create_new_emu_engine()
        hFile = self.obj_manager.get_object_handle(
            'File', virtual_file_path, DesiredAccess.GENERIC_ALL,
            CreationDisposition.OPEN_EXISTING, 0,
            FileAttribute.FILE_ATTRIBUTE_NORMAL)

        if hFile == windef.INVALID_HANDLE_VALUE:
            raise Exception("There is no target file to execute")

        pHandle = self.obj_manager.create_new_object('Process', uc_eng, self,
                                                     virtual_file_path, hFile)
        proc_obj = self.obj_manager.get_obj_by_handle(pHandle)
        file_obj = self.obj_manager.get_obj_by_handle(hFile)
        rf = file_obj.im_read_file()

        if not rf["success"]:
            return None

        pe_bin = rf["data"]
        _pe_ = parse_pe_binary(pe_bin)
        proc_obj.set_parsed_pe(_pe_)
        self.mem_manager.register_new_process(proc_obj)

        self.init_vas(proc_obj)
        self.init_peb(proc_obj)
        self.load_target_proc(proc_obj)
        self.setup_uc_hooks(proc_obj)
        self.load_import_mods(proc_obj)
        self.setup_import_tab(proc_obj)
        hThread = self.create_thread(proc_obj, proc_obj.entry_point)

        return proc_obj, pHandle, hThread

    def create_process_ex(self, section_handle):
        pass

    def __update_api_va_dict__(self, va, dll: str, api: str):
        self.api_va_dict[va] = (dll, api)
        pass

    def __set_emulation_config(self, config=None):
        """
        Parse the config to be used for emulation
        """
        import json

        if not config:
            config_path = os.path.join(os.getcwd(), "env.config")
            with open(config_path, 'r') as f:
                self.config = json.load(f)
                config = self.config
        else:
            self.config = config

        if isinstance(config, str):
            config = json.loads(config)
        self.osversion = config.get('os_ver', {})
        self.env = config.get('env', {})
        self.user_config = config.get('user', {})
        self.domain = config.get('domain')
        self.hostname = config.get('hostname')
        self.symlinks = config.get('symlinks', [])
        self.drive_config = config.get('drives', [])
        self.registry_config = config.get('registry', {})
        self.network_config = config.get('network', {})
        self.process_config = config.get('processes', [])
        self.command_line = config.get('command_line', '')
        self.img_name = config.get('image_name' '')
        self.img_path = config.get('image_path', '')
        self.emu_home_dir = config.get('home_dir',
                                       '').lower().replace("\\", "/")

        self.parse_api_conf()

    def parse_api_conf(self, conf_path="./winapi.config"):
        with open(conf_path, "rt") as f:
            confs = f.readlines()
        for line in confs:
            line = line[:-1]
            if not line:
                continue
            if line[0] == "#":
                continue
            s = line.split("|")
            rettype = s[0]
            api_name = s[1]
            if len(s) > 2:
                args_types = s[2:]
            else:
                args_types = []
            self.winapi_info_dict[api_name] = {
                "rettype": rettype,
                "argc": len(args_types),
                "args_types": args_types
            }

    def new_unicode_string(self, proc_obj: EmuProcess, ustr, pystr: str):
        uBytes = (pystr + "\x00").encode("utf-16le")
        pMem = self.mem_manager.alloc_heap(proc_obj.proc_default_heap,
                                           len(uBytes) + 1)
        ustr.Length = len(uBytes)
        ustr.MaximumLength = len(uBytes) + 1
        ustr.Buffer = pMem
        self.mem_manager.write_process_memory(proc_obj.pid, pMem, uBytes)

        pass

    def get_ptr_size(self):
        return self.ptr_size

    def get_arch(self):
        return self.arch

    def set_ptr_size(self):
        if self.arch == UC_ARCH_X86 and self.mode == UC_MODE_32:
            self.ptr_size = 4
        # elif self.arch == UC_ARCH_X86 and self.mode == UC_MODE_64: # reserved
        #     self.ptr_size = 8
        else:
            raise Exception("Unsupported architecture")

    def get_param(self):
        return self.command_line.split(" ")[1:]
예제 #17
0
 def free_heap(self, handle, address):
     heap = ObjectManager.get_obj_by_handle(handle)
     heap.free_heap_segment(address=address)
     pass