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