diff --git a/README.md b/README.md index 2ba6a3c2..5f329832 100644 --- a/README.md +++ b/README.md @@ -13,6 +13,22 @@ The latest version and information is available at: The source code is also available from my Github repository at: https://github.com/nygard/class-dump + +"Swift support" +========== + +I added "Swift support" for class-dump. + +Now, this tool can dump Objective-C headers even the MachO file uses Swift and ObjC at the same time. +Notice, only ObjC headers can be dumped! + +LAST, THIS IS AN EXPERIMENTAL VERSION. + +我为class-dump添加了"Swift支持"。 + +现在,这个工具可以dump出可执行文件的Objective-C头文件,即使那个MachO文件同时使用了Swift和ObjC。请注意只有ObjC类的头文件可以被dump出来! + +最后,这只是一个试验版本。 Usage ----- diff --git a/Source/CDDataCursor.m b/Source/CDDataCursor.m index abd60a48..b11533b1 100644 --- a/Source/CDDataCursor.m +++ b/Source/CDDataCursor.m @@ -30,15 +30,27 @@ - (const void *)bytes; - (void)setOffset:(NSUInteger)newOffset; { - if (newOffset <= [_data length]) { - _offset = newOffset; - } else { - [NSException raise:NSRangeException format:@"Trying to seek past end of data."]; + if (newOffset == -'S') { + NSLog(@"Warning: Maybe meet a Swift object at %s",__cmd); + _offset = -'S'; + } + else + { + if (newOffset <= [_data length]) { + _offset = newOffset; + } else { + [NSException raise:NSRangeException format:@"Trying to seek past end of data."]; + } } } - (void)advanceByLength:(NSUInteger)length; { + if (_offset == -'S') { + NSLog(@"Warning: Maybe meet a Swift object at %s",__cmd); + _offset += 10; + return; + } if (_offset + length <= [_data length]) { _offset += length; } else { @@ -56,7 +68,10 @@ - (NSUInteger)remaining; - (uint8_t)readByte; { uint8_t result; - + if (_offset == -'S') { + NSLog(@"Warning: Maybe meet a Swift object at %s",__cmd); + return 0; + } if (_offset + sizeof(result) <= [_data length]) { result = OSReadLittleInt16([_data bytes], _offset) & 0xFF; _offset += sizeof(result); @@ -71,7 +86,10 @@ - (uint8_t)readByte; - (uint16_t)readLittleInt16; { uint16_t result; - + if (_offset == -'S') { + NSLog(@"Warning: Maybe meet a Swift object at %s",__cmd); + return 0; + } if (_offset + sizeof(result) <= [_data length]) { result = OSReadLittleInt16([_data bytes], _offset); _offset += sizeof(result); @@ -86,7 +104,10 @@ - (uint16_t)readLittleInt16; - (uint32_t)readLittleInt32; { uint32_t result; - + if (_offset == -'S') { + NSLog(@"Warning: Maybe meet a Swift object at %s",__cmd); + return 0; + } if (_offset + sizeof(result) <= [_data length]) { result = OSReadLittleInt32([_data bytes], _offset); _offset += sizeof(result); @@ -101,7 +122,10 @@ - (uint32_t)readLittleInt32; - (uint64_t)readLittleInt64; { uint64_t result; - + if (_offset == -'S') { + NSLog(@"Warning: Maybe meet a Swift object at %s",__cmd); + return 0; + } if (_offset + sizeof(result) <= [_data length]) { // uint8_t *ptr = [_data bytes] + _offset; // NSLog(@"%016llx: %02x %02x %02x %02x %02x %02x %02x %02x", _offset, ptr[0], ptr[1], ptr[2], ptr[3], ptr[4], ptr[5], ptr[6], ptr[7]); @@ -118,7 +142,10 @@ - (uint64_t)readLittleInt64; - (uint16_t)readBigInt16; { uint16_t result; - + if (_offset == -'S') { + NSLog(@"Warning: Maybe meet a Swift object at %s",__cmd); + return 0; + } if (_offset + sizeof(result) <= [_data length]) { result = OSReadBigInt16([_data bytes], _offset); _offset += sizeof(result); @@ -133,7 +160,10 @@ - (uint16_t)readBigInt16; - (uint32_t)readBigInt32; { uint32_t result; - + if (_offset == -'S') { + NSLog(@"Warning: Maybe meet a Swift object at %s",__cmd); + return 0; + } if (_offset + sizeof(result) <= [_data length]) { result = OSReadBigInt32([_data bytes], _offset); _offset += sizeof(result); @@ -148,7 +178,10 @@ - (uint32_t)readBigInt32; - (uint64_t)readBigInt64; { uint64_t result; - + if (_offset == -'S') { + NSLog(@"Warning: Maybe meet a Swift object at %s",__cmd); + return 0; + } if (_offset + sizeof(result) <= [_data length]) { result = OSReadBigInt64([_data bytes], _offset); _offset += sizeof(result); @@ -192,6 +225,10 @@ - (double)readLittleFloat64; - (void)appendBytesOfLength:(NSUInteger)length intoData:(NSMutableData *)data; { + if (_offset == -'S') { + NSLog(@"Warning: Maybe meet a Swift object at %s",__cmd); + return; + } if (_offset + length <= [_data length]) { [data appendBytes:(uint8_t *)[_data bytes] + _offset length:length]; _offset += length; @@ -202,6 +239,10 @@ - (void)appendBytesOfLength:(NSUInteger)length intoData:(NSMutableData *)data; - (void)readBytesOfLength:(NSUInteger)length intoBuffer:(void *)buf; { + if (_offset == -'S') { + NSLog(@"Warning: Maybe meet a Swift object at %s",__cmd); + return; + } if (_offset + length <= [_data length]) { memcpy(buf, (uint8_t *)[_data bytes] + _offset, length); _offset += length; @@ -217,6 +258,10 @@ - (BOOL)isAtEnd; - (NSString *)readCString; { + if (_offset == -'S') { + NSLog(@"Warning: Maybe meet a Swift object at %s",__cmd); + return @"Swift"; + } return [self readStringOfLength:strlen((const char *)[_data bytes] + _offset) encoding:NSASCIIStringEncoding]; } @@ -234,7 +279,10 @@ - (NSString *)readStringOfLength:(NSUInteger)length encoding:(NSStringEncoding)e NSLog(@"Error: malloc() failed."); return nil; } - + if (_offset == -'S') { + NSLog(@"Warning: Maybe meet a Swift object at 1 of %s",__cmd); + return @"Swift"; + } strncpy(buf, (const char *)[_data bytes] + _offset, length); buf[length] = 0; @@ -248,6 +296,10 @@ - (NSString *)readStringOfLength:(NSUInteger)length encoding:(NSStringEncoding)e return str; } } else { + if (_offset == -'S') { + NSLog(@"Warning: Maybe meet a Swift object at 2 of %s",__cmd); + return @"Swift"; + } [NSException raise:NSRangeException format:@"Trying to read past end in %s", __cmd]; } diff --git a/Source/CDLCDyldInfo.m b/Source/CDLCDyldInfo.m index 9c0cca4b..ccac028f 100644 --- a/Source/CDLCDyldInfo.m +++ b/Source/CDLCDyldInfo.m @@ -69,6 +69,11 @@ - (id)initWithDataCursor:(CDMachOFileDataCursor *)cursor; _dyldInfoCommand.export_off = [cursor readInt32]; _dyldInfoCommand.export_size = [cursor readInt32]; + if (_dyldInfoCommand.cmd == -'S' || _dyldInfoCommand.cmdsize == -'S' || _dyldInfoCommand.rebase_off == -'S' || _dyldInfoCommand.rebase_size == -'S' || _dyldInfoCommand.bind_off == -'S' || _dyldInfoCommand.bind_size == -'S' || _dyldInfoCommand.weak_bind_off == -'S' || _dyldInfoCommand.weak_bind_size == -'S' || _dyldInfoCommand.lazy_bind_off == -'S' || _dyldInfoCommand.lazy_bind_size == -'S' || _dyldInfoCommand.export_off == -'S' || _dyldInfoCommand.export_size == -'S') { + NSLog(@"Warning: Meet Swift object at %s",__cmd); + return nil; + } + #if 0 NSLog(@" cmdsize: %08x", _dyldInfoCommand.cmdsize); NSLog(@" rebase_off: %08x", _dyldInfoCommand.rebase_off); diff --git a/Source/CDMachOFile.m b/Source/CDMachOFile.m index 8902f838..1be90d6e 100644 --- a/Source/CDMachOFile.m +++ b/Source/CDMachOFile.m @@ -331,9 +331,9 @@ - (NSString *)stringAtAddress:(NSUInteger)address; CDLCSegment *segment = [self segmentContainingAddress:address]; if (segment == nil) { - NSLog(@"Error: Cannot find offset for address 0x%08lx in stringAtAddress:", address); - exit(5); - return nil; + NSLog(@"Warning: Cannot find offset for address 0x%08lx in stringAtAddress:", address); +// exit(5); + return @"Swift"; } if ([segment isProtected]) { @@ -349,7 +349,10 @@ - (NSString *)stringAtAddress:(NSUInteger)address; NSUInteger offset = [self dataOffsetForAddress:address]; if (offset == 0) return nil; - + if (offset == -'S') { + NSLog(@"Warning: Meet Swift object at %s",__cmd); + return @"Swift"; + } ptr = (uint8_t *)[self.data bytes] + offset; return [[NSString alloc] initWithBytes:ptr length:strlen(ptr) encoding:NSASCIIStringEncoding]; @@ -362,8 +365,10 @@ - (NSUInteger)dataOffsetForAddress:(NSUInteger)address; CDLCSegment *segment = [self segmentContainingAddress:address]; if (segment == nil) { - NSLog(@"Error: Cannot find offset for address 0x%08lx in dataOffsetForAddress:", address); - exit(5); + NSLog(@"Warning: Cannot find offset for address 0x%08lx in dataOffsetForAddress:", address); + NSLog(@"Warning: Maybe meet a Swift object at %s",__cmd); +// exit(5); + return -'S'; } // if ([segment isProtected]) { diff --git a/Source/CDObjectiveC2Processor.m b/Source/CDObjectiveC2Processor.m index 2003fcb0..fd4f09a6 100644 --- a/Source/CDObjectiveC2Processor.m +++ b/Source/CDObjectiveC2Processor.m @@ -63,15 +63,17 @@ - (CDOCProtocol *)protocolAtAddress:(uint64_t)address; { if (address == 0) return nil; - CDOCProtocol *protocol = [self.protocolUniquer protocolWithAddress:address]; if (protocol == nil) { protocol = [[CDOCProtocol alloc] init]; [self.protocolUniquer setProtocol:protocol withAddress:address]; CDMachOFileDataCursor *cursor = [[CDMachOFileDataCursor alloc] initWithFile:self.machOFile address:address]; + if ([cursor offset] == -'S') { + NSLog(@"Warning: Meet Swift object at %s",__cmd); + return nil; + } NSParameterAssert([cursor offset] != 0); - struct cd_objc2_protocol objc2Protocol; objc2Protocol.isa = [cursor readPtr]; objc2Protocol.name = [cursor readPtr]; @@ -320,18 +322,23 @@ - (NSArray *)loadPropertiesAtAddress:(uint64_t)address; listHeader.entsize = [cursor readInt32]; listHeader.count = [cursor readInt32]; - NSParameterAssert(listHeader.entsize == 2 * [self.machOFile ptrSize]); - for (uint32_t index = 0; index < listHeader.count; index++) { - struct cd_objc2_property objc2Property; - - objc2Property.name = [cursor readPtr]; - objc2Property.attributes = [cursor readPtr]; - NSString *name = [self.machOFile stringAtAddress:objc2Property.name]; - NSString *attributes = [self.machOFile stringAtAddress:objc2Property.attributes]; - - CDOCProperty *property = [[CDOCProperty alloc] initWithName:name attributes:attributes]; - [properties addObject:property]; + if (listHeader.entsize == 2 * [self.machOFile ptrSize]) { + for (uint32_t index = 0; index < listHeader.count; index++) { + struct cd_objc2_property objc2Property; + + objc2Property.name = [cursor readPtr]; + objc2Property.attributes = [cursor readPtr]; + NSString *name = [self.machOFile stringAtAddress:objc2Property.name]; + NSString *attributes = [self.machOFile stringAtAddress:objc2Property.attributes]; + + CDOCProperty *property = [[CDOCProperty alloc] initWithName:name attributes:attributes]; + [properties addObject:property]; + } + } + else + { + return nil; } }