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