changeset 23:671db68916c7

MysteryFFS: dump2 started, dumping the initial frag of each file
author Michael Spacefalcon <msokolov@ivan.Harhan.ORG>
date Sat, 18 May 2013 19:48:07 +0000
parents 00ad22936ca5
children 9f3a7b014e63
files .hgignore mysteryffs/Makefile mysteryffs/dump2.c
diffstat 3 files changed, 287 insertions(+), 2 deletions(-) [+]
line wrap: on
line diff
--- a/.hgignore	Sat May 18 19:21:09 2013 +0000
+++ b/.hgignore	Sat May 18 19:48:07 2013 +0000
@@ -1,3 +1,3 @@
 re:^mokosrec2bin$
-re:^mysteryffs/dump1$
+re:^mysteryffs/dump[12]$
 re:^mysteryffs/scan1$
--- a/mysteryffs/Makefile	Sat May 18 19:21:09 2013 +0000
+++ b/mysteryffs/Makefile	Sat May 18 19:48:07 2013 +0000
@@ -1,6 +1,6 @@
 CC=	gcc
 CFLAGS=	-O2
-PROGS=	dump1 scan1
+PROGS=	dump1 dump2 scan1
 
 all:	${PROGS}
 
@@ -8,6 +8,7 @@
 	${CC} ${CFLAGS} -o $@ $@.c
 
 dump1:	dump1.c
+dump2:	dump2.c
 scan1:	scan1.c
 
 clean:
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mysteryffs/dump2.c	Sat May 18 19:48:07 2013 +0000
@@ -0,0 +1,284 @@
+/*
+ * 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_data_frag(entryidx, rec)
+	struct index_entry *rec;
+{
+	u32 dptr, endptr;
+	int i, c;
+
+	if (rec->len & 0xF || !rec->len) {
+	    printf("entry #%x: don't know how to dump fragment of length %x\n",
+			entryidx, rec->len);
+	    return(-1);
+	}
+	dptr = rec->dataptr;
+	if (dptr > 0x0FFFFFFF) {
+inv:		printf("entry #%x: invalid data pointer\n", entryidx);
+		return(-1);
+	}
+	dptr <<= 4;
+	if (dptr > total_img_size - rec->len)
+		goto inv;
+	for (endptr = dptr + rec->len; dptr < endptr; dptr += 0x10) {
+		printf("%08X:  ", dptr);
+		for (i = 0; i < 16; i++) {
+			printf("%02X ", image[dptr + i]);
+			if (i == 7 || i == 15)
+				putchar(' ');
+		}
+		for (i = 0; i < 16; i++) {
+			c = image[dptr + i];
+			if (!isprint(c))
+				c = '.';
+			putchar(c);
+		}
+		putchar('\n');
+	}
+	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);
+			dump_data_frag(ent, &rec);
+			continue;
+		case 0xE1:
+			/* special .journal file */
+			dump_common(ent, &rec, path_prefix, "E1 file", 0);
+			dump_data_frag(ent, &rec);
+			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);
+}