def test_container_of(self): """From a pointer to a member, returns the parent struct""" # depends on offsetof ctypes = types.reload_ctypes(8, 8, 16) class X(ctypes.Structure): _pack_ = True _fields_ = [('a', ctypes.c_long), ('p', ctypes.POINTER(ctypes.c_int)), ('b', ctypes.c_ubyte)] x = X() x.a = 1 x.b = 2 addr_b = ctypes.addressof(x) + 16 # a + p o = utils.container_of(addr_b, X, 'b') self.assertEquals(ctypes.addressof(o), ctypes.addressof(x)) ctypes = types.reload_ctypes(4, 4, 8) class Y(ctypes.Structure): _pack_ = True _fields_ = [('a', ctypes.c_long), ('p', ctypes.POINTER(ctypes.c_int)), ('b', ctypes.c_ubyte)] y = Y() y.a = 1 y.b = 2 addr_b = ctypes.addressof(y) + 8 # a + p o = utils.container_of(addr_b, Y, 'b') self.assertEquals(ctypes.addressof(o), ctypes.addressof(y)) pass
def test_array2bytes(self): """array to bytes""" ctypes = types.reload_ctypes(4, 4, 8) a = (ctypes.c_long * 12)(4, 1, 1, 1, 2) x = utils.array2bytes(a) self.assertEquals(b'\x04' + 3 * b'\x00' + b'\x01' + 3 * b'\x00' + b'\x01' + 3 * b'\x00' + b'\x01' + 3 * b'\x00' + b'\x02' + 3 * b'\x00' + 7 * 4 * '\x00', x) ctypes = types.reload_ctypes(8, 8, 16) a = (ctypes.c_long * 12)(4, 1, 1, 1, 2) x = utils.array2bytes(a) self.assertEquals(b'\x04' + 7 * b'\x00' + b'\x01' + 7 * b'\x00' + b'\x01' + 7 * b'\x00' + b'\x01' + 7 * b'\x00' + b'\x02' + 7 * b'\x00' + 7 * 8 * '\x00', x) a = (ctypes.c_char * 12).from_buffer_copy('1234567890AB') x = utils.array2bytes(a) self.assertEquals(b'1234567890AB', x) # mimics what ctypes gives us on memory loading. a = b'1234567890AB' x = utils.array2bytes(a) self.assertEquals(b'1234567890AB', x) pass
def test_offsetof(self): """returns the offset of a member fields in a record""" ctypes = types.reload_ctypes(4, 4, 8) class Y(ctypes.Structure): _pack_ = True _fields_ = [('a', ctypes.c_long), ('p', ctypes.POINTER(ctypes.c_int)), ('b', ctypes.c_ubyte)] o = utils.offsetof(Y, 'b') self.assertEquals(o, 8) ctypes = types.reload_ctypes(8, 8, 16) class X(ctypes.Structure): _pack_ = True _fields_ = [('a', ctypes.c_long), ('p', ctypes.POINTER(ctypes.c_int)), ('b', ctypes.c_ubyte)] o = utils.offsetof(X, 'b') self.assertEquals(o, 16) class X2(ctypes.Union): _pack_ = True _fields_ = [('a', ctypes.c_long), ('p', ctypes.POINTER(ctypes.c_int)), ('b', ctypes.c_ubyte)] o = utils.offsetof(X2, 'b') self.assertEquals(o, 0) pass
def test_get_pointee_address(self): """tests get_pointee_address on host ctypes POINTER and haystack POINTER""" ctypes = types.reload_ctypes(8, 8, 16) class X(ctypes.Structure): _pack_ = True _fields_ = [('a', ctypes.c_long), ('p', ctypes.POINTER(ctypes.c_int)), ('b', ctypes.c_ubyte)] self.assertEquals(ctypes.sizeof(X), 17) i = X.from_buffer_copy( b'\xAA\xAA\xBB\xBB' + 4 * '\xBB' + 8 * '\x11' + '\xCC') a = utils.get_pointee_address(i.p) self.assertEquals(ctypes.sizeof(i.p), 8) self.assertNotEquals(a, 0) self.assertEquals(a, 0x1111111111111111) # 8*'\x11' # null pointer i = X.from_buffer_copy( b'\xAA\xAA\xBB\xBB' + 4 * '\xBB' + 8 * '\x00' + '\xCC') pnull = utils.get_pointee_address(i.p) self.assertEquals(utils.get_pointee_address(pnull), 0) # change arch, and retry ctypes = types.reload_ctypes(4, 4, 8) class Y(ctypes.Structure): _pack_ = True _fields_ = [('a', ctypes.c_long), ('p', ctypes.POINTER(ctypes.c_int)), ('b', ctypes.c_ubyte)] self.assertEquals(ctypes.sizeof(Y), 9) i = Y.from_buffer_copy(b'\xAA\xAA\xBB\xBB' + 4 * '\x11' + '\xCC') a = utils.get_pointee_address(i.p) self.assertEquals(ctypes.sizeof(i.p), 4) self.assertNotEquals(a, 0) self.assertEquals(a, 0x11111111) # 4*'\x11' # null pointer i = Y.from_buffer_copy(b'\xAA\xAA\xBB\xBB' + 4 * '\x00' + '\xCC') pnull = utils.get_pointee_address(i.p) self.assertEquals(utils.get_pointee_address(pnull), 0) # non-pointer, and void null pointer ctypes = types.load_ctypes_default() i = ctypes.c_int(69) self.assertEquals(utils.get_pointee_address(i), 0) pnull = ctypes.c_void_p(0) self.assertEquals(utils.get_pointee_address(pnull), 0) pass
def test_formatAddress(self): types.reload_ctypes(8, 8, 16) x = utils.formatAddress(0x12345678) self.assertEquals('0x0000000012345678', x) # 32b types.reload_ctypes(4, 4, 8) x = utils.formatAddress(0x12345678) self.assertEquals('0x12345678', x)
def setUp(self): model.reset() from haystack import types types.reload_ctypes(4, 4, 8) self.cpu_bits = '32' self.os_name = 'linux' self.tgts = [] self.process = None self.tests = {"test1": "test-ctypes1.%d" % (32), "test2": "test-ctypes2.%d" % (32), "test3": "test-ctypes3.%d" % (32), }
def setUp(self): model.reset() types.reload_ctypes(4, 4, 8) self.memdumpname = 'test/src/test-ctypes7.32.dump' self.classname = 'test.src.ctypes7.struct_Node' self._load_offsets_values(self.memdumpname) self.address = self.offsets['test1'][0] # 0x8f40008 # load layout in x32 from test.src import ctypes7 from test.src import ctypes7_gen32 model.copyGeneratedClasses(ctypes7_gen32, ctypes7) model.registerModule(ctypes7) # apply constraints ctypes7.populate()
def setUp(self): model.reset() types.reload_ctypes(8, 8, 16) self.memdumpname = 'test/src/test-ctypes7.64.dump' self.classname = 'test.src.ctypes7.struct_Node' self._load_offsets_values(self.memdumpname) self.address = self.offsets['test1'][0] # 0x000000001b1e010 # load layout in x64 from test.src import ctypes7 from test.src import ctypes7_gen64 model.copyGeneratedClasses(ctypes7_gen64, ctypes7) model.registerModule(ctypes7) # apply constraints ctypes7.populate()
def test_bytes2array(self): """bytes to ctypes array""" ctypes = types.reload_ctypes(4, 4, 8) bytes = 4 * b'\xAA' + 4 * b'\xBB' + 4 * b'\xCC' + \ 4 * b'\xDD' + 4 * b'\xEE' + 4 * b'\xFF' array = utils.bytes2array(bytes, ctypes.c_ulong) self.assertEquals(array[0], 0xAAAAAAAA) self.assertEquals(len(array), 6) ctypes = types.reload_ctypes(8, 8, 16) bytes = 4 * b'\xAA' + 4 * b'\xBB' + 4 * b'\xCC' + \ 4 * b'\xDD' + 4 * b'\xEE' + 4 * b'\xFF' array = utils.bytes2array(bytes, ctypes.c_ulong) self.assertEquals(array[0], 0xBBBBBBBBAAAAAAAA) self.assertEquals(len(array), 3) pass
def test_unpackWord(self): # 64b types.reload_ctypes(8, 8, 16) one = b'\x01' + 7 * b'\x00' x = utils.unpackWord(one) self.assertEquals(x, 1) # 32b types.reload_ctypes(4, 4, 8) one32 = b'\x01' + 3 * b'\x00' x = utils.unpackWord(one32) self.assertEquals(x, 1) pass # endianness two32 = 3 * b'\x00' + '\x02' x = utils.unpackWord(two32, '>') self.assertEquals(x, 2) pass
def set_word_size(self, wordsize, ptrsize, ldsize): from haystack import types self.__size = wordsize # FIXME # win 32 bits, 4,4,8 # linux 32 bits, 4,4,12 # linux 64 bits, 8,8,16 self.ctypes = types.reload_ctypes(wordsize, ptrsize, ldsize) return
def setUp(self): model.reset() types.reload_ctypes(8, 8, 16) class MyConfig: def get_word_size(self): return 8 self.memdumpname = 'test/src/test-ctypes6.64.dump' self.node_structname = 'test.src.ctypes6.struct_Node' self.usual_structname = 'test.src.ctypes6.struct_usual' self._load_offsets_values(self.memdumpname) self.address1 = self.offsets['test1'][0] # struct_usual self.address2 = self.offsets['test2'][0] # struct_Node self.address3 = self.offsets['test3'][0] # struct_Node # load layout in x64 from test.src import ctypes6 from test.src import ctypes6_gen64 model.copyGeneratedClasses(ctypes6_gen64, ctypes6) model.registerModule(ctypes6) # apply constraints ctypes6.populate(MyConfig())
def test_walker_after_arch_change(self): x32 = types.reload_ctypes(4, 4, 8) x64 = types.reload_ctypes(8, 8, 16) from haystack.structures.libc import libcheapwalker from haystack.structures.win32 import winheapwalker from haystack.structures.win32 import win7heapwalker if False: # set the arch ctypes = types.set_ctypes(x32) libc_x32 = libcheapwalker.LibcHeapFinder(x32) winxp_x32 = winheapwalker.WinHeapFinder(x32) win7_x32 = win7heapwalker.Win7HeapFinder(x32) from haystack.structures.win32 import win7heap t = win7heap.HEAP_ENTRY for fi, tp in t._fields_: f = getattr(t, fi) print fi, " : ", hex(f.offset), hex(f.size) self.assertEquals(ctypes.sizeof(libc_x32.heap_type), 8) self.assertEquals(ctypes.sizeof(winxp_x32.heap_type), 1430) self.assertEquals(ctypes.sizeof(win7_x32.heap_type), 312) # 0x138 # set the arch model.reset() ctypes = types.set_ctypes(x64) libc_x64 = libcheapwalker.LibcHeapFinder(x64) winxp_x64 = winheapwalker.WinHeapFinder(x64) win7_x64 = win7heapwalker.Win7HeapFinder(x64) # import code # code.interact(local=locals()) self.assertEquals(ctypes.sizeof(libc_x64.heap_type), 16) # who knows... self.assertEquals(ctypes.sizeof(win7_x64.heap_type), 520) # BUG FIXME, what is the size of winxp64 HEAP ? self.assertEquals(ctypes.sizeof(winxp_x64.heap_type), 2792) # 0xae8
def test_get_subtype(self): ctypes = types.reset_ctypes() class X(ctypes.Structure): _fields_ = [('p', ctypes.POINTER(ctypes.c_long))] PX = ctypes.POINTER(X) self.assertEquals(utils.get_subtype(PX), X) ctypes = types.reload_ctypes(4, 4, 8) # different arch class Y(ctypes.Structure): _fields_ = [('p', ctypes.POINTER(ctypes.c_long))] PY = ctypes.POINTER(Y) self.assertEquals(utils.get_subtype(PY), Y)
def test_mmap_hack32(self): ctypes = types.reload_ctypes(4, 4, 8) real_ctypes_long = ctypes.get_real_ctypes_member('c_ulong') fname = os.path.normpath(os.path.abspath(__file__)) fin = file(fname) local_mmap_bytebuffer = mmap.mmap( fin.fileno(), 1024, access=mmap.ACCESS_READ) fin.close() fin = None # yeap, that right, I'm stealing the pointer value. DEAL WITH IT. heapmap = struct.unpack('L', (real_ctypes_long).from_address(id(local_mmap_bytebuffer) + 2 * (ctypes.sizeof(real_ctypes_long))))[0] log.debug('MMAP HACK: heapmap: 0x%0.8x' % (heapmap)) maps = readLocalProcessMappings() ret = [m for m in maps if heapmap in m] # heapmap is a pointer value in local memory self.assertEquals(len(ret), 1) # heapmap is a pointer value to this executable? self.assertEquals(ret[0].pathname, fname) import ctypes self.assertIn('CTypesProxy-4:4:8', str(ctypes))