Example #1
0
 def _get_rpath(self, header):
     """Returns a generator of RPATH string values in the header."""
     for (idx, (lc, cmd, data)) in enumerate(header.commands):
         if lc.cmd == mach_o.LC_RPATH:
             ofs = cmd.path - sizeof(lc.__class__) - sizeof(cmd.__class__)
             yield data[ofs:data.find(b'\x00', ofs)].decode(
                 sys.getfilesystemencoding())
Example #2
0
def _add_rpath_to_header(header, rpath):
    """Add an LC_RPATH load command to a MachOHeader.

    Parameters
    ----------
    header: MachOHeader instances
        A mach-o header to add rpath to
    rpath: str
        The rpath to add to the given header
    """
    if header.header.magic in (macholib.mach_o.MH_MAGIC,
                               macholib.mach_o.MH_CIGAM):
        pad_to = 4
    else:
        pad_to = 8
    data = macho_path_as_data(rpath, pad_to=pad_to)
    header_size = sizeof(macholib.mach_o.load_command) + sizeof(
        macholib.mach_o.rpath_command)

    rem = (header_size + len(data)) % pad_to
    if rem > 0:
        data += b'\x00' * (pad_to - rem)

    command_size = header_size + len(data)

    cmd = macholib.mach_o.rpath_command(header_size, _endian_=header.endian)
    lc = macholib.mach_o.load_command(macholib.mach_o.LC_RPATH,
                                      command_size,
                                      _endian_=header.endian)
    header.commands.append((lc, cmd, data))
    header.header.ncmds += 1
    header.changedHeaderSizeBy(command_size)
Example #3
0
def _add_rpath_to_header(header, rpath):
    """Add an LC_RPATH load command to a MachOHeader.

    Parameters
    ----------
    header: MachOHeader instances
        A mach-o header to add rpath to
    rpath: str
        The rpath to add to the given header
    """
    if header.header.magic in (macholib.mach_o.MH_MAGIC, macholib.mach_o.MH_CIGAM):
        pad_to = 4
    else:
        pad_to = 8
    data = macho_path_as_data(rpath, pad_to=pad_to)
    header_size = sizeof(macholib.mach_o.load_command) + sizeof(macholib.mach_o.rpath_command)

    rem = (header_size + len(data)) % pad_to
    if rem > 0:
        data += b'\x00' * (pad_to - rem)

    command_size = header_size + len(data)

    cmd = macholib.mach_o.rpath_command(header_size, _endian_=header.endian)
    lc = macholib.mach_o.load_command(macholib.mach_o.LC_RPATH, command_size,
        _endian_=header.endian)
    header.commands.append((lc, cmd, data))
    header.header.ncmds += 1
    header.changedHeaderSizeBy(command_size)
def _add_dependency_to_header(header, new_dependency, compatibility_version,
                              current_version):
    """Add an LC_LOAD_DYLIB load command to a MachOHeader.

    Parameters
    ----------
    header: MachOHeader instances
        A mach-o header to add dependency to
    new_dependency: str
        Name of the dependency to be added to the header
    compatibility_version: str
        Compatibility Version of the new dependency
        Example: 1.2.3
    current_version: str
        Current Version of the new dependency
        Example: 1.2.3
    """
    if header.header.magic in (macholib.mach_o.MH_MAGIC,
                               macholib.mach_o.MH_CIGAM):
        pad_to = 4
    else:
        pad_to = 8
    data = macho_path_as_data(new_dependency, pad_to=pad_to)
    header_size = sizeof(macholib.mach_o.load_command) + sizeof(
        macholib.mach_o.dylib_command)

    rem = (header_size + len(data)) % pad_to
    if rem > 0:
        data += b'\x00' * (pad_to - rem)

    command_size = header_size + len(data)

    cmd = macholib.mach_o.dylib_command(header_size, _endian_=header.endian)

    # We assume that the compatibility version data is in the format major.minor.rev version numbers. Example: 1.2.3
    version_array = compatibility_version.split('.')
    compatibility_version_object = macholib.mach_o.mach_version_helper(
        int(version_array[0]), int(version_array[1]), int(version_array[2]))
    cmd.compatibility_version = compatibility_version_object

    # We assume that the current version data is in the format major.minor.rev version numbers. Example: 1.2.3
    version_array = current_version.split('.')
    current_version_object = macholib.mach_o.mach_version_helper(
        int(version_array[0]), int(version_array[1]), int(version_array[2]))
    cmd.current_version = current_version_object

    lc = macholib.mach_o.load_command(macholib.mach_o.LC_LOAD_DYLIB,
                                      command_size,
                                      _endian_=header.endian)
    header.commands.append((lc, cmd, data))
    header.header.ncmds += 1
    header.changedHeaderSizeBy(command_size)
Example #5
0
    def test_sizeof(self):
        self.assertEqual(ptypes.sizeof(b"foobar"), 6)

        self.assertRaises(ValueError, ptypes.sizeof, [])
        self.assertRaises(ValueError, ptypes.sizeof, {})
        self.assertRaises(ValueError, ptypes.sizeof, b"foo".decode('ascii'))

        class M (object):
            pass

        m = M()
        m._size_ = 42
        self.assertEqual(ptypes.sizeof(m), 42)
Example #6
0
    def test_sizeof(self):
        self.assertEqual(ptypes.sizeof(b"foobar"), 6)

        self.assertRaises(ValueError, ptypes.sizeof, [])
        self.assertRaises(ValueError, ptypes.sizeof, {})
        self.assertRaises(ValueError, ptypes.sizeof, b"foo".decode('ascii'))

        class M(object):
            pass

        m = M()
        m._size_ = 42
        self.assertEqual(ptypes.sizeof(m), 42)
Example #7
0
    def verifyType(self, ptype, size, pytype, values):
        self.assertEqual(ptypes.sizeof(ptype), size)
        self.assertIsSubclass(ptype, pytype)

        for v in values:
            pv = ptype(v)
            packed = pv.to_str()
            self.assertIsInstance(packed, bytes)
            self.assertEqual(len(packed), size)

            unp = ptype.from_str(packed)
            self.assertIsInstance(unp, ptype)
            self.assertEqual(unp, pv)

            fp = BytesIO(packed)
            unp = ptype.from_fileobj(fp)
            fp.close()
            self.assertIsInstance(unp, ptype)
            self.assertEqual(unp, pv)

            fp = BytesIO()
            pv.to_fileobj(fp)
            data = fp.getvalue()
            fp.close()
            self.assertEqual(data, packed)

            mm = mmap.mmap(-1, size+20)
            mm[:] = b'\x00' * (size+20)
            pv.to_mmap(mm, 10)

            self.assertEqual(ptype.from_mmap(mm, 10), pv)
            self.assertEqual(mm[:], (b'\x00'*10) + packed + (b'\x00'*10))

            self.assertEqual(ptype.from_tuple((v,)), pv)
Example #8
0
    def verifyType(self, ptype, size, pytype, values):
        self.assertEqual(ptypes.sizeof(ptype), size)
        self.assertIsSubclass(ptype, pytype)

        for v in values:
            pv = ptype(v)
            packed = pv.to_str()
            self.assertIsInstance(packed, bytes)
            self.assertEqual(len(packed), size)

            unp = ptype.from_str(packed)
            self.assertIsInstance(unp, ptype)
            self.assertEqual(unp, pv)

            fp = BytesIO(packed)
            unp = ptype.from_fileobj(fp)
            fp.close()
            self.assertIsInstance(unp, ptype)
            self.assertEqual(unp, pv)

            fp = BytesIO()
            pv.to_fileobj(fp)
            data = fp.getvalue()
            fp.close()
            self.assertEqual(data, packed)

            mm = mmap.mmap(-1, size + 20)
            mm[:] = b'\x00' * (size + 20)
            pv.to_mmap(mm, 10)

            self.assertEqual(ptype.from_mmap(mm, 10), pv)
            self.assertEqual(mm[:], (b'\x00' * 10) + packed + (b'\x00' * 10))

            self.assertEqual(ptype.from_tuple((v, )), pv)
def _add_dependency_to_header(header, new_dependency, compatibility_version, current_version):
    """Add an LC_LOAD_DYLIB load command to a MachOHeader.

    Parameters
    ----------
    header: MachOHeader instances
        A mach-o header to add dependency to
    new_dependency: str
        Name of the dependency to be added to the header
    compatibility_version: str
        Compatibility Version of the new dependency
        Example: 1.2.3
    current_version: str
        Current Version of the new dependency
        Example: 1.2.3
    """
    if header.header.magic in (macholib.mach_o.MH_MAGIC, macholib.mach_o.MH_CIGAM):
        pad_to = 4
    else:
        pad_to = 8
    data = macho_path_as_data(new_dependency, pad_to=pad_to)
    header_size = sizeof(macholib.mach_o.load_command) + sizeof(macholib.mach_o.dylib_command)

    rem = (header_size + len(data)) % pad_to
    if rem > 0:
        data += b'\x00' * (pad_to - rem)

    command_size = header_size + len(data)

    cmd = macholib.mach_o.dylib_command(header_size, _endian_=header.endian)
    
    # We assume that the compatibility version data is in the format major.minor.rev version numbers. Example: 1.2.3
    version_array = compatibility_version.split('.')
    compatibility_version_object = macholib.mach_o.mach_version_helper(int(version_array[0]), int(version_array[1]), int(version_array[2]))
    cmd.compatibility_version = compatibility_version_object

    # We assume that the current version data is in the format major.minor.rev version numbers. Example: 1.2.3    
    version_array = current_version.split('.')
    current_version_object = macholib.mach_o.mach_version_helper(int(version_array[0]), int(version_array[1]), int(version_array[2]))
    cmd.current_version = current_version_object
    
    lc = macholib.mach_o.load_command(macholib.mach_o.LC_LOAD_DYLIB, command_size, _endian_=header.endian)
    header.commands.append((lc, cmd, data))
    header.header.ncmds += 1
    header.changedHeaderSizeBy(command_size)
Example #10
0
def generate_dylib_load_command(header, libary_install_name):
    """ Generates a LC_LOAD_DYLIB command for the given header and a library install path.
	
	Note: the header must already contain at least one LC_LOAD_DYLIB command (see code comments).
	Returns a ready-for-use load_command in terms of macholib.
	"""

    # One can not simply create instances of `dylib_command` and `load_command` classes,
    # because that's just not the way macholib works. If we try then all we'll get is a bunch
    # of endian (big/little) issues when these objects are serialized into a file.
    # BUT THAT'S PROGRAMMING RIGHT?
    # So instead I'll iterate *existing* load commands, find a dyld_command, copy it
    # and modify this copy. This existing command is said to be fully initialized.
    lc = None
    cmd = None
    for (command, internal_cmd, data) in header.commands:
        if (command.cmd == LC_LOAD_DYLIB) and isinstance(
                internal_cmd, dylib_command):
            lc = deepcopy(command)
            cmd = deepcopy(internal_cmd)
            break
    if not lc or not cmd:
        raise Exception(
            "Invalid Mach-O file. I mean, there must be at least one LC_LOAD_DYLIB load command."
        )
        return None

    # Well, now we just replace everything with our own stuff
    cmd.timestamp = 0
    cmd.current_version = cmd.compatibility_version = 0x1000
    # Since we store the library's path just after the load command itself, we need to find out it's offset.
    base = sizeof(load_command) + sizeof(dylib_command)
    # `name` is rather bad name for this property: actually it means a path string offset
    cmd.name = base
    # Also the whole thing must be aligned by 4 bytes on 32-bit arches and by 8 bytes on 64-bit arches
    align = 4 if header.header.magic == MH_MAGIC else 8
    aligned_name = libary_install_name + (b'\x00' *
                                          (align -
                                           (len(libary_install_name) % align)))
    # So now we finally can say what size this load_command is
    lc.cmdsize = base + len(aligned_name)

    return (lc, cmd, aligned_name)
Example #11
0
    def testBasic(self):
        for endian in "><":
            kw = dict(_endian_=endian)
            MYSTRUCTURE = b"\x00\x01\x02\x03\xFF"
            for fn, args in [
                ("from_str", (MYSTRUCTURE, )),
                ("from_mmap", (MYSTRUCTURE, 0)),
                ("from_fileobj", (BytesIO(MYSTRUCTURE), )),
            ]:
                with self.subTest("MYSTRUCTURE", endian=endian, fn=fn):
                    myStructure = getattr(MyStructure, fn)(*args, **kw)
                    if endian == ">":
                        self.assertEqual(myStructure.foo, 0x00010203)
                    else:
                        self.assertEqual(myStructure.foo, 0x03020100)
                    self.assertEqual(myStructure.bar, 0xFF)
                    self.assertEqual(myStructure._endian_, endian)
                    self.assertEqual(myStructure.to_str(), MYSTRUCTURE)

            MYFUNSTRUCTURE = b"!" + MYSTRUCTURE
            for fn, args in [
                ("from_str", (MYFUNSTRUCTURE, )),
                ("from_mmap", (MYFUNSTRUCTURE, 0)),
                ("from_fileobj", (BytesIO(MYFUNSTRUCTURE), )),
            ]:
                with self.subTest("MYFUNSTRUCTURE", fn=fn):
                    myFunStructure = getattr(MyFunStructure, fn)(*args, **kw)
                    self.assertEqual(myFunStructure.mystruct, myStructure)
                    self.assertEqual(myFunStructure.fun, b"!",
                                     (myFunStructure.fun, b"!"))
                    self.assertEqual(myFunStructure.to_str(), MYFUNSTRUCTURE)

            sio = BytesIO()
            myFunStructure.to_fileobj(sio)
            self.assertEqual(sio.getvalue(), MYFUNSTRUCTURE)

            mm = mmap.mmap(-1, ptypes.sizeof(MyFunStructure) * 2)
            mm[:] = b"\x00" * (ptypes.sizeof(MyFunStructure) * 2)
            myFunStructure.to_mmap(mm, 0)
            self.assertEqual(MyFunStructure.from_mmap(mm, 0, **kw),
                             myFunStructure)
            self.assertEqual(mm[:ptypes.sizeof(MyFunStructure)],
                             MYFUNSTRUCTURE)
            self.assertEqual(
                mm[ptypes.sizeof(MyFunStructure):],
                b"\x00" * ptypes.sizeof(MyFunStructure),
            )
            myFunStructure.to_mmap(mm, ptypes.sizeof(MyFunStructure))
            self.assertEqual(mm[:], MYFUNSTRUCTURE + MYFUNSTRUCTURE)
            self.assertEqual(
                MyFunStructure.from_mmap(mm, ptypes.sizeof(MyFunStructure),
                                         **kw),
                myFunStructure,
            )
Example #12
0
def generate_dylib_load_command(header, libary_install_name):
	""" Generates a LC_LOAD_DYLIB command for the given header and a library install path.
	
	Note: the header must already contain at least one LC_LOAD_DYLIB command (see code comments).
	Returns a ready-for-use load_command in terms of macholib.
	"""
	
	# One can not simply create instances of `dylib_command` and `load_command` classes,
	# because that's just not the way macholib works. If we try then all we'll get is a bunch
	# of endian (big/little) issues when these objects are serialized into a file.
	# BUT THAT'S PROGRAMMING RIGHT?
	# So instead I'll iterate *existing* load commands, find a dyld_command, copy it
	# and modify this copy. This existing command is said to be fully initialized.
	lc = None
	cmd = None
	for (command, internal_cmd, data) in header.commands:
		if (command.cmd == LC_LOAD_DYLIB) and isinstance(internal_cmd, dylib_command):
			lc = deepcopy(command)
			cmd = deepcopy(internal_cmd)
			break
	if not lc or not cmd:
		raise Exception("Invalid Mach-O file. I mean, there must be at least one LC_LOAD_DYLIB load command.")
		return None
	
	# Well, now we just replace everything with our own stuff
	cmd.timestamp = 0
	cmd.current_version = cmd.compatibility_version = 0x1000
	# Since we store the library's path just after the load command itself, we need to find out it's offset.
	base = sizeof(load_command) + sizeof(dylib_command)
	# `name` is rather bad name for this property: actually it means a path string offset
	cmd.name = base
	# Also the whole thing must be aligned by 4 bytes on 32-bit arches and by 8 bytes on 64-bit arches
	align = 4 if header.header.magic == MH_MAGIC else 8
	aligned_name = libary_install_name + (b'\x00' * (align - (len(libary_install_name) % align)))
	# So now we finally can say what size this load_command is
	lc.cmdsize = base + len(aligned_name)
	
	return (lc, cmd, aligned_name)	
Example #13
0
    def testBasic(self):
        for endian in '><':
            kw = dict(_endian_=endian)
            MYSTRUCTURE = b'\x00\x11\x22\x33\xFF'
            for fn, args in [
                ('from_str', (MYSTRUCTURE, )),
                ('from_mmap', (MYSTRUCTURE, 0)),
                ('from_fileobj', (BytesIO(MYSTRUCTURE), )),
            ]:
                myStructure = getattr(MyStructure, fn)(*args, **kw)
                if endian == '>':
                    self.assertEqual(myStructure.foo, 0x00112233)
                else:
                    self.assertEqual(myStructure.foo, 0x33221100)
                self.assertEqual(myStructure.bar, 0xFF)
                self.assertEqual(myStructure.to_str(), MYSTRUCTURE)

            MYFUNSTRUCTURE = b'!' + MYSTRUCTURE
            for fn, args in [
                ('from_str', (MYFUNSTRUCTURE, )),
                ('from_mmap', (MYFUNSTRUCTURE, 0)),
                ('from_fileobj', (BytesIO(MYFUNSTRUCTURE), )),
            ]:
                myFunStructure = getattr(MyFunStructure, fn)(*args, **kw)
                self.assertEqual(myFunStructure.mystruct, myStructure)
                self.assertEqual(myFunStructure.fun, b'!',
                                 (myFunStructure.fun, b'!'))
                self.assertEqual(myFunStructure.to_str(), MYFUNSTRUCTURE)

            sio = BytesIO()
            myFunStructure.to_fileobj(sio)
            self.assertEqual(sio.getvalue(), MYFUNSTRUCTURE)

            mm = mmap.mmap(-1, ptypes.sizeof(MyFunStructure) * 2)
            mm[:] = b'\x00' * (ptypes.sizeof(MyFunStructure) * 2)
            myFunStructure.to_mmap(mm, 0)
            self.assertEqual(MyFunStructure.from_mmap(mm, 0, **kw),
                             myFunStructure)
            self.assertEqual(mm[:ptypes.sizeof(MyFunStructure)],
                             MYFUNSTRUCTURE)
            self.assertEqual(mm[ptypes.sizeof(MyFunStructure):],
                             b'\x00' * ptypes.sizeof(MyFunStructure))
            myFunStructure.to_mmap(mm, ptypes.sizeof(MyFunStructure))
            self.assertEqual(mm[:], MYFUNSTRUCTURE + MYFUNSTRUCTURE)
            self.assertEqual(
                MyFunStructure.from_mmap(mm, ptypes.sizeof(MyFunStructure),
                                         **kw), myFunStructure)
Example #14
0
    def testBasic(self):
        for endian in '><':
            kw = dict(_endian_=endian)
            MYSTRUCTURE = b'\x00\x11\x22\x33\xFF'
            for fn, args in [
                        ('from_str', (MYSTRUCTURE,)),
                        ('from_mmap', (MYSTRUCTURE, 0)),
                        ('from_fileobj', (BytesIO(MYSTRUCTURE),)),
                    ]:
                myStructure = getattr(MyStructure, fn)(*args, **kw)
                if endian == '>':
                    self.assertEqual(myStructure.foo, 0x00112233)
                else:
                    self.assertEqual( myStructure.foo, 0x33221100)
                self.assertEqual(myStructure.bar, 0xFF)
                self.assertEqual(myStructure.to_str(), MYSTRUCTURE)

            MYFUNSTRUCTURE = b'!' + MYSTRUCTURE
            for fn, args in [
                        ('from_str', (MYFUNSTRUCTURE,)),
                        ('from_mmap', (MYFUNSTRUCTURE, 0)),
                        ('from_fileobj', (BytesIO(MYFUNSTRUCTURE),)),
                    ]:
                myFunStructure = getattr(MyFunStructure, fn)(*args, **kw)
                self.assertEqual(myFunStructure.mystruct, myStructure)
                self.assertEqual(myFunStructure.fun, b'!', (myFunStructure.fun, b'!'))
                self.assertEqual(myFunStructure.to_str(), MYFUNSTRUCTURE)

            sio = BytesIO()
            myFunStructure.to_fileobj(sio)
            self.assertEqual(sio.getvalue(), MYFUNSTRUCTURE)

            mm = mmap.mmap(-1, ptypes.sizeof(MyFunStructure) * 2) 
            mm[:] = b'\x00' * (ptypes.sizeof(MyFunStructure) * 2)
            myFunStructure.to_mmap(mm, 0)
            self.assertEqual(MyFunStructure.from_mmap(mm, 0, **kw), myFunStructure)
            self.assertEqual(mm[:ptypes.sizeof(MyFunStructure)], MYFUNSTRUCTURE)
            self.assertEqual(mm[ptypes.sizeof(MyFunStructure):], b'\x00' * ptypes.sizeof(MyFunStructure))
            myFunStructure.to_mmap(mm, ptypes.sizeof(MyFunStructure))
            self.assertEqual(mm[:], MYFUNSTRUCTURE + MYFUNSTRUCTURE)
            self.assertEqual(MyFunStructure.from_mmap(mm, ptypes.sizeof(MyFunStructure), **kw), myFunStructure)