mirror of
https://github.com/mandiant/speakeasy.git
synced 2026-10-12 02:18:47 +00:00
EmuStruct caches each generated ctypes type by class name and pointer size. PROCESSENTRY32, MODULEENTRY32, WIN32_FIND_DATA and SID take a second constructor argument, a character width or a sub-authority count, that changes their fields. The first instance in the process fixed the layout for every later instance, so a wide call after an ANSI call wrote the ANSI layout. The cache key now includes the pack value and the field list.
74 lines
2.1 KiB
Python
74 lines
2.1 KiB
Python
import ctypes as ct
|
|
|
|
from speakeasy.struct import EmuStruct, Ptr
|
|
|
|
EXPECTED_32BIT_BYTES = (
|
|
b"\x01\x01\x02\x02\x03\x03\x03\x03\x04\x04\x04\x04\x05\x05"
|
|
b"\x06\x06\x06\x06\x07\x07\x07\x07AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
|
|
b"\x08\x08\t\t\t\t\n\n\n\nBBBBBBBBBBBBBBBBBBBBBBBB"
|
|
)
|
|
|
|
|
|
class DEEP_NEST(EmuStruct):
|
|
def __init__(self, ptr_size):
|
|
super().__init__(ptr_size)
|
|
self.Field1 = ct.c_uint32
|
|
self.Field2 = ct.c_uint32
|
|
self.DeepData = ct.c_uint8 * 32
|
|
|
|
|
|
class SHALLOW_NEST(EmuStruct):
|
|
def __init__(self, ptr_size):
|
|
super().__init__(ptr_size, pack=1)
|
|
self.Field1 = ct.c_uint16
|
|
self.DeepStruct = DEEP_NEST
|
|
self.Field2 = ct.c_uint16
|
|
|
|
|
|
class TOP_OBJECT(EmuStruct):
|
|
def __init__(self, ptr_size):
|
|
super().__init__(ptr_size=ptr_size, pack=1)
|
|
self.Field1 = ct.c_uint16
|
|
self.Field2 = ct.c_uint16
|
|
self.Field3 = ct.c_uint32
|
|
self.Field4 = Ptr
|
|
self.NestedStruct = SHALLOW_NEST
|
|
self.Field5 = Ptr
|
|
self.Field6 = ct.c_uint32
|
|
self.Field7 = ct.c_uint8 * 24
|
|
|
|
|
|
def test_32bit_emit():
|
|
ptr_size = 4
|
|
top = TOP_OBJECT(ptr_size)
|
|
|
|
top.Field1 = 0x0101
|
|
top.Field2 = 0x0202
|
|
top.Field3 = 0x03030303
|
|
top.Field4 = 0x04040404
|
|
top.NestedStruct.Field1 = 0x0505
|
|
top.NestedStruct.DeepStruct.Field1 = 0x06060606
|
|
top.NestedStruct.DeepStruct.Field2 = 0x07070707
|
|
top.NestedStruct.DeepStruct.DeepData = b"A" * 32
|
|
top.NestedStruct.Field2 = 0x0808
|
|
top.Field5 = 0x09090909
|
|
top.Field6 = 0x0A0A0A0A
|
|
top.Field7 = b"B" * 24
|
|
|
|
bytez = top.get_bytes()
|
|
assert bytez == EXPECTED_32BIT_BYTES
|
|
|
|
|
|
class WIDE_OR_NARROW(EmuStruct):
|
|
def __init__(self, ptr_size, width):
|
|
super().__init__(ptr_size)
|
|
self.Size = ct.c_uint32
|
|
self.Name = ct.c_uint8 * (4 * width)
|
|
|
|
|
|
def test_struct_layout_follows_constructor_arguments():
|
|
assert WIDE_OR_NARROW(4, 1).sizeof() == 8
|
|
assert WIDE_OR_NARROW(4, 2).sizeof() == 12
|
|
assert WIDE_OR_NARROW(4, 1).sizeof() == 8
|
|
assert type(WIDE_OR_NARROW(4, 2).get_cstruct()) is type(WIDE_OR_NARROW(4, 2).get_cstruct())
|