Skip to content

Instantly share code, notes, and snippets.

@wh1te4ever
Created June 12, 2023 17:50
Show Gist options
  • Save wh1te4ever/36ab42dd81095be4c5f42887485e93c8 to your computer and use it in GitHub Desktop.
Save wh1te4ever/36ab42dd81095be4c5f42887485e93c8 to your computer and use it in GitHub Desktop.
Patch platform of build_version_command to iPhoneOS!
#import <Foundation/Foundation.h>
#include <stdio.h>
#include <string>
#include <mach-o/loader.h>
#include <mach-o/fat.h>
#include <mach/machine.h>
#include <iostream>
#include <cstdlib>
#include <new>
#include <spawn.h>
//How to Compile
// clang++ -o patch_iphoneos patch.mm -framework Foundation
//How to Patch
// ./patch_iphoneos <binary>
uint32_t swap_uint32(uint32_t val) {
val = ((val << 8) & 0xFF00FF00) | ((val >> 8) & 0xFF00FF);
return (val << 16) | (val >> 16);
}
uint64_t swap_uint64(uint64_t val) {
val = ((val << 8) & 0xFF00FF00FF00FF00ULL) | ((val >> 8) & 0x00FF00FF00FF00FFULL);
val = ((val << 16) & 0xFFFF0000FFFF0000ULL) | ((val >> 16) & 0x0000FFFF0000FFFFULL);
return (val << 32) | (val >> 32);
}
bool patch_build_version_command(const char* filepath) {
static struct {
build_version_command cmd;
build_tool_version tool_ver;
} buildVersionForSimulator = {LC_BUILD_VERSION, 0x20, 7, 0xE0000, 0xE0200, 1, 3, 0x2610700};
FILE* file = fopen(filepath, "r+b");
if (!file) {
printf("[-] error: failed to open file\n");
return false;
}
fseek(file, 0, SEEK_END);
long fileSize = ftell(file);
fseek(file, 0, SEEK_SET);
char* buffer = new char[fileSize];
size_t readLen = fread(buffer, 1, fileSize, file);
mach_header_64* header = (mach_header_64*)buffer;
if (header->magic == FAT_CIGAM_64 || header->magic == FAT_CIGAM) {
fat_header* fat = (fat_header*)buffer;
if (swap_uint32(fat->nfat_arch) != 1) {
printf("[-] error: App has fat macho with more than one architecture? (%d)\n", fat->nfat_arch);
delete[] buffer;
fclose(file);
return false;
}
cpu_type_t cputype;
uint64_t offset;
if (header->magic == FAT_CIGAM_64) {
fat_arch_64* farch64 = (fat_arch_64*)(buffer + sizeof(fat_header));
cputype = swap_uint32(farch64->cputype);
offset = swap_uint64(farch64->offset);
} else {
fat_arch* farch = (fat_arch*)(buffer + sizeof(fat_header));
cputype = swap_uint32(farch->cputype);
offset = swap_uint32(farch->offset);
}
if (cputype != CPU_TYPE_ARM64) {
printf("[-] error: iOS App has macho with wrong cputype:0x%x\n", cputype);
delete[] buffer;
fclose(file);
return false;
}
if (offset > fileSize) {
printf("[-] error: huge fat arch offset 0x%llx > 0x%lx\n", offset, fileSize);
delete[] buffer;
fclose(file);
return false;
}
header = (mach_header_64*)(buffer + offset);
}
if (header->magic != MH_MAGIC_64) {
printf("[-] error: not a valid macho file\n");
delete[] buffer;
fclose(file);
return false;
}
struct load_command* lc = (load_command*)((mach_vm_address_t)header + sizeof(mach_header_64));
bool found_build_version_command = false;
for (uint32_t i = 0; i < header->ncmds; i++) {
if (lc->cmd == LC_BUILD_VERSION) {
build_version_command* buildCmd = (build_version_command*)lc;
printf("[+] Platform: %u\n", buildCmd->platform);
found_build_version_command = true;
printf("[+] Found platform of build version command at offset: 0x%llx\n", (mach_vm_address_t)lc + offsetof(struct build_version_command, platform) - (mach_vm_address_t)header);
uint32_t platform_ios = 2;
memcpy((char*)lc + offsetof(struct build_version_command, platform), &platform_ios, sizeof(uint32_t));
break;
}
lc = (struct load_command*)((mach_vm_address_t)lc + lc->cmdsize);
}
if (!found_build_version_command) {
printf("[-] error: LC_BUILD_VERSION command not found\n");
delete[] buffer;
fclose(file);
return false;
}
fseek(file, 0, SEEK_SET);
fwrite(buffer, 1, fileSize, file);
delete[] buffer;
fclose(file);
return true;
}
void unzip(char* zippath, char *outputDir) {
pid_t pid;
int status;
const char* args[] = {"unzip", "-o", zippath, "-d", outputDir, NULL};
posix_spawn(&pid, "/usr/bin/unzip", NULL, NULL, (char* const*)args, NULL);
waitpid(pid, &status, 0);
}
void modify_library_path(char* bin, char* from, char* to) {
pid_t pid;
int status;
const char* args[] = {"install_name_tool", "-change", from, to, bin, NULL};
posix_spawn(&pid, "/usr/bin/install_name_tool", NULL, NULL, (char* const*)args, NULL);
waitpid(pid, &status, 0);
}
void sign(char* bin, char* ent) {
pid_t pid;
int status;
char ent_arg[16] = "-S";
strcat(ent_arg, ent);
const char* args[] = {"ldid", ent_arg, bin, NULL};
posix_spawn(&pid, "/usr/local/bin/ldid", NULL, NULL, (char* const*)args, NULL);
waitpid(pid, &status, 0);
}
void create_ent(char *outputPath) {
NSMutableDictionary *plistDict = [NSMutableDictionary dictionary];
// Add the key-value pairs to the dictionary
[plistDict setObject:@YES forKey:@"platform-application"];
[plistDict setObject:@YES forKey:@"com.apple.private.security.no-container"];
[plistDict setObject:@YES forKey:@"com.apple.private.skip-library-validation"];
// Create a property list object
NSError *error = nil;
NSData *plistData = [NSPropertyListSerialization dataWithPropertyList:plistDict format:NSPropertyListXMLFormat_v1_0 options:0 error:nil];
[plistData writeToFile:[NSString stringWithUTF8String: outputPath] atomically:YES];
}
void cleanup() {
}
int main(int argc, const char* argv[]) {
if (!patch_build_version_command(argv[1])) {
return 1;
}
printf("[+] Patch applied successfully!\n");
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment