运行期修改 iOS 进程中的指令或数据

| 分类 文档  | 标签 分享  iOS 

做个 mobile substrate 插件,然后用下面的方法在运行时修改指令或者数据,需要做 memory patch 外挂内挂倒挂什么的,直接看代码了:

 1 //
 2 extern "C" kern_return_t mach_vm_region
 3 (
 4  vm_map_t target_task,
 5  vm_address_t *address,
 6  vm_size_t *size,
 7  vm_region_flavor_t flavor,
 8  vm_region_info_t info,
 9  mach_msg_type_number_t *infoCnt,
10  mach_port_t *object_name
11  );
12 
13 //
14 template <typename TYPE> NS_INLINE bool FakeCode(TYPE *addr, TYPE code)
15 {
16  mach_port_t task;
17  vm_size_t region_size = 0;
18  vm_address_t region = (vm_address_t)addr;
19 
20  /* Get region boundaries */
21 #if defined(_MAC64) || defined(__LP64__)
22  vm_region_basic_info_data_64_t info;
23  mach_msg_type_number_t info_count = VM_REGION_BASIC_INFO_COUNT_64;
24  vm_region_flavor_t flavor = VM_REGION_BASIC_INFO_64;
25  if (mach_vm_region(mach_task_self(), &region, &region_size, flavor, (vm_region_info_t)&info, (mach_msg_type_number_t*)&info_count, (mach_port_t*)&task) != KERN_SUCCESS)
26  {
27      return false;
28  }
29 #else
30  vm_region_basic_info_data_t info;
31  mach_msg_type_number_t info_count = VM_REGION_BASIC_INFO_COUNT;
32  vm_region_flavor_t flavor = VM_REGION_BASIC_INFO;
33  if (vm_region(mach_task_self(), &region, &region_size, flavor, (vm_region_info_t)&info, (mach_msg_type_number_t*)&info_count, (mach_port_t*)&task) != KERN_SUCCESS)
34  {
35      return false;
36  }
37 #endif
38  
39  /* Change memory protections to rw- */
40  if (vm_protect(mach_task_self(), region, region_size, false, VM_PROT_READ | VM_PROT_WRITE | VM_PROT_COPY) != KERN_SUCCESS)
41  {
42      _LineLog();
43      return false;
44  }
45  
46  /* Actually perform the write */
47  *addr = code;
48  
49  /* Flush CPU data cache to save write to RAM */
50  sys_dcache_flush(addr, sizeof(code));
51  
52  /* Invalidate instruction cache to make the CPU read patched instructions from RAM */
53  sys_icache_invalidate(addr, sizeof(code));
54  
55  /* Change memory protections back to r-x */
56  vm_protect(mach_task_self(), region, region_size, false, VM_PROT_EXECUTE | VM_PROT_READ);
57  return true;
58 }

好了,修改方法有了,ARM64也支持了。但 Module Base 是变化的,对一个模块逆向工程后,如何确定运行时模块的基址呢?

——我也想知道……,不过我想了一个山寨的方法,先看到一个导出符号,作为参照基准,运行期获取这个导出符号,然后做一个差值计算,搞定:

 1 NS_INLINE uint8_t *ModuleBase(NSString *path, NSString *refFunc, unsigned int refAddr = 0x1000)
 2 {
 3  unsigned char *base = (unsigned char *)dlsym(dlopen(path.UTF8String, RTLD_LAZY), refFunc.UTF8String);
 4  if (base == nil)
 5  {
 6      _Log(@"HOOK Base symbol not found");
 7      return nil;
 8  }
 9  
10  if (((unsigned int)base & 0x0FF0) != (refAddr & 0x0FF0))
11  {
12      _Log(@"HOOK Base symbol miss match: %p !=! %08X", base, refAddr);
13      return nil;
14  }
15  
16  base -= refAddr;
17  _Log(@"HOOK Base: %@ at %p", path, base);
18  return base;
19 }

上一篇     下一篇