diff --git a/Source/CDMachOFile.m b/Source/CDMachOFile.m index 8902f838..a7047fcd 100644 --- a/Source/CDMachOFile.m +++ b/Source/CDMachOFile.m @@ -350,6 +350,13 @@ - (NSString *)stringAtAddress:(NSUInteger)address; if (offset == 0) return nil; + // Support small methods referencing selector names in __objc_selrefs. + CDSection *section = [segment sectionContainingAddress:address]; + if ([[section sectionName] isEqualToString:@"__objc_selrefs"]) { + const void * reference = [self.data bytes] + offset; + offset = ([self ptrSize] == 8) ? *((uint64_t *)reference) : *((uint32_t *)reference); + } + ptr = (uint8_t *)[self.data bytes] + offset; return [[NSString alloc] initWithBytes:ptr length:strlen(ptr) encoding:NSASCIIStringEncoding]; diff --git a/Source/CDMachOFileDataCursor.h b/Source/CDMachOFileDataCursor.h index 35946348..9fbed9d5 100644 --- a/Source/CDMachOFileDataCursor.h +++ b/Source/CDMachOFileDataCursor.h @@ -28,5 +28,6 @@ // Read using the current byteOrder and ptrSize (from the machOFile) - (uint64_t)readPtr; +- (uint64_t)readPtr:(bool)small; @end diff --git a/Source/CDMachOFileDataCursor.m b/Source/CDMachOFileDataCursor.m index 5fe981d3..869a776f 100644 --- a/Source/CDMachOFileDataCursor.m +++ b/Source/CDMachOFileDataCursor.m @@ -110,4 +110,15 @@ - (uint64_t)readPtr; return 0; } +- (uint64_t)readPtr:(bool)small; +{ + // "small" pointers are signed 32-bit values + if (small) { + // The pointers are relative to the location in the image, so get the offset before reading the offset: + return [self offset] + [self readInt32]; + } else { + return [self readPtr]; + } +} + @end diff --git a/Source/CDObjectiveC2Processor.h b/Source/CDObjectiveC2Processor.h index 989c2280..9bdce200 100644 --- a/Source/CDObjectiveC2Processor.h +++ b/Source/CDObjectiveC2Processor.h @@ -5,6 +5,10 @@ #import "CDObjectiveCProcessor.h" +#define METHOD_LIST_T_RESERVED_BITS 0x7FFF0003 +#define METHOD_LIST_T_SMALL_METHOD_FLAG 0x80000000 +#define METHOD_LIST_T_ENTSIZE_MASK (METHOD_LIST_T_RESERVED_BITS|METHOD_LIST_T_SMALL_METHOD_FLAG) + @interface CDObjectiveC2Processor : CDObjectiveCProcessor @end diff --git a/Source/CDObjectiveC2Processor.m b/Source/CDObjectiveC2Processor.m index 2003fcb0..ad9f76f1 100644 --- a/Source/CDObjectiveC2Processor.m +++ b/Source/CDObjectiveC2Processor.m @@ -398,17 +398,19 @@ - (NSArray *)loadMethodsAtAddress:(uint64_t)address extendedMethodTypesCursor:(C struct cd_objc2_list_header listHeader; - // See getEntsize() from http://www.opensource.apple.com/source/objc4/objc4-532.2/runtime/objc-runtime-new.h - listHeader.entsize = [cursor readInt32] & ~(uint32_t)3; - listHeader.count = [cursor readInt32]; - NSParameterAssert(listHeader.entsize == 3 * [self.machOFile ptrSize]); - + // See https://opensource.apple.com/source/objc4/objc4-787.1/runtime/objc-runtime-new.h + uint32_t value = [cursor readInt32]; + listHeader.entsize = value & ~METHOD_LIST_T_ENTSIZE_MASK; + bool small = (value & METHOD_LIST_T_SMALL_METHOD_FLAG) != 0; + listHeader.count = [cursor readInt32]; + NSParameterAssert(listHeader.entsize == 3 * (small ? sizeof(int32_t) : [self.machOFile ptrSize])); + for (uint32_t index = 0; index < listHeader.count; index++) { struct cd_objc2_method objc2Method; - - objc2Method.name = [cursor readPtr]; - objc2Method.types = [cursor readPtr]; - objc2Method.imp = [cursor readPtr]; + + objc2Method.name = [cursor readPtr:small]; + objc2Method.types = [cursor readPtr:small]; + objc2Method.imp = [cursor readPtr:small]; NSString *name = [self.machOFile stringAtAddress:objc2Method.name]; NSString *types = [self.machOFile stringAtAddress:objc2Method.types]; @@ -417,7 +419,7 @@ - (NSArray *)loadMethodsAtAddress:(uint64_t)address extendedMethodTypesCursor:(C types = [self.machOFile stringAtAddress:extendedMethodTypes]; } - //NSLog(@"%3u: %016lx %016lx %016lx", index, objc2Method.name, objc2Method.types, objc2Method.imp); + //NSLog(@"%3u: %016llx %016llx %016llx", index, objc2Method.name, objc2Method.types, objc2Method.imp); //NSLog(@"name: %@", name); //NSLog(@"types: %@", types);