| Index: class-dump/src/CDMachOFile.m
|
| ===================================================================
|
| --- class-dump/src/CDMachOFile.m (revision 0)
|
| +++ class-dump/src/CDMachOFile.m (revision 0)
|
| @@ -0,0 +1,682 @@
|
| +// -*- mode: ObjC -*-
|
| +
|
| +// This file is part of class-dump, a utility for examining the Objective-C segment of Mach-O files.
|
| +// Copyright (C) 1997-1998, 2000-2001, 2004-2010 Steve Nygard.
|
| +
|
| +#import "CDMachOFile.h"
|
| +
|
| +#include <mach-o/arch.h>
|
| +#include <mach-o/loader.h>
|
| +#include <mach-o/fat.h>
|
| +
|
| +#import "CDDataCursor.h"
|
| +#import "CDFatFile.h"
|
| +#import "CDLoadCommand.h"
|
| +#import "CDLCDyldInfo.h"
|
| +#import "CDLCDylib.h"
|
| +#import "CDLCDynamicSymbolTable.h"
|
| +#import "CDLCEncryptionInfo.h"
|
| +#import "CDLCRunPath.h"
|
| +#import "CDLCSegment.h"
|
| +#import "CDLCSegment64.h"
|
| +#import "CDLCSymbolTable.h"
|
| +#import "CDLCUUID.h"
|
| +#import "CDObjectiveCProcessor.h"
|
| +#import "CDSection.h"
|
| +#import "CDSymbol.h"
|
| +#import "CDRelocationInfo.h"
|
| +#import "CDSearchPathState.h"
|
| +
|
| +NSString *CDMagicNumberString(uint32_t magic)
|
| +{
|
| + switch (magic) {
|
| + case MH_MAGIC: return @"MH_MAGIC";
|
| + case MH_CIGAM: return @"MH_CIGAM";
|
| + case MH_MAGIC_64: return @"MH_MAGIC_64";
|
| + case MH_CIGAM_64: return @"MH_CIGAM_64";
|
| + }
|
| +
|
| + return [NSString stringWithFormat:@"0x%08x", magic];
|
| +}
|
| +
|
| +static BOOL debug = NO;
|
| +
|
| +@implementation CDMachOFile
|
| +
|
| +- (id)initWithData:(NSData *)someData offset:(NSUInteger)anOffset filename:(NSString *)aFilename searchPathState:(CDSearchPathState *)aSearchPathState;
|
| +{
|
| + if ([super initWithData:someData offset:anOffset filename:aFilename searchPathState:aSearchPathState] == nil)
|
| + return nil;
|
| +
|
| + byteOrder = CDByteOrderLittleEndian;
|
| + loadCommands = [[NSMutableArray alloc] init];
|
| + segments = [[NSMutableArray alloc] init];
|
| + symbolTable = nil;
|
| + dynamicSymbolTable = nil;
|
| + dyldInfo = nil;
|
| + runPaths = [[NSMutableArray alloc] init];
|
| + _flags.uses64BitABI = NO;
|
| +
|
| + return self;
|
| +}
|
| +
|
| +- (void)_readLoadCommands:(CDDataCursor *)cursor count:(uint32_t)count;
|
| +{
|
| + uint32_t index;
|
| +
|
| + for (index = 0; index < count; index++) {
|
| + id loadCommand;
|
| +
|
| + loadCommand = [CDLoadCommand loadCommandWithDataCursor:cursor machOFile:self];
|
| + if (loadCommand != nil) {
|
| + [loadCommands addObject:loadCommand];
|
| +
|
| + if ([loadCommand isKindOfClass:[CDLCSegment class]])
|
| + [segments addObject:loadCommand];
|
| +
|
| + if ([loadCommand isKindOfClass:[CDLCSymbolTable class]])
|
| + [self setSymbolTable:(CDLCSymbolTable *)loadCommand];
|
| + else if ([loadCommand isKindOfClass:[CDLCDynamicSymbolTable class]])
|
| + [self setDynamicSymbolTable:(CDLCDynamicSymbolTable *)loadCommand];
|
| + else if ([loadCommand isKindOfClass:[CDLCDyldInfo class]])
|
| + [self setDyldInfo:(CDLCDyldInfo *)loadCommand];
|
| + else if ([loadCommand isKindOfClass:[CDLCRunPath class]])
|
| + [runPaths addObject:[(CDLCRunPath *)loadCommand resolvedRunPath]];
|
| + }
|
| + //NSLog(@"loadCommand: %@", loadCommand);
|
| + }
|
| +}
|
| +
|
| +- (void)dealloc;
|
| +{
|
| + [loadCommands release]; // These all reference data, so release them first... Should they just retain data themselves?
|
| + [segments release];
|
| + [symbolTable release];
|
| + [dynamicSymbolTable release];
|
| + [dyldInfo release];
|
| + [runPaths release];
|
| +
|
| + [super dealloc];
|
| +}
|
| +
|
| +- (CDByteOrder)byteOrder;
|
| +{
|
| + return byteOrder;
|
| +}
|
| +
|
| +- (CDMachOFile *)machOFileWithArch:(CDArch)arch;
|
| +{
|
| + if ([self cputype] == arch.cputype)
|
| + return self;
|
| +
|
| + return nil;
|
| +}
|
| +
|
| +- (uint32_t)magic;
|
| +{
|
| + // Implement in subclasses.
|
| + return 0;
|
| +}
|
| +
|
| +- (cpu_type_t)cputype;
|
| +{
|
| + // Implement in subclasses.
|
| + return 0;
|
| +}
|
| +
|
| +- (cpu_subtype_t)cpusubtype;
|
| +{
|
| + // Implement in subclasses.
|
| + return 0;
|
| +}
|
| +
|
| +// Well... only the arch bits it knows about.
|
| +- (cpu_type_t)cputypePlusArchBits;
|
| +{
|
| + if ([self uses64BitABI])
|
| + return [self cputype] | CPU_ARCH_ABI64;
|
| +
|
| + return [self cputype];
|
| +}
|
| +
|
| +#if 0
|
| +- (const NXArchInfo *)archInfo;
|
| +{
|
| + const NXArchInfo *archInfo;
|
| +
|
| + if ([self uses64BitABI]) {
|
| + archInfo = NXGetArchInfoFromCpuType([self cputype] | CPU_ARCH_ABI64, [self cpusubtype]);
|
| + } else {
|
| + archInfo = NXGetArchInfoFromCpuType([self cputype], [self cpusubtype]);
|
| + }
|
| +
|
| + return archInfo;
|
| +}
|
| +#endif
|
| +
|
| +- (uint32_t)filetype;
|
| +{
|
| + // Implement in subclasses.
|
| + return 0;
|
| +}
|
| +
|
| +- (uint32_t)flags;
|
| +{
|
| + // Implement in subclasses.
|
| + return 0;
|
| +}
|
| +
|
| +- (NSArray *)loadCommands;
|
| +{
|
| + return loadCommands;
|
| +}
|
| +
|
| +- (NSArray *)dylibLoadCommands;
|
| +{
|
| + NSMutableArray *dylibLoadCommands = [NSMutableArray array];
|
| + for (id loadCommand in loadCommands) {
|
| + if ([loadCommand isKindOfClass:[CDLCDylib class]])
|
| + [dylibLoadCommands addObject:loadCommand];
|
| + }
|
| + return dylibLoadCommands;
|
| +}
|
| +
|
| +- (NSArray *)segments;
|
| +{
|
| + return segments;
|
| +}
|
| +
|
| +@synthesize symbolTable;
|
| +@synthesize dynamicSymbolTable;
|
| +@synthesize dyldInfo;
|
| +
|
| +- (BOOL)uses64BitABI;
|
| +{
|
| + return _flags.uses64BitABI;
|
| +}
|
| +
|
| +- (NSString *)filetypeDescription;
|
| +{
|
| + switch ([self filetype]) {
|
| + case MH_OBJECT: return @"OBJECT";
|
| + case MH_EXECUTE: return @"EXECUTE";
|
| + case MH_FVMLIB: return @"FVMLIB";
|
| + case MH_CORE: return @"CORE";
|
| + case MH_PRELOAD: return @"PRELOAD";
|
| + case MH_DYLIB: return @"DYLIB";
|
| + case MH_DYLINKER: return @"DYLINKER";
|
| + case MH_BUNDLE: return @"BUNDLE";
|
| + case MH_DYLIB_STUB: return @"DYLIB_STUB";
|
| + case MH_DSYM: return @"DSYM";
|
| + default:
|
| + break;
|
| + }
|
| +
|
| + return nil;
|
| +}
|
| +
|
| +- (NSString *)flagDescription;
|
| +{
|
| + NSMutableArray *setFlags;
|
| + uint32_t flags;
|
| +
|
| + setFlags = [NSMutableArray array];
|
| + flags = [self flags];
|
| + if (flags & MH_NOUNDEFS)
|
| + [setFlags addObject:@"NOUNDEFS"];
|
| + if (flags & MH_INCRLINK)
|
| + [setFlags addObject:@"INCRLINK"];
|
| + if (flags & MH_DYLDLINK)
|
| + [setFlags addObject:@"DYLDLINK"];
|
| + if (flags & MH_BINDATLOAD)
|
| + [setFlags addObject:@"BINDATLOAD"];
|
| + if (flags & MH_PREBOUND)
|
| + [setFlags addObject:@"PREBOUND"];
|
| + if (flags & MH_SPLIT_SEGS)
|
| + [setFlags addObject:@"SPLIT_SEGS"];
|
| + if (flags & MH_LAZY_INIT)
|
| + [setFlags addObject:@"LAZY_INIT"];
|
| + if (flags & MH_TWOLEVEL)
|
| + [setFlags addObject:@"TWOLEVEL"];
|
| + if (flags & MH_FORCE_FLAT)
|
| + [setFlags addObject:@"FORCE_FLAT"];
|
| + if (flags & MH_NOMULTIDEFS)
|
| + [setFlags addObject:@"NOMULTIDEFS"];
|
| + if (flags & MH_NOFIXPREBINDING)
|
| + [setFlags addObject:@"NOFIXPREBINDING"];
|
| + if (flags & MH_PREBINDABLE)
|
| + [setFlags addObject:@"PREBINDABLE"];
|
| + if (flags & MH_ALLMODSBOUND)
|
| + [setFlags addObject:@"ALLMODSBOUND"];
|
| + if (flags & MH_SUBSECTIONS_VIA_SYMBOLS)
|
| + [setFlags addObject:@"SUBSECTIONS_VIA_SYMBOLS"];
|
| + if (flags & MH_CANONICAL)
|
| + [setFlags addObject:@"CANONICAL"];
|
| + if (flags & MH_WEAK_DEFINES)
|
| + [setFlags addObject:@"WEAK_DEFINES"];
|
| + if (flags & MH_BINDS_TO_WEAK)
|
| + [setFlags addObject:@"BINDS_TO_WEAK"];
|
| + if (flags & MH_ALLOW_STACK_EXECUTION)
|
| + [setFlags addObject:@"ALLOW_STACK_EXECUTION"];
|
| +#if 1
|
| + // 10.5 only, but I'm still using the 10.4 sdk.
|
| + if (flags & MH_ROOT_SAFE)
|
| + [setFlags addObject:@"ROOT_SAFE"];
|
| + if (flags & MH_SETUID_SAFE)
|
| + [setFlags addObject:@"SETUID_SAFE"];
|
| + if (flags & MH_NO_REEXPORTED_DYLIBS)
|
| + [setFlags addObject:@"NO_REEXPORTED_DYLIBS"];
|
| + if (flags & MH_PIE)
|
| + [setFlags addObject:@"PIE"];
|
| +#endif
|
| +
|
| + return [setFlags componentsJoinedByString:@" "];
|
| +}
|
| +
|
| +- (CDLCDylib *)dylibIdentifier;
|
| +{
|
| + for (CDLoadCommand *loadCommand in loadCommands) {
|
| + if ([loadCommand cmd] == LC_ID_DYLIB)
|
| + return (CDLCDylib *)loadCommand;
|
| + }
|
| +
|
| + return nil;
|
| +}
|
| +
|
| +- (CDLCSegment *)segmentWithName:(NSString *)segmentName;
|
| +{
|
| + for (id loadCommand in loadCommands) {
|
| + if ([loadCommand isKindOfClass:[CDLCSegment class]] && [[loadCommand name] isEqual:segmentName]) {
|
| + return loadCommand;
|
| + }
|
| + }
|
| +
|
| + return nil;
|
| +}
|
| +
|
| +- (CDLCSegment *)segmentContainingAddress:(NSUInteger)address;
|
| +{
|
| + for (id loadCommand in loadCommands) {
|
| + if ([loadCommand isKindOfClass:[CDLCSegment class]] && [loadCommand containsAddress:address]) {
|
| + return loadCommand;
|
| + }
|
| + }
|
| +
|
| + return nil;
|
| +}
|
| +
|
| +- (void)showWarning:(NSString *)aWarning;
|
| +{
|
| + NSLog(@"Warning: %@", aWarning);
|
| +}
|
| +
|
| +- (NSString *)stringAtAddress:(NSUInteger)address;
|
| +{
|
| + CDLCSegment *segment;
|
| +
|
| + NSUInteger anOffset;
|
| + const void *ptr;
|
| +
|
| + if (address == 0)
|
| + return nil;
|
| +
|
| + segment = [self segmentContainingAddress:address];
|
| + if (segment == nil) {
|
| + NSLog(@"Error: Cannot find offset for address 0x%08x in dataOffsetForAddress:", address);
|
| + exit(5);
|
| + return nil;
|
| + }
|
| +
|
| + if ([segment isProtected]) {
|
| + NSData *d2;
|
| + NSUInteger d2Offset;
|
| +
|
| + d2 = [segment decryptedData];
|
| + d2Offset = [segment segmentOffsetForAddress:address];
|
| + if (d2Offset == 0)
|
| + return nil;
|
| +
|
| + ptr = [d2 bytes] + d2Offset;
|
| + return [[[NSString alloc] initWithBytes:ptr length:strlen(ptr) encoding:NSASCIIStringEncoding] autorelease];
|
| + }
|
| +
|
| + anOffset = [self dataOffsetForAddress:address];
|
| + if (anOffset == 0)
|
| + return nil;
|
| +
|
| + ptr = [data bytes] + anOffset;
|
| +
|
| + return [[[NSString alloc] initWithBytes:ptr length:strlen(ptr) encoding:NSASCIIStringEncoding] autorelease];
|
| +}
|
| +
|
| +- (const void *)machODataBytes;
|
| +{
|
| + return [data bytes] + offset;
|
| +}
|
| +
|
| +- (NSUInteger)dataOffsetForAddress:(NSUInteger)address;
|
| +{
|
| + return [self dataOffsetForAddress:address segmentName:nil];
|
| +}
|
| +
|
| +- (NSUInteger)dataOffsetForAddress:(NSUInteger)address segmentName:(NSString *)aSegmentName;
|
| +{
|
| + CDLCSegment *segment;
|
| +
|
| + if (address == 0)
|
| + return 0;
|
| +
|
| + segment = [self segmentContainingAddress:address];
|
| + if (segment == nil) {
|
| + NSLog(@"Error: Cannot find offset for address 0x%08lx in dataOffsetForAddress:", address);
|
| + exit(5);
|
| + return 0;
|
| + }
|
| +
|
| + if (aSegmentName != nil && [[segment name] isEqual:aSegmentName] == NO) {
|
| + // This can happen with the symtab in a module. In one case, the symtab is in __DATA, __bss, in the zero filled area.
|
| + // i.e. section offset is 0.
|
| + if (debug) NSLog(@"Note: Couldn't find address in specified segment (%08lx, %@)", address, aSegmentName);
|
| + //NSLog(@"\tsegment was: %@", segment);
|
| + //exit(5);
|
| + return 0;
|
| + }
|
| +
|
| + if ([segment isProtected]) {
|
| + NSLog(@"Error: Segment is protected.");
|
| + exit(5);
|
| + }
|
| +
|
| +#if 0
|
| + NSLog(@"---------->");
|
| + NSLog(@"segment is: %@", segment);
|
| + NSLog(@"address: 0x%08x", address);
|
| + NSLog(@"CDFile offset: 0x%08x", offset);
|
| + NSLog(@"file off for address: 0x%08x", [segment fileOffsetForAddress:address]);
|
| + NSLog(@"data offset: 0x%08x", offset + [segment fileOffsetForAddress:address]);
|
| + NSLog(@"<----------");
|
| +#endif
|
| + return offset + [segment fileOffsetForAddress:address];
|
| +}
|
| +
|
| +- (const void *)bytes;
|
| +{
|
| + return [data bytes];
|
| +}
|
| +
|
| +- (const void *)bytesAtOffset:(NSUInteger)anOffset;
|
| +{
|
| + return [data bytes] + anOffset;
|
| +}
|
| +
|
| +- (NSString *)importBaseName;
|
| +{
|
| + if ([self filetype] == MH_DYLIB) {
|
| + NSString *str;
|
| +
|
| + str = [filename lastPathComponent];
|
| + if ([str hasPrefix:@"lib"])
|
| + str = [[[str substringFromIndex:3] componentsSeparatedByString:@"."] objectAtIndex:0];
|
| +
|
| + return str;
|
| + }
|
| +
|
| + return nil;
|
| +}
|
| +
|
| +- (BOOL)isEncrypted;
|
| +{
|
| + for (CDLoadCommand *loadCommand in loadCommands) {
|
| + if ([loadCommand isKindOfClass:[CDLCEncryptionInfo class]] && [(CDLCEncryptionInfo *)loadCommand isEncrypted]) {
|
| + return YES;
|
| + }
|
| + }
|
| +
|
| + return NO;
|
| +}
|
| +
|
| +- (BOOL)hasProtectedSegments;
|
| +{
|
| + for (CDLoadCommand *loadCommand in loadCommands) {
|
| + if ([loadCommand isKindOfClass:[CDLCSegment class]] && [(CDLCSegment *)loadCommand isProtected])
|
| + return YES;
|
| + }
|
| +
|
| + return NO;
|
| +}
|
| +
|
| +- (BOOL)canDecryptAllSegments;
|
| +{
|
| + for (CDLoadCommand *loadCommand in loadCommands) {
|
| + if ([loadCommand isKindOfClass:[CDLCSegment class]] && [(CDLCSegment *)loadCommand canDecrypt] == NO)
|
| + return NO;
|
| + }
|
| +
|
| + return YES;
|
| +}
|
| +
|
| +- (NSString *)loadCommandString:(BOOL)isVerbose;
|
| +{
|
| + NSMutableString *resultString;
|
| + unsigned int count, index;
|
| +
|
| + resultString = [NSMutableString string];
|
| + count = [loadCommands count];
|
| + for (index = 0; index < count; index++) {
|
| + CDLoadCommand *loadCommand;
|
| +
|
| + [resultString appendFormat:@"Load command %u\n", index];
|
| + loadCommand = [loadCommands objectAtIndex:index];
|
| + [loadCommand appendToString:resultString verbose:isVerbose];
|
| + [resultString appendString:@"\n"];
|
| + }
|
| +
|
| + return resultString;
|
| +}
|
| +
|
| +- (NSString *)headerString:(BOOL)isVerbose;
|
| +{
|
| + NSMutableString *resultString;
|
| +
|
| + resultString = [NSMutableString string];
|
| + [resultString appendString:@"Mach header\n"];
|
| + [resultString appendString:@" magic cputype cpusubtype filetype ncmds sizeofcmds flags\n"];
|
| + // Grr, %11@ doesn't work.
|
| + if (isVerbose)
|
| + [resultString appendFormat:@"%11@ %7@ %10u %8@ %5u %10u %@\n",
|
| + CDMagicNumberString([self magic]), [self archName], [self cpusubtype],
|
| + [self filetypeDescription], [loadCommands count], 0, [self flagDescription]];
|
| + else
|
| + [resultString appendFormat:@" 0x%08x %7u %10u %8u %5u %10u 0x%08x\n",
|
| + [self magic], [self cputype], [self cpusubtype], [self filetype], [loadCommands count], 0, [self flags]];
|
| + [resultString appendString:@"\n"];
|
| +
|
| + return resultString;
|
| +}
|
| +
|
| +- (NSString *)uuidString;
|
| +{
|
| + for (CDLoadCommand *loadCommand in loadCommands)
|
| + if ([loadCommand isKindOfClass:[CDLCUUID class]])
|
| + return [(CDLCUUID*)loadCommand uuidString];
|
| +
|
| + return @"N/A";
|
| +}
|
| +
|
| +// Must not return nil.
|
| +- (NSString *)archName;
|
| +{
|
| + return CDNameForCPUType([self cputype], [self cpusubtype]);
|
| +}
|
| +
|
| +- (NSString *)description;
|
| +{
|
| + return [NSString stringWithFormat:@"<%@:%p> magic: 0x%08x, cputype: %x, cpusubtype: %x, filetype: %d, ncmds: %d, sizeofcmds: %d, flags: 0x%x, uses64BitABI? %d, filename: %@, data: %p, offset: %p",
|
| + NSStringFromClass([self class]), self,
|
| + [self magic], [self cputype], [self cpusubtype], [self filetype], [loadCommands count], 0, [self flags], _flags.uses64BitABI,
|
| + filename, data, offset];
|
| +}
|
| +
|
| +- (Class)processorClass;
|
| +{
|
| + // Implement in subclasses
|
| + return [CDObjectiveCProcessor class];
|
| +}
|
| +
|
| +- (void)logInfoForAddress:(NSUInteger)address;
|
| +{
|
| + if (address != 0) {
|
| + CDLCSegment *segment;
|
| + NSString *str;
|
| +
|
| + segment = [self segmentContainingAddress:address];
|
| + if (segment == nil) {
|
| + NSLog(@"No segment contains address: %016lx", address);
|
| + } else {
|
| + CDSection *section;
|
| +
|
| + //NSLog(@"Found address %016lx in segment, sections= %@", address, [segment sections]);
|
| + section = [segment sectionContainingAddress:address];
|
| + if (section == nil) {
|
| + NSLog(@"Found address %016lx in segment %@, but not in a section", address, [segment name]);
|
| + } else {
|
| + NSLog(@"Found address %016lx in segment %@, section %@", address, [segment name], [section sectionName]);
|
| + }
|
| + }
|
| +
|
| + str = [self stringAtAddress:address];
|
| + NSLog(@" address %016lx as a string: '%@' (length %lu)", address, str, [str length]);
|
| + NSLog(@" address %016lx data offset: %lu", address, [self dataOffsetForAddress:address]);
|
| + }
|
| +}
|
| +
|
| +- (NSString *)externalClassNameForAddress:(NSUInteger)address;
|
| +{
|
| + CDRelocationInfo *rinfo;
|
| +
|
| + // Not for NSCFArray (NSMutableArray), NSSimpleAttributeDictionaryEnumerator (NSEnumerator), NSSimpleAttributeDictionary (NSDictionary), etc.
|
| + // It turns out NSMutableArray is in /System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation, so...
|
| + // ... it's an undefined symbol, need to look it up.
|
| + rinfo = [dynamicSymbolTable relocationEntryWithOffset:address - [symbolTable baseAddress]];
|
| + //NSLog(@"rinfo: %@", rinfo);
|
| + if (rinfo != nil) {
|
| + CDSymbol *symbol;
|
| + NSString *str;
|
| +
|
| + symbol = [[symbolTable symbols] objectAtIndex:rinfo.symbolnum];
|
| + //NSLog(@"symbol: %@", symbol);
|
| +
|
| + // Now we could use GET_LIBRARY_ORDINAL(), look up the the appropriate mach-o file (being sure to have loaded them even without -r),
|
| + // look up the symbol in that mach-o file, get the address, look up the class based on that address, and finally get the class name
|
| + // from that.
|
| +
|
| + // Or, we could be lazy and take advantage of the fact that the class name we're after is in the symbol name:
|
| + str = [symbol name];
|
| + if ([str hasPrefix:ObjCClassSymbolPrefix]) {
|
| + return [str substringFromIndex:[ObjCClassSymbolPrefix length]];
|
| + } else {
|
| + NSLog(@"Warning: Unknown prefix on symbol name... %@ (addr %lx)", str, address);
|
| + return str;
|
| + }
|
| + }
|
| +
|
| + // This is fine, they might really be root objects. NSObject, NSProxy.
|
| + return nil;
|
| +}
|
| +
|
| +- (BOOL)hasRelocationEntryForAddress:(NSUInteger)address;
|
| +{
|
| + CDRelocationInfo *rinfo;
|
| +
|
| + rinfo = [dynamicSymbolTable relocationEntryWithOffset:address - [symbolTable baseAddress]];
|
| + //NSLog(@"%s, rinfo= %@", _cmd, rinfo);
|
| + return rinfo != nil;
|
| +}
|
| +
|
| +- (BOOL)hasRelocationEntryForAddress2:(NSUInteger)address;
|
| +{
|
| + return [dyldInfo symbolNameForAddress:address] != nil;
|
| +}
|
| +
|
| +- (NSString *)externalClassNameForAddress2:(NSUInteger)address;
|
| +{
|
| + NSString *str = [dyldInfo symbolNameForAddress:address];
|
| +
|
| + if (str != nil) {
|
| + if ([str hasPrefix:ObjCClassSymbolPrefix]) {
|
| + return [str substringFromIndex:[ObjCClassSymbolPrefix length]];
|
| + } else {
|
| + NSLog(@"Warning: Unknown prefix on symbol name... %@ (addr %lx)", str, address);
|
| + return str;
|
| + }
|
| + }
|
| +
|
| + return nil;
|
| +}
|
| +
|
| +- (BOOL)hasObjectiveC1Data;
|
| +{
|
| + return [self segmentWithName:@"__OBJC"] != nil;
|
| +}
|
| +
|
| +- (BOOL)hasObjectiveC2Data;
|
| +{
|
| + // http://twitter.com/gparker/status/17962955683
|
| + return [[self segmentWithName:@"__DATA"] sectionWithName:@"__objc_imageinfo"] != nil;
|
| +}
|
| +
|
| +- (void)saveDeprotectedFileToPath:(NSString *)path;
|
| +{
|
| + NSMutableData *mdata;
|
| +
|
| + // Not going to handle fat files -- thin it first
|
| + NSParameterAssert(offset == 0);
|
| +
|
| + mdata = [[NSMutableData alloc] initWithData:data];
|
| + for (CDLoadCommand *command in loadCommands) {
|
| + if ([command isKindOfClass:[CDLCSegment class]]) {
|
| + CDLCSegment *segment = (CDLCSegment *)command;
|
| +
|
| + if ([segment isProtected]) {
|
| + NSData *decryptedData;
|
| + NSRange range;
|
| + uint32_t flags;
|
| + NSUInteger flagOffset;
|
| +
|
| + NSLog(@"segment is protected: %@", segment);
|
| + range.location = [segment fileoff];
|
| + range.length = [segment filesize];
|
| +
|
| + decryptedData = [segment decryptedData];
|
| + NSParameterAssert([decryptedData length] == range.length);
|
| +
|
| + [mdata replaceBytesInRange:range withBytes:[decryptedData bytes]];
|
| + if ([segment isKindOfClass:[CDLCSegment64 class]]) {
|
| + flagOffset = [segment commandOffset] + offsetof(struct segment_command_64, flags);
|
| + } else {
|
| + flagOffset = [segment commandOffset] + offsetof(struct segment_command, flags);
|
| + }
|
| +
|
| + // TODO (2009-07-10): Needs to be endian-neutral
|
| + flags = OSReadLittleInt32([mdata mutableBytes], flagOffset);
|
| + NSLog(@"old flags: %08x", flags);
|
| + NSLog(@"segment flags: %08x", [segment flags]);
|
| + flags &= ~SG_PROTECTED_VERSION_1;
|
| + NSLog(@"new flags: %08x", flags);
|
| +
|
| + OSWriteLittleInt32([mdata mutableBytes], flagOffset, flags);
|
| + }
|
| + }
|
| + }
|
| +
|
| + [mdata writeToFile:path atomically:NO];
|
| +
|
| + [mdata release];
|
| +}
|
| +
|
| +- (NSArray *)runPaths;
|
| +{
|
| + return runPaths;
|
| +}
|
| +
|
| +@end
|
|
|
| Property changes on: class-dump/src/CDMachOFile.m
|
| ___________________________________________________________________
|
| Added: svn:eol-style
|
| + LF
|
|
|
|
|