Skip to content

Commit 40dabf1

Browse files
author
Mike Richter
committed
Fix method name resolution #19525
1 parent d3b61ec commit 40dabf1

9 files changed

Lines changed: 127 additions & 45 deletions

Source/CDMachOFile.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ typedef enum : NSUInteger {
5555
- (CDLCSegment *)segmentWithName:(NSString *)segmentName;
5656
- (CDLCSegment *)segmentContainingAddress:(NSUInteger)address;
5757
- (NSString *)stringAtAddress:(NSUInteger)address;
58+
- (NSString *)stringAtAddress2:(NSUInteger)address;
5859

5960
- (NSUInteger)dataOffsetForAddress:(NSUInteger)address;
6061

Source/CDMachOFile.m

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -352,6 +352,67 @@ - (NSString *)stringAtAddress:(NSUInteger)address;
352352
if (offset == 0)
353353
return nil;
354354

355+
CDSection *section = [segment sectionContainingAddress:address];
356+
if ([[section sectionName] isEqualToString:@"__objc_selrefs"]) {
357+
NSLog(@"large method reference (0x%016lx) into __objc_selrefs!", address);
358+
}
359+
360+
ptr = (uint8_t *)[self.data bytes] + offset;
361+
362+
return [[NSString alloc] initWithBytes:ptr length:strlen(ptr) encoding:NSASCIIStringEncoding];
363+
}
364+
365+
- (NSString *)stringAtAddress2:(NSUInteger)address;
366+
{
367+
const void *ptr;
368+
369+
if (address == 0)
370+
return nil;
371+
372+
CDLCSegment *segment = [self segmentContainingAddress:address];
373+
if (segment == nil) {
374+
NSLog(@"Error: Cannot find offset for address 0x%08lx in stringAtAddress:", address);
375+
exit(5);
376+
return nil;
377+
}
378+
379+
if ([segment isProtected]) {
380+
NSData *d2 = [segment decryptedData];
381+
NSUInteger d2Offset = [segment segmentOffsetForAddress:address];
382+
if (d2Offset == 0)
383+
return nil;
384+
385+
ptr = (uint8_t *)[d2 bytes] + d2Offset;
386+
return [[NSString alloc] initWithBytes:ptr length:strlen(ptr) encoding:NSASCIIStringEncoding];
387+
}
388+
389+
NSUInteger offset = [self dataOffsetForAddress:address];
390+
if (offset == 0)
391+
return nil;
392+
393+
CDSection *section = [segment sectionContainingAddress:address];
394+
if ([[section sectionName] isEqualToString:@"__objc_selrefs"]) {
395+
// int pointerSize = (int)[self ptrSize];
396+
// int numberOfBytes = pointerSize;//([section alignment] == 8) ? 8 : 4;
397+
// if ((1 << [section alignment]) != pointerSize) {
398+
// NSLog(@"__objc_selrefs with alignment of %lu and pointerSize of %d!", (unsigned long)[section alignment], pointerSize);
399+
// }
400+
// const void * reference = [self.data bytes] + offset;
401+
// uint64_t referencedAddress = 0ULL;
402+
// for (int index = 0; index < numberOfBytes; index++) {
403+
// referencedAddress |= ((uint64_t)bytes[index]) << (index * 8);
404+
// }
405+
406+
const void * reference = [self.data bytes] + offset;
407+
offset = ([self ptrSize] == 8) ? *((uint64_t *)reference) : *((uint32_t *)reference);
408+
409+
// This is probably not the right translation: how do we know that this address is correct, does it need to go through dataOffsetForAddress?
410+
// ptr = (uint8_t *)([self.data bytes] + selectorOffset);
411+
// } else {
412+
// NSLog(@"small method pointer into %@ section!", [section sectionName]);
413+
// ptr = (uint8_t *)[self.data bytes] + offset;
414+
}
415+
355416
ptr = (uint8_t *)[self.data bytes] + offset;
356417

357418
return [[NSString alloc] initWithBytes:ptr length:strlen(ptr) encoding:NSASCIIStringEncoding];

Source/CDMachOFileDataCursor.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,5 +28,6 @@
2828

2929
// Read using the current byteOrder and ptrSize (from the machOFile)
3030
- (uint64_t)readPtr;
31+
- (uint64_t)readSmallPtr:(uint64_t)base;
3132

3233
@end

Source/CDMachOFileDataCursor.m

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,4 +110,13 @@ - (uint64_t)readPtr;
110110
return 0;
111111
}
112112

113+
- (uint64_t)readSmallPtr:(uint64_t)base;
114+
{
115+
uint64_t offsetIntoFile = [self offset];
116+
int32_t offset = [self readInt32];
117+
return (uint64_t)((int64_t)(offsetIntoFile) + offset);
118+
// return (uint64_t)((int64_t)(base) + offset);
119+
//return (uint64_t)(uint32_t)[self readInt32];
120+
}
121+
113122
@end

Source/CDObjectiveC2Processor.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,10 @@
55

66
#import "CDObjectiveCProcessor.h"
77

8+
#define METHOD_LIST_T_RESERVED_BITS 0x7FFF0003
9+
#define METHOD_LIST_T_SMALL_METHOD_FLAG 0x80000000
10+
#define METHOD_LIST_T_ENTSIZE_MASK (METHOD_LIST_T_RESERVED_BITS|METHOD_LIST_T_SMALL_METHOD_FLAG)
11+
812
@interface CDObjectiveC2Processor : CDObjectiveCProcessor
913

1014
@end

Source/CDObjectiveC2Processor.m

Lines changed: 44 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -400,79 +400,79 @@ - (NSArray *)loadMethodsAtAddress:(uint64_t)address;
400400
}
401401

402402
- (NSArray *)loadMethodsAtAddress:(uint64_t)address extendedMethodTypesCursor:(CDMachOFileDataCursor *)extendedMethodTypesCursor;
403+
{
404+
return [self loadMethodsAtAddress:address extendedMethodTypesCursor:extendedMethodTypesCursor base:0ULL];
405+
}
406+
407+
- (NSArray *)loadMethodsAtAddress:(uint64_t)address extendedMethodTypesCursor:(CDMachOFileDataCursor *)extendedMethodTypesCursor base:(uint64_t)base;
403408
{
404409
NSMutableArray *methods = [NSMutableArray array];
405410

406411
if (address != 0) {
407412
CDMachOFileDataCursor *cursor = [[CDMachOFileDataCursor alloc] initWithFile:self.machOFile address:address];
413+
NSLog(@"initial offset 0x%016lx address 0x%016llx", [cursor offset], address);
408414
NSParameterAssert([cursor offset] != 0);
409415
//NSLog(@"method list data offset: %lu", [cursor offset]);
410416

411417
struct cd_objc2_list_header listHeader;
412418

413419
// See https://opensource.apple.com/source/objc4/objc4-787.1/runtime/objc-runtime-new.h
414-
uint32_t mask = 0xFFFF0003;
415420
uint32_t value = [cursor readInt32];
416-
listHeader.entsize = value & ~mask;
417-
uint32_t flags = value & mask;
418-
int smallMethods = (flags & 0x80000000) != 0;
419-
/*
420-
Tests show no leftovers were present. Consistent with comments indicating smallMethodListFlag is currently the only flag.
421-
int leftOvers = flags & ~0x80000000;
422-
if (leftOvers != 0) {
423-
NSLog(@"Leftovers was non-zero: 0x%08x (0x%08x)", leftOvers, value);
424-
}
425-
*/
421+
listHeader.entsize = value & ~METHOD_LIST_T_ENTSIZE_MASK;
422+
int smallMethodPointers = (value & METHOD_LIST_T_SMALL_METHOD_FLAG) != 0;
426423
listHeader.count = [cursor readInt32];
427-
// NSLog(@"Info: %u == %lu?: listHeader.entsize=%u self.machOFile ptrSize=%lu (%d 0x%x)", listHeader.entsize, (3 * [self.machOFile ptrSize]), listHeader.entsize, [self.machOFile ptrSize], listHeader.entsize, listHeader.entsize);
428-
if (smallMethods) {
429-
NSParameterAssert(listHeader.entsize == (3 * sizeof(uint32_t)));
430-
} else {
431-
NSParameterAssert(listHeader.entsize == 3 * [self.machOFile ptrSize]);
432-
}
424+
NSParameterAssert(listHeader.entsize == 3 * (smallMethodPointers ? sizeof(int32_t) : [self.machOFile ptrSize]));
425+
426+
uint64_t min1 = 0xFFFFFFFFFFFFFFFFULL;
427+
uint64_t max1 = 0ULL;
428+
uint64_t min2 = 0xFFFFFFFFFFFFFFFFULL;
429+
uint64_t max2 = 0ULL;
430+
uint64_t min3 = 0xFFFFFFFFFFFFFFFFULL;
431+
uint64_t max3 = 0ULL;
432+
uint64_t val2;
433+
433434
for (uint32_t index = 0; index < listHeader.count; index++) {
434435
struct cd_objc2_method objc2Method;
435-
436-
if (smallMethods) {
437-
// NSLog(@"NEW METHOD!!");
438-
uint64_t offset1 = [cursor offset];
439-
int value1 = [cursor readInt32];
440-
objc2Method.name = (uint64_t)(((int64_t)offset1) + value1);
441-
442-
uint64_t offset2 = [cursor offset];
443-
int value2 = [cursor readInt32];
444-
objc2Method.types = (uint64_t)(((int64_t)offset2) + value2);
445-
446-
uint64_t offset3 = [cursor offset];
447-
int value3 = [cursor readInt32];
448-
objc2Method.imp = (uint64_t)(((int64_t)offset3) + value3);
449-
450-
// NSLog(@"values12f: 0x%016llx 0x%016llx 0x%016llx", objc2Method.name, objc2Method.types, objc2Method.imp);
436+
uint64_t offset = [cursor offset];
437+
if (smallMethodPointers) {
438+
val2 = [cursor readSmallPtr:address]; if (val2 < min1) min1 = val2; if (val2 > max1) max1 = val2;
439+
objc2Method.name = val2;
440+
val2 = [cursor readSmallPtr:address]; if (val2 < min2) min2 = val2; if (val2 > max2) max2 = val2;
441+
objc2Method.types = val2;
442+
val2 = [cursor readSmallPtr:address]; if (val2 < min3) min3 = val2; if (val2 > max3) max3 = val2;
443+
objc2Method.imp = val2;
444+
// NSLog(@"values12f: 0x%016llx 0x%016llx 0x%016llx", objc2Method.name, objc2Method.types, objc2Method.imp);
451445
// NSLog(@"values12: 0x%08x 0x%08x 0x%08x", value1, value2, value3);
452446
} else {
453-
uint64_t value1 = [cursor readPtr];
454-
uint64_t value2 = [cursor readPtr];
455-
uint64_t value3 = [cursor readPtr];
456-
// NSLog(@"values24: 0x%016llx 0x%016llx 0x%016llx", value1, value2, value3);
457-
objc2Method.name = value1;
458-
objc2Method.types = value2;
459-
objc2Method.imp = value3;
447+
objc2Method.name = [cursor readPtr];
448+
objc2Method.types = [cursor readPtr];
449+
objc2Method.imp = [cursor readPtr];
450+
}
451+
NSString *name;
452+
if (smallMethodPointers) {
453+
name = [self.machOFile stringAtAddress2:objc2Method.name];
454+
NSLog(@"small name: %@", name);
455+
} else {
456+
name = [self.machOFile stringAtAddress:objc2Method.name];
460457
}
461-
NSString *name = [self.machOFile stringAtAddress:objc2Method.name];
462458
NSString *types = [self.machOFile stringAtAddress:objc2Method.types];
463459

464460
if (extendedMethodTypesCursor) {
465461
uint64_t extendedMethodTypes = [extendedMethodTypesCursor readPtr];
466462
types = [self.machOFile stringAtAddress:extendedMethodTypes];
467463
}
468464

469-
//NSLog(@"%3u: %016lx %016lx %016lx", index, objc2Method.name, objc2Method.types, objc2Method.imp);
470-
//NSLog(@"name: %@", name);
471-
//NSLog(@"types: %@", types);
465+
// NSLog(@"%s%3u: 0x%016llx 0x%016llx 0x%016llx 0x%016llx 0x%016llx", (smallMethodPointers ? "small " : ""), index, objc2Method.name, objc2Method.types, objc2Method.imp, offset, address);
466+
// NSLog(@"name: %@", name);
467+
// NSLog(@"types: %@", types);
472468

473469
CDOCMethod *method = [[CDOCMethod alloc] initWithName:name typeString:types address:objc2Method.imp];
474470
[methods addObject:method];
475471
}
472+
473+
// if (smallMethodPointers) {
474+
// NSLog(@"Small method range: 0x%016llx 0x%016llx 0x%016llx 0x%016llx 0x%016llx 0x%016llx", min1, max1, min2, max2, min3, max3);
475+
// }
476476
}
477477

478478
return [methods reversedArray];
@@ -491,7 +491,6 @@ - (NSArray *)loadIvarsAtAddress:(uint64_t)address;
491491

492492
listHeader.entsize = [cursor readInt32];
493493
listHeader.count = [cursor readInt32];
494-
// NSLog(@"Info: %u == %lu?: listHeader.entsize=%u self.machOFile ptrSize=%lu", listHeader.entsize, (3 * [self.machOFile ptrSize] + 2 * sizeof(uint32_t)), listHeader.entsize, [self.machOFile ptrSize]);
495494
NSParameterAssert(listHeader.entsize == 3 * [self.machOFile ptrSize] + 2 * sizeof(uint32_t));
496495

497496
for (uint32_t index = 0; index < listHeader.count; index++) {

Source/CDObjectiveCProcessor.m

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,7 @@ - (void)addCategory:(CDOCCategory *)category;
139139
- (int)process;
140140
{
141141
if (self.machOFile.isEncrypted == NO && self.machOFile.canDecryptAllSegments) {
142+
NSLog(@"Loading file %@", [[self machOFile] filename]);
142143
[self.machOFile.symbolTable loadSymbols];
143144
[self.machOFile.dynamicSymbolTable loadSymbols];
144145

Source/CDSection.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919

2020
@property (nonatomic, readonly) NSUInteger addr;
2121
@property (nonatomic, readonly) NSUInteger size;
22+
@property (nonatomic, readonly) NSUInteger alignment;
2223

2324
- (BOOL)containsAddress:(NSUInteger)address;
2425
- (NSUInteger)fileOffsetForAddress:(NSUInteger)address;

Source/CDSection.m

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,11 @@ - (NSUInteger)size;
6868
return _section.size;
6969
}
7070

71+
- (NSUInteger)alignment;
72+
{
73+
return _section.align;
74+
}
75+
7176
- (BOOL)containsAddress:(NSUInteger)address;
7277
{
7378
return (address >= _section.addr) && (address < _section.addr + _section.size);

0 commit comments

Comments
 (0)