mirror of
				https://github.com/opa334/TrollStore.git
				synced 2025-11-04 15:42:35 +08:00 
			
		
		
		
	Merge pull request #63 from luken11/signing-fast-path
Add fast path for apps that are already signed with a custom root
This commit is contained in:
		
						commit
						a0dc58a4c0
					
				
							
								
								
									
										355
									
								
								Helper/main.m
									
									
									
									
									
								
							
							
						
						
									
										355
									
								
								Helper/main.m
									
									
									
									
									
								
							@ -8,53 +8,10 @@
 | 
				
			|||||||
#import <objc/runtime.h>
 | 
					#import <objc/runtime.h>
 | 
				
			||||||
#import "CoreServices.h"
 | 
					#import "CoreServices.h"
 | 
				
			||||||
#import "Shared.h"
 | 
					#import "Shared.h"
 | 
				
			||||||
#import <mach-o/getsect.h>
 | 
					 | 
				
			||||||
#import <mach-o/dyld.h>
 | 
					 | 
				
			||||||
#import <mach/mach.h>
 | 
					 | 
				
			||||||
#import <mach-o/loader.h>
 | 
					 | 
				
			||||||
#import <mach-o/nlist.h>
 | 
					 | 
				
			||||||
#import <mach-o/reloc.h>
 | 
					 | 
				
			||||||
#import <mach-o/dyld_images.h>
 | 
					 | 
				
			||||||
#import <mach-o/fat.h>
 | 
					 | 
				
			||||||
#import <sys/utsname.h>
 | 
					#import <sys/utsname.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#import <SpringBoardServices/SpringBoardServices.h>
 | 
					#import <SpringBoardServices/SpringBoardServices.h>
 | 
				
			||||||
 | 
					#import <Security/Security.h>
 | 
				
			||||||
#ifdef __LP64__
 | 
					 | 
				
			||||||
#define segment_command_universal segment_command_64
 | 
					 | 
				
			||||||
#define mach_header_universal mach_header_64
 | 
					 | 
				
			||||||
#define MH_MAGIC_UNIVERSAL MH_MAGIC_64
 | 
					 | 
				
			||||||
#define MH_CIGAM_UNIVERSAL MH_CIGAM_64
 | 
					 | 
				
			||||||
#else
 | 
					 | 
				
			||||||
#define segment_command_universal segment_command
 | 
					 | 
				
			||||||
#define mach_header_universal mach_header
 | 
					 | 
				
			||||||
#define MH_MAGIC_UNIVERSAL MH_MAGIC
 | 
					 | 
				
			||||||
#define MH_CIGAM_UNIVERSAL MH_CIGAM
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#define SWAP32(x) ((((x) & 0xff000000) >> 24) | (((x) & 0xff0000) >> 8) | (((x) & 0xff00) << 8) | (((x) & 0xff) << 24))
 | 
					 | 
				
			||||||
uint32_t s32(uint32_t toSwap, BOOL shouldSwap)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	return shouldSwap ? SWAP32(toSwap) : toSwap;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#define CPU_SUBTYPE_ARM64E_NEW_ABI 0x80000002
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
struct CSSuperBlob {
 | 
					 | 
				
			||||||
	uint32_t magic;
 | 
					 | 
				
			||||||
	uint32_t length;
 | 
					 | 
				
			||||||
	uint32_t count;
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
struct CSBlob {
 | 
					 | 
				
			||||||
	uint32_t type;
 | 
					 | 
				
			||||||
	uint32_t offset;
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#define CS_MAGIC_EMBEDDED_SIGNATURE 0xfade0cc0
 | 
					 | 
				
			||||||
#define CS_MAGIC_EMBEDDED_SIGNATURE_REVERSED 0xc00cdefa
 | 
					 | 
				
			||||||
#define CS_MAGIC_EMBEDDED_ENTITLEMENTS 0xfade7171
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
extern mach_msg_return_t SBReloadIconForIdentifier(mach_port_t machport, const char* identifier);
 | 
					extern mach_msg_return_t SBReloadIconForIdentifier(mach_port_t machport, const char* identifier);
 | 
				
			||||||
@interface SBSHomeScreenService : NSObject
 | 
					@interface SBSHomeScreenService : NSObject
 | 
				
			||||||
@ -65,6 +22,26 @@ extern NSString* BKSOpenApplicationOptionKeyActivateForEvent;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
extern void BKSTerminateApplicationForReasonAndReportWithDescription(NSString *bundleID, int reasonID, bool report, NSString *description);
 | 
					extern void BKSTerminateApplicationForReasonAndReportWithDescription(NSString *bundleID, int reasonID, bool report, NSString *description);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef CF_OPTIONS(uint32_t, SecCSFlags) {
 | 
				
			||||||
 | 
					    kSecCSDefaultFlags = 0
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define kSecCSRequirementInformation 1 << 2
 | 
				
			||||||
 | 
					#define kSecCSSigningInformation 1 << 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef struct __SecCode const *SecStaticCodeRef;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extern CFStringRef kSecCodeInfoEntitlementsDict;
 | 
				
			||||||
 | 
					extern CFStringRef kSecCodeInfoCertificates;
 | 
				
			||||||
 | 
					extern CFStringRef kSecPolicyAppleiPhoneApplicationSigning;
 | 
				
			||||||
 | 
					extern CFStringRef kSecPolicyLeafMarkerOid;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					OSStatus SecStaticCodeCreateWithPathAndAttributes(CFURLRef path, SecCSFlags flags, CFDictionaryRef attributes, SecStaticCodeRef *staticCode);
 | 
				
			||||||
 | 
					OSStatus SecCodeCopySigningInformation(SecStaticCodeRef code, SecCSFlags flags, CFDictionaryRef *information);
 | 
				
			||||||
 | 
					CFDataRef SecCertificateCopyExtensionValue(SecCertificateRef certificate, CFTypeRef extensionOID, bool *isCritical);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define kCFPreferencesNoContainer CFSTR("kCFPreferencesNoContainer")
 | 
					#define kCFPreferencesNoContainer CFSTR("kCFPreferencesNoContainer")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
typedef CFPropertyListRef (*_CFPreferencesCopyValueWithContainerType)(CFStringRef key, CFStringRef applicationID, CFStringRef userName, CFStringRef hostName, CFStringRef containerPath);
 | 
					typedef CFPropertyListRef (*_CFPreferencesCopyValueWithContainerType)(CFStringRef key, CFStringRef applicationID, CFStringRef userName, CFStringRef hostName, CFStringRef containerPath);
 | 
				
			||||||
@ -221,118 +198,189 @@ int runLdid(NSArray* args, NSString** output, NSString** errorOutput)
 | 
				
			|||||||
	return WEXITSTATUS(status);
 | 
						return WEXITSTATUS(status);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
NSDictionary* dumpEntitlements(NSString* binaryPath)
 | 
					SecStaticCodeRef getStaticCodeRef(NSString *binaryPath)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	char* entitlementsData = NULL;
 | 
					 | 
				
			||||||
	uint32_t entitlementsLength = 0;
 | 
					 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
	FILE* machoFile = fopen(binaryPath.UTF8String, "rb");
 | 
					    if(binaryPath == nil)
 | 
				
			||||||
	struct mach_header_universal header;
 | 
					    {
 | 
				
			||||||
	fread(&header,sizeof(header),1,machoFile);
 | 
					        return NULL;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
	uint32_t archOffset = 0;
 | 
					    CFURLRef binaryURL = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, (__bridge CFStringRef)binaryPath, kCFURLPOSIXPathStyle, false);
 | 
				
			||||||
 | 
					    if(binaryURL == NULL)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        NSLog(@"[getStaticCodeRef] failed to get URL to binary %@", binaryPath);
 | 
				
			||||||
 | 
					        return NULL;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
	// Get arch offset if FAT binary
 | 
					    SecStaticCodeRef codeRef = NULL;
 | 
				
			||||||
	if(header.magic == FAT_MAGIC || header.magic == FAT_CIGAM)
 | 
					    OSStatus result;
 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		fseek(machoFile,0,SEEK_SET);
 | 
					 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
		struct fat_header fatHeader;
 | 
					    result = SecStaticCodeCreateWithPathAndAttributes(binaryURL, kSecCSDefaultFlags, NULL, &codeRef);
 | 
				
			||||||
		fread(&fatHeader,sizeof(fatHeader),1,machoFile);
 | 
					 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
		BOOL swpFat = fatHeader.magic == FAT_CIGAM;
 | 
					    CFRelease(binaryURL);
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
		for(int i = 0; i < s32(fatHeader.nfat_arch, swpFat); i++)
 | 
					    if(result != errSecSuccess)
 | 
				
			||||||
		{
 | 
					    {
 | 
				
			||||||
			struct fat_arch fatArch;
 | 
					        NSLog(@"[getStaticCodeRef] failed to create static code for binary %@", binaryPath);
 | 
				
			||||||
			fseek(machoFile,sizeof(fatHeader) + sizeof(fatArch) * i,SEEK_SET);
 | 
					        return NULL;
 | 
				
			||||||
			fread(&fatArch,sizeof(fatArch),1,machoFile);
 | 
					    }
 | 
				
			||||||
        
 | 
					        
 | 
				
			||||||
			if(s32(fatArch.cputype, swpFat) != CPU_TYPE_ARM64)
 | 
					    return codeRef;
 | 
				
			||||||
			{
 | 
					}
 | 
				
			||||||
				continue;
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
			archOffset = s32(fatArch.offset, swpFat);
 | 
					NSDictionary* dumpEntitlements(SecStaticCodeRef codeRef)
 | 
				
			||||||
			break;
 | 
					{
 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
	fseek(machoFile,archOffset,SEEK_SET);
 | 
					    if(codeRef == NULL)
 | 
				
			||||||
	fread(&header,sizeof(header),1,machoFile);
 | 
					    {
 | 
				
			||||||
 | 
					        NSLog(@"[dumpEntitlements] attempting to dump entitlements without a StaticCodeRef");
 | 
				
			||||||
 | 
					        return nil;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
	if(header.magic == MH_MAGIC_UNIVERSAL || header.magic == MH_CIGAM_UNIVERSAL)
 | 
					    CFDictionaryRef signingInfo = NULL;
 | 
				
			||||||
	{
 | 
					    OSStatus result;
 | 
				
			||||||
		BOOL swp = header.magic == MH_CIGAM_UNIVERSAL;
 | 
					 | 
				
			||||||
		// This code is cursed, don't stare at it too long or it will stare back at you
 | 
					 | 
				
			||||||
		uint32_t offset = archOffset + sizeof(header);
 | 
					 | 
				
			||||||
		for(int c = 0; c < s32(header.ncmds, swp); c++)
 | 
					 | 
				
			||||||
		{
 | 
					 | 
				
			||||||
			fseek(machoFile,offset,SEEK_SET);
 | 
					 | 
				
			||||||
			struct load_command cmd;
 | 
					 | 
				
			||||||
			fread(&cmd,sizeof(cmd),1,machoFile);
 | 
					 | 
				
			||||||
			uint32_t normalizedCmd = s32(cmd.cmd,swp);
 | 
					 | 
				
			||||||
			if(normalizedCmd == LC_CODE_SIGNATURE)
 | 
					 | 
				
			||||||
			{
 | 
					 | 
				
			||||||
				struct linkedit_data_command codeSignCommand;
 | 
					 | 
				
			||||||
				fseek(machoFile,offset,SEEK_SET);
 | 
					 | 
				
			||||||
				fread(&codeSignCommand,sizeof(codeSignCommand),1,machoFile);
 | 
					 | 
				
			||||||
				uint32_t codeSignCmdOffset = archOffset + s32(codeSignCommand.dataoff, swp);
 | 
					 | 
				
			||||||
				fseek(machoFile, codeSignCmdOffset, SEEK_SET);
 | 
					 | 
				
			||||||
				struct CSSuperBlob superBlob;
 | 
					 | 
				
			||||||
				fread(&superBlob, sizeof(superBlob), 1, machoFile);
 | 
					 | 
				
			||||||
				if(SWAP32(superBlob.magic) == CS_MAGIC_EMBEDDED_SIGNATURE) // YES starting here everything is swapped no matter if CIGAM or MAGIC...
 | 
					 | 
				
			||||||
				{
 | 
					 | 
				
			||||||
					uint32_t itemCount = SWAP32(superBlob.count);
 | 
					 | 
				
			||||||
					for(int i = 0; i < itemCount; i++)
 | 
					 | 
				
			||||||
					{
 | 
					 | 
				
			||||||
						fseek(machoFile, codeSignCmdOffset + sizeof(superBlob) + i * sizeof(struct CSBlob),SEEK_SET);
 | 
					 | 
				
			||||||
						struct CSBlob blob;
 | 
					 | 
				
			||||||
						fread(&blob, sizeof(struct CSBlob), 1, machoFile);
 | 
					 | 
				
			||||||
						fseek(machoFile, codeSignCmdOffset + SWAP32(blob.offset),SEEK_SET);
 | 
					 | 
				
			||||||
						uint32_t blobMagic;
 | 
					 | 
				
			||||||
						fread(&blobMagic, sizeof(uint32_t), 1, machoFile);
 | 
					 | 
				
			||||||
						if(SWAP32(blobMagic) == CS_MAGIC_EMBEDDED_ENTITLEMENTS)
 | 
					 | 
				
			||||||
						{
 | 
					 | 
				
			||||||
							uint32_t entitlementsLengthTmp;
 | 
					 | 
				
			||||||
							fread(&entitlementsLengthTmp, sizeof(uint32_t), 1, machoFile);
 | 
					 | 
				
			||||||
							entitlementsLength = SWAP32(entitlementsLengthTmp);
 | 
					 | 
				
			||||||
							entitlementsData = malloc(entitlementsLength - 8);
 | 
					 | 
				
			||||||
							fread(&entitlementsData[0], entitlementsLength - 8, 1, machoFile);
 | 
					 | 
				
			||||||
							break;
 | 
					 | 
				
			||||||
						}
 | 
					 | 
				
			||||||
					}
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
				break;
 | 
					    result = SecCodeCopySigningInformation(codeRef, kSecCSRequirementInformation, &signingInfo);
 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
			offset += cmd.cmdsize;
 | 
					    if(result != errSecSuccess)
 | 
				
			||||||
		}
 | 
					    {
 | 
				
			||||||
	}
 | 
					        NSLog(@"[dumpEntitlements] failed to copy signing info from static code");
 | 
				
			||||||
 | 
					        return nil;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
	fclose(machoFile);
 | 
					    NSDictionary *entitlementsNSDict = nil;
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
	NSData* entitlementsNSData = nil;
 | 
					    CFDictionaryRef entitlements = CFDictionaryGetValue(signingInfo, kSecCodeInfoEntitlementsDict);
 | 
				
			||||||
 | 
					    if(entitlements == NULL)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        NSLog(@"[dumpEntitlements] no entitlements specified");
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    else if(CFGetTypeID(entitlements) != CFDictionaryGetTypeID())
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        NSLog(@"[dumpEntitlements] invalid entitlements");
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    else
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        entitlementsNSDict = (__bridge NSDictionary *)(entitlements);
 | 
				
			||||||
 | 
					        NSLog(@"[dumpEntitlements] dumped %@", entitlementsNSDict);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
	if(entitlementsData)
 | 
					    CFRelease(signingInfo);
 | 
				
			||||||
	{
 | 
					    return entitlementsNSDict;
 | 
				
			||||||
		entitlementsNSData = [NSData dataWithBytes:entitlementsData length:entitlementsLength];
 | 
					}
 | 
				
			||||||
		free(entitlementsData);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if(entitlementsNSData)
 | 
					NSDictionary* dumpEntitlementsFromBinaryAtPath(NSString *binaryPath)
 | 
				
			||||||
	{
 | 
					{
 | 
				
			||||||
		NSDictionary* plist = [NSPropertyListSerialization propertyListWithData:entitlementsNSData options:NSPropertyListImmutable format:nil error:nil];
 | 
					    // This function is intended for one-shot checks. Main-event functions should retain/release their own SecStaticCodeRefs
 | 
				
			||||||
		NSLog(@"%@ dumped entitlements %@", binaryPath, plist);
 | 
					 | 
				
			||||||
		return plist;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	else
 | 
					 | 
				
			||||||
	{
 | 
					 | 
				
			||||||
		NSLog(@"Failed to dump entitlements of %@... This is bad", binaryPath);
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
	return nil;
 | 
					    if(binaryPath == nil)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return nil;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    SecStaticCodeRef codeRef = getStaticCodeRef(binaryPath);
 | 
				
			||||||
 | 
					    if(codeRef == NULL)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        return nil;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    NSDictionary *entitlements = dumpEntitlements(codeRef);
 | 
				
			||||||
 | 
					    CFRelease(codeRef);
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    return entitlements;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					BOOL certificateHasDataForExtensionOID(SecCertificateRef certificate, CFStringRef oidString)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    if(certificate == NULL || oidString == NULL)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        NSLog(@"[certificateHasDataForExtensionOID] attempted to check null certificate or OID");
 | 
				
			||||||
 | 
					        return NO;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    CFDataRef extensionData = SecCertificateCopyExtensionValue(certificate, oidString, NULL);
 | 
				
			||||||
 | 
					    if(extensionData != NULL)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        CFRelease(extensionData);
 | 
				
			||||||
 | 
					        return YES;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    return NO;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					BOOL codeCertChainContainsFakeAppStoreExtensions(SecStaticCodeRef codeRef)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    if(codeRef == NULL)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        NSLog(@"[codeCertChainContainsFakeAppStoreExtensions] attempted to check cert chain of null static code object");
 | 
				
			||||||
 | 
					        return NO;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    CFDictionaryRef signingInfo = NULL;
 | 
				
			||||||
 | 
					    OSStatus result;
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					    result = SecCodeCopySigningInformation(codeRef, kSecCSSigningInformation, &signingInfo);
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    if(result != errSecSuccess)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        NSLog(@"[codeCertChainContainsFakeAppStoreExtensions] failed to copy signing info from static code");
 | 
				
			||||||
 | 
					        return NO;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    CFArrayRef certificates = CFDictionaryGetValue(signingInfo, kSecCodeInfoCertificates);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // If we match the standard Apple policy, we are signed properly, but we haven't been deliberately signed with a custom root
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    SecPolicyRef genuineApplePolicy = SecPolicyCreateWithProperties(kSecPolicyAppleiPhoneApplicationSigning, NULL);
 | 
				
			||||||
 | 
					    SecTrustRef genuineAppleTrust = NULL;
 | 
				
			||||||
 | 
					    SecTrustCreateWithCertificates(certificates, genuineApplePolicy, &genuineAppleTrust);
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    if(SecTrustEvaluateWithError(genuineAppleTrust, nil))
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        CFRelease(genuineAppleTrust);
 | 
				
			||||||
 | 
					        CFRelease(genuineApplePolicy);
 | 
				
			||||||
 | 
					        CFRelease(signingInfo);
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        NSLog(@"[codeCertChainContainsFakeAppStoreExtensions] found certificate extension, but was issued by Apple");
 | 
				
			||||||
 | 
					        return NO;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    // We haven't matched Apple, so keep going. Are we using a custom root that would take the App Store fastpath?
 | 
				
			||||||
 | 
					    CFRelease(genuineAppleTrust);
 | 
				
			||||||
 | 
					    CFRelease(genuineApplePolicy);
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    // Cert chain should be of length 3
 | 
				
			||||||
 | 
					    if(CFArrayGetCount(certificates) != 3)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        CFRelease(signingInfo);
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        NSLog(@"[codeCertChainContainsFakeAppStoreExtensions] certificate chain length != 3");
 | 
				
			||||||
 | 
					        return NO;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    const void *keys[1] = { kSecPolicyLeafMarkerOid };
 | 
				
			||||||
 | 
					    const void *values[1] = { CFSTR("1.2.840.113635.100.6.1.3") };
 | 
				
			||||||
 | 
					    CFDictionaryRef customPolicyOptions = CFDictionaryCreate(NULL, keys, values, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    // AppleCodeSigning only checks for the codeSigning EKU by default
 | 
				
			||||||
 | 
					    SecPolicyRef customRootPolicy = SecPolicyCreateWithProperties(kSecPolicyAppleCodeSigning, customPolicyOptions);
 | 
				
			||||||
 | 
					    SecTrustRef customRootTrust = NULL;
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    // Need to add our certificate chain to the anchor as it is expected to be a self-signed root
 | 
				
			||||||
 | 
					    SecTrustCreateWithCertificates(certificates, customRootPolicy, &customRootTrust);
 | 
				
			||||||
 | 
					    SecTrustSetAnchorCertificates(customRootTrust, certificates);
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    BOOL evaluatesToCustomAnchor = SecTrustEvaluateWithError(customRootTrust, nil);
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    CFRelease(customRootTrust);
 | 
				
			||||||
 | 
					    CFRelease(customRootPolicy);
 | 
				
			||||||
 | 
					    CFRelease(customPolicyOptions);
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    CFRelease(signingInfo);
 | 
				
			||||||
 | 
					    return evaluatesToCustomAnchor;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
BOOL signApp(NSString* appPath, NSError** error)
 | 
					BOOL signApp(NSString* appPath, NSError** error)
 | 
				
			||||||
@ -347,12 +395,41 @@ BOOL signApp(NSString* appPath, NSError** error)
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	if(![[NSFileManager defaultManager] fileExistsAtPath:executablePath]) return NO;
 | 
						if(![[NSFileManager defaultManager] fileExistsAtPath:executablePath]) return NO;
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
 | 
					    NSObject *tsBundleIsPreSigned = appInfoDict[@"TSBundlePreSigned"];
 | 
				
			||||||
 | 
					    if([tsBundleIsPreSigned isKindOfClass:[NSNumber class]])
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        // if TSBundlePreSigned = YES, this bundle has been externally signed so we can skip over signing it now
 | 
				
			||||||
 | 
					        NSNumber *tsBundleIsPreSignedNum = (NSNumber *)tsBundleIsPreSigned;
 | 
				
			||||||
 | 
					        if([tsBundleIsPreSignedNum boolValue] == YES)
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            NSLog(@"[signApp] taking fast path for app which declares it has already been signed (%@)", executablePath);
 | 
				
			||||||
 | 
					            return YES;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    SecStaticCodeRef codeRef = getStaticCodeRef(executablePath);
 | 
				
			||||||
 | 
					    if(codeRef == NULL)
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        NSLog(@"[signApp] failed to get static code, can't derive entitlements from %@", executablePath);
 | 
				
			||||||
 | 
					        return NO;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
 | 
					    if(codeCertChainContainsFakeAppStoreExtensions(codeRef))
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        NSLog(@"[signApp] taking fast path for app signed using a custom root certificate (%@)", executablePath);
 | 
				
			||||||
 | 
					        CFRelease(codeRef);
 | 
				
			||||||
 | 
					        return YES;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	NSString* certPath = [trollStoreAppPath() stringByAppendingPathComponent:@"cert.p12"];
 | 
						NSString* certPath = [trollStoreAppPath() stringByAppendingPathComponent:@"cert.p12"];
 | 
				
			||||||
	NSString* certArg = [@"-K" stringByAppendingPathComponent:certPath];
 | 
						NSString* certArg = [@"-K" stringByAppendingPathComponent:certPath];
 | 
				
			||||||
	NSString* errorOutput;
 | 
						NSString* errorOutput;
 | 
				
			||||||
	int ldidRet;
 | 
						int ldidRet;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	NSDictionary* entitlements = dumpEntitlements(executablePath);
 | 
					    NSDictionary* entitlements = dumpEntitlements(codeRef);
 | 
				
			||||||
 | 
					    CFRelease(codeRef);
 | 
				
			||||||
 | 
					    
 | 
				
			||||||
	if(!entitlements)
 | 
						if(!entitlements)
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		NSLog(@"app main binary has no entitlements, signing app with fallback entitlements...");
 | 
							NSLog(@"app main binary has no entitlements, signing app with fallback entitlements...");
 | 
				
			||||||
 | 
				
			|||||||
@ -6,7 +6,7 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
// uicache on steroids
 | 
					// uicache on steroids
 | 
				
			||||||
 | 
					
 | 
				
			||||||
extern NSDictionary* dumpEntitlements(NSString* binaryPath);
 | 
					extern NSDictionary* dumpEntitlementsFromBinaryAtPath(NSString* binaryPath);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
NSDictionary* constructGroupsContainersForEntitlements(NSDictionary* entitlements, BOOL systemGroups)
 | 
					NSDictionary* constructGroupsContainersForEntitlements(NSDictionary* entitlements, BOOL systemGroups)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
@ -118,7 +118,7 @@ void registerPath(char* cPath, int unregister)
 | 
				
			|||||||
		// Add entitlements
 | 
							// Add entitlements
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		NSString* appExecutablePath = [path stringByAppendingPathComponent:appInfoPlist[@"CFBundleExecutable"]];
 | 
							NSString* appExecutablePath = [path stringByAppendingPathComponent:appInfoPlist[@"CFBundleExecutable"]];
 | 
				
			||||||
		NSDictionary* entitlements = dumpEntitlements(appExecutablePath);
 | 
							NSDictionary* entitlements = dumpEntitlementsFromBinaryAtPath(appExecutablePath);
 | 
				
			||||||
		if(entitlements)
 | 
							if(entitlements)
 | 
				
			||||||
		{
 | 
							{
 | 
				
			||||||
			dictToRegister[@"Entitlements"] = entitlements;
 | 
								dictToRegister[@"Entitlements"] = entitlements;
 | 
				
			||||||
@ -188,7 +188,7 @@ void registerPath(char* cPath, int unregister)
 | 
				
			|||||||
			// Add entitlements
 | 
								// Add entitlements
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			NSString* pluginExecutablePath = [pluginPath stringByAppendingPathComponent:pluginInfoPlist[@"CFBundleExecutable"]];
 | 
								NSString* pluginExecutablePath = [pluginPath stringByAppendingPathComponent:pluginInfoPlist[@"CFBundleExecutable"]];
 | 
				
			||||||
			NSDictionary* pluginEntitlements = dumpEntitlements(pluginExecutablePath);
 | 
								NSDictionary* pluginEntitlements = dumpEntitlementsFromBinaryAtPath(pluginExecutablePath);
 | 
				
			||||||
			if(pluginEntitlements)
 | 
								if(pluginEntitlements)
 | 
				
			||||||
			{
 | 
								{
 | 
				
			||||||
				pluginDict[@"Entitlements"] = pluginEntitlements;
 | 
									pluginDict[@"Entitlements"] = pluginEntitlements;
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
		Reference in New Issue
	
	Block a user