2023年7月3日发(作者:)
iReSign源码分析启动之后⾸先会去查询可⽤的签名证书,这⾥⽤到了NSTask,NSTask是可以在APP⾥调⽤终端命令的。⽽终端是另外⼀个进程,需要进程间通信,可以使⽤NSPipe,security find-identity -v -p codesigning 则可以查询到当前设备下所有证书: certTask = [[NSTask alloc] init]; [certTask setLaunchPath:@"/usr/bin/security"]; [certTask setArguments:[NSArray arrayWithObjects:@"find-identity", @"-v", @"-p", @"codesigning", nil]];
[NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(checkCerts:) userInfo:nil repeats:TRUE];
NSPipe *pipe=[NSPipe pipe]; [certTask setStandardOutput:pipe]; [certTask setStandardError:pipe]; NSFileHandle *handle=[pipe fileHandleForReading];
[certTask launch]; //创建⼦线程,将读取的结果返回给watchGetCerts⽅法 [NSThread detachNewThreadSelector:@selector(watchGetCerts:) toTarget:self withObject:handle];//watchGetCerts没啥特别之处,根据返回的字符串进⾏解析,由于结果是证书uuid+账号的形式,所以字符串分割之后遍历的时候是+2的步长- (void)watchGetCerts:(NSFileHandle*)streamHandle { @autoreleasepool { NSString *securityResult = [[NSString alloc] initWithData:[streamHandle readDataToEndOfFile] encoding:NSASCIIStringEncoding]; // Verify the security result if (securityResult == nil || < 1) { // Nothing in the result, return return; } NSArray *rawResult = [securityResult componentsSeparatedByString:@"""]; NSMutableArray *tempGetCertsResult = [NSMutableArray arrayWithCapacity:20]; for (int i = 0; i <= [rawResult count] - 2; i+=2) {
NSLog(@"i:%d", i+1); if ( - 1 < i + 1) { // Invalid array, don't add an object to that position } else { // Valid object [tempGetCertsResult addObject:[rawResult objectAtIndex:i+1]]; } } certComboBoxItems = [NSMutableArray arrayWithArray:tempGetCertsResult]; [certComboBox reloadData]; }}certTask执⾏完之后,会把timer取消,然后设置默认选中状态。接下来⼏个设置都是使⽤的NSOpenPanel类增加类型⽽已,直接来到resign⽅法:- (IBAction)resign:(id)sender { //Save cert name [defaults setValue:[NSNumber numberWithInteger:[certComboBox indexOfSelectedItem]] forKey:@"CERT_INDEX"]; [defaults setValue:[entitlementField stringValue] forKey:@"ENTITLEMENT_PATH"]; [defaults setValue:[provisioningPathField stringValue] forKey:@"MOBILEPROVISION_PATH"]; [defaults setValue:[bundleIDField stringValue] forKey:kKeyPrefsBundleIDChange]; [defaults synchronize];
codesigningResult = nil; verificationResult = nil; //源ipa路径 sourcePath = [pathField stringValue]; //⼯作区路径 workingPath = [NSTemporaryDirectory() stringByAppendingPathComponent:@"n"];
if ([certComboBox objectValue]) { //重签的对象必须为ipa或者xcarchive⽂件,也就是签名之后的产物 if (([[[sourcePath pathExtension] lowercaseString] isEqualToString:@"ipa"]) || if (([[[sourcePath pathExtension] lowercaseString] isEqualToString:@"ipa"]) || ([[[sourcePath pathExtension] lowercaseString] isEqualToString:@"xcarchive"])) { [self disableControls];
NSLog(@"Setting up working directory in %@",workingPath); [statusLabel setHidden:NO]; [statusLabel setStringValue:@"Setting up working directory"]; //先移除缓存,再创建该路径的⽂件夹 [[NSFileManager defaultManager] removeItemAtPath:workingPath error:nil]; [[NSFileManager defaultManager] createDirectoryAtPath:workingPath withIntermediateDirectories:TRUE attributes:nil error:nil];
if ([[[sourcePath pathExtension] lowercaseString] isEqualToString:@"ipa"]) { if (sourcePath && [sourcePath length] > 0) { NSLog(@"Unzipping %@",sourcePath); [statusLabel setStringValue:@"Extracting original app"]; } //ipa执⾏解压操作,同理结果在checkUnzip unzipTask = [[NSTask alloc] init]; [unzipTask setLaunchPath:@"/usr/bin/unzip"]; [unzipTask setArguments:[NSArray arrayWithObjects:@"-q", sourcePath, @"-d", workingPath, nil]];
[NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(checkUnzip:) userInfo:nil repeats:TRUE];
[unzipTask launch]; } else { //否则为xcarchive,不需要unzip,其他同理 NSString* payloadPath = [workingPath stringByAppendingPathComponent:kPayloadDirName];
if (infoPListDict != nil) { NSString* applicationPath = nil; NSDictionary* applicationPropertiesDict = [infoPListDict objectForKey:kKeyInfoPlistApplicationProperties];
if (applicationPath != nil) { applicationPath = [[sourcePath stringByAppendingPathComponent:kProductsDirName] stringByAppendingPathComponent:applicationPath];
NSLog(@"Copying %@ to %@ path in %@", applicationPath, kPayloadDirName, payloadPath); [statusLabel setStringValue:[NSString stringWithFormat:@"Copying .xcarchive app to %@ path", kPayloadDirName]];
copyTask = [[NSTask alloc] init]; [copyTask setLaunchPath:@"/bin/cp"]; [copyTask setArguments:[NSArray arrayWithObjects:@"-r", applicationPath, payloadPath, nil]];
[NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(checkCopy:) userInfo:nil repeats:TRUE];
[copyTask launch]; } } } } else { [self showAlertOfKind:NSCriticalAlertStyle WithTitle:@"Error" AndMessage:@"You must choose an *.ipa or *.xcarchive file"]; [self enableControls]; [statusLabel setStringValue:@"Please try again"]; } } else { [self showAlertOfKind:NSCriticalAlertStyle WithTitle:@"Error" AndMessage:@"You must choose an signing certificate from dropdown."]; [self enableControls]; [statusLabel setStringValue:@"Please try again"]; }}- (void)checkUnzip:(NSTimer *)timer { if ([unzipTask isRunning] == 0) { [timer invalidate]; unzipTask = nil;
if ([[NSFileManager defaultManager] fileExistsAtPath:[workingPath stringByAppendingPathComponent:kPayloadDirName]]) { NSLog(@"Unzipping done"); [statusLabel setStringValue:@"Original app extracted"];
if ( == NSOnState) { //如果修改了bundleID,则需要将新的bundleID覆盖掉原本中的CFBundleIdentifier [self doBundleIDChange:Value]; } }
if ([[provisioningPathField stringValue] isEqualTo:@""]) { [self doCodeSigning]; } else { //如果本地存在provision,则需要先删除;然后将mobileprovision拷贝到.app路径下 //其中会解析provision,进⾏校验:取出application-identifier对应的内容与的CFBundleIdentifier [self doProvisioning]; } } else { [self showAlertOfKind:NSCriticalAlertStyle WithTitle:@"Error" AndMessage:@"Unzip failed"]; [self enableControls]; [statusLabel setStringValue:@"Ready"]; } }}- (void)doEntitlementsFixing{ //最后调⽤doEntitlementsFixing,如何不存在则直接codesign if (![Value isEqualToString:@""] || [Value isEqualToString:@""]) { [self doCodeSigning]; return; // Using a pre-made entitlements file or we're not re-provisioning. }
[statusLabel setStringValue:@"Generating entitlements"]; //否则security cms -D -i XXX 对Entitlements进⾏修复,最后写⼊到 if (appPath) { generateEntitlementsTask = [[NSTask alloc] init]; [generateEntitlementsTask setLaunchPath:@"/usr/bin/security"]; [generateEntitlementsTask setArguments:@[@"cms", @"-D", @"-i", Value]]; [generateEntitlementsTask setCurrentDirectoryPath:workingPath]; [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(checkEntitlementsFix:) userInfo:nil repeats:TRUE]; NSPipe *pipe=[NSPipe pipe]; [generateEntitlementsTask setStandardOutput:pipe]; [generateEntitlementsTask setStandardError:pipe]; NSFileHandle *handle = [pipe fileHandleForReading]; [generateEntitlementsTask launch]; [NSThread detachNewThreadSelector:@selector(watchEntitlements:) toTarget:self withObject:handle]; }}- (void)doCodeSigning { appPath = nil; frameworksDirPath = nil; hasFrameworks = NO; frameworks = [[NSMutableArray alloc] init];
NSArray *dirContents = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:[workingPath stringByAppendingPathComponent:kPayloadDirName] error:nil];
for (NSString *file in dirContents) { if ([[[file pathExtension] lowercaseString] isEqualToString:@"app"]) { appPath = [[workingPath stringByAppendingPathComponent:kPayloadDirName] stringByAppendingPathComponent:file]; frameworksDirPath = [appPath stringByAppendingPathComponent:kFrameworksDirName]; NSLog(@"Found %@",appPath); appName = file; if ([[NSFileManager defaultManager] fileExistsAtPath:frameworksDirPath]) { NSLog(@"Found %@",frameworksDirPath); hasFrameworks = YES; NSArray *frameworksContents = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:frameworksDirPath error:nil]; for (NSString *frameworkFile in frameworksContents) { //如果存在framework或者dylib,则需要对每⼀个framework中的进⾏更新,并调⽤codesign对库逐⼀进⾏签名 NSString *extension = [[frameworkFile pathExtension] lowercaseString]; if ([extension isEqualTo:@"framework"] || [extension isEqualTo:@"dylib"]) { frameworkPath = [frameworksDirPath stringByAppendingPathComponent:frameworkFile]; NSLog(@"Found %@",frameworkPath); [frameworks addObject:frameworkPath]; } } } } [statusLabel setStringValue:[NSString stringWithFormat:@"Codesigning %@",file]]; break; } }
if (appPath) { if (hasFrameworks) { //然后codesign -v XXX 进⾏校验 //最后校验通过则对ipa进⾏重命名,并zip到原路径下 [self signFile:[frameworks lastObject]]; [frameworks removeLastObject]; } else { //app同理 [self signFile:appPath]; } }}
发布者:admin,转转请注明出处:http://www.yc00.com/news/1688382922a129734.html
评论列表(0条)