221 lines
7.2 KiB
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;
|
|
}
|