class ContStruct(MemStruct): fields = [ ("one", Num("B")), # Shorthand for: ("instruct", InStruct.get_type()), ("instruct", InStruct), ("last", Num("B")), ]
class UniStruct(MemStruct): fields = [ ("one", Num("B")), ("union", Union([ ("instruct", InStruct), ("i", Num(">I")), ])), ("last", Num("B")), ]
class BitStruct(MemUnion): fields = [ ("ValueB", BitField(Num("<Q"), [ ("field_00", 32), ("field_01", 32), ])), ("Value", Num("<Q")), ]
class BitStruct(MemUnion): fields = [ ("flags_num", Num("H")), ("flags", BitField(Num("H"), [ ("f1_1", 1), ("f2_5", 5), ("f3_8", 8), ("f4_1", 1), ])), ]
class DataArray(MemStruct): fields = [ ("val1", Num("B")), ("val2", Num("B")), # Ptr can also be instantiated 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 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 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 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 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 Anon(MemStruct): fields = [ ("a", Num("B")), # If a field name evaluates to False ("" or None for example) and the # field type is a Struct subclass (Struct, Union, BitField), the field # is considered as an anonymous struct or union. Therefore, Anon will # have b1, b2 and c1, c2 attributes in that case. ("", Union([("b1", Num("B")), ("b2", Num("H"))])), ("", Struct("", [("c1", Num("B")), ("c2", Num("B"))])), ("d", Num("B")), ]
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())), ]
class MyStruct2(MemStruct): fields = [ ("s1", RawStruct("=BI")), ("s2", Array(Num("B"), 10)), ]
class UnicodeString(MemStruct): fields = [ ("length", Num("H")), ("maxlength", Num("H")), ("data", Ptr("<I", Str("utf16"))), ]
class ContextException(MemStruct): fields = [ ("ContextFlags", Num("<I")), ("dr0", Num("<I")), ("dr1", Num("<I")), ("dr2", Num("<I")), ("dr3", Num("<I")), ("dr4", Num("<I")), ("dr5", Num("<I")), ("Float", Array(Num("B"), 112)), ("gs", Num("<I")), ("fs", Num("<I")), ("es", Num("<I")), ("ds", Num("<I")), ("edi", Num("<I")), ("esi", Num("<I")), ("ebx", Num("<I")), ("edx", Num("<I")), ("ecx", Num("<I")), ("eax", Num("<I")), ("ebp", Num("<I")), ("eip", Num("<I")), ("cs", Num("<I")), ("eflags", Num("<I")), ("esp", Num("<I")), ("ss", Num("<I")), ]
class OtherStruct(MemStruct): fields = [ ("foo", Num("H")), ]
class DataStr(MemStruct): fields = [ ("valshort", Num("<H")), # Pointer to an utf16 null terminated string ("data", Ptr("<I", Str("utf16"))), ]
class InStruct(MemStruct): fields = [ ("foo", Num("B")), ("bar", Num("B")), ]
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()
## Same value, other encoding memstr3 = Str("utf16").lval(jitter.vm, addr_str3) memstr3.val = "That's all folks!" assert memstr3.get_addr() != memstr.get_addr() assert memstr3.get_size() != memstr.get_size() # Size is different assert bytes(memstr3) != bytes(memstr) # Mem representation is different assert memstr3 != memstr # Encoding is different, so they are not eq assert memstr3.val == memstr.val # But the python value is the same # Array tests # Construction methods assert Array(MyStruct) == Array(MyStruct.get_type()) assert Array(MyStruct, 10) == Array(MyStruct.get_type(), 10) # Allocate buffer manually, since memarray is unsized alloc_addr = my_heap.vm_alloc(jitter.vm, 0x100) memarray = Array(Num("I")).lval(jitter.vm, alloc_addr) memarray[0] = 0x02 assert memarray[0] == 0x02 assert jitter.vm.get_mem(memarray.get_addr(), Num("I").size) == b'\x02\x00\x00\x00' memarray[2] = 0xbbbbbbbb assert memarray[2] == 0xbbbbbbbb assert jitter.vm.get_mem(memarray.get_addr() + 2 * Num("I").size, Num("I").size) == b'\xbb\xbb\xbb\xbb' try: s = bytes(memarray) assert False, "Should raise" except (NotImplementedError, ValueError): pass try: s = len(memarray)