PatchSwiftDemo icon indicating copy to clipboard operation
PatchSwiftDemo copied to clipboard

使用 mprotect Patch 纯 Swift 方法的 Demo,真机不可用

void patchSwift(void) {
    
    // 根据符号获取要 patch swift 方法地址
    void *handle = dlopen(NULL/* current image */, RTLD_GLOBAL);
    // 这个符号 nm 取到的,dlsym 会在符号前加下划线
    // 根据 swift name mangling 可以动态生成这个串
    int64_t *swiftFunc = dlsym(handle, "_TFC14PatchSwiftDemo4Sark3foofSiSi");
    int64_t *newFunc = (int64_t *)&patchedFunction;
    
    // 原函数和 patch 函数的 offset
    int64_t offset = (int64_t)newFunc - ((int64_t)swiftFunc + 5 * sizeof(char));
    
    // 将代码区这个 page 改成可写
    size_t pageSize = sysconf(_SC_PAGESIZE);
    uintptr_t start = (uintptr_t)swiftFunc;
    uintptr_t end = start + 1;
    uintptr_t pageStart = start & -pageSize;
    // 注意,这个方法在非越狱 iOS 真机被禁用
    mprotect((void *)pageStart, end - pageStart, PROT_READ | PROT_WRITE | PROT_EXEC);

    // swift 函数第一行指令改成 jmp offset
    int64_t instruction = 0xe9 | offset << 8;
    *swiftFunc = instruction;
}