def run_shellcode(self, sc_addr, offset=0): """ Begin emulating position independent code (i.e. shellcode) to prepare for emulation """ target = None for sc_path, _sc_addr, size in self.pic_buffers: if _sc_addr == sc_addr: target = _sc_addr break if not target: raise Win32EmuError("Invalid shellcode address") stack_commit = 0x4000 self.stack_base, stack_addr = self.alloc_stack(stack_commit) self.set_func_args(self.stack_base, self.return_hook, 0x7000) run = Run() run.type = "shellcode" run.start_addr = sc_addr + offset run.instr_cnt = 0 args = [ self.mem_map(1024, tag="emu.shellcode_arg_%d" % (i), base=0x41420000 + i) for i in range(4) ] run.args = args self.reg_write(_arch.X86_REG_ECX, 1024) self.add_run(run) # Create an empty process object for the shellcode if none is # supplied container = self.init_container_process() if container: self.processes.append(container) self.curr_process = container else: p = objman.Process(self) self.processes.append(p) self.curr_process = p mm = self.get_address_map(sc_addr) if mm: mm.set_process(self.curr_process) t = objman.Thread(self, stack_base=self.stack_base, stack_commit=stack_commit) self.om.objects.update({t.address: t}) self.curr_process.threads.append(t) self.curr_thread = t peb = self.alloc_peb(self.curr_process) # Set the TEB self.init_teb(t, peb) self.start()
def run_module(self, module, all_entrypoints=False, entrypoints:List[str]=None): """ Begin emulation fo a previously loaded kernel module """ if entrypoints is None: entrypoints = [] self.all_entrypoints = all_entrypoints # Create the service key for the driver drv = self.create_driver_object(pe=module) svc_key = self.regman.create_key(drv.get_reg_path()) # Create the values for the service key svc_key.create_value("ImagePath", regdefs.REG_EXPAND_SZ, module.get_emu_path()) svc_key.create_value("Type", regdefs.REG_DWORD, 0x1) # SERVICE_KERNEL_DRIVER svc_key.create_value("Start", regdefs.REG_DWORD, 0x3) # SERVICE_DEMAND_START svc_key.create_value( "ErrorControl", regdefs.REG_DWORD, 0x1 ) # SERVICE_ERROR_NORMAL # Create the parameters subkey self.regman.create_key(drv.get_reg_path() + "\\Parameters") if module.ep > 0: ep = module.base + module.ep run = Run() run.type = EP_DRIVER_ENTRY run.start_addr = ep run.instr_cnt = 0 run.args = [drv.address, drv.reg_path_ptr] self.add_run(run) if self.all_entrypoints or entrypoints: # Only emulate a subset of all the exported functions # There are some modules (such as the windows kernel) with thousands of exports exports = [k for k in module.get_exports()[:MAX_EXPORTS_TO_EMULATE]] if exports: args = [ self.mem_map(8, tag="emu.export_arg_%d" % (i)) for i in range(4) ] for exp in exports: if all_entrypoints or exp.name in entrypoints: run = Run() if exp.name: fn = exp.name else: fn = "no_name" run.type = "export.%s" % (fn) run.start_addr = exp.address # Here we set dummy args to pass into the export function run.args = args # Store these runs and only queue them before the unload routine # this is because some exports may not be ready to be called yet self.delayed_runs.append(run) self.start()
def next_driver_func(self, drv): func_addr = None func_handler = None if self.curr_run.type is not None: self.curr_run.ret_val = self.get_return_val() # Check if theres anything in the run queue if len(self.run_queue): return if not self.all_entrypoints: return # TODO right now just use the first device object that was created dev = None if len(drv.devices): dev = drv.devices[0] # Run any remaining IRP handlers for hdlr, i in ( (self.irp_mj_create, ddk.IRP_MJ_CREATE), (self.irp_mj_dev_io, ddk.IRP_MJ_DEVICE_CONTROL), (self.irp_mj_read, ddk.IRP_MJ_READ), (self.irp_mj_write, ddk.IRP_MJ_WRITE), (self.irp_mj_close, ddk.IRP_MJ_CLOSE), (self.irp_mj_cleanup, ddk.IRP_MJ_CLEANUP), ): # Did we run this mj func yet? if i not in [r.type for r in self.runs]: func_handler = hdlr func_addr = int(drv.mj_funcs[i]) if not func_addr: continue break if len(self.delayed_runs): [self.add_run(r) for r in self.delayed_runs] self.delayed_runs = [] if not func_addr or not dev: # We are done here, call the unload routine self.driver_unload(drv) return irp = func_handler(func_addr, dev) run = Run() run.type = i run.start_addr = func_addr run.instr_cnt = 0 run.args = (dev.address, irp.address) self.add_run(run)
def driver_unload(self, drv): """ Call the unload routine for a driver """ if not drv.on_unload or drv.unload_called: self.on_emu_complete() return stk_ptr = self.get_stack_ptr() self.set_func_args(stk_ptr, self.exit_hook, drv.address) self.set_pc(drv.on_unload) run = Run() run.type = EP_DRIVER_UNLOAD run.start_addr = drv.on_unload run.instr_cnt = 0 run.args = (drv.address, ) run.ret_val = None self.add_run(run) drv.unload_called = True
def run_module(self, module, all_entrypoints=False): """ Begin emulating a previously loaded module Arguments: module: Module to emulate """ if not module: self.stop() raise Win32EmuError('Module not found') ep = module.base + module.ep run = Run() run.start_addr = ep run.instr_cnt = 0 main_exe = None if not module.is_exe(): run.args = [module.base, DLL_PROCESS_ATTACH, 0] run.type = 'dll_entry.DLL_PROCESS_ATTACH' container = self.init_container_process() if container: self.processes.append(container) self.curr_process = container else: run.type = 'module_entry' main_exe = module run.args = [ self.mem_map(8, tag='emu.module_arg_%d' % (i)) for i in range(4) ] if main_exe: self.user_modules = [main_exe] + self.user_modules self.add_run(run) if all_entrypoints: # Only emulate a subset of all the exported functions # There are some modules (such as the windows kernel) with # thousands of exports exports = [ k for k in module.get_exports()[:MAX_EXPORTS_TO_EMULATE] ] if exports: args = [ self.mem_map(8, tag='emu.export_arg_%d' % (i), base=0x41420000) for i in range(4) ] # noqa for exp in exports: if exp.name in ('DllMain', 'ServiceMain'): continue run = Run() if exp.name: fn = exp.name else: fn = 'no_name' run.type = 'export.%s' % (fn) run.start_addr = exp.address # Here we set dummy args to pass into the export function run.args = args # Store these runs and only queue them before the unload # routine this is because some exports may not be ready to # be called yet self.add_run(run) # Create an empty process object for the module if none is # supplied if len(self.processes) == 0: p = objman.Process(self, path=module.get_emu_path(), base=module.base, pe=module, cmdline=self.command_line) self.curr_process = p t = objman.Thread(self, stack_base=self.stack_base, stack_commit=module.stack_commit) self.om.objects.update({t.address: t}) self.curr_process.threads.append(t) self.curr_thread = t peb = self.alloc_peb(self.curr_process) # Set the TEB self.init_teb(t, peb) # Begin emulation self.start()