class EXCEPTION_REGISTRATION_RECORD(MemStruct): """ +0x00 Next : struct _EXCEPTION_REGISTRATION_RECORD * +0x04 Handler : Ptr32 Void """ fields = [ ("Next", Ptr("<I", Self())), ("Handler", Ptr("<I", Void())), ]
class UnhealthyIdeas(MemStruct): fields = [ ("pastruct", Ptr("I", Array(RawStruct("=Bf")))), ("apstr", Array(Ptr("I", Str()), 10)), ("pself", Ptr("I", Self())), ("apself", Array(Ptr("I", Self()), 2)), ("ppself", Ptr("I", Ptr("I", Self()))), ("pppself", Ptr("I", Ptr("I", Ptr("I", Self())))), ]
class MyStruct(MemStruct): fields = [ # Number field: just struct.pack fields with one value ("num", Num("I")), ("flags", Num("B")), # This field is a pointer to another struct, it has a numeric # value (mystruct.other.val) and can be dereferenced to get an # OtherStruct instance (mystruct.other.deref) ("other", Ptr("I", OtherStruct)), # Ptr to a variable length String ("s", Ptr("I", Str())), ("i", Ptr("I", Num("I"))), ]
class EXCEPTION_RECORD(MemStruct): """ DWORD ExceptionCode; DWORD ExceptionFlags; struct _EXCEPTION_RECORD *ExceptionRecord; PVOID ExceptionAddress; DWORD NumberParameters; ULONG_PTR ExceptionInformation[EXCEPTION_MAXIMUM_PARAMETERS]; """ EXCEPTION_MAXIMUM_PARAMETERS = 15 fields = [ ("ExceptionCode", Num("<I")), ("ExceptionFlags", Num("<I")), ("ExceptionRecord", Ptr("<I", Self())), ("ExceptionAddress", Ptr("<I", Void())), ("NumberParameters", Num("<I")), ("ExceptionInformation", Ptr("<I", Void())), ]
class DataArray(MemStruct): fields = [ ("val1", Num("B")), ("val2", Num("B")), # Ptr can also be instanciated with a Type instance as an argument, the # corresponding Memtype will be returned when dereferencing # Here, data_array.array.deref will allow to access an Array ("arrayptr", Ptr("<I", Array(Num("B"), 16))), # Array of 10 uint8 ("array", Array(Num("B"), 16)), ]
class PEB(MemStruct): """ +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 """ fields = [ ("InheritedAddressSpace", Num("B")), ("ReadImageFileExecOptions", Num("B")), ("BeingDebugged", Num("B")), ("SpareBool", Num("B")), ("Mutant", Ptr("<I", Void())), ("ImageBaseAddress", Num("<I")), ("Ldr", Ptr("<I", PEB_LDR_DATA)), ]
class TEB(MemStruct): """ +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 ... """ fields = [ ("NtTib", NT_TIB), ("EnvironmentPointer", Ptr("<I", Void())), ("ClientId", Array(Num("B"), 0x8)), ("ActiveRpcHandle", Ptr("<I", Void())), ("ThreadLocalStoragePointer", Ptr("<I", Void())), ("ProcessEnvironmentBlock", Ptr("<I", PEB)), ("LastErrorValue", Num("<I")), ]
class ListNode(MemStruct): fields = [ # The "<I" is the struct-like format of the pointer in memory, in this # case a Little Endian 32 bits unsigned int. # One way to handle reference to ListNode in ListNode is to use the # special marker Self(). # You could also generate ListNode's fields with ListNode.gen_field # after the class declaration, so that the ListNode is defined when # fields are generated. ("next", Ptr("<I", Self())), # Ptr(_, Void()) is analogous to void*, Void() is a kind of "empty type" ("data", Ptr("<I", Void())), ] def get_next(self): if self.next.val == 0: return None return self.next.deref def get_data(self, data_type=None): if data_type is not None: return self.data.deref.cast(data_type) else: return self.data.deref
class PEB_LDR_DATA(MemStruct): """ +0x000 Length : Uint4B +0x004 Initialized : UChar +0x008 SsHandle : Ptr32 Void +0x00c InLoadOrderModuleList : _LIST_ENTRY +0x014 InMemoryOrderModuleList : _LIST_ENTRY +0x01C InInitializationOrderModuleList : _LIST_ENTRY """ fields = [("Length", Num("<I")), ("Initialized", Num("<I")), ("SsHandle", Ptr("<I", Void())), ("InLoadOrderModuleList", ListEntry), ("InMemoryOrderModuleList", ListEntry), ("InInitializationOrderModuleList", ListEntry)]
class LdrDataEntry(MemStruct): """ +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 """ fields = [ ("InLoadOrderLinks", ListEntry), ("InMemoryOrderLinks", ListEntry), ("InInitializationOrderLinks", ListEntry), ("DllBase", Ptr("<I", Void())), ("EntryPoint", Ptr("<I", Void())), ("SizeOfImage", Num("<I")), ("FullDllName", UnicodeString), ("BaseDllName", UnicodeString), ("Flags", Array(Num("B"), 4)), ("LoadCount", Num("H")), ("TlsIndex", Num("H")), ("union1", Union([ ("HashLinks", Ptr("<I", Void())), ("SectionPointer", Ptr("<I", Void())), ])), ("CheckSum", Num("<I")), ("union2", Union([ ("TimeDateStamp", Num("<I")), ("LoadedImports", Ptr("<I", Void())), ])), ("EntryPointActivationContext", Ptr("<I", Void())), ("PatchInformation", Ptr("<I", Void())), ]
class NT_TIB(MemStruct): """ +00 struct _EXCEPTION_REGISTRATION_RECORD *ExceptionList +04 void *StackBase +08 void *StackLimit +0c void *SubSystemTib +10 void *FiberData +10 uint32 Version +14 void *ArbitraryUserPointer +18 struct _NT_TIB *Self """ fields = [ ("ExceptionList", Ptr("<I", EXCEPTION_REGISTRATION_RECORD)), ("StackBase", Ptr("<I", Void())), ("StackLimit", Ptr("<I", Void())), ("SubSystemTib", Ptr("<I", Void())), (None, Union([("FiberData", Ptr("<I", Void())), ("Version", Num("<I"))])), ("ArbitraryUserPointer", Ptr("<I", Void())), ("Self", Ptr("<I", Self())), ]
assert bit.flags.f4_1 == 1 # Unhealthy ideas class UnhealthyIdeas(MemStruct): fields = [ ("pastruct", Ptr("I", Array(RawStruct("=Bf")))), ("apstr", Array(Ptr("I", Str()), 10)), ("pself", Ptr("I", Self())), ("apself", Array(Ptr("I", Self()), 2)), ("ppself", Ptr("I", Ptr("I", Self()))), ("pppself", Ptr("I", Ptr("I", Ptr("I", Self())))), ] p_size = Ptr("I", Void()).size ideas = UnhealthyIdeas(jitter.vm) ideas.memset() ideas.pself = ideas.get_addr() assert ideas == ideas.pself.deref ideas.apself[0] = ideas.get_addr() assert ideas.apself[0].deref == ideas ideas.apself[1] = my_heap.vm_alloc(jitter.vm, UnhealthyIdeas.sizeof()) ideas.apself[1].deref = ideas assert ideas.apself[1] != ideas.get_addr() assert ideas.apself[1].deref == ideas ideas.ppself = my_heap.vm_alloc(jitter.vm, p_size) ideas.ppself.deref.val = ideas.get_addr()
class LinkedList(MemStruct): fields = [ # For convenience, either a Type instance (like Self() or Num("I") or a # MemStruct subclass can be passed to the Ptr constructor. ("head", Ptr("<I", ListNode)), ("tail", Ptr("<I", ListNode)), # Num can take any one-field struct-like format, including floats and # doubles ("size", Num("<I")), ] def get_head(self): """Returns the head ListNode instance""" if self.head == 0: return None return self.head.deref def get_tail(self): """Returns the tail ListNode instance""" if self.tail == 0: return None return self.tail.deref def push(self, data): """Push a data (MemType instance) to the linked list.""" # Allocate a new node node = ListNode(self._vm) # Set the data pointer node.data = data.get_addr() # re-link if self.head != 0: # get the head ListNode head = self.get_head() node.next = head.get_addr() # pointer to head assigned to the new node address self.head = node.get_addr() # Do not forget the tail :) if self.tail == 0: self.tail = node.get_addr() self.size += 1 def pop(self, data_type=None): """Pop one data from the LinkedList.""" # Nothing to pop if self.head == 0: return None node = self.get_head() self.head = node.next # empty if self.head == 0: self.tail = 0 self.size -= 1 return node.get_data(data_type) def empty(self): """True if the list is empty.""" return self.head == 0 def __iter__(self): if not self.empty(): cur = self.get_head() while cur is not None: yield cur.data.deref cur = cur.get_next()
class DataStr(MemStruct): fields = [ ("valshort", Num("<H")), # Pointer to an utf16 null terminated string ("data", Ptr("<I", Str("utf16"))), ]
class UnicodeString(MemStruct): fields = [ ("length", Num("H")), ("maxlength", Num("H")), ("data", Ptr("<I", Str("utf16"))), ]
class ListEntry(MemStruct): fields = [ ("flink", Ptr("<I", Void())), ("blink", Ptr("<I", Void())), ]
class B(MemStruct): fields = [ ("a", Ptr("I", A)), ]
raw_miams_array = [ord(c) for c in raw_miams] assert list(data.array)[:len(raw_miams_array)] == raw_miams_array assert data.array.cast(Str("utf16")) == memstr # Default is "ansi" assert data.array.cast(Str()) != memstr assert data.array.cast(Str("utf16")).val == memstr.val print "See that the original array has been modified:" print repr(data) print # Some type manipulation examples, for example let's construct an argv for # a program: # Let's say that we have two arguments, +1 for the program name and +1 for the # final null ptr in argv, the array has 4 elements: argv_t = Array(Ptr("<I", Str()), 4) print "3 arguments argv type:", argv_t # alloc argv somewhere argv = argv_t.lval(vm) # Auto alloc with the MemStr.from_str helper MemStrAnsi = Str().lval argv[0].val = MemStrAnsi.from_str(vm, "./my-program").get_addr() argv[1].val = MemStrAnsi.from_str(vm, "arg1").get_addr() argv[2].val = MemStrAnsi.from_str(vm, "27").get_addr() argv[3].val = 0 # If you changed your mind on the second arg, you could do: argv[2].deref.val = "42"