mirror of
https://github.com/corellium/projectsandcastle.git
synced 2025-12-23 22:29:34 -05:00
Loader and utilities for Android on iPhone.
This commit is contained in:
@@ -1,2 +1,7 @@
|
||||
# projectsandcastle
|
||||
Android/Linux for the iPhone
|
||||
|
||||
## Provided utilities:
|
||||
|
||||
* `loader/` loads kernel and device tree via pongoOS
|
||||
* `syscfg/` tool to extract configuration information from syscfg partition on devices
|
||||
7
loader/Makefile
Normal file
7
loader/Makefile
Normal file
@@ -0,0 +1,7 @@
|
||||
CFLAGS += -O2 -Wall
|
||||
LDFLAGS += -lusb-1.0
|
||||
|
||||
load-linux: load-linux.c
|
||||
|
||||
clean:
|
||||
rm -f load-linux
|
||||
202
loader/load-linux.c
Normal file
202
loader/load-linux.c
Normal file
@@ -0,0 +1,202 @@
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <libusb-1.0/libusb.h>
|
||||
|
||||
#define DTREECMD "fdt\n"
|
||||
#define BOOTCMD "bootl\n"
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
libusb_device **devs;
|
||||
libusb_device *dev;
|
||||
struct libusb_device_descriptor desc;
|
||||
libusb_device_handle *device = NULL;
|
||||
unsigned int i = 0, j = 0;
|
||||
unsigned vid = 0x05ac, pid = 0x4141;
|
||||
int status = 0, tsize = 0, chunk, done;
|
||||
struct stat st;
|
||||
size_t size, dsize;
|
||||
FILE *fp;
|
||||
char *kbuff = NULL;
|
||||
char *dtree[1024*64] = {0};
|
||||
|
||||
if (argc < 3) {
|
||||
printf("syntax :./loadbin linux.bin dtree.bin\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
status = libusb_init(NULL);
|
||||
if (status < 0)
|
||||
return status;
|
||||
|
||||
status = libusb_get_device_list(NULL, &devs);
|
||||
if (status < 0)
|
||||
return status;
|
||||
|
||||
fp = fopen(argv[1], "r");
|
||||
if(!fp) {
|
||||
printf("Failed to open file\n");
|
||||
status = 1;
|
||||
goto err;
|
||||
}
|
||||
|
||||
if(stat(argv[1], &st) != 0) {
|
||||
printf("Failed to get file size\n");
|
||||
fclose(fp);
|
||||
status = 1;
|
||||
goto err;
|
||||
}
|
||||
size = st.st_size;
|
||||
|
||||
kbuff = malloc(size);
|
||||
if(!kbuff) {
|
||||
printf("failed to allocate buffer\n");
|
||||
fclose(fp);
|
||||
status = 1;
|
||||
goto err;
|
||||
}
|
||||
|
||||
if(fread(kbuff, 1, size, fp) != size) {
|
||||
printf("error reading file %s\n", argv[1]);
|
||||
fclose(fp);
|
||||
status = 1;
|
||||
goto err;
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
fp = fopen(argv[2], "r");
|
||||
if(!fp) {
|
||||
printf("Failed to open dtree\n");
|
||||
status = 1;
|
||||
goto err;
|
||||
}
|
||||
|
||||
if(stat(argv[2], &st) != 0) {
|
||||
printf("Failed to get file size\n");
|
||||
fclose(fp);
|
||||
status = 1;
|
||||
goto err;
|
||||
}
|
||||
|
||||
dsize = st.st_size;
|
||||
if(fread(dtree, 1, dsize, fp) <= 0) {
|
||||
printf("error reading dtree %s\n", argv[2]);
|
||||
fclose(fp);
|
||||
status = 1;
|
||||
goto err;
|
||||
}
|
||||
fclose(fp);
|
||||
|
||||
for (i=0; (dev=devs[i]) != NULL; i++) {
|
||||
status = libusb_get_device_descriptor(dev, &desc);
|
||||
if ((desc.idVendor == vid)
|
||||
&& (desc.idProduct == pid)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (dev == NULL) {
|
||||
printf("Couldn't find device\n");
|
||||
status = 1;
|
||||
goto err;
|
||||
}
|
||||
|
||||
status = libusb_open(dev, &device);
|
||||
libusb_free_device_list(devs, 1);
|
||||
if (status < 0) {
|
||||
printf("libusb_open() failed: %s\n", libusb_error_name(status));
|
||||
goto err;
|
||||
}
|
||||
|
||||
libusb_set_auto_detach_kernel_driver(device, 1);
|
||||
status = libusb_claim_interface(device, 0);
|
||||
if (status != LIBUSB_SUCCESS) {
|
||||
libusb_close(device);
|
||||
printf("libusb_claim_interface failed: %s\n", libusb_error_name(status));
|
||||
goto err;
|
||||
}
|
||||
|
||||
status = libusb_control_transfer(device, 0x21, 2, 0, 0, 0, 0, 1000);
|
||||
if (status < 0) {
|
||||
fprintf(stderr, "libcontrol failed %d\n", status);
|
||||
goto err;
|
||||
}
|
||||
|
||||
status = libusb_control_transfer(device, 0x21, 1, 0, 0, 0, 0, 1000);
|
||||
if (status < 0) {
|
||||
fprintf(stderr, "libcontrol failed %d\n", status);
|
||||
goto err;
|
||||
}
|
||||
|
||||
status = libusb_bulk_transfer(device, 2, (unsigned char *)dtree, dsize, &tsize, 5000);
|
||||
if (status < 0) {
|
||||
fprintf(stderr, "Sending dtree failed with status %d\n", status);
|
||||
goto err;
|
||||
}
|
||||
|
||||
status = libusb_control_transfer(device, 0x21, 3, 0, 0, (unsigned char *)DTREECMD, strlen(DTREECMD)+1, 1000);
|
||||
if (status < 0) {
|
||||
fprintf(stderr, "failed sending dtree cmd %d\n", status);
|
||||
goto err;
|
||||
}
|
||||
|
||||
done = 0;
|
||||
status = libusb_control_transfer(device, 0x21, 2, 0, 0, 0, 0, 0);
|
||||
if (status < 0) {
|
||||
fprintf(stderr, "libcontrol failed %d\n", status);
|
||||
goto err;
|
||||
}
|
||||
|
||||
status = libusb_control_transfer(device, 0x21, 1, 0, 0, 0, 0, 0);
|
||||
if (status < 0) {
|
||||
fprintf(stderr, "libcontrol failed %d\n", status);
|
||||
goto err;
|
||||
}
|
||||
|
||||
while(done < size) {
|
||||
chunk = size - done;
|
||||
if(chunk > 1048576)
|
||||
chunk = 1048576;
|
||||
status = libusb_bulk_transfer(device, 2, (unsigned char *)kbuff + done, chunk, &tsize, 5000);
|
||||
if(status == LIBUSB_ERROR_PIPE) {
|
||||
printf("libusb_bulk_transfer failed with error %d\n", status);
|
||||
libusb_clear_halt(device, 2);
|
||||
j ++;
|
||||
if(j >= 5)
|
||||
break;
|
||||
} else {
|
||||
done += tsize;
|
||||
if(!tsize)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(done != size) {
|
||||
printf("Failed to transfer image to device\n");
|
||||
status = 1;
|
||||
goto err;
|
||||
}
|
||||
|
||||
status = libusb_control_transfer(device, 0x21, 4, 0, 0, 0, 0, 0);
|
||||
if (status < 0) {
|
||||
fprintf(stderr, "libcontrol failed %d\n", status);
|
||||
goto err;
|
||||
}
|
||||
libusb_control_transfer(device, 0x21, 3, 0, 0, (unsigned char *)BOOTCMD, strlen(BOOTCMD)+1, 0);
|
||||
|
||||
printf("Success!\n");
|
||||
|
||||
err:
|
||||
if(kbuff)
|
||||
free(kbuff);
|
||||
|
||||
if(device) {
|
||||
libusb_release_interface(device, 0);
|
||||
libusb_close(device);
|
||||
}
|
||||
libusb_exit(NULL);
|
||||
return status;
|
||||
}
|
||||
7
syscfg/Makefile
Normal file
7
syscfg/Makefile
Normal file
@@ -0,0 +1,7 @@
|
||||
CFLAGS = -O2 -Wall -I.
|
||||
|
||||
syscfg: main.o syscfg.o
|
||||
$(CC) -o $@ $(LDFLAGS) $^ $(LIBRARIES)
|
||||
|
||||
clean:
|
||||
rm -f main.o syscfg.o syscfg
|
||||
86
syscfg/main.c
Normal file
86
syscfg/main.c
Normal file
@@ -0,0 +1,86 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* Copyright (C) 2020 Corellium LLC
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <syscfg.h>
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
uint8_t *buf, ch;
|
||||
unsigned long len, explen = 0, i;
|
||||
char fmt = 's', sep = 0, *fa;
|
||||
uint64_t ubuf;
|
||||
|
||||
if(argc < 3 || argc > 4) {
|
||||
fprintf(stderr, "usage: syscfg <syscfg.bin> <entry> [<format>]\n"
|
||||
" <syscfg.bin> is usually /dev/nvme0n3\n"
|
||||
" <entry> is 4-characted entry ID\n"
|
||||
" <format> is [<type>][<len>]\n"
|
||||
" <type> is 's' for string, 'z' for zero-terminated string,\n"
|
||||
" 'u' for unsigned decimal, 'x' for hex\n"
|
||||
" (optionally followed by separator character)\n"
|
||||
" <len> is expected number of bytes (otherwise prints all)\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
buf = syscfg_get(argv[1], argv[2], &len);
|
||||
if(!buf) {
|
||||
fprintf(stderr, "SysCfg item '%s' not found.\n", argv[2]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if(argc >= 4) {
|
||||
fa = argv[3];
|
||||
if(fa[0] > '9') {
|
||||
fmt = fa[0];
|
||||
fa ++;
|
||||
if(fa[0] && (fa[0] < '0' || fa[0] > '9')) {
|
||||
sep = fa[0];
|
||||
fa ++;
|
||||
}
|
||||
}
|
||||
if(fa[0])
|
||||
explen = strtoul(fa, NULL, 0);
|
||||
}
|
||||
|
||||
if(!explen)
|
||||
explen = len;
|
||||
|
||||
if(fmt == 'u') {
|
||||
if(len > 8)
|
||||
len = 8;
|
||||
ubuf = 0;
|
||||
memcpy(&ubuf, buf, len);
|
||||
printf("%llu", (unsigned long long)ubuf);
|
||||
return 0;
|
||||
}
|
||||
|
||||
for(i=0; i<explen; i++) {
|
||||
ch = (i < len) ? buf[i] : 0;
|
||||
switch(fmt) {
|
||||
case 's':
|
||||
putchar(ch);
|
||||
break;
|
||||
case 'z':
|
||||
if(ch == '\0')
|
||||
return 0;
|
||||
putchar(ch);
|
||||
break;
|
||||
case 'x':
|
||||
printf("%02x", ch);
|
||||
if(sep && i < explen - 1)
|
||||
putchar(sep);
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "unknown format character '%c'.\n", fmt);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
136
syscfg/syscfg.c
Normal file
136
syscfg/syscfg.c
Normal file
@@ -0,0 +1,136 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* Copyright (C) 2018-20 Corellium LLC
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#define DEFAULT_SIZE 131072
|
||||
#define MAX_SIZE 8192
|
||||
|
||||
struct syscfg_hdr {
|
||||
char magic[4];
|
||||
uint32_t unk_0; /* 0x7C */
|
||||
uint32_t size;
|
||||
uint32_t version;
|
||||
uint32_t unk_1; /* 0 */
|
||||
uint32_t nkeys;
|
||||
};
|
||||
|
||||
struct syscfg_key {
|
||||
char name[4];
|
||||
union {
|
||||
uint8_t value[16];
|
||||
struct {
|
||||
char name[4];
|
||||
uint32_t size;
|
||||
uint32_t offset;
|
||||
uint32_t rsvd; /* -1 */
|
||||
} jumbo;
|
||||
};
|
||||
};
|
||||
|
||||
static void flip4(char *out, char *in)
|
||||
{
|
||||
unsigned i;
|
||||
for(i=0; i<4; i++)
|
||||
out[i] = in[3-i];
|
||||
}
|
||||
|
||||
void *syscfg_get(const char *fname, const char *elem, unsigned long *plen)
|
||||
{
|
||||
FILE *f = fopen(fname, "rb");
|
||||
unsigned size, elen = 0;
|
||||
uint8_t *buf;
|
||||
struct syscfg_hdr *hdr;
|
||||
struct syscfg_key *key;
|
||||
unsigned idx;
|
||||
char name[5];
|
||||
void *eval = NULL, *res = NULL;
|
||||
|
||||
if(!f) {
|
||||
fprintf(stderr, "Could not open file '%s'.\n", fname);
|
||||
return NULL;
|
||||
}
|
||||
fseek(f, 0, SEEK_END);
|
||||
size = ftell(f);
|
||||
fseek(f, 0, SEEK_SET);
|
||||
|
||||
if(!size)
|
||||
size = DEFAULT_SIZE;
|
||||
|
||||
buf = malloc(size);
|
||||
if(!buf) {
|
||||
fclose(f);
|
||||
fprintf(stderr, "Could not allocate memory.\n");
|
||||
return NULL;
|
||||
}
|
||||
size = fread(buf, 1, size, f);
|
||||
fclose(f);
|
||||
|
||||
if(size < sizeof(struct syscfg_hdr)) {
|
||||
fprintf(stderr, "SysCfg too small for header.\n");
|
||||
free(buf);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
hdr = (void *)buf;
|
||||
if(memcmp(hdr->magic, "gfCS", 4)) {
|
||||
fprintf(stderr, "SysCfg header magic value incorrect.\n");
|
||||
free(buf);
|
||||
return NULL;
|
||||
}
|
||||
if(hdr->size > size) {
|
||||
fprintf(stderr, "SysCfg header declares %d bytes, but only %d in file.\n", hdr->size, size);
|
||||
free(buf);
|
||||
return NULL;
|
||||
}
|
||||
if(hdr->nkeys * sizeof(struct syscfg_key) + sizeof(struct syscfg_hdr) > hdr->size) {
|
||||
fprintf(stderr, "SysCfg header declares %d entries, does not fit in %d bytes.\n", hdr->nkeys, hdr->size);
|
||||
free(buf);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
key = (void *)(hdr + 1);
|
||||
name[4] = 0;
|
||||
for(idx=0; idx<hdr->nkeys; idx++)
|
||||
if(memcmp(key[idx].name, "BTNC", 4)) {
|
||||
flip4(name, key[idx].name);
|
||||
if(!strcmp(name, elem)) {
|
||||
eval = key[idx].value;
|
||||
elen = sizeof(key[idx].value);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
flip4(name, key[idx].jumbo.name);
|
||||
if(!strcmp(name, elem)) {
|
||||
if(key[idx].jumbo.offset > hdr->size || key[idx].jumbo.offset + key[idx].jumbo.size > hdr->size) {
|
||||
fprintf(stderr, "SysCfg jumbo key '%s' does not fit in %d bytes (%d+%d).\n", name, hdr->size, key[idx].jumbo.offset, key[idx].jumbo.size);
|
||||
free(buf);
|
||||
return NULL;
|
||||
}
|
||||
eval = buf + key[idx].jumbo.offset;
|
||||
elen = key[idx].jumbo.size;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(eval) {
|
||||
res = malloc(elen);
|
||||
if(!res) {
|
||||
free(buf);
|
||||
fprintf(stderr, "Could not allocate memory.\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memcpy(res, eval, elen);
|
||||
}
|
||||
|
||||
free(buf);
|
||||
if(plen)
|
||||
*plen = elen;
|
||||
return res;
|
||||
}
|
||||
11
syscfg/syscfg.h
Normal file
11
syscfg/syscfg.h
Normal file
@@ -0,0 +1,11 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* Copyright (C) 2018-20 Corellium LLC
|
||||
*/
|
||||
|
||||
#ifndef _SYSCFG_H
|
||||
#define _SYSCFG_H
|
||||
|
||||
void *syscfg_get(const char *fname, const char *elem, unsigned long *plen);
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user