FreeCalypso > hg > freecalypso-reveng
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 } |