Unity版本变化
新版 Unity 打包 iOS 版本后,Unity 编写的代码会编译生成一个名为 UnityFramework.framework
的 Framework
,存放在 xxx.app/Frameworks
目录下:
而 Unity 老版本打包的不会:
获取基址
使用 Unity 开发的手游,我们一般会使用 IDA 和 Il2CppDumper 分析出我们需要的函数虚拟内存地址后,调用 MSHookFunction
函数进行注入。
但是新版本 Unity 打包生成的二进制位置发生变化,这就会涉及动态库加载顺序和基址的问题。(这里说的二进制文件就是指 Mach-O
文件,也叫 image
或 镜像)。
在 iOS 中一般加载的第一个镜像就是 APP 的默认镜像,我们获取默认镜像的偏移基址,可以直接用下面方式:
_dyld_get_image_vmaddr_slide(0);
如果要获取指定镜像的偏移基址,就需要遍历加载的所有镜像,找到我们要获取的镜像:
intptr_t get_image_vmaddr_slide(const char * image_name) {
uint32_t count = _dyld_image_count();
for (int i = 0; i < count; i++) {
const char *path = _dyld_get_image_name(i);
const char *name = strrchr(path, '/');
// printf("name = %s, path = %s", name, path);
if (name != NULL && strcmp(image_name, name) == 0) {
return _dyld_get_image_vmaddr_slide(i);
}
}
return -1;
}
但是很可能我们编写的 Tweak 的 dylib
会比我们想要注入的 Framework
加载更早,所以需要稍作处理:
static void didFinishLaunching(CFNotificationCenterRef center, void *observer, CFStringRef name, const void *object, CFDictionaryRef info) {
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
intptr_t base_addr = get_image_vmaddr_slide("/UnityFramework");
printf("didFinishLaunching-base_addr = 0x%lx", base_addr);
});
}
void launchEvent() {
CFNotificationCenterAddObserver(CFNotificationCenterGetLocalCenter(), NULL, &didFinishLaunching, (CFStringRef)UIApplicationDidFinishLaunchingNotification, NULL, CFNotificationSuspensionBehaviorDrop);
}
__attribute__((constructor)) static void initialize() {
launchEvent();
}
完整代码
#import <substrate.h>
#import <dlfcn.h>
#import <mach-o/dyld.h>
#import <string.h>
#import <stdio.h>
#import <UIKit/UIKit.h>
int (*old_get_Gem)();
int new_get_Gem() {
return 99999;
}
int (*old_get_Coin)();
int new_get_Coin() {
return 300000000;
}
// 根据镜像名称获取镜像的偏移基址
intptr_t get_image_vmaddr_slide(const char * image_name) {
uint32_t count = _dyld_image_count();
for (int i = 0; i < count; i++) {
const char *path = _dyld_get_image_name(i);
const char *name = strrchr(path, '/');
// printf("name = %s, path = %s", name, path);
if (name != NULL && strcmp(image_name, name) == 0) {
return _dyld_get_image_vmaddr_slide(i);
}
}
return -1;
}
static void didFinishLaunching(CFNotificationCenterRef center, void *observer, CFStringRef name, const void *object, CFDictionaryRef info) {
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
intptr_t base_addr = get_image_vmaddr_slide("/UnityFramework");
printf("didFinishLaunching-base_addr = 0x%lx", base_addr);
MSHookFunction((void *)(base_addr + 0x1E15468), (void *)&new_get_Gem, (void **)&old_get_Gem);
MSHookFunction((void *)(base_addr + 0x1E1545C), (void *)&new_get_Coin, (void **)&old_get_Coin);
});
}
void launchEvent() {
CFNotificationCenterAddObserver(CFNotificationCenterGetLocalCenter(), NULL, &didFinishLaunching, (CFStringRef)UIApplicationDidFinishLaunchingNotification, NULL, CFNotificationSuspensionBehaviorDrop);
}
__attribute__((constructor)) static void initialize() {
launchEvent();
}