comparison 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
comparison
equal deleted inserted replaced
21:d41c555d7f1d 22:00ad22936ca5
1 /*
2 * This program attempts to traverse the FFS directory tree
3 * from the root down, following the descendant and sibling
4 * pointers, and dumps everything it encounters.
5 *
6 * The objective is to understand how to extract the precise
7 * content of data files.
8 */
9
10 #include <sys/types.h>
11 #include <sys/file.h>
12 #include <sys/stat.h>
13 #include <endian.h>
14 #include <ctype.h>
15 #include <stdio.h>
16 #include <string.h>
17 #include <strings.h>
18 #include <stdlib.h>
19 #include <unistd.h>
20
21 typedef unsigned char u8;
22 typedef unsigned short u16;
23 typedef unsigned int u32;
24
25 u8 mysteryffs_hdr[6] = {'F', 'f', 's', '#', 0x10, 0x02};
26
27 struct index_entry {
28 u16 len;
29 u8 unknown_b1;
30 u8 type;
31 u16 descend;
32 u16 sibling;
33 u32 dataptr;
34 u16 unknown_w1;
35 u16 unknown_w2;
36 };
37
38 char *imgfile;
39 u32 eraseblk_size;
40 int total_blocks;
41 u32 total_img_size;
42 u8 *image, *indexblk;
43
44 char workpath[512];
45
46 read_img_file()
47 {
48 int fd;
49 struct stat st;
50
51 fd = open(imgfile, O_RDONLY);
52 if (fd < 0) {
53 perror(imgfile);
54 exit(1);
55 }
56 fstat(fd, &st);
57 if (!S_ISREG(st.st_mode)) {
58 fprintf(stderr, "%s is not a regular file\n", imgfile);
59 exit(1);
60 }
61 if (st.st_size < total_img_size) {
62 fprintf(stderr, "%s has fewer than 0x%x bytes\n", imgfile,
63 total_img_size);
64 exit(1);
65 }
66 image = malloc(total_img_size);
67 if (!image) {
68 perror("malloc");
69 exit(1);
70 }
71 read(fd, image, total_img_size);
72 close(fd);
73 }
74
75 find_index_block()
76 {
77 int i;
78 u8 *ptr;
79
80 for (ptr = image, i = 0; i < total_blocks; i++, ptr += eraseblk_size) {
81 if (bcmp(ptr, mysteryffs_hdr, 6))
82 continue;
83 if (ptr[8] != 0xAB)
84 continue;
85 printf("Found index in erase block #%d (offset %x)\n", i,
86 ptr - image);
87 indexblk = ptr;
88 return(0);
89 }
90 fprintf(stderr, "could not find a MysteryFFS index block in %s\n",
91 imgfile);
92 exit(1);
93 }
94
95 get_index_entry(num, host)
96 int num;
97 struct index_entry *host;
98 {
99 struct index_entry *le;
100
101 le = (struct index_entry *) indexblk + num;
102 host->len = le16toh(le->len);
103 host->unknown_b1 = le->unknown_b1;
104 host->type = le->type;
105 host->descend = le16toh(le->descend);
106 host->sibling = le16toh(le->sibling);
107 host->dataptr = le32toh(le->dataptr);
108 host->unknown_w1 = le16toh(le->unknown_w1);
109 host->unknown_w2 = le16toh(le->unknown_w2);
110 }
111
112 is_namestr_ok(s)
113 char *s;
114 {
115 int cnt;
116
117 for (cnt = 0; *s; s++, cnt++) {
118 if (cnt >= 32)
119 return(0);
120 if (!isprint(*s))
121 return(0);
122 }
123 if (cnt)
124 return(1);
125 else
126 return(0);
127 }
128
129 char *
130 get_name(dptr)
131 u32 dptr;
132 {
133 u8 *name;
134
135 if (dptr > 0x0FFFFFFF)
136 return(0);
137 dptr <<= 4;
138 if (dptr >= total_img_size - 32)
139 return(0);
140 name = image + dptr;
141 if (is_namestr_ok(name))
142 return(name);
143 else
144 return(0);
145 }
146
147 dump_common(idx, rec, path_prefix, typestr, newprefix)
148 int idx, path_prefix, *newprefix;
149 struct index_entry *rec;
150 char *typestr;
151 {
152 u8 *name;
153
154 name = get_name(rec->dataptr);
155 if (!name) {
156 printf("entry #%x has an invalid name pointer!\n", idx);
157 return(-1);
158 }
159 if (sizeof(workpath) - path_prefix < strlen(name) + 2) {
160 printf("entry #%x: pathname buffer overflow!\n", idx);
161 return(-1);
162 }
163 path_prefix += sprintf(workpath + path_prefix, "/%s", name);
164 printf("\n%s (%s)\n", workpath, typestr);
165 printf("len=%x, unknown fields: %02X %04X %04X\n", rec->len,
166 rec->unknown_b1, rec->unknown_w1, rec->unknown_w2);
167 if (newprefix)
168 *newprefix = path_prefix;
169 return(0);
170 }
171
172 dump_dir(firstent, path_prefix)
173 {
174 struct index_entry rec;
175 int ent;
176 int subprefix;
177
178 for (ent = firstent; ent != 0xFFFF; ent = rec.sibling) {
179 get_index_entry(ent, &rec);
180 switch (rec.type) {
181 case 0x00:
182 /* deleted object - skip it */
183 continue;
184 case 0xF2:
185 /* subdirectory */
186 if (dump_common(ent, &rec, path_prefix, "directory",
187 &subprefix) < 0)
188 continue;
189 dump_dir(rec.descend, subprefix);
190 continue;
191 case 0xF1:
192 /* regular file */
193 dump_common(ent, &rec, path_prefix, "file", 0);
194 continue;
195 case 0xE1:
196 /* special .journal file */
197 dump_common(ent, &rec, path_prefix, "E1 file", 0);
198 continue;
199 default:
200 printf("entry #%x: unexpected type %02X\n", ent,
201 rec.type);
202 }
203 }
204 }
205
206 dump_root()
207 {
208 struct index_entry rec;
209 char *name;
210
211 get_index_entry(1, &rec);
212 if (rec.type != 0xF2) {
213 fprintf(stderr,
214 "error: entry #1 (expected root dir) is not a directory\n");
215 exit(1);
216 }
217 name = get_name(rec.dataptr);
218 if (!name) {
219 fprintf(stderr, "root entry has an invalid name pointer!\n");
220 exit(1);
221 }
222 printf("Root node name: %s\n", name);
223 printf("len=%x, unknown fields: %02X %04X %04X\n", rec.len,
224 rec.unknown_b1, rec.unknown_w1, rec.unknown_w2);
225 if (rec.sibling != 0xFFFF)
226 printf("warning: root entry has a non-nil sibling pointer\n");
227 dump_dir(rec.descend, 0);
228 }
229
230 main(argc, argv)
231 char **argv;
232 {
233 if (argc != 4) {
234 fprintf(stderr, "usage: %s imgfile blksize nblocks\n", argv[0]);
235 exit(1);
236 }
237 imgfile = argv[1];
238 eraseblk_size = strtoul(argv[2], 0, 0);
239 total_blocks = strtoul(argv[3], 0, 0);
240 total_img_size = eraseblk_size * total_blocks;
241 read_img_file();
242 find_index_block();
243 dump_root();
244 exit(0);
245 }