25 from elfesteem
import pe_init
33 EXCEPTION_BREAKPOINT = 0x80000003
34 EXCEPTION_ACCESS_VIOLATION = 0xc0000005
35 EXCEPTION_INT_DIVIDE_BY_ZERO = 0xc0000094
36 EXCEPTION_PRIV_INSTRUCTION = 0xc0000096
37 EXCEPTION_ILLEGAL_INSTRUCTION = 0xc000001d
40 log = logging.getLogger(
"seh_helper")
41 console_handler = logging.StreamHandler()
42 console_handler.setFormatter(logging.Formatter(
"%(levelname)-5s: %(message)s"))
43 log.addHandler(console_handler)
44 log.setLevel(logging.INFO)
55 peb_ldr_data_offset = 0x1ea0
56 peb_ldr_data_address = LDR_AD + peb_ldr_data_offset
59 modules_list_offset = 0x1f00
61 InInitializationOrderModuleList_offset = 0x1ee0
62 InInitializationOrderModuleList_address = LDR_AD + \
63 InInitializationOrderModuleList_offset
65 InLoadOrderModuleList_offset = 0x1ee0 + \
67 InLoadOrderModuleList_address = LDR_AD + \
68 InLoadOrderModuleList_offset
70 default_seh = PEB_AD + 0x20000
72 process_environment_address = 0x10000
73 process_parameters_address = 0x200000
75 context_address = 0x201000
76 exception_record_address = context_address + 0x1000
77 return_from_exception = 0x6eadbeef
79 FAKE_SEH_B_AD = context_address + 0x2000
81 cur_seh_ad = FAKE_SEH_B_AD
83 loaded_modules = [
"ntdll.dll",
"kernel32.dll"]
85 main_pe_name =
"c:\\xxx\\toto.exe"
92 +0x000 NtTib : _NT_TIB
93 +0x01c EnvironmentPointer : Ptr32 Void
94 +0x020 ClientId : _CLIENT_ID
95 +0x028 ActiveRpcHandle : Ptr32 Void
96 +0x02c ThreadLocalStoragePointer : Ptr32 Void
97 +0x030 ProcessEnvironmentBlock : Ptr32 _PEB
98 +0x034 LastErrorValue : Uint4B
102 o +=
pck32(default_seh)
103 o += (0x18 - len(o)) *
"\x00"
104 o +=
pck32(tib_address)
106 o += (0x30 - len(o)) *
"\x00"
107 o +=
pck32(peb_address)
108 o +=
pck32(0x11223344)
110 myjit.vm.add_memory_page(teb_address, PAGE_READ | PAGE_WRITE, o)
115 +0x000 InheritedAddressSpace : UChar
116 +0x001 ReadImageFileExecOptions : UChar
117 +0x002 BeingDebugged : UChar
118 +0x003 SpareBool : UChar
119 +0x004 Mutant : Ptr32 Void
120 +0x008 ImageBaseAddress : Ptr32 Void
121 +0x00c Ldr : Ptr32 _PEB_LDR_DATA
122 +0x010 processparameter
125 offset = peb_address + 8
128 o +=
pck32(main_pe.NThdr.ImageBase)
131 o +=
pck32(peb_ldr_data_address)
132 o +=
pck32(process_parameters_address)
133 myjit.vm.add_memory_page(offset, PAGE_READ | PAGE_WRITE, o)
138 +0x000 Length : Uint4B
139 +0x004 Initialized : UChar
140 +0x008 SsHandle : Ptr32 Void
141 +0x00c InLoadOrderModuleList : _LIST_ENTRY
142 +0x014 InMemoryOrderModuleList : _LIST_ENTRY
143 +0x01C InInitializationOrderModuleList : _LIST_ENTRY
147 offset = LDR_AD + peb_ldr_data_offset + 0xC
151 for bname, (addr, e)
in modules_info.items():
153 m_e = (e, bname, addr)
156 log.warn(
'No main pe, ldr data will be unconsistant')
157 offset, data = offset + 8,
""
159 log.info(
'Ldr %x', m_e[2])
164 for bname, (addr, e)
in modules_info.items():
165 if bname[::2].lower() ==
"ntdll.dll":
166 ntdll_e = (e, bname, addr)
169 log.warn(
'No ntdll, ldr data will be unconsistant')
175 myjit.vm.add_memory_page(offset, PAGE_READ | PAGE_WRITE, data)
178 dummy_e = pe_init.PE()
179 dummy_e.NThdr.ImageBase = 0
180 dummy_e.Opthdr.AddressOfEntryPoint = 0
181 dummy_e.NThdr.sizeofimage = 0
186 kd> dt nt!_LDR_DATA_TABLE_ENTRY
187 +0x000 InLoadOrderLinks : _LIST_ENTRY
188 +0x008 InMemoryOrderLinks : _LIST_ENTRY
189 +0x010 InInitializationOrderLinks : _LIST_ENTRY
190 +0x018 DllBase : Ptr32 Void
191 +0x01c EntryPoint : Ptr32 Void
192 +0x020 SizeOfImage : Uint4B
193 +0x024 FullDllName : _UNICODE_STRING
194 +0x02c BaseDllName : _UNICODE_STRING
195 +0x034 Flags : Uint4B
196 +0x038 LoadCount : Uint2B
197 +0x03a TlsIndex : Uint2B
198 +0x03c HashLinks : _LIST_ENTRY
199 +0x03c SectionPointer : Ptr32 Void
200 +0x040 CheckSum : Uint4B
201 +0x044 TimeDateStamp : Uint4B
202 +0x044 LoadedImports : Ptr32 Void
203 +0x048 EntryPointActivationContext : Ptr32 Void
204 +0x04c PatchInformation : Ptr32 Void
208 base_addr = LDR_AD + modules_list_offset
213 for i, m
in enumerate([(main_pe_name, main_pe),
214 (
"", dummy_e)] + modules_name):
215 addr = base_addr + i * 0x1000
216 if isinstance(m, tuple):
220 bpath = fname.replace(
'/',
'\\')
221 bname_str = os.path.split(fname)[1].lower()
222 bname =
"\x00".join(bname_str) +
"\x00"
227 full_name = os.path.join(
"win_dll", fname)
229 e = pe_init.PE(open(full_name,
'rb').read())
231 log.error(
'No main pe, ldr data will be unconsistant!')
235 log.info(
"Add module %x %r", e.NThdr.ImageBase, bname_str)
237 modules_info[bname] = addr, e
246 m_o +=
pck32(e.NThdr.ImageBase)
247 m_o +=
pck32(e.rva2virt(e.Opthdr.AddressOfEntryPoint))
248 m_o +=
pck32(e.NThdr.sizeofimage)
249 m_o += struct.pack(
'HH', len(bname), len(bname) + 2)
250 m_o +=
pck32(addr + offset_path)
251 m_o += struct.pack(
'HH', len(bname), len(bname) + 2)
252 m_o +=
pck32(addr + offset_name)
253 myjit.vm.add_memory_page(addr, PAGE_READ | PAGE_WRITE, m_o)
258 myjit.vm.add_memory_page(
259 addr + offset_name, PAGE_READ | PAGE_WRITE, m_o)
262 m_o +=
"\x00".join(bpath) +
"\x00"
264 myjit.vm.add_memory_page(
265 addr + offset_path, PAGE_READ | PAGE_WRITE, m_o)
271 log.debug(
"Fix InLoadOrderModuleList")
277 for m
in [main_pe_name,
""] + loaded_modules:
279 if isinstance(m, tuple):
285 fname = fname[fname.rfind(
"/") + 1:]
287 bname =
'\x00'.join(bname_str) +
'\x00'
288 if not bname.lower()
in module_info:
289 log.warn(
'Module not found, ldr data will be unconsistant')
292 addr, e = module_info[bname.lower()]
295 m_e = (e, bname, addr)
298 d_e = (e, bname, addr)
300 olist.append((e, bname, addr))
301 if not m_e
or not d_e:
302 log.warn(
'No main pe, ldr data will be unconsistant')
308 for i
in xrange(len(olist)):
309 e, bname, addr = olist[i]
310 p_e, p_bname, p_addr = olist[(i - 1) % len(olist)]
311 n_e, n_bname, n_addr = olist[(i + 1) % len(olist)]
312 myjit.vm.set_mem(addr + 0,
pck32(n_addr) +
pck32(p_addr))
316 log.debug(
"Fix InMemoryOrderModuleList")
322 for m
in [main_pe_name,
""] + loaded_modules:
324 if isinstance(m, tuple):
330 fname = fname[fname.rfind(
"/") + 1:]
332 bname =
'\x00'.join(bname_str) +
'\x00'
333 if not bname.lower()
in module_info:
334 log.warn(
'Module not found, ldr data will be unconsistant')
336 addr, e = module_info[bname.lower()]
339 m_e = (e, bname, addr)
342 d_e = (e, bname, addr)
344 olist.append((e, bname, addr))
345 if not m_e
or not d_e:
346 log.warn(
'No main pe, ldr data will be unconsistant')
353 for i
in xrange(len(olist)):
354 e, bname, addr = olist[i]
355 p_e, p_bname, p_addr = olist[(i - 1) % len(olist)]
356 n_e, n_bname, n_addr = olist[(i + 1) % len(olist)]
358 addr + 0x8,
pck32(n_addr + 0x8) +
pck32(p_addr + 0x8))
367 for bname, (addr, e)
in module_info.items():
368 if bname[::2].lower() ==
"ntdll.dll":
369 ntdll_e = (e, bname, addr)
371 elif bname[::2].lower() ==
"kernel32.dll":
372 kernel_e = (e, bname, addr)
375 d_e = (e, bname, addr)
379 olist.append((e, bname, addr))
380 if not ntdll_e
or not kernel_e
or not d_e:
381 log.warn(
'No kernel ntdll, ldr data will be unconsistant')
383 olist[0:0] = [ntdll_e]
384 olist[1:1] = [kernel_e]
389 for i
in xrange(len(olist)):
390 e, bname, addr = olist[i]
391 p_e, p_bname, p_addr = olist[(i - 1) % len(olist)]
392 n_e, n_bname, n_addr = olist[(i + 1) % len(olist)]
394 addr + 0x10,
pck32(n_addr + 0x10) +
pck32(p_addr + 0x10))
398 env_str =
'ALLUSEESPROFILE=C:\\Documents and Settings\\All Users\x00'
399 env_str =
'\x00'.join(env_str)
400 env_str +=
"\x00" * 0x10
401 myjit.vm.add_memory_page(process_environment_address,
402 PAGE_READ | PAGE_WRITE,
404 myjit.vm.set_mem(process_environment_address, env_str)
410 o +=
"E" * (0x48 - len(o))
411 o +=
pck32(process_environment_address)
412 myjit.vm.add_memory_page(process_parameters_address,
413 PAGE_READ | PAGE_WRITE,
417 all_seh_ad = dict([(x,
None)
418 for x
in xrange(FAKE_SEH_B_AD, FAKE_SEH_B_AD + 0x1000, 0x20)])
438 myjit.vm.add_memory_page(default_seh, PAGE_READ | PAGE_WRITE,
pck32(
439 0xffffffff) +
pck32(0x41414141) +
pck32(0x42424242))
441 myjit.vm.add_memory_page(
442 context_address, PAGE_READ | PAGE_WRITE,
'\x00' * 0x2cc)
443 myjit.vm.add_memory_page(
444 exception_record_address, PAGE_READ | PAGE_WRITE,
'\x00' * 200)
446 myjit.vm.add_memory_page(
447 FAKE_SEH_B_AD, PAGE_READ | PAGE_WRITE, 0x10000 *
"\x00")
454 Build x86_32 cpu context for exception handling
455 @myjit: jitload instance
462 ctxt += [
pck32(0x0)] * 6
464 ctxt += [
'\x00' * 112]
466 ctxt += [
pck32(reg)
for reg
in (myjit.cpu.GS, myjit.cpu.FS,
467 myjit.cpu.ES, myjit.cpu.DS)]
469 ctxt += [
pck32(reg)
for reg
in (myjit.cpu.EDI, myjit.cpu.ESI,
470 myjit.cpu.EBX, myjit.cpu.EDX,
471 myjit.cpu.ECX, myjit.cpu.EAX,
472 myjit.cpu.EBP, myjit.cpu.EIP)]
474 ctxt += [
pck32(myjit.cpu.CS)]
479 ctxt += [
pck32(myjit.cpu.ESP)]
481 ctxt += [
pck32(myjit.cpu.SS)]
487 Restore x86_32 registers from an exception context
488 @ctxt: the serialized context
489 @myjit: jitload instance
500 myjit.cpu.GS =
upck32(ctxt[:4])
503 myjit.cpu.FS =
upck32(ctxt[:4])
506 myjit.cpu.ES =
upck32(ctxt[:4])
509 myjit.cpu.DS =
upck32(ctxt[:4])
513 myjit.cpu.EDI =
upck32(ctxt[:4])
515 myjit.cpu.ESI =
upck32(ctxt[:4])
517 myjit.cpu.EBX =
upck32(ctxt[:4])
519 myjit.cpu.EDX =
upck32(ctxt[:4])
521 myjit.cpu.ECX =
upck32(ctxt[:4])
523 myjit.cpu.EAX =
upck32(ctxt[:4])
525 myjit.cpu.EBP =
upck32(ctxt[:4])
527 myjit.cpu.EIP =
upck32(ctxt[:4])
531 myjit.cpu.CS =
upck32(ctxt[:4])
536 myjit.cpu.ESP =
upck32(ctxt[:4])
541 global seh_count, context_address
542 regs = myjit.cpu.get_gpreg()
543 log.warning(
'Exception at %x %r', myjit.cpu.EIP, seh_count)
547 p =
lambda s: struct.pack(
'I', s)
553 seh_ptr =
upck32(myjit.vm.get_mem(tib_address, 4))
556 old_seh, eh, safe_place = struct.unpack(
557 'III', myjit.vm.get_mem(seh_ptr, 0xc))
560 myjit.cpu.ESP -= 0x3c8
561 exception_base_address = myjit.cpu.ESP
562 exception_record_address = exception_base_address + 0xe8
563 context_address = exception_base_address + 0xfc
564 fake_seh_address = exception_base_address + 0x14
566 log.info(
'seh_ptr %x { old_seh %x eh %x safe_place %x} ctx_addr %x',
567 seh_ptr, old_seh, eh, safe_place, context_address)
570 myjit.vm.set_mem(context_address, ctxt)
575 #http://msdn.microsoft.com/en-us/library/aa363082(v=vs.85).aspx
577 typedef struct _EXCEPTION_RECORD {
579 DWORD ExceptionFlags;
580 struct _EXCEPTION_RECORD *ExceptionRecord;
581 PVOID ExceptionAddress;
582 DWORD NumberParameters;
583 ULONG_PTR ExceptionInformation[EXCEPTION_MAXIMUM_PARAMETERS];
584 } EXCEPTION_RECORD, *PEXCEPTION_RECORD;
587 myjit.vm.set_mem(exception_record_address,
592 myjit.push_uint32_t(context_address)
593 myjit.push_uint32_t(seh_ptr)
594 myjit.push_uint32_t(exception_record_address)
595 myjit.push_uint32_t(return_from_exception)
598 log.info(
"Fake seh ad %x", fake_seh_address)
599 myjit.vm.set_mem(fake_seh_address,
pck32(seh_ptr) +
pck32(
600 0xaaaaaaaa) +
pck32(0xaaaaaabb) +
pck32(0xaaaaaacc))
601 myjit.vm.set_mem(tib_address,
pck32(fake_seh_address))
605 log.info(
'Jumping at %x', eh)
606 myjit.vm.set_exception(0)
607 myjit.cpu.set_exception(0)
614 fake_seh_handler.base = FAKE_SEH_B_AD
618 log.info(
'Dump_seh. Tib_address: %x', tib_address)
619 cur_seh_ptr =
upck32(myjit.vm.get_mem(tib_address, 4))
624 log.warn(
"Too many seh, quit")
626 prev_seh, eh = struct.unpack(
'II', myjit.vm.get_mem(cur_seh_ptr, 8))
627 log.info(
'\t' * indent +
'seh_ptr: %x { prev_seh: %x eh %x }',
628 cur_seh_ptr, prev_seh, eh)
629 if prev_seh
in [0xFFFFFFFF, 0]:
631 cur_seh_ptr = prev_seh
637 regs = myjit.cpu.get_gpreg()
639 myjit.cpu.set_gpreg(regs)
640 myjit.cpu.set_segm_base(regs[
'FS'], FS_0_AD)
641 segm_to_do = set([x86_regs.FS])
646 global main_pe, main_pe_name, loaded_modules
650 main_pe_name = pe_in_name
651 loaded_modules = all_pe
655 "Handle return after a call to fake seh handler"
658 context_address =
upck32(myjit.vm.get_mem(myjit.cpu.ESP + 0x8, 4))
659 log.info(
'Context address: %x', context_address)
660 myjit.cpu.ESP =
upck32(myjit.vm.get_mem(context_address + 0xc4, 4))
661 log.info(
'New esp: %x', myjit.cpu.ESP)
664 old_seh =
upck32(myjit.vm.get_mem(tib_address, 4))
665 new_seh =
upck32(myjit.vm.get_mem(old_seh, 4))
666 log.info(
'Old seh: %x New seh: %x', old_seh, new_seh)
667 myjit.vm.set_mem(tib_address,
pck32(new_seh))
671 if myjit.cpu.EAX == 0x0:
673 ctxt_ptr = context_address
674 log.info(
'Seh continues Context: %x', ctxt_ptr)
677 ctxt_str = myjit.vm.get_mem(ctxt_ptr, 0x2cc)
679 myjit.pc = myjit.cpu.EIP
680 log.info(
'Context::Eip: %x', myjit.pc)
682 elif myjit.cpu.EAX == -1:
683 raise NotImplementedError(
"-> seh try to go to the next handler")
685 elif myjit.cpu.EAX == 1:
687 raise NotImplementedError(
"-> seh, gameover")
def fix_InLoadOrderModuleList
def add_process_parameters
def fix_InMemoryOrderModuleList
def fix_InInitializationOrderModuleList