1*c54f35caSApple OSS Distributionsfrom __future__ import absolute_import, division, print_function 2*c54f35caSApple OSS Distributions 3*c54f35caSApple OSS Distributionsfrom builtins import range 4*c54f35caSApple OSS Distributionsfrom builtins import object 5*c54f35caSApple OSS Distributions 6*c54f35caSApple OSS Distributionsimport macholib 7*c54f35caSApple OSS Distributionsfrom macholib import MachO as macho 8*c54f35caSApple OSS Distributionsfrom collections import namedtuple 9*c54f35caSApple OSS Distributionsimport six 10*c54f35caSApple OSS Distributionsimport uuid 11*c54f35caSApple OSS Distributionsimport sys 12*c54f35caSApple OSS Distributions 13*c54f35caSApple OSS Distributions 14*c54f35caSApple OSS Distributions# 15*c54f35caSApple OSS Distributions# Defines segment/section descriptions that can be used by external users 16*c54f35caSApple OSS Distributions# like kext management to keep track about memory layout. To avoid the need 17*c54f35caSApple OSS Distributions# to keep full Mach-O instance around. 18*c54f35caSApple OSS Distributions# 19*c54f35caSApple OSS Distributions 20*c54f35caSApple OSS DistributionsMachOSegment = namedtuple( 21*c54f35caSApple OSS Distributions 'MachOSegment', 22*c54f35caSApple OSS Distributions 'name vmaddr vmsize fileoff filesize sections' 23*c54f35caSApple OSS Distributions) 24*c54f35caSApple OSS Distributions 25*c54f35caSApple OSS DistributionsMachOSection = namedtuple( 26*c54f35caSApple OSS Distributions 'MachOSection', 27*c54f35caSApple OSS Distributions 'sectname addr size fileoff' 28*c54f35caSApple OSS Distributions) 29*c54f35caSApple OSS Distributions 30*c54f35caSApple OSS Distributions 31*c54f35caSApple OSS Distributions# 32*c54f35caSApple OSS Distributions# The Mach-O library loads data for each section in a Mach-O. 33*c54f35caSApple OSS Distributions# This breaks our macros in few ways: 34*c54f35caSApple OSS Distributions# - It is slow and no one is really using it. 35*c54f35caSApple OSS Distributions# - File offsets in fileset KC points outside of the file window reported 36*c54f35caSApple OSS Distributions# by OSkext API. 37*c54f35caSApple OSS Distributions# 38*c54f35caSApple OSS Distributions# Until macholib gets some optin to avoid reading section data we have to 39*c54f35caSApple OSS Distributions# patch it here. 40*c54f35caSApple OSS Distributions# 41*c54f35caSApple OSS Distributions# !!! Note. This works only with the latest lib 1.15.1 !!! 42*c54f35caSApple OSS Distributions 43*c54f35caSApple OSS Distributionsif macholib.__version__ == "1.15.2": 44*c54f35caSApple OSS Distributions from macholib.mach_o import ( 45*c54f35caSApple OSS Distributions LC_ID_DYLIB, 46*c54f35caSApple OSS Distributions LC_REGISTRY, 47*c54f35caSApple OSS Distributions LC_SEGMENT, 48*c54f35caSApple OSS Distributions LC_SEGMENT_64, 49*c54f35caSApple OSS Distributions S_ZEROFILL, 50*c54f35caSApple OSS Distributions load_command, 51*c54f35caSApple OSS Distributions section, 52*c54f35caSApple OSS Distributions section_64, 53*c54f35caSApple OSS Distributions ) 54*c54f35caSApple OSS Distributions from macholib.ptypes import sizeof 55*c54f35caSApple OSS Distributions from macholib.util import fileview 56*c54f35caSApple OSS Distributions 57*c54f35caSApple OSS Distributions 58*c54f35caSApple OSS Distributions # !!! This is the actual patch for macholib 1.15.2 !!! 59*c54f35caSApple OSS Distributions # 60*c54f35caSApple OSS Distributions # 1. MemMachOHeader subclasses macho.MachOHeader 61*c54f35caSApple OSS Distributions # 2. Overloaded load() method is copy/paste of the original load() with 62*c54f35caSApple OSS Distributions # small patch added that disables section contents loading. 63*c54f35caSApple OSS Distributions # 3. The new MemMachOHeader is injected back into library and used 64*c54f35caSApple OSS Distributions # in place of macho.MachOHeader. 65*c54f35caSApple OSS Distributions # 66*c54f35caSApple OSS Distributions # This code should not ever exist in the first place. So the plan is to 67*c54f35caSApple OSS Distributions # remove it when macholib gets improved or abandoned by our own 68*c54f35caSApple OSS Distributions # implementation. 69*c54f35caSApple OSS Distributions class MemMachOHeader(macho.MachOHeader): 70*c54f35caSApple OSS Distributions """ Mach-O header parser that does not try to load section data. """ 71*c54f35caSApple OSS Distributions 72*c54f35caSApple OSS Distributions def load(self, fh): 73*c54f35caSApple OSS Distributions fh = fileview(fh, self.offset, self.size) 74*c54f35caSApple OSS Distributions fh.seek(0) 75*c54f35caSApple OSS Distributions 76*c54f35caSApple OSS Distributions self.sizediff = 0 77*c54f35caSApple OSS Distributions kw = {"_endian_": self.endian} 78*c54f35caSApple OSS Distributions header = self.mach_header.from_fileobj(fh, **kw) 79*c54f35caSApple OSS Distributions self.header = header 80*c54f35caSApple OSS Distributions # If header.magic != self.MH_MAGIC: 81*c54f35caSApple OSS Distributions # raise ValueError("header has magic %08x, expecting %08x" % ( 82*c54f35caSApple OSS Distributions # header.magic, self.MH_MAGIC)) 83*c54f35caSApple OSS Distributions 84*c54f35caSApple OSS Distributions cmd = self.commands = [] 85*c54f35caSApple OSS Distributions 86*c54f35caSApple OSS Distributions self.filetype = self.get_filetype_shortname(header.filetype) 87*c54f35caSApple OSS Distributions 88*c54f35caSApple OSS Distributions read_bytes = 0 89*c54f35caSApple OSS Distributions low_offset = sys.maxsize 90*c54f35caSApple OSS Distributions for i in range(header.ncmds): 91*c54f35caSApple OSS Distributions # read the load command 92*c54f35caSApple OSS Distributions cmd_load = load_command.from_fileobj(fh, **kw) 93*c54f35caSApple OSS Distributions 94*c54f35caSApple OSS Distributions # read the specific command 95*c54f35caSApple OSS Distributions klass = LC_REGISTRY.get(cmd_load.cmd, None) 96*c54f35caSApple OSS Distributions if klass is None: 97*c54f35caSApple OSS Distributions raise ValueError("Unknown load command: %d" % (cmd_load.cmd,)) 98*c54f35caSApple OSS Distributions cmd_cmd = klass.from_fileobj(fh, **kw) 99*c54f35caSApple OSS Distributions 100*c54f35caSApple OSS Distributions if cmd_load.cmd == LC_ID_DYLIB: 101*c54f35caSApple OSS Distributions # remember where this command was 102*c54f35caSApple OSS Distributions if self.id_cmd is not None: 103*c54f35caSApple OSS Distributions raise ValueError("This dylib already has an id") 104*c54f35caSApple OSS Distributions self.id_cmd = i 105*c54f35caSApple OSS Distributions 106*c54f35caSApple OSS Distributions if cmd_load.cmd in (LC_SEGMENT, LC_SEGMENT_64): 107*c54f35caSApple OSS Distributions # for segment commands, read the list of segments 108*c54f35caSApple OSS Distributions segs = [] 109*c54f35caSApple OSS Distributions # assert that the size makes sense 110*c54f35caSApple OSS Distributions if cmd_load.cmd == LC_SEGMENT: 111*c54f35caSApple OSS Distributions section_cls = section 112*c54f35caSApple OSS Distributions else: # LC_SEGMENT_64 113*c54f35caSApple OSS Distributions section_cls = section_64 114*c54f35caSApple OSS Distributions 115*c54f35caSApple OSS Distributions expected_size = ( 116*c54f35caSApple OSS Distributions sizeof(klass) 117*c54f35caSApple OSS Distributions + sizeof(load_command) 118*c54f35caSApple OSS Distributions + (sizeof(section_cls) * cmd_cmd.nsects) 119*c54f35caSApple OSS Distributions ) 120*c54f35caSApple OSS Distributions if cmd_load.cmdsize != expected_size: 121*c54f35caSApple OSS Distributions raise ValueError("Segment size mismatch") 122*c54f35caSApple OSS Distributions # this is a zero block or something 123*c54f35caSApple OSS Distributions # so the beginning is wherever the fileoff of this command is 124*c54f35caSApple OSS Distributions if cmd_cmd.nsects == 0: 125*c54f35caSApple OSS Distributions if cmd_cmd.filesize != 0: 126*c54f35caSApple OSS Distributions low_offset = min(low_offset, cmd_cmd.fileoff) 127*c54f35caSApple OSS Distributions else: 128*c54f35caSApple OSS Distributions # this one has multiple segments 129*c54f35caSApple OSS Distributions for _j in range(cmd_cmd.nsects): 130*c54f35caSApple OSS Distributions # read the segment 131*c54f35caSApple OSS Distributions seg = section_cls.from_fileobj(fh, **kw) 132*c54f35caSApple OSS Distributions # If the segment has a size and is not zero filled 133*c54f35caSApple OSS Distributions # then its beginning is the offset of this segment 134*c54f35caSApple OSS Distributions not_zerofill = (seg.flags & S_ZEROFILL) != S_ZEROFILL 135*c54f35caSApple OSS Distributions if seg.offset > 0 and seg.size > 0 and not_zerofill: 136*c54f35caSApple OSS Distributions low_offset = min(low_offset, seg.offset) 137*c54f35caSApple OSS Distributions 138*c54f35caSApple OSS Distributions # Do NOT read section data. It is not required and 139*c54f35caSApple OSS Distributions # does not work well with filset KC offsets. 140*c54f35caSApple OSS Distributions """ 141*c54f35caSApple OSS Distributions if not_zerofill: 142*c54f35caSApple OSS Distributions c = fh.tell() 143*c54f35caSApple OSS Distributions fh.seek(seg.offset) 144*c54f35caSApple OSS Distributions sd = fh.read(seg.size) 145*c54f35caSApple OSS Distributions seg.add_section_data(sd) 146*c54f35caSApple OSS Distributions fh.seek(c) 147*c54f35caSApple OSS Distributions """ 148*c54f35caSApple OSS Distributions segs.append(seg) 149*c54f35caSApple OSS Distributions # data is a list of segments 150*c54f35caSApple OSS Distributions cmd_data = segs 151*c54f35caSApple OSS Distributions 152*c54f35caSApple OSS Distributions else: 153*c54f35caSApple OSS Distributions # data is a raw str 154*c54f35caSApple OSS Distributions data_size = cmd_load.cmdsize - sizeof(klass) - sizeof(load_command) 155*c54f35caSApple OSS Distributions cmd_data = fh.read(data_size) 156*c54f35caSApple OSS Distributions cmd.append((cmd_load, cmd_cmd, cmd_data)) 157*c54f35caSApple OSS Distributions read_bytes += cmd_load.cmdsize 158*c54f35caSApple OSS Distributions 159*c54f35caSApple OSS Distributions # make sure the header made sense 160*c54f35caSApple OSS Distributions if read_bytes != header.sizeofcmds: 161*c54f35caSApple OSS Distributions raise ValueError( 162*c54f35caSApple OSS Distributions "Read %d bytes, header reports %d bytes" 163*c54f35caSApple OSS Distributions % (read_bytes, header.sizeofcmds) 164*c54f35caSApple OSS Distributions ) 165*c54f35caSApple OSS Distributions self.total_size = sizeof(self.mach_header) + read_bytes 166*c54f35caSApple OSS Distributions self.low_offset = low_offset 167*c54f35caSApple OSS Distributions 168*c54f35caSApple OSS Distributions 169*c54f35caSApple OSS Distributions # Patch the library to use our own header class instead. 170*c54f35caSApple OSS Distributions macho.MachOHeader = MemMachOHeader 171*c54f35caSApple OSS Distributions 172*c54f35caSApple OSS Distributions 173*c54f35caSApple OSS Distributionsclass MemMachO(macho.MachO): 174*c54f35caSApple OSS Distributions """ Mach-O implementation that accepts I/O stream instead of file. """ 175*c54f35caSApple OSS Distributions 176*c54f35caSApple OSS Distributions def __init__(self, file): 177*c54f35caSApple OSS Distributions """ Creates Mach-O parser on top of provided I/O. """ 178*c54f35caSApple OSS Distributions 179*c54f35caSApple OSS Distributions # Figured out file size from the I/O. 180*c54f35caSApple OSS Distributions file.seek(0, 2) 181*c54f35caSApple OSS Distributions size = file.tell() 182*c54f35caSApple OSS Distributions file.seek(0, 0) 183*c54f35caSApple OSS Distributions 184*c54f35caSApple OSS Distributions # supports the ObjectGraph protocol 185*c54f35caSApple OSS Distributions self.graphident = 'mem:%d//'.format(size) 186*c54f35caSApple OSS Distributions self.filename = 'mem:%d//'.format(size) 187*c54f35caSApple OSS Distributions self.loader_path = "<no-path>" 188*c54f35caSApple OSS Distributions 189*c54f35caSApple OSS Distributions # initialized by load 190*c54f35caSApple OSS Distributions self.fat = None 191*c54f35caSApple OSS Distributions self.headers = [] 192*c54f35caSApple OSS Distributions 193*c54f35caSApple OSS Distributions self.load(file) 194*c54f35caSApple OSS Distributions 195*c54f35caSApple OSS Distributions @staticmethod 196*c54f35caSApple OSS Distributions def make_seg(seg, sects): 197*c54f35caSApple OSS Distributions """ Constructs MachOSegment from input. """ 198*c54f35caSApple OSS Distributions 199*c54f35caSApple OSS Distributions # Wrap all sections in MachOSection tuple. 200*c54f35caSApple OSS Distributions segsec = [ 201*c54f35caSApple OSS Distributions MachOSection( 202*c54f35caSApple OSS Distributions sectname = six.ensure_str(s.segname[:s.segname.find(b'\x00')]), 203*c54f35caSApple OSS Distributions addr = s.addr, 204*c54f35caSApple OSS Distributions fileoff = s.offset, 205*c54f35caSApple OSS Distributions size = s.size 206*c54f35caSApple OSS Distributions ) 207*c54f35caSApple OSS Distributions for s in sects 208*c54f35caSApple OSS Distributions ] 209*c54f35caSApple OSS Distributions 210*c54f35caSApple OSS Distributions # Return MachOSegment 211*c54f35caSApple OSS Distributions return MachOSegment( 212*c54f35caSApple OSS Distributions name=six.ensure_str(seg.segname[:seg.segname.find(b'\x00')]), 213*c54f35caSApple OSS Distributions vmaddr = seg.vmaddr, 214*c54f35caSApple OSS Distributions vmsize = seg.vmsize, 215*c54f35caSApple OSS Distributions fileoff = seg.fileoff, 216*c54f35caSApple OSS Distributions filesize = seg.filesize, 217*c54f35caSApple OSS Distributions sections = segsec 218*c54f35caSApple OSS Distributions ) 219*c54f35caSApple OSS Distributions 220*c54f35caSApple OSS Distributions @property 221*c54f35caSApple OSS Distributions def segments(self): 222*c54f35caSApple OSS Distributions """ Constructs section/segment descriptors. 223*c54f35caSApple OSS Distributions 224*c54f35caSApple OSS Distributions Values are cached in an instance attribute. 225*c54f35caSApple OSS Distributions """ 226*c54f35caSApple OSS Distributions if hasattr(self, '_segments'): 227*c54f35caSApple OSS Distributions return self._segments 228*c54f35caSApple OSS Distributions 229*c54f35caSApple OSS Distributions # Wrap all segments/sections into a MachOSegment/MachOSection. 230*c54f35caSApple OSS Distributions self._segments = [ 231*c54f35caSApple OSS Distributions self.make_seg(seg, sec) 232*c54f35caSApple OSS Distributions for h in self.headers 233*c54f35caSApple OSS Distributions for _, seg, sec in h.commands 234*c54f35caSApple OSS Distributions if isinstance(seg, SEGMENT_TYPES) 235*c54f35caSApple OSS Distributions ] 236*c54f35caSApple OSS Distributions 237*c54f35caSApple OSS Distributions return self._segments 238*c54f35caSApple OSS Distributions 239*c54f35caSApple OSS Distributions @property 240*c54f35caSApple OSS Distributions def uuid(self): 241*c54f35caSApple OSS Distributions """ Returns UUID of the Mach-O. """ 242*c54f35caSApple OSS Distributions if hasattr(self, '_uuid'): 243*c54f35caSApple OSS Distributions return self._uuid 244*c54f35caSApple OSS Distributions 245*c54f35caSApple OSS Distributions for h in self.headers: 246*c54f35caSApple OSS Distributions for cmd in h.commands: 247*c54f35caSApple OSS Distributions # cmds is [(load_command, segment, [sections..])] 248*c54f35caSApple OSS Distributions (_, segment, _) = cmd 249*c54f35caSApple OSS Distributions if isinstance(segment, macholib.mach_o.uuid_command): 250*c54f35caSApple OSS Distributions self._uuid = str(uuid.UUID(bytes=segment.uuid)).upper() 251*c54f35caSApple OSS Distributions return self._uuid 252*c54f35caSApple OSS Distributions 253*c54f35caSApple OSS Distributions 254*c54f35caSApple OSS Distributions# some fixups in macholib that are required for kext support 255*c54f35caSApple OSS Distributionsmacholib.mach_o.MH_KEXT_BUNDLE = 0xB 256*c54f35caSApple OSS Distributions 257*c54f35caSApple OSS Distributionsmacholib.mach_o.MH_FILETYPE_NAMES[macholib.mach_o.MH_KEXT_BUNDLE] = "kext bundle" 258*c54f35caSApple OSS Distributionsmacholib.mach_o.MH_FILETYPE_SHORTNAMES[macholib.mach_o.MH_KEXT_BUNDLE] = "kext" 259*c54f35caSApple OSS Distributions 260*c54f35caSApple OSS DistributionsSEGMENT_TYPES = (macholib.mach_o.segment_command_64, macholib.mach_o.segment_command) 261*c54f35caSApple OSS Distributions 262*c54f35caSApple OSS Distributionsif six.PY3: 263*c54f35caSApple OSS Distributions # Use newer macholib interface on Python 3. 264*c54f35caSApple OSS Distributions def get_load_command_human_name(lc): 265*c54f35caSApple OSS Distributions return lc.get_cmd_name() 266*c54f35caSApple OSS Distributionselse: 267*c54f35caSApple OSS Distributions def get_load_command_human_name(lc): 268*c54f35caSApple OSS Distributions """ return string name of LC_LOAD_DYLIB => "load_dylib" 269*c54f35caSApple OSS Distributions "<unknown>" if not found 270*c54f35caSApple OSS Distributions """ 271*c54f35caSApple OSS Distributions retval = "<unknown>" 272*c54f35caSApple OSS Distributions if lc.cmd in macho.LC_REGISTRY: 273*c54f35caSApple OSS Distributions retval = macho.LC_REGISTRY[lc.cmd].__name__ 274*c54f35caSApple OSS Distributions retval = retval.replace("_command", "") 275*c54f35caSApple OSS Distributions return retval 276*c54f35caSApple OSS Distributions 277*c54f35caSApple OSS Distributions 278*c54f35caSApple OSS Distributionsclass VisualMachoMap(object): 279*c54f35caSApple OSS Distributions KB_1 = 1024 280*c54f35caSApple OSS Distributions KB_16 = 16 * 1024 281*c54f35caSApple OSS Distributions MB_1 = 1 * 1024 * 1024 282*c54f35caSApple OSS Distributions GB_1 = 1 * 1024 * 1024 * 1024 283*c54f35caSApple OSS Distributions 284*c54f35caSApple OSS Distributions def __init__(self, name, width=40): 285*c54f35caSApple OSS Distributions self.name = name 286*c54f35caSApple OSS Distributions self.width = 40 287*c54f35caSApple OSS Distributions self.default_side_padding = 2 288*c54f35caSApple OSS Distributions 289*c54f35caSApple OSS Distributions def get_header_line(self): 290*c54f35caSApple OSS Distributions return '+' + '-' * (self.width - 2) + '+' 291*c54f35caSApple OSS Distributions 292*c54f35caSApple OSS Distributions def get_space_line(self): 293*c54f35caSApple OSS Distributions return '|' + ' ' * (self.width - 2) + '|' 294*c54f35caSApple OSS Distributions 295*c54f35caSApple OSS Distributions def get_dashed_line(self): 296*c54f35caSApple OSS Distributions return '|' + '-' * (self.width - 2) + '|' 297*c54f35caSApple OSS Distributions 298*c54f35caSApple OSS Distributions def get_dotted_line(self): 299*c54f35caSApple OSS Distributions return '|' + '.' * (self.width - 2) + '|' 300*c54f35caSApple OSS Distributions 301*c54f35caSApple OSS Distributions def center_text_in_line(self, line, text): 302*c54f35caSApple OSS Distributions even_length = bool(len(text) % 2 == 0) 303*c54f35caSApple OSS Distributions if len(text) > len(line) - 2: 304*c54f35caSApple OSS Distributions raise ValueError("text is larger than line of text") 305*c54f35caSApple OSS Distributions 306*c54f35caSApple OSS Distributions lbreak_pos = (len(line) // 2) - (len(text) // 2) 307*c54f35caSApple OSS Distributions if not even_length: 308*c54f35caSApple OSS Distributions lbreak_pos -= 1 309*c54f35caSApple OSS Distributions out = line[:lbreak_pos] + text 310*c54f35caSApple OSS Distributions return out + line[len(out):] 311*c54f35caSApple OSS Distributions 312*c54f35caSApple OSS Distributions def get_separator_lines(self): 313*c54f35caSApple OSS Distributions return ['/' + ' ' * (self.width - 2) + '/', '/' + ' ' * (self.width - 2) + '/'] 314*c54f35caSApple OSS Distributions 315*c54f35caSApple OSS Distributions def printMachoMap(self, mobj): 316*c54f35caSApple OSS Distributions MapBlock = namedtuple('MapBlock', 'name vmaddr vmsize fileoff filesize extra_info is_segment') 317*c54f35caSApple OSS Distributions outstr = self.name + '\n' 318*c54f35caSApple OSS Distributions other_cmds = '' 319*c54f35caSApple OSS Distributions blocks = [] 320*c54f35caSApple OSS Distributions for hdr in mobj.headers: 321*c54f35caSApple OSS Distributions cmd_index = 0 322*c54f35caSApple OSS Distributions for cmd in hdr.commands: 323*c54f35caSApple OSS Distributions # cmds is [(load_command, segment, [sections..])] 324*c54f35caSApple OSS Distributions (lc, segment, sections) = cmd 325*c54f35caSApple OSS Distributions lc_cmd_str = get_load_command_human_name(lc) 326*c54f35caSApple OSS Distributions lc_str_rep = "\n\t LC: {:s} size:{:d} nsects:{:d}".format(lc_cmd_str, lc.cmdsize, len(sections)) 327*c54f35caSApple OSS Distributions # print lc_str_rep 328*c54f35caSApple OSS Distributions if isinstance(segment, SEGMENT_TYPES): 329*c54f35caSApple OSS Distributions segname = six.ensure_str(segment.segname[:segment.segname.find(b'\x00')]) 330*c54f35caSApple OSS Distributions # print "\tsegment: {:s} vmaddr: {:x} vmsize:{:d} fileoff: {:x} filesize: {:d}".format( 331*c54f35caSApple OSS Distributions # segname, segment.vmaddr, segment.vmsize, segment.fileoff, segment.filesize) 332*c54f35caSApple OSS Distributions blocks.append(MapBlock(segname, segment.vmaddr, segment.vmsize, segment.fileoff, segment.filesize, 333*c54f35caSApple OSS Distributions ' LC:{} : {} init:{:#0X} max:{:#0X}'.format(lc_cmd_str, segname, segment.initprot, segment.maxprot), 334*c54f35caSApple OSS Distributions True)) 335*c54f35caSApple OSS Distributions for section in sections: 336*c54f35caSApple OSS Distributions section_name = six.ensure_str(section.sectname[:section.sectname.find(b'\x00')]) 337*c54f35caSApple OSS Distributions blocks.append(MapBlock(section_name, section.addr, section.size, section.offset, 338*c54f35caSApple OSS Distributions section.size, 'al:{} flags:{:#0X}'.format(section.align, section.flags), False)) 339*c54f35caSApple OSS Distributions #print "\t\tsection:{:s} addr:{:x} off:{:x} size:{:d}".format(section_name, section.addr, section.offset, section.size) 340*c54f35caSApple OSS Distributions elif isinstance(segment, macholib.mach_o.uuid_command): 341*c54f35caSApple OSS Distributions other_cmds += "\n\t uuid: {:s}".format(str(uuid.UUID(bytes=segment.uuid)).upper()) 342*c54f35caSApple OSS Distributions elif isinstance(segment, macholib.mach_o.rpath_command): 343*c54f35caSApple OSS Distributions other_cmds += "\n\t rpath: {:s}".format(segment.path) 344*c54f35caSApple OSS Distributions elif isinstance(segment, macholib.mach_o.dylib_command): 345*c54f35caSApple OSS Distributions other_cmds += "\n\t dylib: {:s} ({:s})".format(str(sections[:sections.find(b'\x00')]), str(segment.current_version)) 346*c54f35caSApple OSS Distributions else: 347*c54f35caSApple OSS Distributions other_cmds += lc_str_rep 348*c54f35caSApple OSS Distributions cmd_index += 1 349*c54f35caSApple OSS Distributions 350*c54f35caSApple OSS Distributions # fixup the self.width param 351*c54f35caSApple OSS Distributions for _b in blocks: 352*c54f35caSApple OSS Distributions if self.default_side_padding + len(_b.name) + 2 > self.width: 353*c54f35caSApple OSS Distributions self.width = self.default_side_padding + len(_b.name) + 2 354*c54f35caSApple OSS Distributions if self.width % 2 != 0: 355*c54f35caSApple OSS Distributions self.width += 1 356*c54f35caSApple OSS Distributions 357*c54f35caSApple OSS Distributions sorted_blocks = sorted(blocks, key=lambda b: b.vmaddr) 358*c54f35caSApple OSS Distributions mstr = [self.get_header_line()] 359*c54f35caSApple OSS Distributions prev_block = MapBlock('', 0, 0, 0, 0, '', False) 360*c54f35caSApple OSS Distributions for b in sorted_blocks: 361*c54f35caSApple OSS Distributions # TODO add separator blocks if vmaddr is large from prev_block 362*c54f35caSApple OSS Distributions if b.is_segment: 363*c54f35caSApple OSS Distributions s = self.get_dashed_line() 364*c54f35caSApple OSS Distributions else: 365*c54f35caSApple OSS Distributions s = self.get_dotted_line() 366*c54f35caSApple OSS Distributions s = self.center_text_in_line(s, b.name) 367*c54f35caSApple OSS Distributions line = "{:s} {: <#020X} ({: <10d}) floff:{: <#08x} {}".format(s, b.vmaddr, b.vmsize, b.fileoff, b.extra_info) 368*c54f35caSApple OSS Distributions if (b.vmaddr - prev_block.vmaddr) > VisualMachoMap.KB_16: 369*c54f35caSApple OSS Distributions mstr.append(self.get_space_line()) 370*c54f35caSApple OSS Distributions mstr.append(self.get_space_line()) 371*c54f35caSApple OSS Distributions 372*c54f35caSApple OSS Distributions mstr.append(line) 373*c54f35caSApple OSS Distributions 374*c54f35caSApple OSS Distributions if b.vmsize > VisualMachoMap.MB_1: 375*c54f35caSApple OSS Distributions mstr.append(self.get_space_line()) 376*c54f35caSApple OSS Distributions mstr.extend(self.get_separator_lines()) 377*c54f35caSApple OSS Distributions mstr.append(self.get_space_line()) 378*c54f35caSApple OSS Distributions #mstr.append(self.get_space_line()) 379*c54f35caSApple OSS Distributions prev_block = b 380*c54f35caSApple OSS Distributions mstr.append(self.get_space_line()) 381*c54f35caSApple OSS Distributions if prev_block.vmsize > VisualMachoMap.KB_16: 382*c54f35caSApple OSS Distributions mstr.append(self.get_space_line()) 383*c54f35caSApple OSS Distributions mstr.append(self.get_header_line()) 384*c54f35caSApple OSS Distributions print(outstr) 385*c54f35caSApple OSS Distributions print("\n".join(mstr)) 386*c54f35caSApple OSS Distributions print("\n\n=============== Other Load Commands ===============") 387*c54f35caSApple OSS Distributions print(other_cmds) 388*c54f35caSApple OSS Distributions 389*c54f35caSApple OSS Distributions 390*c54f35caSApple OSS Distributionsif __name__ == '__main__': 391*c54f35caSApple OSS Distributions import sys 392*c54f35caSApple OSS Distributions if len(sys.argv) < 2: 393*c54f35caSApple OSS Distributions print("Usage: {} /path/to/macho_binary".format(sys.argv[0])) 394*c54f35caSApple OSS Distributions sys.exit(1) 395*c54f35caSApple OSS Distributions with open(sys.argv[-1], 'rb') as fp: 396*c54f35caSApple OSS Distributions mobject = MemMachO(fp) 397*c54f35caSApple OSS Distributions 398*c54f35caSApple OSS Distributions p = VisualMachoMap(sys.argv[-1]) 399*c54f35caSApple OSS Distributions p.printMachoMap(mobject) 400*c54f35caSApple OSS Distributions sys.exit(0) 401