def build_peb(jitter, peb_address): """ Build PEB informations using following structure: +0x000 InheritedAddressSpace : UChar +0x001 ReadImageFileExecOptions : UChar +0x002 BeingDebugged : UChar +0x003 SpareBool : UChar +0x004 Mutant : Ptr32 Void +0x008 ImageBaseAddress : Ptr32 Void +0x00c Ldr : Ptr32 _PEB_LDR_DATA +0x010 processparameter @jitter: jitter instance @peb_address: the PEB address """ offset = peb_address + 8 o = "" if main_pe: o += pck32(main_pe.NThdr.ImageBase) else: offset += 4 o += pck32(peb_ldr_data_address) o += pck32(process_parameters_address) jitter.vm.add_memory_page(offset, PAGE_READ | PAGE_WRITE, o)
def fix_InInitializationOrderModuleList(myjit, module_info): # first binary is ntdll # second binary is kernel32 olist = [] ntdll_e = None kernel_e = None for bname, (addr, e) in module_info.items(): if bname[::2].lower() == "ntdll.dll": ntdll_e = (e, bname, addr) continue elif bname[::2].lower() == "kernel32.dll": kernel_e = (e, bname, addr) continue elif e == dummy_e: d_e = (e, bname, addr) continue elif e == main_pe: continue olist.append((e, bname, addr)) if not ntdll_e or not kernel_e or not d_e: log.warn('No kernel ntdll, ldr data will be unconsistant') else: olist[0:0] = [ntdll_e] olist[1:1] = [kernel_e] olist.append(d_e) last_addr = 0 for i in xrange(len(olist)): e, bname, addr = olist[i] p_e, p_bname, p_addr = olist[(i - 1) % len(olist)] n_e, n_bname, n_addr = olist[(i + 1) % len(olist)] myjit.vm.set_mem( addr + 0x10, pck32(n_addr + 0x10) + pck32(p_addr + 0x10))
def fix_InInitializationOrderModuleList(jitter, modules_info): """Fix InInitializationOrderModuleList double link list. First module is the ntdll, then kernel32. dummy is last pe. @jitter: the jitter instance @modules_info: the LoadedModules instance """ log.debug("Fix InInitializationOrderModuleList") main_pe = modules_info.name2module.get(main_pe_name, None) kernel32_pe = modules_info.name2module.get("kernel32.dll", None) ntdll_pe = modules_info.name2module.get("ntdll.dll", None) dummy_pe = modules_info.name2module.get("", None) special_modules = [main_pe, kernel32_pe, ntdll_pe, dummy_pe] if not all(special_modules): log.warn('No main pe, ldr data will be unconsistant') loaded_modules = modules_info.modules else: loaded_modules = [module for module in modules_info.modules if module not in special_modules] loaded_modules[0:0] = [ntdll_pe] loaded_modules[1:1] = [kernel32_pe] loaded_modules.append(dummy_pe) for i, module in enumerate(loaded_modules): cur_module_entry = modules_info.module2entry[module] prev_module = loaded_modules[(i - 1) % len(loaded_modules)] next_module = loaded_modules[(i + 1) % len(loaded_modules)] prev_module_entry = modules_info.module2entry[prev_module] next_module_entry = modules_info.module2entry[next_module] jitter.vm.set_mem(cur_module_entry + 0x10, (pck32(next_module_entry + 0x10) + pck32(prev_module_entry + 0x10)))
def add_process_parameters(myjit): o = "" o += pck32(0x1000) # size o += "E" * (0x48 - len(o)) o += pck32(process_environment_address) myjit.vm.add_memory_page(process_parameters_address, PAGE_READ | PAGE_WRITE, o)
def init_seh(jitter): """ Build the modules entries and create double links @jitter: jitter instance """ global seh_count seh_count = 0 build_teb(jitter, FS_0_AD) build_peb(jitter, peb_address) modules_info = create_modules_chain(jitter, name2module) fix_InLoadOrderModuleList(jitter, modules_info) fix_InMemoryOrderModuleList(jitter, modules_info) fix_InInitializationOrderModuleList(jitter, modules_info) build_ldr_data(jitter, modules_info) add_process_env(jitter) add_process_parameters(jitter) jitter.vm.add_memory_page(default_seh, PAGE_READ | PAGE_WRITE, pck32( 0xffffffff) + pck32(0x41414141) + pck32(0x42424242)) jitter.vm.add_memory_page( context_address, PAGE_READ | PAGE_WRITE, '\x00' * 0x2cc) jitter.vm.add_memory_page( exception_record_address, PAGE_READ | PAGE_WRITE, '\x00' * 200) jitter.vm.add_memory_page( FAKE_SEH_B_AD, PAGE_READ | PAGE_WRITE, 0x10000 * "\x00")
def init_seh(myjit): global seh_count seh_count = 0 build_teb(myjit, FS_0_AD) build_peb(myjit, peb_address) module_info = create_modules_chain(myjit, loaded_modules) fix_InLoadOrderModuleList(myjit, module_info) fix_InMemoryOrderModuleList(myjit, module_info) fix_InInitializationOrderModuleList(myjit, module_info) build_ldr_data(myjit, module_info) add_process_env(myjit) add_process_parameters(myjit) myjit.vm.add_memory_page(default_seh, PAGE_READ | PAGE_WRITE, pck32( 0xffffffff) + pck32(0x41414141) + pck32(0x42424242)) myjit.vm.add_memory_page( context_address, PAGE_READ | PAGE_WRITE, '\x00' * 0x2cc) myjit.vm.add_memory_page( exception_record_address, PAGE_READ | PAGE_WRITE, '\x00' * 200) myjit.vm.add_memory_page( FAKE_SEH_B_AD, PAGE_READ | PAGE_WRITE, 0x10000 * "\x00")
def init_seh(jitter): """ Build the modules entries and create double links @jitter: jitter instance """ global seh_count seh_count = 0 build_teb(jitter, FS_0_AD) build_peb(jitter, peb_address) modules_info = create_modules_chain(jitter, name2module) fix_InLoadOrderModuleList(jitter, modules_info) fix_InMemoryOrderModuleList(jitter, modules_info) fix_InInitializationOrderModuleList(jitter, modules_info) build_ldr_data(jitter, modules_info) add_process_env(jitter) add_process_parameters(jitter) jitter.vm.add_memory_page( default_seh, PAGE_READ | PAGE_WRITE, pck32(0xffffffff) + pck32(0x41414141) + pck32(0x42424242)) jitter.vm.add_memory_page(context_address, PAGE_READ | PAGE_WRITE, '\x00' * 0x2cc) jitter.vm.add_memory_page(exception_record_address, PAGE_READ | PAGE_WRITE, '\x00' * 200) jitter.vm.add_memory_page(FAKE_SEH_B_AD, PAGE_READ | PAGE_WRITE, 0x10000 * "\x00")
def build_teb(jitter, teb_address): """ Build TEB informations using following structure: +0x000 NtTib : _NT_TIB +0x01c EnvironmentPointer : Ptr32 Void +0x020 ClientId : _CLIENT_ID +0x028 ActiveRpcHandle : Ptr32 Void +0x02c ThreadLocalStoragePointer : Ptr32 Void +0x030 ProcessEnvironmentBlock : Ptr32 _PEB +0x034 LastErrorValue : Uint4B ... @jitter: jitter instance @teb_address: the TEB address """ o = "" o += pck32(default_seh) o += (0x18 - len(o)) * "\x00" o += pck32(tib_address) o += (0x30 - len(o)) * "\x00" o += pck32(peb_address) o += pck32(0x11223344) jitter.vm.add_memory_page(teb_address, PAGE_READ | PAGE_WRITE, o)
def fix_InInitializationOrderModuleList(myjit, module_info): # first binary is ntdll # second binary is kernel32 olist = [] ntdll_e = None kernel_e = None for bname, (addr, e) in module_info.items(): if bname[::2].lower() == "ntdll.dll": ntdll_e = (e, bname, addr) continue elif bname[::2].lower() == "kernel32.dll": kernel_e = (e, bname, addr) continue elif e == dummy_e: d_e = (e, bname, addr) continue elif e == main_pe: continue olist.append((e, bname, addr)) if not ntdll_e or not kernel_e or not d_e: log.warn('no kernel ntdll, ldr data will be unconsistant') else: olist[0:0] = [ntdll_e] olist[1:1] = [kernel_e] olist.append(d_e) last_addr = 0 for i in xrange(len(olist)): e, bname, addr = olist[i] p_e, p_bname, p_addr = olist[(i - 1) % len(olist)] n_e, n_bname, n_addr = olist[(i + 1) % len(olist)] myjit.vm.set_mem(addr + 0x10, pck32(n_addr + 0x10) + pck32(p_addr + 0x10))
def add_process_parameters(jitter): """ Build a process parameters structure @jitter: jitter instance """ o = "" o += pck32(0x1000) # size o += "E" * (0x48 - len(o)) o += pck32(process_environment_address) jitter.vm.add_memory_page(process_parameters_address, PAGE_READ | PAGE_WRITE, o, "Process parameters")
def add_process_parameters(jitter): """ Build a process parameters structure @jitter: jitter instance """ o = "" o += pck32(0x1000) # size o += "E" * (0x48 - len(o)) o += pck32(process_environment_address) jitter.vm.add_memory_page(process_parameters_address, PAGE_READ | PAGE_WRITE, o)
def set_link_list_entry(jitter, loaded_modules, modules_info, offset): for i, module in enumerate(loaded_modules): cur_module_entry = modules_info.module2entry[module] prev_module = loaded_modules[(i - 1) % len(loaded_modules)] next_module = loaded_modules[(i + 1) % len(loaded_modules)] prev_module_entry = modules_info.module2entry[prev_module] next_module_entry = modules_info.module2entry[next_module] if i == 0: prev_module_entry = peb_ldr_data_address + 0xC if i == len(loaded_modules) - 1: next_module_entry = peb_ldr_data_address + 0xC jitter.vm.set_mem(cur_module_entry + offset, (pck32(next_module_entry + offset) + pck32(prev_module_entry + offset)))
def regs2ctxt(jitter): """ Build x86_32 cpu context for exception handling @jitter: jitload instance """ ctxt = [] # ContextFlags ctxt += [pck32(0x0)] # DRX ctxt += [pck32(0x0)] * 6 # Float context ctxt += ['\x00' * 112] # Segment selectors ctxt += [ pck32(reg) for reg in (jitter.cpu.GS, jitter.cpu.FS, jitter.cpu.ES, jitter.cpu.DS) ] # Gpregs ctxt += [ pck32(reg) for reg in (jitter.cpu.EDI, jitter.cpu.ESI, jitter.cpu.EBX, jitter.cpu.EDX, jitter.cpu.ECX, jitter.cpu.EAX, jitter.cpu.EBP, jitter.cpu.EIP) ] # CS ctxt += [pck32(jitter.cpu.CS)] # Eflags # XXX TODO real eflag ctxt += [pck32(0x0)] # ESP ctxt += [pck32(jitter.cpu.ESP)] # SS ctxt += [pck32(jitter.cpu.SS)] return "".join(ctxt)
def regs2ctxt(jitter): """ Build x86_32 cpu context for exception handling @jitter: jitload instance """ ctxt = [] # ContextFlags ctxt += [pck32(0x0)] # DRX ctxt += [pck32(0x0)] * 6 # Float context ctxt += ['\x00' * 112] # Segment selectors ctxt += [pck32(reg) for reg in (jitter.cpu.GS, jitter.cpu.FS, jitter.cpu.ES, jitter.cpu.DS)] # Gpregs ctxt += [pck32(reg) for reg in (jitter.cpu.EDI, jitter.cpu.ESI, jitter.cpu.EBX, jitter.cpu.EDX, jitter.cpu.ECX, jitter.cpu.EAX, jitter.cpu.EBP, jitter.cpu.EIP)] # CS ctxt += [pck32(jitter.cpu.CS)] # Eflags # XXX TODO real eflag ctxt += [pck32(0x0)] # ESP ctxt += [pck32(jitter.cpu.ESP)] # SS ctxt += [pck32(jitter.cpu.SS)] return "".join(ctxt)
def return_from_seh(jitter): """Handle the return from an exception handler @jitter: jitter instance""" # Get current context context_address = upck32(jitter.vm.get_mem(jitter.cpu.ESP + 0x8, 4)) log.info('Context address: %x', context_address) jitter.cpu.ESP = upck32(jitter.vm.get_mem(context_address + 0xc4, 4)) log.info('New esp: %x', jitter.cpu.ESP) # Rebuild SEH old_seh = upck32(jitter.vm.get_mem(tib_address, 4)) new_seh = upck32(jitter.vm.get_mem(old_seh, 4)) log.info('Old seh: %x New seh: %x', old_seh, new_seh) jitter.vm.set_mem(tib_address, pck32(new_seh)) dump_seh(jitter) if jitter.cpu.EAX == 0x0: # ExceptionContinueExecution ctxt_ptr = context_address log.info('Seh continues Context: %x', ctxt_ptr) # Get registers changes ctxt_str = jitter.vm.get_mem(ctxt_ptr, 0x2cc) ctxt2regs(ctxt_str, jitter) jitter.pc = jitter.cpu.EIP log.info('Context::Eip: %x', jitter.pc) elif jitter.cpu.EAX == -1: raise NotImplementedError("-> seh try to go to the next handler") elif jitter.cpu.EAX == 1: # ExceptionContinueSearch raise NotImplementedError("-> seh, gameover")
def return_from_seh(myjit): "Handle return after a call to fake seh handler" # Get current context context_address = upck32(myjit.vm.get_mem(myjit.cpu.ESP + 0x8, 4)) log.info('Context address: %x', context_address) myjit.cpu.ESP = upck32(myjit.vm.get_mem(context_address + 0xc4, 4)) log.info('New esp: %x', myjit.cpu.ESP) # Rebuild SEH old_seh = upck32(myjit.vm.get_mem(tib_address, 4)) new_seh = upck32(myjit.vm.get_mem(old_seh, 4)) log.info('Old seh: %x New seh: %x', old_seh, new_seh) myjit.vm.set_mem(tib_address, pck32(new_seh)) dump_seh(myjit) if myjit.cpu.EAX == 0x0: # ExceptionContinueExecution ctxt_ptr = context_address log.info('Seh continues Context: %x', ctxt_ptr) # Get registers changes ctxt_str = myjit.vm.get_mem(ctxt_ptr, 0x2cc) ctxt2regs(ctxt_str, myjit) myjit.pc = myjit.cpu.EIP log.info('Context::Eip: %x', myjit.pc) elif myjit.cpu.EAX == -1: raise NotImplementedError("-> seh try to go to the next handler") elif myjit.cpu.EAX == 1: # ExceptionContinueSearch raise NotImplementedError("-> seh, gameover")
def init_seh(myjit): global seh_count seh_count = 0 # myjit.vm.add_memory_page(tib_address, PAGE_READ | PAGE_WRITE, # p(default_seh) + p(0) * 11 + p(peb_address)) myjit.vm.add_memory_page( FS_0_AD, PAGE_READ | PAGE_WRITE, build_fake_teb()) # myjit.vm.add_memory_page(peb_address, PAGE_READ | PAGE_WRITE, p(0) * # 3 + p(peb_ldr_data_address)) myjit.vm.add_memory_page( peb_address, PAGE_READ | PAGE_WRITE, build_fake_peb()) # myjit.vm.add_memory_page(peb_ldr_data_address, PAGE_READ | # PAGE_WRITE, p(0) * 3 + p(in_load_order_module_list_address) + p(0) * # 0x20) """ ldr_data += "\x00"*(InInitializationOrderModuleList_offset - len(ldr_data)) ldr_data += build_fake_InInitializationOrderModuleList(loaded_modules) ldr_data += "\x00"*(InLoadOrderModuleList_offset - len(ldr_data)) ldr_data += build_fake_InLoadOrderModuleList(loaded_modules) """ myjit.vm.add_memory_page( LDR_AD, PAGE_READ | PAGE_WRITE, "\x00" * MAX_MODULES * 0x1000) module_info = create_modules_chain(myjit, loaded_modules) fix_InLoadOrderModuleList(myjit, module_info) fix_InMemoryOrderModuleList(myjit, module_info) fix_InInitializationOrderModuleList(myjit, module_info) ldr_data = build_fake_ldr_data(module_info) myjit.vm.set_mem(LDR_AD, ldr_data) add_process_env(myjit) add_process_parameters(myjit) # myjit.vm.add_memory_page(in_load_order_module_list_address, # PAGE_READ | PAGE_WRITE, p(0) * 40) # myjit.vm.add_memory_page(in_load_order_module_list_address, # PAGE_READ | PAGE_WRITE, build_fake_inordermodule(loaded_modules)) myjit.vm.add_memory_page(default_seh, PAGE_READ | PAGE_WRITE, pck32( 0xffffffff) + pck32(0x41414141) + pck32(0x42424242)) myjit.vm.add_memory_page( context_address, PAGE_READ | PAGE_WRITE, '\x00' * 0x2cc) myjit.vm.add_memory_page( exception_record_address, PAGE_READ | PAGE_WRITE, '\x00' * 200) myjit.vm.add_memory_page( FAKE_SEH_B_AD, PAGE_READ | PAGE_WRITE, 0x10000 * "\x00")
def test_init(self): init_regs(self) self.buf = "" for reg_name in reversed(["EAX", "ECX", "EDX", "EBX", "ESP", "EBP", "ESI", "EDI"]): self.buf += pck32(getattr(self.myjit.cpu, reg_name))
def init_seh(myjit): global seh_count seh_count = 0 # myjit.vm.add_memory_page(tib_address, PAGE_READ | PAGE_WRITE, # p(default_seh) + p(0) * 11 + p(peb_address)) myjit.vm.add_memory_page(FS_0_AD, PAGE_READ | PAGE_WRITE, build_fake_teb()) # myjit.vm.add_memory_page(peb_address, PAGE_READ | PAGE_WRITE, p(0) * # 3 + p(peb_ldr_data_address)) myjit.vm.add_memory_page(peb_address, PAGE_READ | PAGE_WRITE, build_fake_peb()) # myjit.vm.add_memory_page(peb_ldr_data_address, PAGE_READ | # PAGE_WRITE, p(0) * 3 + p(in_load_order_module_list_address) + p(0) * # 0x20) """ ldr_data += "\x00"*(InInitializationOrderModuleList_offset - len(ldr_data)) ldr_data += build_fake_InInitializationOrderModuleList(loaded_modules) ldr_data += "\x00"*(InLoadOrderModuleList_offset - len(ldr_data)) ldr_data += build_fake_InLoadOrderModuleList(loaded_modules) """ myjit.vm.add_memory_page(LDR_AD, PAGE_READ | PAGE_WRITE, "\x00" * MAX_MODULES * 0x1000) module_info = create_modules_chain(myjit, loaded_modules) fix_InLoadOrderModuleList(myjit, module_info) fix_InMemoryOrderModuleList(myjit, module_info) fix_InInitializationOrderModuleList(myjit, module_info) ldr_data = build_fake_ldr_data(module_info) myjit.vm.set_mem(LDR_AD, ldr_data) add_process_env(myjit) add_process_parameters(myjit) # myjit.vm.add_memory_page(in_load_order_module_list_address, # PAGE_READ | PAGE_WRITE, p(0) * 40) # myjit.vm.add_memory_page(in_load_order_module_list_address, # PAGE_READ | PAGE_WRITE, build_fake_inordermodule(loaded_modules)) myjit.vm.add_memory_page( default_seh, PAGE_READ | PAGE_WRITE, pck32(0xffffffff) + pck32(0x41414141) + pck32(0x42424242)) myjit.vm.add_memory_page(context_address, PAGE_READ | PAGE_WRITE, '\x00' * 0x2cc) myjit.vm.add_memory_page(exception_record_address, PAGE_READ | PAGE_WRITE, '\x00' * 200) myjit.vm.add_memory_page(FAKE_SEH_B_AD, PAGE_READ | PAGE_WRITE, 0x10000 * "\x00")
def msvcrt___p___argc(jitter): global argc_init ret_ad, _ = jitter.func_args_cdecl(0) addr_argc = 0x13370000 if not argc_init: jitter.vm.add_memory_page(addr_argc, PAGE_READ | PAGE_WRITE, pck32(1), "argc") argc_init = True jitter.func_ret_stdcall(ret_ad, addr_argc)
def fix_InMemoryOrderModuleList(myjit, module_info): log.debug("Fix InMemoryOrderModuleList") # first binary is PE # last is dumm_e olist = [] m_e = None d_e = None for m in [main_pe_name, ""] + loaded_modules: if isinstance(m, tuple): fname, e = m else: fname, e = m, None if "/" in fname: fname = fname[fname.rfind("/") + 1:] bname_str = fname bname = '\x00'.join(bname_str) + '\x00' if not bname.lower() in module_info: log.warn('Module not found, ldr data will be unconsistant') continue addr, e = module_info[bname.lower()] log.debug(bname_str) if e == main_pe: m_e = (e, bname, addr) continue elif e == dummy_e: d_e = (e, bname, addr) continue olist.append((e, bname, addr)) if not m_e or not d_e: log.warn('No main pe, ldr data will be unconsistant') else: olist[0:0] = [m_e] olist.append(d_e) last_addr = 0 for i in xrange(len(olist)): e, bname, addr = olist[i] p_e, p_bname, p_addr = olist[(i - 1) % len(olist)] n_e, n_bname, n_addr = olist[(i + 1) % len(olist)] myjit.vm.set_mem( addr + 0x8, pck32(n_addr + 0x8) + pck32(p_addr + 0x8))
def regs2ctxt(regs): ctxt = "" ctxt += '\x00\x00\x00\x00' # ContextFlags ctxt += '\x00\x00\x00\x00' * 6 # drX ctxt += '\x00' * 112 # float context ctxt += '\x00\x00\x00\x00' + '\x3b\x00\x00\x00' + \ '\x23\x00\x00\x00' + '\x23\x00\x00\x00' # segment selectors ctxt += pck32(regs['EDI']) + pck32(regs['ESI']) + pck32(regs['EBX']) + \ pck32(regs['EDX']) + pck32(regs['ECX']) + pck32(regs['EAX']) + \ pck32(regs['EBP']) + pck32(regs['EIP']) # gpregs ctxt += '\x23\x00\x00\x00' # cs ctxt += '\x00\x00\x00\x00' # eflags ctxt += pck32(regs['ESP']) # esp ctxt += '\x23\x00\x00\x00' # ss segment selector return ctxt
def fix_InLoadOrderModuleList(myjit, module_info): print "fix inloadorder" # first binary is PE # last is dumm_e olist = [] m_e = None d_e = None for m in [main_pe_name, ""] + loaded_modules: if isinstance(m, tuple): fname, e = m else: fname, e = m, None if "/" in fname: fname = fname[fname.rfind("/") + 1:] bname = '\x00'.join(fname) + '\x00' if not bname.lower() in module_info: log.warn('module not found, ldr data will be unconsistant') continue addr, e = module_info[bname.lower()] # for bname, (addr, e) in module_info.items(): print bname if e == main_pe: m_e = (e, bname, addr) continue elif e == dummy_e: d_e = (e, bname, addr) continue olist.append((e, bname, addr)) if not m_e or not d_e: log.warn('no main pe, ldr data will be unconsistant') else: olist[0:0] = [m_e] olist.append(d_e) last_addr = 0 for i in xrange(len(olist)): e, bname, addr = olist[i] p_e, p_bname, p_addr = olist[(i - 1) % len(olist)] n_e, n_bname, n_addr = olist[(i + 1) % len(olist)] myjit.vm.set_mem(addr + 0, pck32(n_addr) + pck32(p_addr))
def build_ldr_data(jitter, modules_info): """ Build Loader informations using following structure: +0x000 Length : Uint4B +0x004 Initialized : UChar +0x008 SsHandle : Ptr32 Void +0x00c InLoadOrderModuleList : _LIST_ENTRY +0x014 InMemoryOrderModuleList : _LIST_ENTRY +0x01C InInitializationOrderModuleList : _LIST_ENTRY # dummy dll base +0x024 DllBase : Ptr32 Void @jitter: jitter instance @modules_info: LoadedModules instance """ # ldr offset pad offset = 0xC addr = LDR_AD + peb_ldr_data_offset ldrdata = PEB_LDR_DATA(jitter.vm, addr) main_pe = modules_info.name2module.get(main_pe_name, None) ntdll_pe = modules_info.name2module.get("ntdll.dll", None) size = 0 if main_pe: size += ListEntry.sizeof() * 2 main_addr_entry = modules_info.module2entry[main_pe] if ntdll_pe: size += ListEntry.sizeof() ntdll_addr_entry = modules_info.module2entry[ntdll_pe] jitter.vm.add_memory_page(addr + offset, PAGE_READ | PAGE_WRITE, "\x00" * size, "Loader struct") # (ldrdata.get_size() - offset)) if main_pe: ldrdata.InLoadOrderModuleList.flink = main_addr_entry ldrdata.InLoadOrderModuleList.blink = 0 ldrdata.InMemoryOrderModuleList.flink = main_addr_entry + \ LdrDataEntry.get_type().get_offset("InMemoryOrderLinks") ldrdata.InMemoryOrderModuleList.blink = 0 if ntdll_pe: ldrdata.InInitializationOrderModuleList.flink = ntdll_addr_entry + \ LdrDataEntry.get_type().get_offset("InInitializationOrderLinks") ldrdata.InInitializationOrderModuleList.blink = 0 # Add dummy dll base jitter.vm.add_memory_page(peb_ldr_data_address + 0x24, PAGE_READ | PAGE_WRITE, pck32(0), "Loader struct dummy dllbase")
def build_fake_teb(): """ +0x000 NtTib : _NT_TIB +0x01c EnvironmentPointer : Ptr32 Void +0x020 ClientId : _CLIENT_ID +0x028 ActiveRpcHandle : Ptr32 Void +0x02c ThreadLocalStoragePointer : Ptr32 Void +0x030 ProcessEnvironmentBlock : Ptr32 _PEB +0x034 LastErrorValue : Uint4B ... """ o = "" o += pck32(default_seh) o += (0x18 - len(o)) * "\x00" o += pck32(tib_address) o += (0x30 - len(o)) * "\x00" o += pck32(peb_address) o += pck32(0x11223344) return o
def build_peb(myjit, peb_address): """ +0x000 InheritedAddressSpace : UChar +0x001 ReadImageFileExecOptions : UChar +0x002 BeingDebugged : UChar +0x003 SpareBool : UChar +0x004 Mutant : Ptr32 Void +0x008 ImageBaseAddress : Ptr32 Void +0x00c Ldr : Ptr32 _PEB_LDR_DATA +0x010 processparameter """ offset = peb_address + 8 o = "" if main_pe: o += pck32(main_pe.NThdr.ImageBase) else: offset += 4 o += pck32(peb_ldr_data_address) o += pck32(process_parameters_address) myjit.vm.add_memory_page(offset, PAGE_READ | PAGE_WRITE, o)
def build_teb(myjit, teb_address): """ +0x000 NtTib : _NT_TIB +0x01c EnvironmentPointer : Ptr32 Void +0x020 ClientId : _CLIENT_ID +0x028 ActiveRpcHandle : Ptr32 Void +0x02c ThreadLocalStoragePointer : Ptr32 Void +0x030 ProcessEnvironmentBlock : Ptr32 _PEB +0x034 LastErrorValue : Uint4B ... """ o = "" o += pck32(default_seh) o += (0x18 - len(o)) * "\x00" o += pck32(tib_address) o += (0x30 - len(o)) * "\x00" o += pck32(peb_address) o += pck32(0x11223344) myjit.vm.add_memory_page(teb_address, PAGE_READ | PAGE_WRITE, o)
def advapi32_CryptImportKey(jitter): ret_ad, args = jitter.func_args_stdcall(['hprov','data','dataLen','pubKey','flags','hKeyRet']) print("Import key: data=%x, len=%d, pubKey=%x, flags=%x, pkeyRet=%x" % ( args.data, args.dataLen, args.pubKey, args.flags, args.hKeyRet)) key = jitter.vm.get_mem(args.data, args.dataLen) key = wincrypt2.CryptImportKey(key) if key is None: jitter.func_ret_stdcall(ret_ad, 0) return handle = winobjs.handle_pool.add("CryptKey", key) jitter.vm.set_mem(args.hKeyRet, pck32(handle)) jitter.func_ret_stdcall(ret_ad, 1)
def init_seh(jitter): """ Build the modules entries and create double links @jitter: jitter instance """ global seh_count seh_count = 0 build_teb(jitter, FS_0_AD) build_peb(jitter, peb_address) modules_info = create_modules_chain(jitter, name2module) fix_InLoadOrderModuleList(jitter, modules_info) fix_InMemoryOrderModuleList(jitter, modules_info) fix_InInitializationOrderModuleList(jitter, modules_info) build_ldr_data(jitter, modules_info) add_process_env(jitter) add_process_parameters(jitter) jitter.vm.add_memory_page(default_seh, PAGE_READ | PAGE_WRITE, pck32( 0xffffffff) + pck32(0x41414141) + pck32(0x42424242), "Default seh handler")
def fix_InLoadOrderModuleList(jitter, modules_info): """Fix InLoadOrderModuleList double link list. First module is the main pe, then ntdll, kernel32. dummy is last pe. @jitter: the jitter instance @modules_info: the LoadedModules instance """ log.debug("Fix InLoadOrderModuleList") main_pe = modules_info.name2module.get(main_pe_name, None) kernel32_pe = modules_info.name2module.get("kernel32.dll", None) ntdll_pe = modules_info.name2module.get("ntdll.dll", None) dummy_pe = modules_info.name2module.get("", None) special_modules = [main_pe, kernel32_pe, ntdll_pe, dummy_pe] if not all(special_modules): log.warn('No main pe, ldr data will be unconsistant %r', special_modules) loaded_modules = modules_info.modules else: loaded_modules = [ module for module in modules_info.modules if module not in special_modules ] loaded_modules[0:0] = [main_pe] loaded_modules[1:1] = [ntdll_pe] loaded_modules[2:2] = [kernel32_pe] loaded_modules.append(dummy_pe) for i, module in enumerate(loaded_modules): cur_module_entry = modules_info.module2entry[module] prev_module = loaded_modules[(i - 1) % len(loaded_modules)] next_module = loaded_modules[(i + 1) % len(loaded_modules)] prev_module_entry = modules_info.module2entry[prev_module] next_module_entry = modules_info.module2entry[next_module] jitter.vm.set_mem( cur_module_entry, (pck32(next_module_entry) + pck32(prev_module_entry)))
def init_seh(jitter): """ Build the modules entries and create double links @jitter: jitter instance """ global seh_count seh_count = 0 build_teb(jitter, FS_0_AD) build_peb(jitter, peb_address) modules_info = create_modules_chain(jitter, name2module) fix_InLoadOrderModuleList(jitter, modules_info) fix_InMemoryOrderModuleList(jitter, modules_info) fix_InInitializationOrderModuleList(jitter, modules_info) build_ldr_data(jitter, modules_info) add_process_env(jitter) add_process_parameters(jitter) jitter.vm.add_memory_page( default_seh, PAGE_READ | PAGE_WRITE, pck32(0xffffffff) + pck32(0x41414141) + pck32(0x42424242), "Default seh handler")
def test_SystemInformationFunctions(self): # DWORD WINAPI GetVersion(void); jit.push_uint32_t(0) # @return winapi.kernel32_GetVersion(jit) dwVer = jit.cpu.EAX self.assertTrue(dwVer) # BOOL WINAPI GetVersionEx(_Inout_ LPOSVERSIONINFO lpVersionInfo); jit.vm.set_mem(jit.stack_base, pck32(0x9c)) jit.push_uint32_t(jit.stack_base) # lpVersionInfo jit.push_uint32_t(0) # @return winapi.kernel32_GetVersionExA(jit) vBool = jit.cpu.EAX self.assertTrue(vBool)
def kernel32_GetComputerNameW(jitter): # https://msdn.microsoft.com/fr-fr/library/windows/desktop/ms724295(v=vs.85).aspx ret_ad, args = jitter.func_args_stdcall(['lpBuffer', 'lpnSize']) # Get buffer size from memory size = upck32(jitter.vm.get_mem(args.lpnSize, 4)) # Removing one character to size, as it includes the terminal null character size = min(size-1, 10) name = "A"*(size) jitter.set_str_unic(args.lpBuffer, name) # Returned size must not include the null terminating character jitter.vm.set_mem(args.lpnSize, pck32(size)) # Returns true jitter.func_ret_stdcall(ret_ad, 1)
def build_ldr_data(jitter, modules_info): """ Build Loader informations using following structure: +0x000 Length : Uint4B +0x004 Initialized : UChar +0x008 SsHandle : Ptr32 Void +0x00c InLoadOrderModuleList : _LIST_ENTRY +0x014 InMemoryOrderModuleList : _LIST_ENTRY +0x01C InInitializationOrderModuleList : _LIST_ENTRY # dummy dll base +0x024 DllBase : Ptr32 Void @jitter: jitter instance @modules_info: LoadedModules instance """ # ldr offset pad offset = peb_ldr_data_address + 0xC # get main pe info main_pe = modules_info.name2module.get(main_pe_name, None) if not main_pe: log.warn('No main pe, ldr data will be unconsistant') offset, data = offset + 8, "" else: main_addr_entry = modules_info.module2entry[main_pe] log.info('Ldr %x', main_addr_entry) data = pck32(main_addr_entry) + pck32(0) data += pck32(main_addr_entry + 0x8) + pck32(0) # XXX TODO fix prev ntdll_pe = modules_info.name2module.get("ntdll.dll", None) if not ntdll_pe: log.warn('No ntdll, ldr data will be unconsistant') else: ntdll_addr_entry = modules_info.module2entry[ntdll_pe] data += pck32(ntdll_addr_entry + 0x10) + pck32(0) # XXX TODO fix prev if data: jitter.vm.add_memory_page(offset, PAGE_READ | PAGE_WRITE, data, "Loader struct") # Add dummy dll base jitter.vm.add_memory_page(peb_ldr_data_address + 0x24, PAGE_READ | PAGE_WRITE, pck32(0), "Loader struct dummy dllbase")
def advapi32_CryptDecrypt(jitter): ret_ad, args = jitter.func_args_stdcall(["hkey", "hhash", "final", "dwflags", "pbdata", "pdwdatalen"]) dataLen = upck32(jitter.vm.get_mem(args.pdwdatalen, 4)) print("CryptDecrypt: hkey = %x, data=%x, dataLen=%d" % (args.hkey, args.pbdata, dataLen)) if not args.hkey in winobjs.handle_pool: jitter.func_ret_stdcall(ret_ad, 0) return key = winobjs.handle_pool[args.hkey].info D = jitter.vm.get_mem(args.pbdata, dataLen) D = wincrypt2.CryptDecrypt(key, D) if D is None: jitter.func_ret_stdcall(ret_ad, 0) return D = str(D) print("Decrypted data: %s" % D.encode("hex")) jitter.vm.set_mem(args.pbdata, D) jitter.vm.set_mem(args.pdwdatalen, pck32(len(D))) jitter.func_ret_stdcall(ret_ad, 1)
def return_from_seh(myjit): "Handle return after a call to fake seh handler" # Get current context myjit.cpu.ESP = upck32(myjit.vm.get_mem(context_address + 0xc4, 4)) logging.info('-> new esp: %x', myjit.cpu.ESP) # Rebuild SEH old_seh = upck32(myjit.vm.get_mem(tib_address, 4)) new_seh = upck32(myjit.vm.get_mem(old_seh, 4)) logging.info('-> old seh: %x', old_seh) logging.info('-> new seh: %x', new_seh) myjit.vm.set_mem(tib_address, pck32(new_seh)) dump_seh(myjit) # Release SEH free_seh_place(old_seh) if myjit.cpu.EAX == 0x0: # ExceptionContinueExecution print '-> seh continues' ctxt_ptr = context_address print '-> context:', hex(ctxt_ptr) # Get registers changes ctxt_str = myjit.vm.get_mem(ctxt_ptr, 0x2cc) regs = ctxt2regs(ctxt_str) myjit.pc = regs["EIP"] for reg_name, reg_value in regs.items(): setattr(myjit.cpu, reg_name, reg_value) logging.info('-> context::Eip: %x', myjit.pc) elif myjit.cpu.EAX == -1: raise NotImplementedError("-> seh try to go to the next handler") elif myjit.cpu.EAX == 1: # ExceptionContinueSearch raise NotImplementedError("-> seh, gameover")
def build_fake_ldr_data(modules_info): """ +0x000 Length : Uint4B +0x004 Initialized : UChar +0x008 SsHandle : Ptr32 Void +0x00c InLoadOrderModuleList : _LIST_ENTRY +0x014 InMemoryOrderModuleList : _LIST_ENTRY +0x01C InInitializationOrderModuleList : _LIST_ENTRY """ o = "" # ldr offset pad o += "\x00" * peb_ldr_data_offset o += "\x00" * 0xc # text XXX # get main pe info m_e = None for bname, (addr, e) in modules_info.items(): if e == main_pe: m_e = (e, bname, addr) break if not m_e: log.warn('no main pe, ldr data will be unconsistant') else: print 'inloadorder first', hex(m_e[2]) o += pck32(m_e[2]) + pck32(0) # get ntdll ntdll_e = None for bname, (addr, e) in modules_info.items(): if bname[::2].lower() == "ntdll.dll": ntdll_e = (e, bname, addr) continue if not ntdll_e: log.warn('no ntdll, ldr data will be unconsistant') else: print 'ntdll', hex(ntdll_e[2]) o += pck32(ntdll_e[2] + 0x8) + pck32(0) # XXX TODO o += pck32(ntdll_e[2] + 0x10) + pck32(0) return o
def build_ldr_data(myjit, modules_info): """ +0x000 Length : Uint4B +0x004 Initialized : UChar +0x008 SsHandle : Ptr32 Void +0x00c InLoadOrderModuleList : _LIST_ENTRY +0x014 InMemoryOrderModuleList : _LIST_ENTRY +0x01C InInitializationOrderModuleList : _LIST_ENTRY """ o = "" # ldr offset pad offset = LDR_AD + peb_ldr_data_offset + 0xC # get main pe info m_e = None for bname, (addr, e) in modules_info.items(): if e == main_pe: m_e = (e, bname, addr) break if not m_e: log.warn('No main pe, ldr data will be unconsistant') offset, data = offset + 8, "" else: log.info('Ldr %x', m_e[2]) data = pck32(m_e[2]) + pck32(0) # get ntdll ntdll_e = None for bname, (addr, e) in modules_info.items(): if bname[::2].lower() == "ntdll.dll": ntdll_e = (e, bname, addr) continue if not ntdll_e: log.warn('No ntdll, ldr data will be unconsistant') else: data += pck32(ntdll_e[2] + 0x8) + pck32(0) # XXX TODO data += pck32(ntdll_e[2] + 0x10) + pck32(0) if data: myjit.vm.add_memory_page(offset, PAGE_READ | PAGE_WRITE, data)
def build_ldr_data(jitter, modules_info): """ Build Loader informations using following structure: +0x000 Length : Uint4B +0x004 Initialized : UChar +0x008 SsHandle : Ptr32 Void +0x00c InLoadOrderModuleList : _LIST_ENTRY +0x014 InMemoryOrderModuleList : _LIST_ENTRY +0x01C InInitializationOrderModuleList : _LIST_ENTRY @jitter: jitter instance @modules_info: LoadedModules instance """ # ldr offset pad offset = LDR_AD + peb_ldr_data_offset + 0xC # get main pe info main_pe = modules_info.name2module.get(main_pe_name, None) if not main_pe: log.warn('No main pe, ldr data will be unconsistant') offset, data = offset + 8, "" else: main_addr_entry = modules_info.module2entry[main_pe] log.info('Ldr %x', main_addr_entry) data = pck32(main_addr_entry) + pck32(0) data += pck32(main_addr_entry + 0x8) + pck32(0) # XXX TODO fix prev ntdll_pe = modules_info.name2module.get("ntdll.dll", None) if not ntdll_pe: log.warn('No ntdll, ldr data will be unconsistant') else: ntdll_addr_entry = modules_info.module2entry[ntdll_pe] data += pck32(ntdll_addr_entry + 0x10) + pck32(0) # XXX TODO fix prev if data: jitter.vm.add_memory_page(offset, PAGE_READ | PAGE_WRITE, data, "Loader struct")
def push_uint32_t(self, value): self.cpu.SP -= 4 self.vm.set_mem(self.cpu.SP, pck32(value))
def push_uint32_t(self, value): setattr(self.cpu, self.ira.sp.name, getattr(self.cpu, self.ira.sp.name) - self.ira.sp.size / 8) self.vm.set_mem(getattr(self.cpu, self.ira.sp.name), pck32(value))
def push_uint32_t(self, value): self.cpu.ESP -= self.ir_arch.sp.size / 8 self.vm.set_mem(self.cpu.ESP, pck32(value))
def create_modules_chain(jitter, name2module): """ Create the modules entries. Those modules are not linked in this function. kd> dt nt!_LDR_DATA_TABLE_ENTRY +0x000 InLoadOrderLinks : _LIST_ENTRY +0x008 InMemoryOrderLinks : _LIST_ENTRY +0x010 InInitializationOrderLinks : _LIST_ENTRY +0x018 DllBase : Ptr32 Void +0x01c EntryPoint : Ptr32 Void +0x020 SizeOfImage : Uint4B +0x024 FullDllName : _UNICODE_STRING +0x02c BaseDllName : _UNICODE_STRING +0x034 Flags : Uint4B +0x038 LoadCount : Uint2B +0x03a TlsIndex : Uint2B +0x03c HashLinks : _LIST_ENTRY +0x03c SectionPointer : Ptr32 Void +0x040 CheckSum : Uint4B +0x044 TimeDateStamp : Uint4B +0x044 LoadedImports : Ptr32 Void +0x048 EntryPointActivationContext : Ptr32 Void +0x04c PatchInformation : Ptr32 Void @jitter: jitter instance @name2module: dict containing association between name and its pe instance """ modules_info = LoadedModules() base_addr = LDR_AD + modules_list_offset # XXXX offset_name = 0x500 offset_path = 0x600 dummy_e = pe_init.PE() dummy_e.NThdr.ImageBase = 0 dummy_e.Opthdr.AddressOfEntryPoint = 0 dummy_e.NThdr.sizeofimage = 0 out = "" for i, (fname, pe_obj) in enumerate([("", dummy_e)] + name2module.items()): if pe_obj is None: log.warning("Unknown module: ommited from link list (%r)", fname) continue addr = base_addr + i * 0x1000 bpath = fname.replace('/', '\\') bname_str = os.path.split(fname)[1].lower() bname = "\x00".join(bname_str) + "\x00" log.info("Add module %x %r", pe_obj.NThdr.ImageBase, bname_str) modules_info.add(bname_str, pe_obj, addr) m_o = "" m_o += pck32(0) m_o += pck32(0) m_o += pck32(0) m_o += pck32(0) m_o += pck32(0) m_o += pck32(0) m_o += pck32(pe_obj.NThdr.ImageBase) m_o += pck32(pe_obj.rva2virt(pe_obj.Opthdr.AddressOfEntryPoint)) m_o += pck32(pe_obj.NThdr.sizeofimage) m_o += struct.pack('HH', len(bname), len(bname) + 2) m_o += pck32(addr + offset_path) m_o += struct.pack('HH', len(bname), len(bname) + 2) m_o += pck32(addr + offset_name) jitter.vm.add_memory_page(addr, PAGE_READ | PAGE_WRITE, m_o) m_o = "" m_o += bname m_o += "\x00" * 3 jitter.vm.add_memory_page(addr + offset_name, PAGE_READ | PAGE_WRITE, m_o) m_o = "" m_o += "\x00".join(bpath) + "\x00" m_o += "\x00" * 3 jitter.vm.add_memory_page(addr + offset_path, PAGE_READ | PAGE_WRITE, m_o) return modules_info
def fake_seh_handler(jitter, except_code): """ Create an exception context @jitter: jitter instance @except_code: x86 exception code """ global seh_count, context_address regs = jitter.cpu.get_gpreg() log.warning('Exception at %x %r', jitter.cpu.EIP, seh_count) seh_count += 1 # Help lambda p = lambda s: struct.pack('I', s) # Forge a CONTEXT ctxt = regs2ctxt(jitter) # Get current seh (fs:[0]) seh_ptr = upck32(jitter.vm.get_mem(tib_address, 4)) # Retrieve seh fields old_seh, eh, safe_place = struct.unpack( 'III', jitter.vm.get_mem(seh_ptr, 0xc)) # Get space on stack for exception handling jitter.cpu.ESP -= 0x3c8 exception_base_address = jitter.cpu.ESP exception_record_address = exception_base_address + 0xe8 context_address = exception_base_address + 0xfc fake_seh_address = exception_base_address + 0x14 log.info('seh_ptr %x { old_seh %x eh %x safe_place %x} ctx_addr %x', seh_ptr, old_seh, eh, safe_place, context_address) # Write context jitter.vm.set_mem(context_address, ctxt) # Write exception_record """ #http://msdn.microsoft.com/en-us/library/aa363082(v=vs.85).aspx typedef struct _EXCEPTION_RECORD { DWORD ExceptionCode; DWORD ExceptionFlags; struct _EXCEPTION_RECORD *ExceptionRecord; PVOID ExceptionAddress; DWORD NumberParameters; ULONG_PTR ExceptionInformation[EXCEPTION_MAXIMUM_PARAMETERS]; } EXCEPTION_RECORD, *PEXCEPTION_RECORD; """ jitter.vm.set_mem(exception_record_address, pck32(except_code) + pck32(0) + pck32(0) + pck32(jitter.cpu.EIP) + pck32(0)) # Prepare the stack jitter.push_uint32_t(context_address) # Context jitter.push_uint32_t(seh_ptr) # SEH jitter.push_uint32_t(exception_record_address) # ExceptRecords jitter.push_uint32_t(return_from_exception) # Ret address # Set fake new current seh for exception log.info("Fake seh ad %x", fake_seh_address) jitter.vm.set_mem(fake_seh_address, pck32(seh_ptr) + pck32( 0xaaaaaaaa) + pck32(0xaaaaaabb) + pck32(0xaaaaaacc)) jitter.vm.set_mem(tib_address, pck32(fake_seh_address)) dump_seh(jitter) log.info('Jumping at %x', eh) jitter.vm.set_exception(0) jitter.cpu.set_exception(0) # XXX set ebx to nul? jitter.cpu.EBX = 0 return eh
def build_fake_InLoadOrderModuleList(modules_name): """ +0x000 Flink : Ptr32 -+ This distance +0x004 Blink : Ptr32 | is eight bytes +0x018 DllBase : Ptr32 Void -+ DllBase -> _IMAGE_DOS_HEADER +0x01c EntryPoint : Ptr32 Void +0x020 SizeOfImage : Uint4B +0x024 FullDllName : _UNICODE_STRING +0x02c BaseDllName : _UNICODE_STRING +0x034 Flags : Uint4B +0x038 LoadCount : Uint2B +0x03a TlsIndex : Uint2B +0x03c HashLinks : _LIST_ENTRY +0x03c SectionPointer : Ptr32 Void +0x040 CheckSum : Uint4B +0x044 TimeDateStamp : Uint4B +0x044 LoadedImports : Ptr32 Void +0x048 EntryPointActivationContext : Ptr32 Void +0x04c PatchInformation : Ptr32 Void """ o = "" offset_name = 0x700 first_name = "\x00".join(main_pe_name + "\x00\x00") o = "" o += pck32(InLoadOrderModuleList_address) o += pck32(InLoadOrderModuleList_address + (len(modules_name) - 1) * 0x1000) o += pck32(InLoadOrderModuleList_address + 8) o += pck32(InLoadOrderModuleList_address + (len(modules_name) - 1) * 0x1000 + 8) o += pck32(InLoadOrderModuleList_address + 0x10) o += pck32(InLoadOrderModuleList_address + (len(modules_name) - 1) * 0x1000 + 0x10) if main_pe: o += pck32(main_pe.NThdr.ImageBase) o += pck32(main_pe.rva2virt(main_pe.Opthdr.AddressOfEntryPoint)) else: # no fixed values pass o += (0x24 - len(o)) * "A" o += struct.pack('HH', len(first_name), len(first_name)) o += pck32(InLoadOrderModuleList_address + offset_name) o += (0x2C - len(o)) * "A" o += struct.pack('HH', len(first_name), len(first_name)) o += pck32(InLoadOrderModuleList_address + offset_name) o += (offset_name - len(o)) * "B" o += first_name o += (0x1000 - len(o)) * "C" for i, m in enumerate(modules_name): # fname = os.path.join('win_dll', m) if isinstance(m, tuple): fname, e = m else: fname, e = m, None bname = os.path.split(fname)[1].lower() bname = "\x00".join(bname) + "\x00" print hex(InLoadOrderModuleList_address + i * 0x1000) if e is None: e = pe_init.PE(open(fname, 'rb').read()) print "add module", hex(e.NThdr.ImageBase), repr(bname) next_ad = InLoadOrderModuleList_address + (i + 1) * 0x1000 if i == len(modules_name) - 1: next_ad = InLoadOrderModuleList_address m_o = "" m_o += pck32(next_ad) m_o += pck32(InLoadOrderModuleList_address + (i - 1) * 0x1000) m_o += pck32(next_ad + 8) m_o += pck32(InLoadOrderModuleList_address + (i - 1) * 0x1000 + 8) m_o += pck32(next_ad + 0x10) m_o += pck32(InLoadOrderModuleList_address + (i - 1) * 0x1000 + 0x10) m_o += pck32(e.NThdr.ImageBase) m_o += pck32(e.rva2virt(e.Opthdr.AddressOfEntryPoint)) m_o += pck32(e.NThdr.sizeofimage) m_o += (0x24 - len(m_o)) * "A" print hex(len(bname)), repr(bname) m_o += struct.pack('HH', len(bname), len(bname) + 2) m_o += pck32(InLoadOrderModuleList_address + i * 0x1000 + offset_name) m_o += (0x2C - len(m_o)) * "A" m_o += struct.pack('HH', len(bname), len(bname) + 2) m_o += pck32(InLoadOrderModuleList_address + i * 0x1000 + offset_name) m_o += (offset_name - len(m_o)) * "B" m_o += bname m_o += "\x00" * 3 m_o += (0x1000 - len(m_o)) * "J" print "module", "%.8X" % e.NThdr.ImageBase, fname o += m_o return o
def fake_seh_handler(jitter, except_code): """ Create an exception context @jitter: jitter instance @except_code: x86 exception code """ global seh_count, context_address regs = jitter.cpu.get_gpreg() log.warning('Exception at %x %r', jitter.cpu.EIP, seh_count) seh_count += 1 # Help lambda p = lambda s: struct.pack('I', s) # Forge a CONTEXT ctxt = regs2ctxt(jitter) # Get current seh (fs:[0]) seh_ptr = upck32(jitter.vm.get_mem(tib_address, 4)) # Retrieve seh fields old_seh, eh, safe_place = struct.unpack('III', jitter.vm.get_mem(seh_ptr, 0xc)) # Get space on stack for exception handling jitter.cpu.ESP -= 0x3c8 exception_base_address = jitter.cpu.ESP exception_record_address = exception_base_address + 0xe8 context_address = exception_base_address + 0xfc fake_seh_address = exception_base_address + 0x14 log.info('seh_ptr %x { old_seh %x eh %x safe_place %x} ctx_addr %x', seh_ptr, old_seh, eh, safe_place, context_address) # Write context jitter.vm.set_mem(context_address, ctxt) # Write exception_record """ #http://msdn.microsoft.com/en-us/library/aa363082(v=vs.85).aspx typedef struct _EXCEPTION_RECORD { DWORD ExceptionCode; DWORD ExceptionFlags; struct _EXCEPTION_RECORD *ExceptionRecord; PVOID ExceptionAddress; DWORD NumberParameters; ULONG_PTR ExceptionInformation[EXCEPTION_MAXIMUM_PARAMETERS]; } EXCEPTION_RECORD, *PEXCEPTION_RECORD; """ jitter.vm.set_mem( exception_record_address, pck32(except_code) + pck32(0) + pck32(0) + pck32(jitter.cpu.EIP) + pck32(0)) # Prepare the stack jitter.push_uint32_t(context_address) # Context jitter.push_uint32_t(seh_ptr) # SEH jitter.push_uint32_t(exception_record_address) # ExceptRecords jitter.push_uint32_t(return_from_exception) # Ret address # Set fake new current seh for exception log.info("Fake seh ad %x", fake_seh_address) jitter.vm.set_mem( fake_seh_address, pck32(seh_ptr) + pck32(0xaaaaaaaa) + pck32(0xaaaaaabb) + pck32(0xaaaaaacc)) jitter.vm.set_mem(tib_address, pck32(fake_seh_address)) dump_seh(jitter) log.info('Jumping at %x', eh) jitter.vm.set_exception(0) jitter.cpu.set_exception(0) # XXX set ebx to nul? jitter.cpu.EBX = 0 return eh
def create_modules_chain(jitter, name2module): """ Create the modules entries. Those modules are not linked in this function. kd> dt nt!_LDR_DATA_TABLE_ENTRY +0x000 InLoadOrderLinks : _LIST_ENTRY +0x008 InMemoryOrderLinks : _LIST_ENTRY +0x010 InInitializationOrderLinks : _LIST_ENTRY +0x018 DllBase : Ptr32 Void +0x01c EntryPoint : Ptr32 Void +0x020 SizeOfImage : Uint4B +0x024 FullDllName : _UNICODE_STRING +0x02c BaseDllName : _UNICODE_STRING +0x034 Flags : Uint4B +0x038 LoadCount : Uint2B +0x03a TlsIndex : Uint2B +0x03c HashLinks : _LIST_ENTRY +0x03c SectionPointer : Ptr32 Void +0x040 CheckSum : Uint4B +0x044 TimeDateStamp : Uint4B +0x044 LoadedImports : Ptr32 Void +0x048 EntryPointActivationContext : Ptr32 Void +0x04c PatchInformation : Ptr32 Void @jitter: jitter instance @name2module: dict containing association between name and its pe instance """ modules_info = LoadedModules() base_addr = LDR_AD + modules_list_offset # XXXX offset_name = 0x500 offset_path = 0x600 dummy_e = pe_init.PE() dummy_e.NThdr.ImageBase = 0 dummy_e.Opthdr.AddressOfEntryPoint = 0 dummy_e.NThdr.sizeofimage = 0 out = "" for i, (fname, pe_obj) in enumerate([("", dummy_e)] + name2module.items()): if pe_obj is None: log.warning("Unknown module: ommited from link list (%r)", fname) continue addr = base_addr + i * 0x1000 bpath = fname.replace('/', '\\') bname_str = os.path.split(fname)[1].lower() bname = "\x00".join(bname_str) + "\x00" log.info("Add module %x %r", pe_obj.NThdr.ImageBase, bname_str) modules_info.add(bname_str, pe_obj, addr) m_o = "" m_o += pck32(0) m_o += pck32(0) m_o += pck32(0) m_o += pck32(0) m_o += pck32(0) m_o += pck32(0) m_o += pck32(pe_obj.NThdr.ImageBase) m_o += pck32(pe_obj.rva2virt(pe_obj.Opthdr.AddressOfEntryPoint)) m_o += pck32(pe_obj.NThdr.sizeofimage) m_o += struct.pack('HH', len(bname), len(bname) + 2) m_o += pck32(addr + offset_path) m_o += struct.pack('HH', len(bname), len(bname) + 2) m_o += pck32(addr + offset_name) jitter.vm.add_memory_page(addr, PAGE_READ | PAGE_WRITE, m_o) m_o = "" m_o += bname m_o += "\x00" * 3 jitter.vm.add_memory_page( addr + offset_name, PAGE_READ | PAGE_WRITE, m_o) m_o = "" m_o += "\x00".join(bpath) + "\x00" m_o += "\x00" * 3 jitter.vm.add_memory_page( addr + offset_path, PAGE_READ | PAGE_WRITE, m_o) return modules_info
def func_prepare_stdcall(self, ret_addr, *args): for index in xrange(min(len(args), 4)): setattr(self.cpu, 'R%d' % index, args[index]) for index in xrange(4, len(args)): self.vm.set_mem(self.cpu.SP + 4 * (index - 4), pck32(args[index])) self.cpu.LR = ret_addr
def fake_seh_handler(myjit, except_code): global seh_count regs = myjit.cpu.get_gpreg() print '-> exception at', hex(myjit.cpu.EIP), seh_count seh_count += 1 # Help lambda p = lambda s: struct.pack('I', s) # dump_gpregs_py() # jitarch.dump_gpregs() # Forge a CONTEXT ctxt = '\x00\x00\x00\x00' + '\x00\x00\x00\x00' * 6 + '\x00' * 112 ctxt += '\x00\x00\x00\x00' + '\x3b\x00\x00\x00' + '\x23\x00\x00\x00' ctxt += '\x23\x00\x00\x00' ctxt += pck32(myjit.cpu.EDI) + pck32(myjit.cpu.ESI) + \ pck32(myjit.cpu.EBX) + pck32(myjit.cpu.EDX) + \ pck32(myjit.cpu.ECX) + pck32(myjit.cpu.EAX) + \ pck32(myjit.cpu.EBP) + pck32(myjit.cpu.EIP) ctxt += '\x23\x00\x00\x00' + '\x00\x00\x00\x00' + pck32(myjit.cpu.ESP) ctxt += '\x23\x00\x00\x00' # ctxt = regs2ctxt(regs) # Find a room for seh # seh = (get_memory_page_max_address_py()+0x1000)&0xfffff000 # Get current seh (fs:[0]) seh_ptr = upck32(myjit.vm.get_mem(tib_address, 4)) # Retrieve seh fields old_seh, eh, safe_place = struct.unpack('III', myjit.vm.get_mem(seh_ptr, 0xc)) print '-> seh_ptr', hex(seh_ptr), '-> { old_seh', print hex(old_seh), 'eh', hex(eh), 'safe_place', hex(safe_place), '}' # print '-> write SEH at', hex(seh&0xffffffff) # Write current seh # myjit.vm.add_memory_page(seh, PAGE_READ | PAGE_WRITE, p(old_seh) + # p(eh) + p(safe_place) + p(0x99999999)) # Write context myjit.vm.set_mem(context_address, ctxt) # Write exception_record """ #http://msdn.microsoft.com/en-us/library/aa363082(v=vs.85).aspx typedef struct _EXCEPTION_RECORD { DWORD ExceptionCode; DWORD ExceptionFlags; struct _EXCEPTION_RECORD *ExceptionRecord; PVOID ExceptionAddress; DWORD NumberParameters; ULONG_PTR ExceptionInformation[EXCEPTION_MAXIMUM_PARAMETERS]; } EXCEPTION_RECORD, *PEXCEPTION_RECORD; """ myjit.vm.set_mem( exception_record_address, pck32(except_code) + pck32(0) + pck32(0) + pck32(myjit.cpu.EIP) + pck32(0) + pck32(0)) # Prepare the stack myjit.push_uint32_t(context_address) # Context myjit.push_uint32_t(seh_ptr) # SEH myjit.push_uint32_t(exception_record_address) # ExceptRecords myjit.push_uint32_t(return_from_exception) # Ret address # Set fake new current seh for exception fake_seh_ad = get_free_seh_place() print hex(fake_seh_ad) myjit.vm.set_mem( fake_seh_ad, pck32(seh_ptr) + pck32(0xaaaaaaaa) + pck32(0xaaaaaabb) + pck32(0xaaaaaacc)) myjit.vm.set_mem(tib_address, pck32(fake_seh_ad)) dump_seh(myjit) print '-> jumping at', hex(eh) myjit.vm.set_exception(0) myjit.cpu.set_exception(0) # XXX set ebx to nul? myjit.cpu.EBX = 0 return eh