Skip to content

Instantly share code, notes, and snippets.

@dlevi309
Forked from DerekSelander/platform_swap.m
Last active October 9, 2023 08:00
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dlevi309/b06e14607e4f7a9d2296145d0734bb32 to your computer and use it in GitHub Desktop.
Save dlevi309/b06e14607e4f7a9d2296145d0734bb32 to your computer and use it in GitHub Desktop.
Exchange Mach-O platform types with min version
//
// main.m
// platform_swap @LOLgrep
//
#import <Foundation/Foundation.h>
#import <mach-o/loader.h>
#define PLATFORM_VISIONOS 11
#define PLATFORM_VISIONOSSIMULATOR 12
struct version {
int fix : 8;
int min : 8;
int max : 16;
};
int main(int argc, const char * argv[]) {
if (argc != 6) {
printf("platform_swap platform_num major minor bugfix (i.e. convert MacOS M1 binary to iOS 10.3.1 -> platform_swap /tmp/afile 2 10 3 1\nSee PLATFORM_* in <mach-o/loader.h>\n");
exit(1);
}
long platform = strtol(argv[2], NULL, 12);
if ( platform < 1 || platform > 12 ) {
printf("Invalid platform number %ld\n", platform);
exit(1);
}
long major = strtol(argv[3], NULL, 12);
long minor = strtol(argv[4], NULL, 12);
long bugfix = strtol(argv[5], NULL, 12);
NSString *file = [NSString stringWithUTF8String:argv[1]];
NSURL *fileURL = [NSURL fileURLWithPath:file];
if (!fileURL) {
printf("Can't find file %s\n", argv[1]);
exit(1);
}
NSMutableData *data = [NSMutableData dataWithContentsOfFile:file];
char *ptr = (void*)[data bytes];
int32_t *magic = (int32_t*)ptr;
if (*magic != MH_MAGIC_64) {
printf("Invalid header file\n");
exit(1);
}
struct mach_header_64 *header = (void*)ptr;
struct load_command *cur = (void*)((uintptr_t)ptr + (uintptr_t)sizeof(struct mach_header_64));
for (int i = 0; i < header->ncmds; i++) {
if (cur->cmd == LC_BUILD_VERSION) {
struct build_version_command*build = (void*)cur;
NSRange platform_range = NSMakeRange((uintptr_t)&build->platform - (uintptr_t)ptr, sizeof(build->platform));
int32_t new_platform = (int)platform;
[data replaceBytesInRange:platform_range withBytes:&new_platform];
NSRange version_range = NSMakeRange((uintptr_t)&build->minos - (uintptr_t)ptr, sizeof(build->minos));
struct version new_version = {(int)bugfix, (int)minor, (int)major};
[data replaceBytesInRange:version_range withBytes:&new_version];
char *platform_name = NULL;
switch (platform) {
case PLATFORM_MACOS:
platform_name = "macos";
break;
case PLATFORM_IOS:
platform_name = "ios";
break;
case PLATFORM_TVOS:
platform_name = "tvos";
break;
case PLATFORM_WATCHOS:
platform_name = "watchos";
break;
case PLATFORM_BRIDGEOS:
platform_name = "bridgeos";
break;
case PLATFORM_MACCATALYST:
platform_name = "maccatalyst";
break;
case PLATFORM_IOSSIMULATOR:
platform_name = "iossimulator";
break;
case PLATFORM_TVOSSIMULATOR:
platform_name = "tvossimulator";
break;
case PLATFORM_WATCHOSSIMULATOR:
platform_name = "watchossimulator";
break;
case PLATFORM_DRIVERKIT:
platform_name = "driverkit";
break;
case PLATFORM_VISIONOS:
platform_name = "visionos";
break;
case PLATFORM_VISIONOSSIMULATOR:
platform_name = "visionossimulator";
break;
default:
break;
}
NSString *resolvedString = [NSString stringWithFormat:@"%@_%s", file, platform_name];
[data writeToFile:resolvedString atomically:YES];
printf("written to \"%s\"\n", resolvedString.UTF8String);
exit(0);
}
cur = (void*)(cur->cmdsize + (uintptr_t)cur);
}
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment