from ctypes import *
libc = cdll.LoadLibrary("libc.so.6")
libc.printf("Hello World!\n")
But what if some function needs a non trivial type of parameter?
from ctypes import *
class Foo(Structure):
_fields_ = [('x', c_uint32), ('y', c_char*20)]
foo = Foo()
foo.x = 5
foo.y = "Hello World!"
buffer(foo)[:]
'\x05\x00\x00\x00Hello World!\x00\x00\x00\x00\x00\x00\x00\x00'
immutable_buf = _
foo = Foo.from_buffer_copy(immutable_buf)
buf = bytearray(immutable_buf)
foo = Foo.from_buffer(buf)
Tell me more about those structs...
Enums
class StructBar(Structure):
_fields_ = [('foo', c_int)]
class EnumFoo(c_int):
pass
class StructBar(Structure):
_fields_ = [('foo', EnumFoo)]
class BaseEnum(c_int):
__repr__ and friends
class EnumFoo(BaseEnum):
_values_ = {0: "A", 1: "B", 2: "C"}
EnumFoo.A = EnumFoo(0)
EnumFoo.B = EnumFoo(1)
EnumFoo.C = EnumFoo(2)
bar.foo = EnumFoo.B
class BaseEnumMixin(object):
__repr__ and friends
class EnumFoo(BaseEnumMixin, c_int):
_values_ = {0: "A", 1: "B", 2: "C"}
EnumFoo.A = EnumFoo(0)
EnumFoo.B = EnumFoo(1)
EnumFoo.C = EnumFoo(2)
bar.foo = EnumFoo.B
Support Name Changes
ALIASES_DICT = {"Foo":
{"x": ("y",)}
}
@aliased_class
class Foo(Structure):
_fields_ = [("y", c_uint64)]
Mimic GCC packing
typedef struct __attribute__ ((__packed__)) Foo {
uint32 x
uint64 y
} Foo;
class Foo(Structure):
_pack_ = 1
_fields_ = [("x", c_uint32), ("y", c_uint64)]
typedef struct Foo {
uint16 x:13;
uint8 y:3;
} Foo;
class Foo(Structure):
_fields_ = [("x", c_uint16, 13), ("y", c_uint8, 3)]
typedef struct __attribute__ ((__packed__)) Foo {
uint64 x:13;
uint8 y:3;
} Foo;
class Foo(Structure):
_pack_ = 1
_fields_ = [(u'_bf_x_0', c_uint8, 8), (u'_bf_x_1', c_uint8, 5),
(u'_bf_y_0', c_uint8, 3),]
def _get_x(self):
return self._bf_x_0 << 0 | self._bf_x_1 << 8
def _set_x(self, value):
self._bf_x_0 = (value >> 0) & 255
self._bf_x_1 = (value >> 8) & 255
x = property(_get_x, _set_x)
...
GDB
(gdb) python print [(f.name, f.bitpos, f.bitsize, str(f.type)) \
for f in gdb.lookup_type("XMemUsePrimitive").fields()]
[('static_in_bytes', 0L, 0L, 'uint64'),
('dynamic_in_bytes', 64L, 0L, 'uint64'),
('mmap_in_bytes', 128L, 0L, 'uint64'),
('mmap_hugepg_in_bytes', 192L, 0L, 'uint64'),
('available_pages_in_global_fbpool', 256L, 0L, 'uint32'),
('prealloc_pages_in_global_fbpool', 288L, 0L, 'uint32')]
readelf
readelf -Wwi
<1><c2>: Abbrev Number: 9 (DW_TAG_structure_type)
<c3> DW_AT_name : (indirect string, offset: 0x14): _IO_FILE
<c7> DW_AT_byte_size : 216
...
<2><cf>: Abbrev Number: 10 (DW_TAG_member)
<d0> DW_AT_name : (indirect string, offset: 0x4c18f): _flags
<d7> DW_AT_type : <0x43>
...
<2>...
<2><25d>: Abbrev Number: 0
<1><43>: Abbrev Number: 4 (DW_TAG_base_type)
<44> DW_AT_byte_size : 4
<46> DW_AT_name : int
Why did we need all that for?
Well obviously, now we won
Upgrade
typedef struct Foo {
float x
float y
float z
uint32_t blah
} Foo;
typedef struct Foo {
double x
double y
uint64_t blah
} Foo;
Recovery & Exploration
class BaseMetaData(object):
CTYPE = NotImplemented
@classmethod
def load(cls, offset):
data = read(offset, sizeof(self.CTYPE))
inst = cls.CTYPE.from_buffer_copy(data)
return cls(inst, offset)
def dump(self):
write(self.offset, buffer(self.inst)[:])
class FooMetaData(BaseMetaData):
CTYPE=Foo
Easy communication over socket
register_handler(0, foo) <=== REGISTER_HANDLER(foo, FooRequestStruct)
register_handler(1, bar) <=== REGISTER_HANDLER(bar, BarRequestStruct)
pickle.dump({"foo": (0, reflected.FooRequestStruct),
"bar": (1, reflected.BarRequestStruct),
}, apifile)
get_buffer("FooResponseStruct", sizeof(FooResponseStruct))
Basically anything