Skip to content

Commit

Permalink
Fixes #140 #138 and #124
Browse files Browse the repository at this point in the history
  • Loading branch information
ttwj committed Aug 23, 2016
1 parent 992103c commit fbb0908
Show file tree
Hide file tree
Showing 13 changed files with 100 additions and 40 deletions.
Binary file modified Clutch/.DS_Store
Binary file not shown.
12 changes: 8 additions & 4 deletions Clutch/ARM64Dumper.m
Original file line number Diff line number Diff line change
Expand Up @@ -30,18 +30,19 @@ - (BOOL)dumpBinary {
NSString* swappedBinaryPath = _originalBinary.binaryPath, *newSinf = _originalBinary.sinfPath, *newSupp = _originalBinary.suppPath, *newSupf = _originalBinary.supfPath; // default values if we dont need to swap archs

//check if cpusubtype matches
if ((_thinHeader.header.cpusubtype != [Device cpu_subtype]) && _originalBinary.hasMultipleARM64Slices) {

if ((_thinHeader.header.cpusubtype != [Device cpu_subtype]) && (_originalBinary.hasMultipleARMSlices || (_originalBinary.hasARM64Slice && ([Device cpu_type]==CPU_TYPE_ARM64)))) {
NSString* suffix = [NSString stringWithFormat:@"_%@", [Dumper readableArchFromHeader:_thinHeader]];

swappedBinaryPath = [_originalBinary.binaryPath stringByAppendingString:suffix];
newSinf = [_originalBinary.sinfPath.stringByDeletingPathExtension stringByAppendingString:[suffix stringByAppendingPathExtension:_originalBinary.sinfPath.pathExtension]];
newSupp = [_originalBinary.suppPath.stringByDeletingPathExtension stringByAppendingString:[suffix stringByAppendingPathExtension:_originalBinary.suppPath.pathExtension]];
newSupf = [_originalBinary.supfPath.stringByDeletingPathExtension stringByAppendingString:[suffix stringByAppendingPathExtension:_originalBinary.supfPath.pathExtension]];


[self swapArch];

}


//actual dumping

[newFileHandle seekToFileOffset:_thinHeader.offset + _thinHeader.size];
Expand Down Expand Up @@ -181,6 +182,7 @@ - (BOOL)dumpBinary {
//done dumping, let's wait for pid

_kill(pid);
[newFileHandle closeFile];
if (![swappedBinaryPath isEqualToString:_originalBinary.binaryPath])
[[NSFileManager defaultManager]removeItemAtPath:swappedBinaryPath error:nil];
if (![newSinf isEqualToString:_originalBinary.sinfPath])
Expand All @@ -195,6 +197,7 @@ - (BOOL)dumpBinary {
gotofail:

_kill(pid);
[newFileHandle closeFile];
if (![swappedBinaryPath isEqualToString:_originalBinary.binaryPath])
[[NSFileManager defaultManager]removeItemAtPath:swappedBinaryPath error:nil];
if (![newSinf isEqualToString:_originalBinary.sinfPath])
Expand All @@ -203,6 +206,7 @@ - (BOOL)dumpBinary {
[[NSFileManager defaultManager]removeItemAtPath:newSupp error:nil];
if (![newSupf isEqualToString:_originalBinary.supfPath])
[[NSFileManager defaultManager]removeItemAtPath:newSupf error:nil];

return NO;
}

Expand Down
11 changes: 5 additions & 6 deletions Clutch/ARMDumper.m
Original file line number Diff line number Diff line change
Expand Up @@ -40,11 +40,11 @@ - (BOOL)dumpBinary {
swappedBinaryPath = [_originalBinary.binaryPath stringByAppendingString:suffix];
newSinf = [_originalBinary.sinfPath.stringByDeletingPathExtension stringByAppendingString:[suffix stringByAppendingPathExtension:_originalBinary.sinfPath.pathExtension]];
newSupp = [_originalBinary.suppPath.stringByDeletingPathExtension stringByAppendingString:[suffix stringByAppendingPathExtension:_originalBinary.suppPath.pathExtension]];

[self swapArch];

}

//actual dumping

[newFileHandle seekToFileOffset:_thinHeader.offset + _thinHeader.size];
Expand Down Expand Up @@ -121,8 +121,7 @@ - (BOOL)dumpBinary {
pid = [self posix_spawn:swappedBinaryPath disableASLR:self.shouldDisableASLR];

if ((err = task_for_pid(mach_task_self(), pid, &port) != KERN_SUCCESS)) {
[[ClutchPrint sharedInstance] printError:@"Could not obtain mach port, did you sign with proper entitlements?"];
sleep(60);
[[ClutchPrint sharedInstance] printError:@"Could not obtain mach port, either the process is dead (codesign error?) or entitlements were not properly signed!?"];
goto gotofail;
}

Expand Down Expand Up @@ -188,15 +187,15 @@ - (BOOL)dumpBinary {
[[NSFileManager defaultManager]removeItemAtPath:newSinf error:nil];
if (![newSupp isEqualToString:_originalBinary.suppPath])
[[NSFileManager defaultManager]removeItemAtPath:newSupp error:nil];

[newFileHandle closeFile];
_kill(pid);

return dumpResult;

gotofail:

_kill(pid);

[newFileHandle closeFile];
if (![swappedBinaryPath isEqualToString:_originalBinary.binaryPath])
[[NSFileManager defaultManager]removeItemAtPath:swappedBinaryPath error:nil];
if (![newSinf isEqualToString:_originalBinary.sinfPath])
Expand Down
2 changes: 1 addition & 1 deletion Clutch/Binary.m
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ - (instancetype)initWithBundle:(ClutchBundle *)path

_dumpOperation = [[BundleDumpOperation alloc]initWithBundle:_bundle];

NSFileHandle *tmpHandle = [[NSFileHandle alloc]initWithFileDescriptor:fileno(fopen(_bundle.executablePath.UTF8String, "r+"))];
NSFileHandle *tmpHandle = [[NSFileHandle alloc]initWithFileDescriptor:fileno(fopen(_bundle.executablePath.UTF8String, "r+")) closeOnDealloc:YES];

NSData *headersData = tmpHandle.availableData;

Expand Down
11 changes: 6 additions & 5 deletions Clutch/BundleDumpOperation.m
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ - (void)main {
//if (![_application isKindOfClass:[Framework class]])
[_fileManager copyItemAtPath:originalBinary.binaryPath toPath:_binaryDumpPath error:nil];

NSFileHandle *tmpHandle = [[NSFileHandle alloc]initWithFileDescriptor:fileno(fopen(originalBinary.binaryPath.UTF8String, "r+"))];
NSFileHandle *tmpHandle = [[NSFileHandle alloc]initWithFileDescriptor:fileno(fopen(originalBinary.binaryPath.UTF8String, "r+")) closeOnDealloc:YES];

NSData *headersData = tmpHandle.availableData;

Expand All @@ -121,6 +121,7 @@ - (void)main {

headersFromBinary(headers, headersData, &numHeaders);


if (numHeaders == 0) {
gbprintln(@"No compatible architecture found");
}
Expand Down Expand Up @@ -159,7 +160,7 @@ - (void)main {

[[ClutchPrint sharedInstance] printDeveloper:@"Found compatible dumper %@ for binary %@ with arch %@",_dumper,originalBinary,[Dumper readableArchFromHeader:macho]];

NSFileHandle *_handle = [[NSFileHandle alloc]initWithFileDescriptor:fileno(fopen(originalBinary.binaryPath.UTF8String, "r+"))];
NSFileHandle *_handle = [[NSFileHandle alloc]initWithFileDescriptor:fileno(fopen(originalBinary.binaryPath.UTF8String, "r+")) closeOnDealloc:YES];

_dumper.originalFileHandle = _handle;

Expand All @@ -186,7 +187,7 @@ - (void)main {

#pragma mark "stripping" headers in FAT binary
if ([_headersToStrip count] > 0) {
NSFileHandle *_dumpHandle = [[NSFileHandle alloc]initWithFileDescriptor:fileno(fopen(_binaryDumpPath.UTF8String, "r+"))];
NSFileHandle *_dumpHandle = [[NSFileHandle alloc]initWithFileDescriptor:fileno(fopen(_binaryDumpPath.UTF8String, "r+")) closeOnDealloc:YES];

uint32_t magic = [_dumpHandle intAtOffset:0];
NSData *buffer = [_dumpHandle readDataOfLength:4096];
Expand Down Expand Up @@ -219,10 +220,10 @@ - (void)main {
#pragma mark lipo ftw

[[NSFileManager defaultManager]moveItemAtPath:_binaryDumpPath toPath:[_binaryDumpPath stringByAppendingPathExtension:@"fatty"] error:nil];
NSFileHandle *_fattyHandle = [[NSFileHandle alloc]initWithFileDescriptor:fileno(fopen([_binaryDumpPath stringByAppendingPathExtension:@"fatty"].UTF8String, "r+"))];
NSFileHandle *_fattyHandle = [[NSFileHandle alloc]initWithFileDescriptor:fileno(fopen([_binaryDumpPath stringByAppendingPathExtension:@"fatty"].UTF8String, "r+")) closeOnDealloc:YES];

[[NSFileManager defaultManager] createFileAtPath:_binaryDumpPath contents:nil attributes:nil];
_dumpHandle = [[NSFileHandle alloc]initWithFileDescriptor:fileno(fopen(_binaryDumpPath.UTF8String, "r+"))];
_dumpHandle = [[NSFileHandle alloc]initWithFileDescriptor:fileno(fopen(_binaryDumpPath.UTF8String, "r+")) closeOnDealloc:YES];

[_dumpHandle replaceBytesInRange:NSMakeRange(0, sizeof(uint32_t)) withBytes:&magic];

Expand Down
2 changes: 1 addition & 1 deletion Clutch/Clutch-Prefix.pch
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ int diff_ms(struct timeval t1, struct timeval t2);



#define CLUTCH_VERSION_ @"2.0.3"
#define CLUTCH_VERSION_ @"2.0.4"

#ifdef DEBUG
#define CLUTCH_VERSION [NSString stringWithFormat:@"%@ DEBUG",CLUTCH_VERSION_]
Expand Down
2 changes: 2 additions & 0 deletions Clutch/ClutchPrint.m
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ - (void)print:(NSString *)format, ...

- (void)printDeveloper:(NSString *)format, ...
{
#ifdef DEBUG
if (verboseLevel == ClutchPrinterVerboseLevelDeveloper || verboseLevel == ClutchPrinterVerboseLevelFull)
{
if (format != nil)
Expand All @@ -78,6 +79,7 @@ - (void)printDeveloper:(NSString *)format, ...
va_end(args);
}
}
#endif
}

- (void)printError:(NSString *)format, ...
Expand Down
1 change: 1 addition & 0 deletions Clutch/Dumper.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ void _kill(pid_t pid);
@property NSFileHandle *originalFileHandle;
@property BOOL shouldDisableASLR;


+ (NSString *)readableArchFromHeader:(thin_header)macho;
+ (NSString *)readableArchFromMachHeader:(struct mach_header)header;
- (pid_t)posix_spawn:(NSString *)binaryPath disableASLR:(BOOL)yrn;
Expand Down
75 changes: 58 additions & 17 deletions Clutch/Dumper.m
Original file line number Diff line number Diff line change
Expand Up @@ -136,11 +136,14 @@ -(void)swapArch {
newSupf = [_originalBinary.supfPath.stringByDeletingPathExtension stringByAppendingString:[suffix stringByAppendingPathExtension:_originalBinary.supfPath.pathExtension]];
}

NSError *error;

[[NSFileManager defaultManager]removeItemAtPath:swappedBinaryPath error:&error];

[[ClutchPrint sharedInstance] printDeveloper: @"%@",error];
NSError *error;

if ([[NSFileManager defaultManager] fileExistsAtPath:swappedBinaryPath isDirectory:NO]){
[[NSFileManager defaultManager]removeItemAtPath:swappedBinaryPath error:nil];
}


[[NSFileManager defaultManager] copyItemAtPath:_originalBinary.binaryPath toPath:swappedBinaryPath error:&error];

Expand All @@ -155,7 +158,7 @@ -(void)swapArch {
}

[self.originalFileHandle closeFile];
self.originalFileHandle = [[NSFileHandle alloc]initWithFileDescriptor:fileno(fopen(swappedBinaryPath.UTF8String, "r+"))];
self.originalFileHandle = [[NSFileHandle alloc]initWithFileDescriptor:fileno(fopen(swappedBinaryPath.UTF8String, "r+")) closeOnDealloc:YES];

uint32_t magic = [self.originalFileHandle intAtOffset:0];
bool shouldSwap = magic == FAT_CIGAM;
Expand All @@ -165,30 +168,68 @@ -(void)swapArch {

struct fat_header fat = *(struct fat_header *)buffer.bytes;
fat.nfat_arch = SWAP(fat.nfat_arch);
uint32_t offset = sizeof(struct fat_header);
int offset = sizeof(struct fat_header);

for (int i = 0; i < fat.nfat_arch; i++) {
struct fat_arch arch;
arch = *(struct fat_arch *)([buffer bytes] + offset);

if (((SWAP(arch.cputype) == _thinHeader.header.cputype) && (SWAP(arch.cpusubtype) == _thinHeader.header.cpusubtype))) {
int origOffset = SWAP(arch.offset);
arch.offset = SWAP(pow(2.0, SWAP(arch.align)));
[self.originalFileHandle seekToFileOffset:origOffset];
NSData *machOData = [self.originalFileHandle readDataOfLength:SWAP(arch.size)];
[self.originalFileHandle replaceBytesInRange:NSMakeRange(sizeof(struct fat_header), sizeof(struct fat_arch)) withBytes:&arch];
[self.originalFileHandle replaceBytesInRange:NSMakeRange(SWAP(arch.offset), SWAP(arch.size)) withBytes:[machOData bytes]];
offset = SWAP(arch.offset) + SWAP(arch.size);
break;
if (!((SWAP(arch.cputype) == _thinHeader.header.cputype) && (SWAP(arch.cpusubtype) == _thinHeader.header.cpusubtype))) {

if (SWAP(arch.cputype) == CPU_TYPE_ARM) {
switch (SWAP(arch.cpusubtype)) {
case CPU_SUBTYPE_ARM_V6:
arch.cputype = SWAP(CPU_TYPE_I386);
arch.cpusubtype = SWAP(CPU_SUBTYPE_PENTIUM_3_XEON);
break;
case CPU_SUBTYPE_ARM_V7:
arch.cputype = SWAP(CPU_TYPE_I386);
arch.cpusubtype = SWAP(CPU_SUBTYPE_PENTIUM_4);
break;
case CPU_SUBTYPE_ARM_V7S:
arch.cputype = SWAP(CPU_TYPE_I386);
arch.cpusubtype = SWAP(CPU_SUBTYPE_ITANIUM);
break;
case CPU_SUBTYPE_ARM_V7K: // Apple Watch FTW
arch.cputype = SWAP(CPU_TYPE_I386);
arch.cpusubtype = SWAP(CPU_SUBTYPE_XEON);
break;
default:
[[ClutchPrint sharedInstance] printColor:ClutchPrinterColorPurple format:@"Warning: A wild 32-bit cpusubtype appeared! %u", SWAP(arch.cpusubtype)];
arch.cputype = SWAP(CPU_TYPE_I386);
arch.cpusubtype = SWAP(CPU_SUBTYPE_PENTIUM_3_XEON); //pentium 3 ftw
break;

}
}else {

switch (SWAP(arch.cpusubtype)) {
case CPU_SUBTYPE_ARM64_ALL:
arch.cputype = SWAP(CPU_TYPE_X86_64);
arch.cpusubtype = SWAP(CPU_SUBTYPE_X86_64_ALL);
break;
case CPU_SUBTYPE_ARM64_V8:
arch.cputype = SWAP(CPU_TYPE_X86_64);
arch.cpusubtype = SWAP(CPU_SUBTYPE_X86_64_H);
break;
default:
[[ClutchPrint sharedInstance] printColor:ClutchPrinterColorPurple format:@"Warning: A wild 64-bit cpusubtype appeared! %u", SWAP(arch.cpusubtype)];
arch.cputype = SWAP(CPU_TYPE_X86_64);
arch.cpusubtype = SWAP(CPU_SUBTYPE_X86_64_ALL);
break;
}

}

[self.originalFileHandle replaceBytesInRange:NSMakeRange(offset, sizeof(struct fat_arch)) withBytes:&arch];
}

offset += sizeof(struct fat_arch);
}

uint32_t nfat_arch = SWAP(1);
[self.originalFileHandle replaceBytesInRange:NSMakeRange(sizeof(uint32_t), sizeof(uint32_t)) withBytes:&nfat_arch];
[self.originalFileHandle truncateFileAtOffset:offset];

[[ClutchPrint sharedInstance] printDeveloper: @"wrote new header to binary"];
//we don't close file handle here since it's reused later in dumping!
}

- (BOOL)_dumpToFileHandle:(NSFileHandle *)fileHandle withDumpSize:(uint32_t)togo pages:(uint32_t)pages fromPort:(mach_port_t)port pid:(pid_t)pid aslrSlide:(mach_vm_address_t)__text_start codeSignature_hashOffset:(uint32_t)hashOffset codesign_begin:(uint32_t)begin
Expand Down
10 changes: 5 additions & 5 deletions Clutch/Framework64Dumper.m
Original file line number Diff line number Diff line change
Expand Up @@ -28,16 +28,16 @@ - (BOOL)dumpBinary

NSString* swappedBinaryPath = _originalBinary.binaryPath, *newSinf = _originalBinary.sinfPath, *newSupp = _originalBinary.suppPath, *newSupf = _originalBinary.supfPath; // default values if we dont need to swap archs


//check if cpusubtype matches
if ((_thinHeader.header.cpusubtype != [Device cpu_subtype]) && _originalBinary.hasMultipleARM64Slices) {

NSString* suffix = [NSString stringWithFormat:@"_%@", [Dumper readableArchFromHeader:_thinHeader]];

swappedBinaryPath = [_originalBinary.binaryPath stringByAppendingString:suffix];
newSinf = [_originalBinary.sinfPath stringByAppendingString:suffix];
newSupp = [_originalBinary.suppPath stringByAppendingString:suffix];
newSupf = [_originalBinary.supfPath stringByAppendingString:suffix];
newSinf = [_originalBinary.sinfPath.stringByDeletingPathExtension stringByAppendingString:[suffix stringByAppendingPathExtension:_originalBinary.sinfPath.pathExtension]];
newSupp = [_originalBinary.suppPath.stringByDeletingPathExtension stringByAppendingString:[suffix stringByAppendingPathExtension:_originalBinary.suppPath.pathExtension]];
newSupf = [_originalBinary.supfPath.stringByDeletingPathExtension stringByAppendingString:[suffix stringByAppendingPathExtension:_originalBinary.supfPath.pathExtension]];

[self swapArch];
}

Expand Down
5 changes: 4 additions & 1 deletion Clutch/FrameworkDumper.m
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@ - (BOOL)dumpBinary

NSString *binaryDumpPath = [_originalBinary.workingPath stringByAppendingPathComponent:_originalBinary.binaryPath.lastPathComponent];

NSString* swappedBinaryPath = _originalBinary.binaryPath, *newSinf = _originalBinary.sinfPath, *newSupp = _originalBinary.suppPath; // default values if we dont need to swap archs

NSString* swappedBinaryPath = _originalBinary.binaryPath, *newSinf = _originalBinary.sinfPath, *newSupp = _originalBinary.suppPath, *newSupf = _originalBinary.supfPath; // default values if we dont need to swap archs

//check if cpusubtype matches
if ((_thinHeader.header.cpusubtype != [Device cpu_subtype]) && (_originalBinary.hasMultipleARMSlices || (_originalBinary.hasARM64Slice && ([Device cpu_type]==CPU_TYPE_ARM64)))) {
Expand All @@ -35,6 +36,8 @@ - (BOOL)dumpBinary
swappedBinaryPath = [_originalBinary.binaryPath stringByAppendingString:suffix];
newSinf = [_originalBinary.sinfPath.stringByDeletingPathExtension stringByAppendingString:[suffix stringByAppendingPathExtension:_originalBinary.sinfPath.pathExtension]];
newSupp = [_originalBinary.suppPath.stringByDeletingPathExtension stringByAppendingString:[suffix stringByAppendingPathExtension:_originalBinary.suppPath.pathExtension]];
newSupf = [_originalBinary.supfPath.stringByDeletingPathExtension stringByAppendingString:[suffix stringByAppendingPathExtension:_originalBinary.supfPath.pathExtension]];


[self swapArch];

Expand Down
4 changes: 4 additions & 0 deletions Clutch/main.m
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#import "FrameworkLoader.h"
#import <sys/time.h>
#import "ClutchPrint.h"
#import "NSTask.h"

int diff_ms(struct timeval t1, struct timeval t2)
{
Expand Down Expand Up @@ -70,6 +71,7 @@ int main (int argc, const char * argv[])

return 0;
}


GBOptionsHelper *options = [[GBOptionsHelper alloc] init];
options.applicationVersion = ^{ return CLUTCH_VERSION; };
Expand All @@ -84,7 +86,9 @@ int main (int argc, const char * argv[])
[options registerOption:0 long:@"version" description:@"Display version and exit" flags:GBValueNone|GBOptionNoPrint];
[options registerOption:'?' long:@"help" description:@"Display this help and exit" flags:GBValueNone|GBOptionNoPrint];
[options registerOption:'n' long:@"no-color" description:@"Print with colors disabled" flags:GBValueNone|GBOptionNoPrint];
#ifdef DEBUG
[options registerOption:'v' long:@"verbose" description:@"Print verbose messages" flags:GBValueNone|GBOptionNoPrint];
#endif

if (argc == 1) {
[options printHelp];
Expand Down
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,11 @@ Clutch

Usage
------------

*Important*
Clutch may encounter `Segmentation Fault: 11` when dumping apps with a large number of frameworks. Increase your device's maximum number of open file descriptors
`ulimit -n 512` (default is 256)

```sh
Clutch [OPTIONS]
-b --binary-dump Only dump binary files from specified bundleID
Expand Down

0 comments on commit fbb0908

Please sign in to comment.