comparison mysteryffs/dump2.c @ 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
children 9f3a7b014e63
comparison
equal deleted inserted replaced
22:00ad22936ca5 23:671db68916c7
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_data_frag(entryidx, rec)
173 struct index_entry *rec;
174 {
175 u32 dptr, endptr;
176 int i, c;
177
178 if (rec->len & 0xF || !rec->len) {
179 printf("entry #%x: don't know how to dump fragment of length %x\n",
180 entryidx, rec->len);
181 return(-1);
182 }
183 dptr = rec->dataptr;
184 if (dptr > 0x0FFFFFFF) {
185 inv: printf("entry #%x: invalid data pointer\n", entryidx);
186 return(-1);
187 }
188 dptr <<= 4;
189 if (dptr > total_img_size - rec->len)
190 goto inv;
191 for (endptr = dptr + rec->len; dptr < endptr; dptr += 0x10) {
192 printf("%08X: ", dptr);
193 for (i = 0; i < 16; i++) {
194 printf("%02X ", image[dptr + i]);
195 if (i == 7 || i == 15)
196 putchar(' ');
197 }
198 for (i = 0; i < 16; i++) {
199 c = image[dptr + i];
200 if (!isprint(c))
201 c = '.';
202 putchar(c);
203 }
204 putchar('\n');
205 }
206 return(0);
207 }
208
209 dump_dir(firstent, path_prefix)
210 {
211 struct index_entry rec;
212 int ent;
213 int subprefix;
214
215 for (ent = firstent; ent != 0xFFFF; ent = rec.sibling) {
216 get_index_entry(ent, &rec);
217 switch (rec.type) {
218 case 0x00:
219 /* deleted object - skip it */
220 continue;
221 case 0xF2:
222 /* subdirectory */
223 if (dump_common(ent, &rec, path_prefix, "directory",
224 &subprefix) < 0)
225 continue;
226 dump_dir(rec.descend, subprefix);
227 continue;
228 case 0xF1:
229 /* regular file */
230 dump_common(ent, &rec, path_prefix, "file", 0);
231 dump_data_frag(ent, &rec);
232 continue;
233 case 0xE1:
234 /* special .journal file */
235 dump_common(ent, &rec, path_prefix, "E1 file", 0);
236 dump_data_frag(ent, &rec);
237 continue;
238 default:
239 printf("entry #%x: unexpected type %02X\n", ent,
240 rec.type);
241 }
242 }
243 }
244
245 dump_root()
246 {
247 struct index_entry rec;
248 char *name;
249
250 get_index_entry(1, &rec);
251 if (rec.type != 0xF2) {
252 fprintf(stderr,
253 "error: entry #1 (expected root dir) is not a directory\n");
254 exit(1);
255 }
256 name = get_name(rec.dataptr);
257 if (!name) {
258 fprintf(stderr, "root entry has an invalid name pointer!\n");
259 exit(1);
260 }
261 printf("Root node name: %s\n", name);
262 printf("len=%x, unknown fields: %02X %04X %04X\n", rec.len,
263 rec.unknown_b1, rec.unknown_w1, rec.unknown_w2);
264 if (rec.sibling != 0xFFFF)
265 printf("warning: root entry has a non-nil sibling pointer\n");
266 dump_dir(rec.descend, 0);
267 }
268
269 main(argc, argv)
270 char **argv;
271 {
272 if (argc != 4) {
273 fprintf(stderr, "usage: %s imgfile blksize nblocks\n", argv[0]);
274 exit(1);
275 }
276 imgfile = argv[1];
277 eraseblk_size = strtoul(argv[2], 0, 0);
278 total_blocks = strtoul(argv[3], 0, 0);
279 total_img_size = eraseblk_size * total_blocks;
280 read_img_file();
281 find_index_block();
282 dump_root();
283 exit(0);
284 }