Skip to content

Commit

Permalink
fix init offsets, merge search
Browse files Browse the repository at this point in the history
  • Loading branch information
ASentientBot committed May 4, 2023
1 parent 2775fda commit e310907
Show file tree
Hide file tree
Showing 5 changed files with 151 additions and 74 deletions.
151 changes: 95 additions & 56 deletions Main.mm
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ void trace(NSString* format,...)
printf("\e[%dm%s\e[0m\n",31+DSCE_VERSION%6,message.UTF8String);
}

BOOL flagList=false;
BOOL flagPad=false;

#import "LocationBase.h"
Expand All @@ -36,93 +35,133 @@ void trace(NSString* format,...)
#import "Selector.m"
#import "Output.m"

void extract(CacheSet* cache,CacheImage* image)
void process(NSMutableArray<NSString*>* args)
{
// TODO: check for leaks between images
NSString* cachePath=args[0];
[args removeObjectAtIndex:0];

@autoreleasepool
CacheSet* cache=[CacheSet.alloc initWithPathPrefix:cachePath].autorelease;
assert(cache);

if([args containsObject:@"list"])
{
double startTime=NSDate.date.timeIntervalSince1970;
assert(args.count==1);

NSString* outPath=[@"Out" stringByAppendingString:image.path];
NSString* outFolder=outPath.stringByDeletingLastPathComponent;
assert([NSFileManager.defaultManager createDirectoryAtPath:outFolder withIntermediateDirectories:true attributes:nil error:nil]);
NSArray<CacheImage*>* images=[cache imagesWithPathPrefix:@"/"];

[Output runWithCache:cache image:image outPath:outPath];
trace(@"list %x images",images.count);

trace(@"image took %.2lf seconds",NSDate.date.timeIntervalSince1970-startTime);
}
}

int main(int argc,char** argv)
{
NSString* edge=[@"" stringByPaddingToLength:9+log10(DSCE_VERSION) withString:@"" startingAtIndex:0];
trace(@"%@",edge);
trace(@"│ dsce v%d",DSCE_VERSION);
trace(@"%@",edge);

if(argc<3)
{
trace(@"usage: dsce <first cache file> [list] [pad] [path prefix ...]");
return 1;
for(CacheImage* image in images)
{
trace(@"%@",image.path);
}

return;
}

double startTime=NSDate.date.timeIntervalSince1970;

NSString* cachePath=[NSString stringWithUTF8String:argv[1]];
CacheSet* cache=[CacheSet.alloc initWithPathPrefix:cachePath].autorelease;
assert(cache);

NSMutableArray<CacheImage*>* images=NSMutableArray.alloc.init.autorelease;

for(int index=2;index<argc;index++)
if([args containsObject:@"search"])
{
NSString* arg=[NSString stringWithUTF8String:argv[index]];
assert(args.count==2);

if([arg isEqual:@"list"])
{
flagList=true;
continue;
}
NSData* target=[args[1] dataUsingEncoding:NSUTF8StringEncoding];
NSMutableSet* seen=NSMutableSet.alloc.init.autorelease;

trace(@"search %@",target);

if([arg isEqual:@"pad"])
for(CacheFile* file in cache.files)
{
flagPad=true;
continue;
long offset=0;
while(true)
{
NSRange range=[file.data rangeOfData:target options:0 range:NSMakeRange(offset,file.data.length-offset)];
if(range.location==NSNotFound)
{
break;
}
else
{
CacheImage* image=[cache imageWithAddress:wrapOffset(file,range.location).address];

if(![seen containsObject:image.path])
{
trace(@"%@",image.path);
if(image.path)
{
[seen addObject:image.path];
}
}

offset=range.location+range.length;
}
}
}

return;
}

flagPad=[args containsObject:@"pad"];
[args removeObject:@"pad"];

NSMutableArray<CacheImage*>* images=NSMutableArray.alloc.init.autorelease;
for(NSString* arg in args)
{
NSArray<CacheImage*>* subset=[cache imagesWithPathPrefix:arg];

if(subset.count==0)
{
trace(@"no images found for %@*",arg);
abort();
}

[images addObjectsFromArray:subset];
}

if(flagList)
for(int index=0;index<images.count;index++)
{
if(images.count==0)
{
[images addObjectsFromArray:[cache imagesWithPathPrefix:@"/"]];
}
trace(@"extract %@ (%x/%x)",images[index].path,index+1,images.count);

trace(@"list %x images",images.count);
// TODO: check for leaks between images

for(CacheImage* image in images)
@autoreleasepool
{
trace(@"%@",image.path);
double startTime=NSDate.date.timeIntervalSince1970;

NSString* outPath=[@"Out" stringByAppendingString:images[index].path];

NSString* outFolder=outPath.stringByDeletingLastPathComponent;
assert([NSFileManager.defaultManager createDirectoryAtPath:outFolder withIntermediateDirectories:true attributes:nil error:nil]);

[Output runWithCache:cache image:images[index] outPath:outPath];

trace(@"image took %.2lf seconds",NSDate.date.timeIntervalSince1970-startTime);
}
}
else
}

int main(int argc,char** argv)
{
NSString* edge=[@"" stringByPaddingToLength:9+log10(DSCE_VERSION) withString:@"" startingAtIndex:0];
trace(@"%@",edge);
trace(@"│ dsce v%d",DSCE_VERSION);
trace(@"%@",edge);

if(argc<3)
{
trace(@"usage: dsce <first cache file> ( list | search <string> | [pad] <extraction path prefix> ... )");
return 1;
}

double startTime=NSDate.date.timeIntervalSince1970;

NSMutableArray<NSString*>* args=NSMutableArray.alloc.init.autorelease;
for(int index=1;index<argc;index++)
{
for(int index=0;index<images.count;index++)
{
trace(@"extract %@ (%x/%x)",images[index].path,index+1,images.count);
extract(cache,images[index]);
}
NSString* arg=[NSString stringWithUTF8String:argv[index]];
[args addObject:arg];
}

process(args);

trace(@"total %.2lf seconds",NSDate.date.timeIntervalSince1970-startTime);

return 0;
Expand Down
1 change: 1 addition & 0 deletions Output.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
@property(retain) NSMutableDictionary<NSNumber*,Address*>* fixups;
@property(retain) NSMutableArray<Address*>* exports;
@property(retain) NSMutableDictionary<NSString*,Selector*>* sels;
@property(assign) long baseAddressDelta;

+(void)runWithCache:(CacheSet*)cache image:(CacheImage*)image outPath:(NSString*)outPath;

Expand Down
57 changes: 44 additions & 13 deletions Output.m
Original file line number Diff line number Diff line change
Expand Up @@ -82,12 +82,15 @@ -(void)extractWithPath:(NSString*)outPath
self.stepFixProtoRefs;
self.stepFixProtos;
self.stepFixPointersNew;
self.stepFixInitOffsets;
self.stepBuildLinkedit;
self.stepMarkUUID;
self.stepSyncHeader;

trace(@"write %@",outPath);
[self.data writeToFile:outPath atomically:false];
NSError* error=nil;
[self.data writeToFile:outPath options:0 error:&error];
assert(!error);
}

-(BOOL)needsObjcImpostor
Expand All @@ -97,7 +100,7 @@ -(BOOL)needsObjcImpostor

-(BOOL)needsGotImpostor
{
if(self.cache.majorVersion!=13)
if(self.cache.majorVersion<13)
{
return false;
}
Expand Down Expand Up @@ -185,8 +188,6 @@ -(void)stepImportHeader
{
if(self.shouldMakeContiguous)
{
// unlike objc impostor, there's a gap here

self.addPadCommandCommon;
}

Expand Down Expand Up @@ -244,6 +245,7 @@ -(void)stepImportHeader
break;

// TODO: explicitly list ignored commands, add assert for unrecognied
// the current list is sort of arbitrary and could be omitting important things

default:
skipped++;
Expand Down Expand Up @@ -410,10 +412,14 @@ -(void)importSegmentsCommon:(BOOL)linkeditPhase
long newSegOffset=self.data.length;
assert(isAligned(newSegOffset,0x1000));

// TODO: in contiguous mode, assert that we are actually contiguous

if(newSegOffset==0)
{
newSegAddress-=HEADER_EXTRA;
addressDelta-=HEADER_EXTRA;

self.baseAddressDelta=addressDelta;
}

[data increaseLengthBy:-addressDelta];
Expand Down Expand Up @@ -642,7 +648,6 @@ -(void)writeFixupsWithData:(NSMutableData*)data
[data appendBytes:trieBytes.data() length:trieBytes.size()];

// to avoid gap before symtab, the padding is counted as part of the exports trie
// this is not an issue since the structure defines its own end

align(data.length,0x1000,true,&padding);
[data increaseLengthBy:padding];
Expand Down Expand Up @@ -818,8 +823,6 @@ -(void)stepImportRebases
{
self.fixups=NSMutableDictionary.alloc.init.autorelease;

// TODO: almost like duplication with LocationBase protocol... not quite

[self.header forEachSectionCommand:^(struct segment_command_64* segment,struct section_64* section)
{
if(self.shouldMakeContiguous&&!strcmp(section->sectname,IMPOSTOR_PAD))
Expand Down Expand Up @@ -898,7 +901,7 @@ -(void)stepFixSelRefs
}

long* refs=(long*)wrapOffset(self,section->offset).pointer;
int count=section->size/sizeof(long*);
int count=section->size/sizeof(long);

trace(@"fixing %x selector refs",count);

Expand Down Expand Up @@ -938,7 +941,7 @@ -(void)stepFixClasses
}

long* classes=(long*)wrapOffset(self,section->offset).pointer;
int count=section->size/sizeof(long*);
int count=section->size/sizeof(long);

trace(@"fixing %x classes",count);

Expand Down Expand Up @@ -968,7 +971,7 @@ -(void)stepFixCats
}

long* cats=(long*)wrapOffset(self,section->offset).pointer;
int count=section->size/sizeof(long*);
int count=section->size/sizeof(long);

trace(@"fixing %x categories",count);

Expand All @@ -993,7 +996,7 @@ -(void)stepFixProtoRefs
}

long* refs=(long*)wrapOffset(self,section->offset).pointer;
int count=section->size/sizeof(long*);
int count=section->size/sizeof(long);

trace(@"fixing %x protocol refs",count);

Expand All @@ -1015,7 +1018,7 @@ -(void)stepFixProtos
}

long* refs=(long*)wrapOffset(self,section->offset).pointer;
int count=section->size/sizeof(long*);
int count=section->size/sizeof(long);

trace(@"fixing %x protocols",count);

Expand All @@ -1039,7 +1042,7 @@ -(long)embeddedProtoAddressWithName:(char*)target
assert(section);

long* refs=(long*)wrapOffset(self,section->offset).pointer;
int count=section->size/sizeof(long*);
int count=section->size/sizeof(long);

for(int index=0;index<count;index++)
{
Expand Down Expand Up @@ -1171,6 +1174,8 @@ -(void)stepFixPointersNew
CacheImage* image=[self.cache imageWithAddress:destination];
if(!image)
{
// TODO: i still don't think this should ever happen (but it does)

noImageCount++;
continue;
}
Expand Down Expand Up @@ -1233,9 +1238,35 @@ -(void)stepFixPointersNew
self.fixups[key]=[Address bindWithAddress:rebase.address ordinal:ordinal name:name addend:addend];
}

// TODO: may be worth creating a "strict" flag to abort on weird ones of these

trace(@"found %lx binds (%lx via C++ hack), skipped %lx internal pointers, failed to find image containing %lx addresses, failed to resolve %lx addresses to symbols, failed to reach %lx dylibs in imports tree (%lx due to uniqued __got)",successCount,cppCount,internalCount,noImageCount,unresolvedCount,unreachableCount,unreachableGotCount);
}

-(void)stepFixInitOffsets
{
if(self.baseAddressDelta==0)
{
return;
}

struct section_64* section=[self.header sectionCommandWithName:(char*)"__init_offsets"];
if(!section)
{
return;
}

int* offsets=(int*)wrapOffset(self,section->offset).pointer;
int count=section->size/sizeof(int);

trace(@"fixing %x initializer offsets",count);

for(int index=0;index<count;index++)
{
offsets[index]+=self.baseAddressDelta;
}
}

-(void)stepMarkUUID
{
struct uuid_command* command=(struct uuid_command*)[self.header commandWithType:LC_UUID];
Expand Down
2 changes: 1 addition & 1 deletion Readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ Incomplete macOS 12+ dyld cache extractor. Used by [OCLP](https://github.com/dor
- [x] 12.6 - AppKit, QuartzCore, CoreGraphics, Carbon, RenderBox, VectorKit, Metal, MetalPerformanceShaders, MTLCompiler, GPUCompiler, AppleGVA, AppleGVACore
- [x] 12.6 - AMDMTLBronzeDriver, AMDShared, AMDRadeonVADriver, AMDRadeonVADriver2
- [x] 13.2.1 - AppKit, QuartzCore, CoreGraphics, Carbon, RenderBox, VectorKit, Metal, MetalPerformanceShaders, MTLCompiler, GPUCompiler
- [ ] 13.2.1 - libSystem, Foundation, Combine, ContactsFoundation, FamilyCircle
- [ ] 13.2.1 - libSystem, Foundation, Combine, ContactsFoundation, FamilyCircle...
- [ ] support Big Sur
- [x] support Monterey
- [x] support Ventura
Expand Down
Loading

0 comments on commit e310907

Please sign in to comment.