Last active
March 4, 2025 06:10
-
-
Save JJTech0130/142aee0f7bda9c61a421140d17afbdeb to your computer and use it in GitHub Desktop.
Improved method of using a debugger for JIT on iOS... Uses split rx/rw regions, and works on iOS 18.4b1
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#import <Foundation/Foundation.h> | |
#import <mach/mach.h> | |
#import <stdio.h> | |
#import <stdlib.h> | |
#import <string.h> | |
#include <libkern/OSCacheControl.h> | |
const int REGION_SIZE = 0x4000*1; | |
void write_instructions(void* page) | |
{ | |
uint32_t instructions[] = { | |
0x52800540, // mov w0, #42 | |
0xD65F03C0 // ret | |
}; | |
memcpy(page, instructions, sizeof(instructions)); | |
} | |
void write_instructions2(void* page) | |
{ | |
uint32_t instructions[] = { | |
0x52800C60, // mov w0, #99 | |
0xD65F03C0 // ret | |
}; | |
memcpy(page, instructions, sizeof(instructions)); | |
} | |
int main(int argc, char* argv[]) | |
{ | |
void* page = mmap( | |
0, REGION_SIZE, PROT_READ | PROT_EXEC, MAP_ANON | MAP_PRIVATE, -1, 0); | |
vm_address_t buf_rw = (vm_address_t)page; | |
vm_address_t buf_rx = 0; | |
vm_prot_t cur_prot, max_prot; | |
kern_return_t ret = vm_remap(mach_task_self(), &buf_rx, REGION_SIZE, 0, | |
VM_FLAGS_ANYWHERE, mach_task_self(), buf_rw, false, &cur_prot, | |
&max_prot, VM_INHERIT_NONE); | |
if (ret != KERN_SUCCESS) { | |
fprintf(stderr, "Failed to remap RX region %d\n", ret); | |
return 1; | |
} | |
// Protect region as RX | |
ret = vm_protect(mach_task_self(), buf_rx, REGION_SIZE, FALSE, | |
VM_PROT_READ | VM_PROT_EXECUTE); | |
if (ret != KERN_SUCCESS) { | |
fprintf(stderr, "Failed to set RX protection %d\n", ret); | |
return 1; | |
} | |
// Make executable region a debug map | |
// You just need to have the debugger write to any pages you want to JIT i.e. "mem w buf_rx 0" | |
// TIP: Here is a nice script you can insert into Xcode's breakpoint box | |
// script lldb.target.process.WriteMemory(int(lldb.frame.FindVariable("buf_rx").GetValue()), b'\x00' * int(lldb.frame.module.FindFirstGlobalVariable(lldb.target, "REGION_SIZE").GetValue()), lldb.SBError()) | |
// Protect region as RW | |
ret = vm_protect(mach_task_self(), buf_rw, REGION_SIZE, FALSE, | |
VM_PROT_READ | VM_PROT_WRITE); | |
if (ret != KERN_SUCCESS) { | |
fprintf(stderr, "Failed to set RW protection %d\n", ret); | |
return 1; | |
} | |
// Write new instructions | |
write_instructions((void*)buf_rw); | |
int (*func)(void) = (int (*)(void))buf_rx; | |
int result = func(); | |
printf("Executed JIT-ed function, result: %d\n", result); // Should print 42 | |
// Write new instructions | |
write_instructions2((void*)buf_rw); | |
// This is important | |
sys_icache_invalidate((void*)buf_rx, REGION_SIZE); | |
int result2 = func(); | |
printf("Executed JIT-ed function, result: %d\n", result2); // Should print 99 | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment