iOS DEP研究(3)——写入Section

拿到vmaddr和ASLR之后,就可以正确计算出Section的内存地址,然后重新写入数据。不过这里为了演示简便,我们直接把解密之后的数据放在了壳程序的代码中,其实这样调试起来也更方便。

解密之后的数据:

unsignedint sectionData[] = {0xA0E1000E,0xE0800001,0xE12FFF30};
// Encrypt      Decrypt      ASM
// 0xCB927360   0xA0E1000E   mov  r0, lr
// 0x8BF3736F   0xE0800001   add  r0, r0, r1
// 0x8A5C8C5E   0xE12FFF30   blx  r0	

计算正确的内存地址,更改段属性,写入解密数据,最后跳转执行。

vm_address_t addr = myseg->vmaddr + reinterpret_cast<unsigned long>(info.dli_fbase) - FILE_BASE_ADDR;
#if __arm64__ || __x86_64__
    printf("__[data deleted],__code at 0x%lX\n",addr);
#else
    printf("__[data deleted],__code at 0x%X\n",addr);
#endif

kern_return_t err = 0;

// 更改段属性为RWE
err = vm_protect(mach_task_self_, addr, myseg->vmsize, 0, VM_PROT_ALL);
if (err == KERN_SUCCESS) {
    printf("[vm_protect] KERN_SUCCESS![0]\n");
} else {
    printf("[vm_protect] KERN_ERROR![%d]\n",err);
}
// 写入数据
err = vm_write(mach_task_self_, addr, (vm_offset_t)&sectionData, sizeof(sectionData));
if (err == KERN_SUCCESS) {
    printf("[vm_write]   KERN_SUCCESS![0]\n");
} else {
    printf("[vm_write] KERN_ERROR![%d]\n",err);
}

// 跳转执行
(*((void (*)())(addr)))();

编译好了之后记得用MachOView改段属性的Max Protect:

屏幕快照 2015-04-20 下午1.14.06

执行结果:

屏幕快照 2015-04-20 下午1.12.59

成功了♪───O(≧∇≦)O────♪

Leave a Reply

Your email address will not be published. Required fields are marked *

3 + 14 =