Files
khanhduytran0 ec04885ce5 Feat: patch dylib for game dlopen calls
Now that game can directly load macOS's JNA native library,
libjnidispatch is removed.
2024-06-09 21:53:15 +07:00

71 lines
2.7 KiB
Objective-C

#import <Foundation/Foundation.h>
#include <libgen.h>
#include <mach-o/fat.h>
#include <mach-o/loader.h>
#include <sys/mman.h>
#include <sys/stat.h>
extern int dyld_get_active_platform();
static BOOL PLPatchMachOPlatformForSlice(const char *path, struct mach_header_64 *header) {
uint8_t *imageHeaderPtr = (uint8_t*)header + sizeof(struct mach_header_64);
struct load_command *command = (struct load_command *)imageHeaderPtr;
for(int i = 0; i < header->ncmds; i++) {
if (command->cmd == LC_BUILD_VERSION) {
struct build_version_command *buildver = (struct build_version_command *)command;
int activePlatform = dyld_get_active_platform();
if (buildver->platform == activePlatform) return NO; // it is already set, stop
buildver->platform = activePlatform; // set to current platform
} else if (command->cmd == LC_LOAD_DYLIB) {
struct dylib_command *dylib = (struct dylib_command *)command;
char *dylibName = (void *)dylib + dylib->dylib.name.offset;
char *verPtr = strstr(dylibName, "/Versions/");
if (verPtr) {
// Remove "/Versions/X"
int lastComponentLen = strlen(dylibName) - (verPtr - dylibName) - 11;
memmove(verPtr, verPtr + 11, lastComponentLen);
verPtr[lastComponentLen] = '\0';
}
}
command = (struct load_command *)((void *)command + command->cmdsize);
}
return YES;
}
BOOL PLPatchMachOPlatformForFile(const char *path) {
int fd = open(path, O_RDWR, (mode_t)0600);
if (fd == -1) return NO;
struct stat s;
fstat(fd, &s);
void *map = mmap(NULL, s.st_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (!map) {
close(fd);
return NO;
}
BOOL patched = NO;
uint32_t magic = *(uint32_t *)map;
if (magic == FAT_CIGAM) {
// Find compatible slice
struct fat_header *header = (struct fat_header *)map;
struct fat_arch *arch = (struct fat_arch *)(map + sizeof(struct fat_header));
for (int i = 0; i < OSSwapInt32(header->nfat_arch); i++) {
if (OSSwapInt32(arch->cputype) == CPU_TYPE_ARM64) {
NSLog(@"[PojavLauncher] Patching %s", path);
patched |= PLPatchMachOPlatformForSlice(path, (struct mach_header_64 *)(map + OSSwapInt32(arch->offset)));
}
arch = (struct fat_arch *)((void *)arch + sizeof(struct fat_arch));
}
} else if (magic == MH_MAGIC_64 && ((struct mach_header_64 *)map)->cputype == CPU_TYPE_ARM64) {
patched = PLPatchMachOPlatformForSlice(path, (struct mach_header_64 *)map);
}
if (patched) msync(map, s.st_size, MS_SYNC);
munmap(map, s.st_size);
close(fd);
return patched;
}