Loader and utilities for Android on iPhone.

This commit is contained in:
Stan Skowronek
2020-03-04 10:39:21 -05:00
parent 49dc50bfba
commit 28283124f9
7 changed files with 454 additions and 0 deletions

View File

@@ -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
View 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
View 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
View 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
View 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
View 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
View 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