initial code for dumping imessages in a reasonable format

This commit is contained in:
Jeffrey Paul
2014-02-09 00:30:49 +01:00
parent c0021efb13
commit 9dd7628f04
157 changed files with 24178 additions and 0 deletions

View File

@@ -0,0 +1,556 @@
#include <stdio.h>
#include <sys/types.h>
#include <sys/mount.h>
#include <fcntl.h>
#include <time.h>
#include <unistd.h>
#include <CoreFoundation/CoreFoundation.h>
#include <CommonCrypto/CommonCryptor.h>
#include <IOKit/IOKitLib.h>
#include "ioflash.h"
/**
used to decrypt special pages when checking if the physical banks parameter is correct
when reading/dumping pages are not decrypted
**/
uint8_t META_KEY[16] = {0x92, 0xa7, 0x42, 0xab, 0x08, 0xc9, 0x69, 0xbf, 0x00, 0x6c, 0x94, 0x12, 0xd3, 0xcc, 0x79, 0xa5};
//uint8_t FILESYSTEM_KEY[16] = {0xf6, 0x5d, 0xae, 0x95, 0x0e, 0x90, 0x6c, 0x42, 0xb2, 0x54, 0xcc, 0x58, 0xfc, 0x78, 0xee, 0xce};
uint32_t gDeviceReadID = 0;
uint32_t gCECount = 0;
uint32_t gBlocksPerCE = 0;
uint32_t gPagesPerBlock = 0;
uint32_t gBytesPerPage = 0;
uint32_t gBytesPerSpare = 0;
uint32_t gBootloaderBytes = 0;
uint32_t gIsBootFromNand = 0;
uint32_t gPagesPerCE = 0;
uint32_t gTotalBlocks = 0;
uint32_t metaPerLogicalPage = 0;
uint32_t validmetaPerLogicalPage = 0;
uint32_t banksPerCE = 0;
uint32_t use_4k_aes_chain = 0;
uint32_t gFSStartBlock= 0;
uint32_t gDumpPageSize = 0;
uint32_t gPPNdevice = 0;
uint32_t banksPerCEphysical = 1;
uint32_t bank_address_space = 0;
uint32_t blocks_per_bank = 0;
//from ioflashstoragetool
io_service_t fsdService = 0;
io_connect_t fsdConnection = 0;
CFMutableDictionaryRef MakeOneStringProp(CFStringRef key, CFStringRef value)
{
CFMutableDictionaryRef dict = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
CFDictionarySetValue(dict, key, value);
return dict;
}
io_service_t _wait_for_io_service_matching_dict(CFDictionaryRef matching)
{
io_service_t service = 0;
/* while(!service) {
*/CFRetain(matching);
service = IOServiceGetMatchingService(kIOMasterPortDefault, matching);
//if(service) break;
/*sleep(1);
//CFRelease(matching);
}
CFRelease(matching);*/
return service;
}
int FSDConnect(const char* name)
{
CFMutableDictionaryRef matching;
matching = IOServiceMatching(name);
fsdService = IOServiceGetMatchingService(kIOMasterPortDefault, matching);
IOServiceOpen(fsdService, mach_task_self(), 0, &fsdConnection);
return fsdConnection != 0;
}
int FSDGetPropertyForKey(io_object_t obj, CFStringRef name, void* out, uint32_t outLen, CFMutableDictionaryRef dict)
{
CFTypeRef data = IORegistryEntryCreateCFProperty(obj, name, kCFAllocatorDefault, 0);
if (!data)
{
return 0;
}
if (dict != NULL)
{
CFDictionaryAddValue(dict, name, data);
}
if (out == NULL)
return 0;
if(CFGetTypeID(data) == CFNumberGetTypeID())
{
CFNumberGetValue((CFNumberRef)data, kCFNumberIntType, out);
return 1;
}
else if(CFGetTypeID(data) == CFDataGetTypeID())
{
CFIndex dataLen = CFDataGetLength(data);
CFDataGetBytes(data, CFRangeMake(0,dataLen < outLen ? dataLen : outLen), out);
return 1;
}
return 0;
}
IOReturn FSDReadPageHelper(struct kIOFlashControllerReadPageIn* in, struct kIOFlashControllerOut* out)
{
size_t outLen = sizeof(struct kIOFlashControllerOut);
IOConnectCallStructMethod(fsdConnection,
kIOFlashControllerReadPage,
in,
sizeof(struct kIOFlashControllerReadPageIn),
out,
&outLen);
// fprintf(stderr, "%x %x %x %x %x\n", in->page, in->ce, r, out->ret1, out->ret2);
return out->ret1;
}
IOReturn FSDReadPageWithOptions(uint32_t ceNum,
uint32_t pageNum,
void* buffer,
void* spareBuffer,
uint32_t spareSize,
uint32_t options,
struct kIOFlashControllerOut* out
)
{
struct kIOFlashControllerReadPageIn in;
in.page = pageNum;
in.ce = ceNum;
in.options = options;
in.buffer = buffer;
in.bufferSize = gBytesPerPage;
in.spare = spareBuffer;
in.spareSize = spareSize;
return FSDReadPageHelper(&in, out);
}
IOReturn FSDReadBootPage(uint32_t ceNum, uint32_t pageNum,uint32_t* buffer, struct kIOFlashControllerOut* out)
{
return FSDReadPageWithOptions(ceNum, pageNum, buffer, NULL, 0, kIOFlashStorageOptionBootPageIO, out);
}
void findPartitionLocation(CFStringRef contentHint, CFMutableDictionaryRef dict)
{
const void* keys[2] = {CFSTR("Block Count"), CFSTR("Block Offset")};
const void* values[2] = {NULL, NULL};
CFMutableDictionaryRef match = MakeOneStringProp(CFSTR("IOProviderClass"), CFSTR("IOFlashStoragePartition"));
CFMutableDictionaryRef iopmatch = MakeOneStringProp(CFSTR("Content Hint"), contentHint);
CFDictionarySetValue(match, CFSTR("IOPropertyMatch"), iopmatch);
CFRelease(iopmatch);
io_service_t service = _wait_for_io_service_matching_dict(match);
if (service)
{
CFNumberRef blockCount = (CFNumberRef) IORegistryEntryCreateCFProperty(service, CFSTR("Block Count"), kCFAllocatorDefault, 0);
CFNumberRef blockOffset = (CFNumberRef) IORegistryEntryCreateCFProperty(service, CFSTR("Block Offset"), kCFAllocatorDefault, 0);
if (dict != NULL)
{
values[0] = (void*) blockCount;
values[1] = (void*) blockOffset;
CFDictionaryRef d = CFDictionaryCreate(kCFAllocatorDefault, keys, values, 2, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
if (d != NULL)
CFDictionaryAddValue(dict, contentHint, d);
}
if( CFStringCompare(contentHint, CFSTR("Filesystem"), 0) == kCFCompareEqualTo)
{
CFNumberGetValue(blockOffset, kCFNumberIntType, &gFSStartBlock);
}
}
CFRelease(match);
}
//openiBoot/util.c
uint32_t next_power_of_two(uint32_t n) {
uint32_t val = 1 << (31 - __builtin_clz(n));
if (n % val)
val *= 2;
return val;
}
void generate_IV(unsigned long lbn, unsigned long *iv)
{
int i;
for(i = 0; i < 4; i++)
{
if(lbn & 1)
lbn = 0x80000061 ^ (lbn >> 1);
else
lbn = lbn >> 1;
iv[i] = lbn;
}
}
void decrypt_page(uint8_t* data, uint32_t dataLength, uint8_t* key, uint32_t keyLength, uint32_t pn)
{
char iv[16];
size_t dataOutMoved=dataLength;
generate_IV(pn, (unsigned long*) iv);
CCCryptorStatus s = CCCrypt(kCCDecrypt,
kCCAlgorithmAES128,
0,
(const void*) key,
keyLength,
(const void*) iv,
(const void*) data,
dataLength,
(const void*) data,
dataLength,
&dataOutMoved);
if (s != kCCSuccess)
{
fprintf(stderr, "decrypt_page: CCCrypt error %x\n", s);
}
}
void set_physical_banks(int n)
{
banksPerCEphysical = n;
blocks_per_bank = gBlocksPerCE / banksPerCEphysical;
if((gBlocksPerCE & (gBlocksPerCE-1)) == 0)
{
// Already a power of two.
bank_address_space = blocks_per_bank;
//total_block_space = gBlocksPerCE;
}
else
{
// Calculate the bank address space.
bank_address_space = next_power_of_two(blocks_per_bank);
//total_block_space = ((banksPerCEphysical-1)*bank_address_space) + blocks_per_bank;
}
}
//"bruteforce" the number of physical banks
//except for PPN devices, DEVICEINFOBBT special pages should always be somewhere at the end
void check_special_pages()
{
if(gPPNdevice)
{
fprintf(stderr, "PPN device, i don't know how to guess the number of physical banks, assuming 1\n");
set_physical_banks(1);
return;
}
uint32_t i,x=1;
uint32_t ok = 0;
uint32_t bank, block, page;
uint8_t* pageBuffer = (uint8_t*) valloc(gDumpPageSize);
printf("Searching for correct banksPerCEphysical value ...\n");
while(!ok && x < 10)
{
set_physical_banks(x);
bank = banksPerCEphysical - 1;
for(block = blocks_per_bank-1; !ok && block > blocks_per_bank-10 ; block--)
{
page = (bank_address_space * bank + block) * gPagesPerBlock;
struct kIOFlashControllerOut *out = (&pageBuffer[gBytesPerPage + metaPerLogicalPage]);
for(i=0; i < gPagesPerBlock; i++)
{
if(FSDReadPageWithOptions(0, page + i, pageBuffer, &pageBuffer[gBytesPerPage], metaPerLogicalPage, 0, out))
continue;
if(pageBuffer[gBytesPerPage] != 0xA5)
continue;
if(!memcmp(pageBuffer, "DEVICEINFOBBT", 13))
{
printf("Found cleartext DEVICEINFOBBT at block %d page %d with banksPerCEphyiscal=%d\n", blocks_per_bank*bank +block, i, banksPerCEphysical);
ok = 1;
break;
}
decrypt_page(pageBuffer, gBytesPerPage, META_KEY, kCCKeySizeAES128, page + i);
if(!memcmp(pageBuffer, "DEVICEINFOBBT", 13))
{
printf("Found encrypted DEVICEINFOBBT at block %d page %d with banksPerCEphyiscal=%d\n", blocks_per_bank*bank +block, i, banksPerCEphysical);
ok = 1;
break;
}
}
}
x++;
}
if(!ok)
{
fprintf(stderr, "Couldnt guess the number of physical banks, exiting\n");
exit(0);
}
free(pageBuffer);
return;
}
//XXX dont read the NAND from this function as it can be called from multiple processes
CFMutableDictionaryRef FSDGetInfo(int printInfo)
{
io_iterator_t iterator = 0;
io_object_t obj = 0;
FSDConnect("IOFlashController");
if(IORegistryEntryCreateIterator(fsdService, "IOService",0, &iterator))
return NULL;
obj = IOIteratorNext(iterator);
if (!obj)
return NULL;
CFMutableDictionaryRef dict = CFDictionaryCreateMutable (kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
FSDGetPropertyForKey(obj, CFSTR("device-readid"), &gDeviceReadID, sizeof(gDeviceReadID), dict);
FSDGetPropertyForKey(obj, CFSTR("#ce"), &gCECount, sizeof(gCECount), dict);
FSDGetPropertyForKey(obj, CFSTR("#ce-blocks"), &gBlocksPerCE, sizeof(gBlocksPerCE), dict);
FSDGetPropertyForKey(obj, CFSTR("#block-pages"), &gPagesPerBlock, sizeof(gPagesPerBlock), dict);
FSDGetPropertyForKey(obj, CFSTR("#page-bytes"), &gBytesPerPage, sizeof(gBytesPerPage), dict);
FSDGetPropertyForKey(obj, CFSTR("#spare-bytes"), &gBytesPerSpare, sizeof(gBytesPerSpare), dict);
FSDGetPropertyForKey(obj, CFSTR("#bootloader-bytes"), &gBootloaderBytes, sizeof(gBootloaderBytes), dict);
FSDGetPropertyForKey(obj, CFSTR("metadata-whitening"), NULL, 0, dict);
FSDGetPropertyForKey(obj, CFSTR("name"), NULL, 0, dict);
FSDGetPropertyForKey(obj, CFSTR("is-bfn-partitioned"), NULL, 0, dict);
FSDGetPropertyForKey(obj, CFSTR("bbt-format"), NULL, 0, dict);
//FSDGetPropertyForKey(obj, CFSTR("channels"), NULL, 0, dict);
FSDGetPropertyForKey(obj, CFSTR("vendor-type"), NULL, 0, dict);
FSDGetPropertyForKey(obj, CFSTR("ppn-device"), &gPPNdevice, sizeof(gPPNdevice), dict);
FSDGetPropertyForKey(obj, CFSTR("valid-meta-per-logical-page"), &validmetaPerLogicalPage, sizeof(gBytesPerSpare), dict);
FSDGetPropertyForKey(obj, CFSTR("meta-per-logical-page"), &metaPerLogicalPage, sizeof(gBytesPerSpare), dict);
if (metaPerLogicalPage == 0)
{
metaPerLogicalPage = 12;//default value?
}
//XXX: returns (possibly wrong) default value (1) when nand-disable-driver is set, use vendor-type + info from openiboot to get correct value : bank-per-ce VFL (!=physical banks)
FSDGetPropertyForKey(obj, CFSTR("banks-per-ce"), &banksPerCE, sizeof(gBytesPerSpare), dict);
FSDGetPropertyForKey(obj, CFSTR("use-4k-aes-chain"), &use_4k_aes_chain, sizeof(gBytesPerSpare), dict);
gPagesPerCE = gBlocksPerCE * gPagesPerBlock;
gTotalBlocks = gCECount * gBlocksPerCE;
FSDGetPropertyForKey(obj, CFSTR("boot-from-nand"), &gIsBootFromNand, sizeof(gIsBootFromNand), dict);
CFMutableDictionaryRef dictPartitions = CFDictionaryCreateMutable (kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
findPartitionLocation(CFSTR("Boot Block"), dictPartitions);
findPartitionLocation(CFSTR("Effaceable"), dictPartitions);
findPartitionLocation(CFSTR("NVRAM"), dictPartitions);
findPartitionLocation(CFSTR("Firmware"), dictPartitions);
findPartitionLocation(CFSTR("Filesystem"), dictPartitions);
/*findPartitionLocation(CFSTR("Diagnostic Data"));
findPartitionLocation(CFSTR("System Config"));
findPartitionLocation(CFSTR("Bad Block Table"));*/
//findPartitionLocation(CFSTR("Unpartitioned"));//never matches
CFDictionaryAddValue(dict, CFSTR("partitions"), dictPartitions);
IOObjectRelease(obj);
IOObjectRelease(iterator);
gDumpPageSize = gBytesPerPage + metaPerLogicalPage + sizeof(struct kIOFlashControllerOut);
CFNumberRef n = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &gDumpPageSize);
CFDictionarySetValue(dict, CFSTR("dumpedPageSize"), n);
CFRelease(n);
if (printInfo)
{
uint64_t total_size = ((uint64_t)gBytesPerPage) * ((uint64_t) (gPagesPerBlock * gBlocksPerCE * gCECount));
total_size /= 1024*1024*1024;
fprintf(stderr, "NAND configuration: %uGiB (%d CEs of %d blocks of %d pages of %d bytes data, %d bytes spare\n",
(uint32_t) total_size,
gCECount,
gBlocksPerCE,
gPagesPerBlock,
gBytesPerPage,
gBytesPerSpare);
}
set_physical_banks(1);
return dict;
}
CFDictionaryRef nand_dump(int fd)
{
uint64_t totalSize = (uint64_t)gPagesPerBlock * (uint64_t)gBlocksPerCE * (uint64_t)gCECount * (uint64_t)gDumpPageSize;
write(fd, &totalSize, sizeof(uint64_t));
dump_nand_to_socket(fd);
return NULL;
}
int dump_nand_to_socket(int fd)
{
int ceNum=0,pageNum,bankNum;
IOReturn r;
uint64_t totalPages = gPagesPerBlock * gBlocksPerCE * gCECount;
uint64_t validPages = 0;
uint64_t blankPages = 0;
uint64_t errorPages = 0;
uint64_t otherPages = 0;
uint64_t counter = 0;
//page data + spare metadata + kernel return values
uint8_t* pageBuffer = (uint8_t*) valloc(gDumpPageSize);
if (pageBuffer == NULL)
{
fprintf(stderr, "valloc(%d) FAIL", gDumpPageSize);
return 0;
}
struct kIOFlashControllerOut *out = (&pageBuffer[gBytesPerPage + metaPerLogicalPage]);
time_t start = time(NULL);
for(bankNum=0; bankNum < banksPerCEphysical; bankNum++)
{
uint32_t start_page = bank_address_space * bankNum * gPagesPerBlock;
uint32_t end_page = start_page + gPagesPerBlock * blocks_per_bank;
for(pageNum=start_page; pageNum < end_page; pageNum++)
{
for(ceNum=0; ceNum < gCECount; ceNum++)
{
uint32_t blockNum = pageNum / gPagesPerBlock;
uint32_t boot = (blockNum < gFSStartBlock);
if(boot)
r = FSDReadBootPage(ceNum, pageNum, pageBuffer, out);
else
r = FSDReadPageWithOptions(ceNum, pageNum, pageBuffer, &pageBuffer[gBytesPerPage], metaPerLogicalPage, 0, out);
//r = FSDReadPageWithOptions(ceNum, pageNum, pageBuffer,NULL, 0, 0x100, out);
if(r == 0)
{
validPages++;
}
else
{
if (r == kIOReturnBadMedia)
{
fprintf(stderr, "CE %x page %x : uncorrectable ECC error\n", ceNum, pageNum);
errorPages++;
}
else if (r == kIOReturnUnformattedMedia)
{
memset(pageBuffer, 0xFF, gBytesPerPage + metaPerLogicalPage);
blankPages++;
}
else if (r == 0xdeadbeef)
{
fprintf(stderr, "0xdeadbeef return code, something is wrong with injected kernel code\n");
exit(0);
}
else if (r == kIOReturnBadArgument || r == kIOReturnNotPrivileged)
{
fprintf(stderr, "Error 0x%x (kIOReturnBadArgument/kIOReturnNotPrivileged)\n", r);
exit(0);
}
else
{
fprintf(stderr, "CE %x page %x : unknown return code 0x%x\n", ceNum, pageNum, r);
otherPages++;
}
}
out->ret2 = 0;
if(write(fd, pageBuffer, gDumpPageSize) != gDumpPageSize)
{
pageNum = gPagesPerBlock * gBlocksPerCE;
fprintf(stderr, "Abort dump\n");
break;
}
if (ceNum == 0 && pageNum % gPagesPerBlock == 0)
{
fprintf(stderr, "Block %d/%d (%d%%)\n", (counter/gPagesPerBlock), gBlocksPerCE, (counter*100)/(gPagesPerBlock*gBlocksPerCE));
}
}
counter++;
}
}
if (ceNum == gCECount && pageNum == (gPagesPerBlock * gBlocksPerCE))
{
time_t duration = time(NULL) - start;
fprintf(stderr, "Finished NAND dump in %lu hours %lu minutes %lu seconds\n", duration / 3600, (duration % 3600) / 60, (duration % 3600) % 60);
fprintf(stderr, "Total pages %llu\n", totalPages);
fprintf(stderr, "In-use pages %llu (%d%%)\n", validPages, (int) (validPages * 100 / totalPages));
fprintf(stderr, "Blank pages %llu (%d%%)\n", blankPages, (int) (blankPages * 100 / totalPages));
fprintf(stderr, "Error pages %llu (%d%%)\n", errorPages, (int) (errorPages * 100 / totalPages));
fprintf(stderr, "Other pages %llu (%d%%)\n", otherPages, (int) (otherPages * 100 / totalPages));
}
free(pageBuffer);
return 0;
}
int nand_proxy(int fd)
{
struct kIOFlashControllerOut out;
proxy_read_cmd cmd;
uint8_t* pageBuffer = (uint8_t*) valloc(gBytesPerPage);
if( pageBuffer == NULL)
{
fprintf(stderr, "pageBuffer = valloc(%d) failed\n", gBytesPerPage);
return 0;
}
while(1)
{
int z = read(fd, &cmd, sizeof(proxy_read_cmd));
if (z != sizeof(proxy_read_cmd))
break;
void* spareBuf = NULL;
uint32_t blockNum = cmd.page / gPagesPerBlock;
uint32_t boot = (blockNum < gFSStartBlock);
if(boot)
{
cmd.spareSize = 0;
cmd.options |= kIOFlashStorageOptionBootPageIO;
}
else if (cmd.spareSize)
{
spareBuf = valloc(cmd.spareSize);
}
FSDReadPageWithOptions(cmd.ce, cmd.page, pageBuffer, spareBuf, cmd.spareSize, cmd.options, &out);
write(fd, pageBuffer, gBytesPerPage);
if (spareBuf != NULL)
{
write(fd, spareBuf, cmd.spareSize);
}
write(fd, &out, sizeof(struct kIOFlashControllerOut));
if (spareBuf != NULL)
{
free(spareBuf);
}
}
free(pageBuffer);
return 0;
}

View File

@@ -0,0 +1,118 @@
#include <IOKit/IOKitLib.h>
#define kIOFlashStorageOptionBootPageIO 0x100
#define kIOFlashStorageOptionRawPageIO 0x002
#define kIOFlashStorageOptionXXXX 0x004
//0xC0 == kIOFlashStorageOptionUseAES | kIOFlashStorageOptionHomogenize
#define kIOFlashControllerReadPage 0x1
#define kIOFlashControllerWritePage 0x2
#define kIOFlashControllerDisableKeepout 0xa
struct kIOFlashControllerReadPageIn;
struct kIOFlashControllerOut;
//from ioflashstoragetool
CFMutableDictionaryRef MakeOneStringProp(CFStringRef key, CFStringRef value);
io_service_t _wait_for_io_service_matching_dict(CFDictionaryRef matching);
int FSDConnect(const char* name);
int FSDGetPropertyForKey(io_object_t obj, CFStringRef name, void* out, uint32_t outLen, CFMutableDictionaryRef dict);
void findPartitionLocation(CFStringRef contentHint, CFMutableDictionaryRef dict);//findNvramLocation
IOReturn FSDReadPageHelper(struct kIOFlashControllerReadPageIn* in, struct kIOFlashControllerOut* out);
IOReturn FSDReadPageWithOptions(uint32_t ceNum, uint32_t pageNum, void* buffer, void* spareBuffer, uint32_t spareSize, uint32_t options, struct kIOFlashControllerOut* out);
IOReturn FSDReadBootPage(uint32_t ceNum, uint32_t pageNum,uint32_t* buffer, struct kIOFlashControllerOut* out);
CFMutableDictionaryRef FSDGetInfo(int);
int IOFlashStorage_kernel_patch();
CFDictionaryRef nand_dump(int fd);
int dump_nand_to_socket(int fd);
int nand_proxy(int fd);
struct kIOFlashControllerReadPageIn
{
uint32_t page;
uint32_t ce;
uint32_t options;
void* buffer;
uint32_t bufferSize;
void* spare;
uint32_t spareSize;
};//sizeof = 0x1C
//sizeof=0x8
struct kIOFlashControllerOut
{
uint32_t ret1;
uint32_t ret2;
};
//sizeof=0x50 AppleIOPFMIDMACommand?
struct IOFlashCommandStruct
{
uint32_t flags0;
uint32_t flags1;
uint32_t field8;
uint32_t fieldC;
uint32_t* page_ptr;
void* bufferDesc;//IOMemoryDescriptor*
uint32_t field18;
uint32_t field1C;
uint32_t field20;
uint32_t* ce_ptr;
void* spareVA;
uint32_t spareSize;
uint32_t field30;
uint32_t field34;
uint32_t field38;
uint32_t errorCode;
uint32_t field40;
uint32_t field44;
uint32_t field48;
uint32_t field4C;
};
typedef struct IOExternalMethodArguments
{
uint32_t version;
uint32_t selector;
mach_port_t asyncWakePort;
io_user_reference_t * asyncReference;
uint32_t asyncReferenceCount;
const uint64_t * scalarInput;
uint32_t scalarInputCount;
const void * structureInput;
uint32_t structureInputSize;
//IOMemoryDescriptor * structureInputDescriptor;
void * structureInputDescriptor;
uint64_t * scalarOutput;
uint32_t scalarOutputCount;
void * structureOutput;
uint32_t structureOutputSize;
void * structureOutputDescriptor;
uint32_t structureOutputDescriptorSize;
uint32_t __reservedA;
//OSObject ** structureVariableOutputData;
void ** structureVariableOutputData;
uint32_t __reserved[30];
} IOExternalMethodArguments;
typedef struct proxy_read_cmd
{
uint32_t ce;
uint32_t page;
uint32_t spareSize;
uint32_t options;
} proxy_read_cmd;

View File

@@ -0,0 +1,220 @@
#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;
}

View File

@@ -0,0 +1,59 @@
#include <stdio.h>
#include <sys/socket.h>
#include <CoreFoundation/CoreFoundation.h>
#include "ioflash.h"
#include "../util.h"
#define LISTEN_PORT 2000
#define CMD_DUMP 0
#define CMD_PROXY 1
int main(int argc, char* argv[])
{
int one=1;
int cmd=0;
if(!IOFlashStorage_kernel_patch())
return -1;
CFMutableDictionaryRef dict = FSDGetInfo(1);
if(dict == NULL)
{
fprintf(stderr, "FAILed to get NAND infos");
return -1;
}
check_special_pages();
int sl = create_listening_socket(LISTEN_PORT);
if(sl == -1)
{
fprintf(stderr, "Error calling create_listening_socket\n");
return -1;
}
fprintf(stderr, "NAND dumper listening on port %d\n", LISTEN_PORT);
while(1)
{
int s = accept(sl, NULL, NULL);
setsockopt(s, SOL_SOCKET, SO_NOSIGPIPE, (void *)&one, sizeof(int));
int r = read(s, (void*) &cmd, sizeof(int));
if(r == sizeof(int))
{
if(cmd == CMD_DUMP)
{
nand_dump(s);
}
else if(cmd == CMD_PROXY)
{
nand_proxy(s);
}
}
shutdown(s, SHUT_RDWR);
close(s);
}
return 0;
}