hacks/dump-imessages/iphone-dataprotection/ramdisk_tools/ioflash/ioflash_kernel.c

221 lines
7.2 KiB
C

#include <stdio.h>
#include <unistd.h>
#include <CoreFoundation/CoreFoundation.h>
#include <sys/types.h>
#include <sys/sysctl.h>
#include <mach/mach.h>
#include <signal.h>
#include "ioflash.h"
CF_EXPORT const CFStringRef _kCFSystemVersionProductVersionKey;
CF_EXPORT CFDictionaryRef _CFCopySystemVersionDictionary(void);
mach_port_t kernel_task=0;
void* externalMethod_original = NULL;
void** externalMethod_ptr = NULL;
void* (*IOMemoryDescriptor__withAddress)(void*, uint32_t, uint32_t, uint32_t) = 0x0;
typedef int (*methodptr)(void*, ...);
#define CALL_VTABLE(this, vtableoff, ...) \
((methodptr) (*(uint32_t**)this)[vtableoff/4]) (this, ##__VA_ARGS__)
//IOReturn externalMethod( uint32_t selector, IOExternalMethodArguments * arguments,IOExternalMethodDispatch * dispatch = 0, OSObject * target = 0, void * reference = 0 );
int myIOFlashStorage_externalMethod(uint32_t* this, uint32_t selector, IOExternalMethodArguments* arguments)
{
if (selector == kIOFlashControllerDisableKeepout)
{
void* obj2 = (void*) this[0x78/4]; //AppleIOPFMI object
CALL_VTABLE(obj2, 0x35C, 0, 0, 1);
return 0x0;
}
if (selector != kIOFlashControllerReadPage) //only support read
return 0xE00002C2;
if (IOMemoryDescriptor__withAddress == 0x0)
return 0xdeadbeef;
struct IOFlashCommandStruct command = {0};
uint32_t** bufferDesc = NULL;
uint32_t** spareDesc = NULL;
uint32_t** md = NULL;
void* obj1 = (void*) this[0x78/4]; //AppleIOPFMI object
struct kIOFlashControllerReadPageIn* in = (struct kIOFlashControllerReadPageIn*) arguments->structureInput;
struct kIOFlashControllerOut* out = (struct kIOFlashControllerOut*) arguments->structureOutput;
uint32_t page = in->page;
uint32_t ce = in->ce;
command.flags1 = 1;
if (in->options & kIOFlashStorageOptionBootPageIO)
{
if(in->spare != NULL)
return 0xE00002C2; //spare buffer is not used with bootloader page I/O
command.flags0 = 9;
}
else
{
if( !(in->options & kIOFlashStorageOptionRawPageIO) && in->spare)
{
command.flags0 = in->options & 2;
}
else
{
return 0xdeadbeef; //raw page io
}
}
command.flags1 |= in->options & 4;
command.field8 = 1;
command.fieldC = 0;
command.page_ptr = &page;
bufferDesc = IOMemoryDescriptor__withAddress(in->buffer, in->bufferSize, 1, this[0x7C/4]);
if (bufferDesc == NULL)
return 0xE00002C2;
command.bufferDesc = bufferDesc;
command.field18 = 0;
command.errorCode = 0;
if (in->spare != NULL)
{
spareDesc = IOMemoryDescriptor__withAddress(in->spare, in-> spareSize, 1, this[0x7C/4]);
if (spareDesc == NULL)
return 0xE00002C2;
//0xAC -> desc2 __ZN25IOGeneralMemoryDescriptor5doMapEP7_vm_mapPjmmm
//virtual IOMemoryMap * map( IOOptionBits options = 0 );
md = (void*) CALL_VTABLE(spareDesc, 0x98); //IOGeneralMemoryDescriptor_map
command.spareSize = in->spareSize;
command.spareVA = (void*) CALL_VTABLE(md, 0x38);
}
else
{
command.spareSize = 0;
command.spareVA = NULL;
}
command.field34 = 0;
command.ce_ptr = &ce;
out->ret1 = CALL_VTABLE(obj1, 0x344, 0, &command);
CALL_VTABLE(bufferDesc, 0x14); //IOGeneralMemoryDescriptor_release
if (md != NULL)
{
CALL_VTABLE(md, 0x14); //IOGeneralMemoryDescriptor_release
}
if (spareDesc != NULL)
{
CALL_VTABLE(spareDesc, 0x14); //IOGeneralMemoryDescriptor_release
}
out->ret2 = command.errorCode;
return 0;
}
kern_return_t write_kernel(mach_port_t p, void* addr, uint32_t value)
{
kern_return_t r = vm_write(p, (vm_address_t)addr, (vm_address_t)&value, sizeof(value ));
if (r)
fprintf(stderr, "vm_write into kernel_task failed\n");
else
fprintf(stderr, "vm_write into kernel_task OK\n");
return r;
}
void __attribute__((destructor)) restore_handler()
{
if (kernel_task != 0 && externalMethod_ptr != NULL && externalMethod_original != NULL)
{
fprintf(stderr, "Restoring IOFlashStorageControler::externalMethod ptr\n");
write_kernel(kernel_task, externalMethod_ptr, (uint32_t) externalMethod_original+1);
}
}
void signal_handler(int sig)
{
restore_handler();
signal(sig, SIG_DFL);
raise(sig);
}
int IOFlashStorage_kernel_patch()
{
CFStringRef version = NULL;
CFDictionaryRef versionDict = _CFCopySystemVersionDictionary();
if (versionDict != NULL)
{
version = CFDictionaryGetValue(versionDict, _kCFSystemVersionProductVersionKey);
}
if (version == NULL)
{
fprintf(stderr, "FAILed to get current version\n");
return 0;
}
if (CFStringCompare(version, CFSTR("4.3.5"), 0) <= 0)
{
fprintf(stderr, "iOS 4 kernel detected, no kernel patching required\n");
return 1;
}
fprintf(stderr, "iOS 5 kernel detected, replacing IOFlashControlerUserClient::externalMethod\n");
kern_return_t r = task_for_pid(mach_task_self(), 0, &kernel_task);
if( r != 0)
{
fprintf(stderr, "task_for_pid returned %x : missing tfp0 kernel patch (use latest kernel_patcher.py) or wrong entitlements\n", r);
return 0;
}
uint32_t i;
pointer_t buf;
unsigned int sz;
vm_address_t addr = 0x80002000;
while( addr < (0x80002000 + 0xA00000))
{
vm_read(kernel_task, addr, 2048, &buf, &sz);
if( buf == NULL || sz == 0)
continue;
uint32_t* p = (uint32_t*) buf;
for(i=0; i < sz/sizeof(uint32_t); i++)
{
if (externalMethod_original != NULL)
{
if (p[i] == (externalMethod_original+1))
{
externalMethod_ptr = (void*) (addr + i*4);
fprintf(stderr, "Found externalMethod ptr at %x\n", (uint32_t) externalMethod_ptr);
write_kernel(kernel_task, externalMethod_ptr, (uint32_t) myIOFlashStorage_externalMethod);
signal(SIGINT, signal_handler);//handle ctrl+c
return 1;
}
else if(IOMemoryDescriptor__withAddress == NULL && !memcmp(&p[i], "\x20\x46\x26\xB0\x5D\xF8\x04\x8B\xF0\xBD", 10))
{
IOMemoryDescriptor__withAddress = (void*) p[i+5];
fprintf(stderr, "IOMemoryDescriptor__withAddress=%x\n", (uint32_t) IOMemoryDescriptor__withAddress);
}
}
else if(!memcmp(&p[i], "\xF0\xB5\x03\xAF\x4D\xF8\x04\x8D\xA6\xB0\x40\xF2\xC2\x24\x13\x6A", 16))
{
externalMethod_original = (void*) (addr + i*4);
fprintf(stderr, "Found IOFlashControlerUserClient::externalMethod at %x\n", (uint32_t) externalMethod_original);
}
}
addr += 2048;
}
fprintf(stderr, "Kernel patching failed\n");
return 0;
}