Add a tool to parse binary Bluetooth firmware files.

This commit is contained in:
Stan Skowronek
2020-03-05 18:13:35 -05:00
parent a4bd5dbf27
commit b35ede6774
3 changed files with 184 additions and 0 deletions

View File

@@ -6,6 +6,7 @@ Android/Linux for the iPhone
* `loader/` loads kernel and device tree via pongoOS
* `syscfg/` tool to extract configuration information from syscfg partition on devices
* `hx-touchd/` touch screen support daemon
* `hcdpack/` tool to heuristically extract Bluetooth firmware from binaries
## Kernel

7
hcdpack/Makefile Normal file
View File

@@ -0,0 +1,7 @@
CFLAGS = -O2 -Wall -I.
hcdpack: hcdpack.o
$(CC) -o $@ $(LDFLAGS) $^ $(LIBRARIES)
clean:
rm -f hcdpack.o hcdpack

176
hcdpack/hcdpack.c Normal file
View File

@@ -0,0 +1,176 @@
#define _XOPEN_SOURCE 500
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <ctype.h>
#define MAX_IMAGES 128
static uint8_t *buf;
static size_t size;
static struct {
size_t offs, size;
char *name;
} images[MAX_IMAGES];
static unsigned nimages;
static void process_cfgd(uint8_t *buf, size_t size, char *name)
{
size_t strsz;
if(size < 11)
return;
strsz = buf[10];
if(strsz > size - 11)
return;
memcpy(name, &buf[11], strsz);
name[strsz] = 0;
}
static size_t process_image(uint8_t *buf, size_t size, char *name)
{
size_t offs, itsz;
uint16_t op;
for(offs=0; offs<=size-3; ) {
op = *(uint16_t *)&buf[offs];
itsz = buf[offs+2];
if(itsz > size - offs - 3)
itsz = size - offs - 3;
if(op != 0xFC4E && op != 0xFC4C)
break;
if(offs > 0 && offs <= size - 15 && buf[offs] == 0x4C && buf[offs+1] == 0xFC && !memcmp(&buf[offs+7], "BRCMcfgS", 8))
break;
if(offs <= size - 15 && buf[offs] == 0x4C && buf[offs+1] == 0xFC && !memcmp(&buf[offs+7], "BRCMcfgD", 8))
process_cfgd(&buf[offs+15], itsz - 12, name);
offs += itsz + 3;
if(op == 0xFC4E)
break;
}
return offs;
}
static void collect_images(int print)
{
size_t offs, imsz;
char name[256];
for(offs=0; offs<=size-15; offs++) {
if(buf[offs] != 0x4C || buf[offs+1] != 0xFC)
continue;
if(memcmp(&buf[offs+7], "BRCMcfgS", 8))
continue;
name[0] = 0;
imsz = process_image(buf + offs, size - offs, name);
if(print)
printf("Found sig at %ld (%ld): %s\n", offs, imsz, name);
if(nimages < MAX_IMAGES) {
images[nimages].offs = offs;
images[nimages].size = imsz;
images[nimages].name = strdup(name);
nimages ++;
}
offs += imsz - 1;
}
}
static void get_tag(const char *str, char id, char *out, size_t outlen)
{
const char *n;
size_t l;
out[0] = 0;
while(*str) {
if(str[0] == '_') {
str ++;
continue;
}
if(str[1] != '-')
return;
n = strchr(str + 2, '_');
if(!n)
n = str + strlen(str);
if(str[0] == id) {
str += 2;
l = n - str;
if(l + 1 > outlen)
l = outlen - 1;
memcpy(out, str, l);
out[l] = 0;
return;
}
str = n;
}
}
int main(int argc, char *argv[])
{
FILE *f;
char chip[8], rev[4], mod[32], vend[4], *vendstr;
char chipstr[64], modstr[64];
unsigned i;
if(argc != 2 && argc != 6) {
fprintf(stderr, "usage: autohcd <hcd-pack>\n");
fprintf(stderr, " autohcd <hcd-pack> <otp-chip> <module> <otp-nvram> <outfile>\n");
return 1;
}
f = fopen(argv[1], "rb");
if(!f) {
fprintf(stderr, "error: failed opening '%s'.\n", argv[1]);
return 1;
}
fseek(f, 0, SEEK_END);
size = ftell(f);
fseek(f, 0, SEEK_SET);
buf = malloc(size);
fread(buf, 1, size, f);
fclose(f);
collect_images(argc == 2);
if(argc < 6)
return 0;
get_tag(argv[2], 'C', chip, sizeof(chip));
get_tag(argv[2], 's', rev, sizeof(rev));
strcpy(mod, argv[3]);
mod[0] = toupper(mod[0]);
get_tag(argv[4], 'V', vend, sizeof(vend));
switch(tolower(vend[0])) {
case 'm': vendstr = "MUR"; break;
case 'u': vendstr = "USI"; break;
case 't': vendstr = "TDK"; break;
default: vendstr = "UNK";
}
sprintf(chipstr, "BCM%s%s ", chip, rev);
sprintf(modstr, " %s %s", mod, vendstr);
for(i=0; i<nimages; i++) {
if(strncmp(images[i].name, chipstr, strlen(chipstr)))
continue;
if(strstr(images[i].name, modstr))
break;
}
if(i >= nimages) {
fprintf(stderr, "Image for %s/%s not found.\n", chipstr, modstr);
return 1;
}
f = fopen(argv[5], "wb");
if(!f) {
fprintf(stderr, "error: failed opening '%s' for write.\n", argv[5]);
return 1;
}
fwrite(buf + images[i].offs, images[i].size, 1, f);
fclose(f);
printf("BCM%s%s.hcd", chip, rev);
return 0;
}