FreeCalypso > hg > freecalypso-reveng
diff mysteryffs/dump1.c @ 22:00ad22936ca5
MysteryFFS dump1 tool written
author | Michael Spacefalcon <msokolov@ivan.Harhan.ORG> |
---|---|
date | Sat, 18 May 2013 19:21:09 +0000 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mysteryffs/dump1.c Sat May 18 19:21:09 2013 +0000 @@ -0,0 +1,245 @@ +/* + * This program attempts to traverse the FFS directory tree + * from the root down, following the descendant and sibling + * pointers, and dumps everything it encounters. + * + * The objective is to understand how to extract the precise + * content of data files. + */ + +#include <sys/types.h> +#include <sys/file.h> +#include <sys/stat.h> +#include <endian.h> +#include <ctype.h> +#include <stdio.h> +#include <string.h> +#include <strings.h> +#include <stdlib.h> +#include <unistd.h> + +typedef unsigned char u8; +typedef unsigned short u16; +typedef unsigned int u32; + +u8 mysteryffs_hdr[6] = {'F', 'f', 's', '#', 0x10, 0x02}; + +struct index_entry { + u16 len; + u8 unknown_b1; + u8 type; + u16 descend; + u16 sibling; + u32 dataptr; + u16 unknown_w1; + u16 unknown_w2; +}; + +char *imgfile; +u32 eraseblk_size; +int total_blocks; +u32 total_img_size; +u8 *image, *indexblk; + +char workpath[512]; + +read_img_file() +{ + int fd; + struct stat st; + + fd = open(imgfile, O_RDONLY); + if (fd < 0) { + perror(imgfile); + exit(1); + } + fstat(fd, &st); + if (!S_ISREG(st.st_mode)) { + fprintf(stderr, "%s is not a regular file\n", imgfile); + exit(1); + } + if (st.st_size < total_img_size) { + fprintf(stderr, "%s has fewer than 0x%x bytes\n", imgfile, + total_img_size); + exit(1); + } + image = malloc(total_img_size); + if (!image) { + perror("malloc"); + exit(1); + } + read(fd, image, total_img_size); + close(fd); +} + +find_index_block() +{ + int i; + u8 *ptr; + + for (ptr = image, i = 0; i < total_blocks; i++, ptr += eraseblk_size) { + if (bcmp(ptr, mysteryffs_hdr, 6)) + continue; + if (ptr[8] != 0xAB) + continue; + printf("Found index in erase block #%d (offset %x)\n", i, + ptr - image); + indexblk = ptr; + return(0); + } + fprintf(stderr, "could not find a MysteryFFS index block in %s\n", + imgfile); + exit(1); +} + +get_index_entry(num, host) + int num; + struct index_entry *host; +{ + struct index_entry *le; + + le = (struct index_entry *) indexblk + num; + host->len = le16toh(le->len); + host->unknown_b1 = le->unknown_b1; + host->type = le->type; + host->descend = le16toh(le->descend); + host->sibling = le16toh(le->sibling); + host->dataptr = le32toh(le->dataptr); + host->unknown_w1 = le16toh(le->unknown_w1); + host->unknown_w2 = le16toh(le->unknown_w2); +} + +is_namestr_ok(s) + char *s; +{ + int cnt; + + for (cnt = 0; *s; s++, cnt++) { + if (cnt >= 32) + return(0); + if (!isprint(*s)) + return(0); + } + if (cnt) + return(1); + else + return(0); +} + +char * +get_name(dptr) + u32 dptr; +{ + u8 *name; + + if (dptr > 0x0FFFFFFF) + return(0); + dptr <<= 4; + if (dptr >= total_img_size - 32) + return(0); + name = image + dptr; + if (is_namestr_ok(name)) + return(name); + else + return(0); +} + +dump_common(idx, rec, path_prefix, typestr, newprefix) + int idx, path_prefix, *newprefix; + struct index_entry *rec; + char *typestr; +{ + u8 *name; + + name = get_name(rec->dataptr); + if (!name) { + printf("entry #%x has an invalid name pointer!\n", idx); + return(-1); + } + if (sizeof(workpath) - path_prefix < strlen(name) + 2) { + printf("entry #%x: pathname buffer overflow!\n", idx); + return(-1); + } + path_prefix += sprintf(workpath + path_prefix, "/%s", name); + printf("\n%s (%s)\n", workpath, typestr); + printf("len=%x, unknown fields: %02X %04X %04X\n", rec->len, + rec->unknown_b1, rec->unknown_w1, rec->unknown_w2); + if (newprefix) + *newprefix = path_prefix; + return(0); +} + +dump_dir(firstent, path_prefix) +{ + struct index_entry rec; + int ent; + int subprefix; + + for (ent = firstent; ent != 0xFFFF; ent = rec.sibling) { + get_index_entry(ent, &rec); + switch (rec.type) { + case 0x00: + /* deleted object - skip it */ + continue; + case 0xF2: + /* subdirectory */ + if (dump_common(ent, &rec, path_prefix, "directory", + &subprefix) < 0) + continue; + dump_dir(rec.descend, subprefix); + continue; + case 0xF1: + /* regular file */ + dump_common(ent, &rec, path_prefix, "file", 0); + continue; + case 0xE1: + /* special .journal file */ + dump_common(ent, &rec, path_prefix, "E1 file", 0); + continue; + default: + printf("entry #%x: unexpected type %02X\n", ent, + rec.type); + } + } +} + +dump_root() +{ + struct index_entry rec; + char *name; + + get_index_entry(1, &rec); + if (rec.type != 0xF2) { + fprintf(stderr, + "error: entry #1 (expected root dir) is not a directory\n"); + exit(1); + } + name = get_name(rec.dataptr); + if (!name) { + fprintf(stderr, "root entry has an invalid name pointer!\n"); + exit(1); + } + printf("Root node name: %s\n", name); + printf("len=%x, unknown fields: %02X %04X %04X\n", rec.len, + rec.unknown_b1, rec.unknown_w1, rec.unknown_w2); + if (rec.sibling != 0xFFFF) + printf("warning: root entry has a non-nil sibling pointer\n"); + dump_dir(rec.descend, 0); +} + +main(argc, argv) + char **argv; +{ + if (argc != 4) { + fprintf(stderr, "usage: %s imgfile blksize nblocks\n", argv[0]); + exit(1); + } + imgfile = argv[1]; + eraseblk_size = strtoul(argv[2], 0, 0); + total_blocks = strtoul(argv[3], 0, 0); + total_img_size = eraseblk_size * total_blocks; + read_img_file(); + find_index_block(); + dump_root(); + exit(0); +}