Rev 16 | Rev 27 | Go to most recent revision | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed
Rev 16 | Rev 26 | ||
---|---|---|---|
Line 21... | Line 21... | ||
21 | #include <unistd.h> |
21 | #include <unistd.h> |
22 | #include <utime.h> |
22 | #include <utime.h> |
23 | #endif // _MSC_VER |
23 | #endif // _MSC_VER |
24 | 24 | ||
25 | // own includes |
25 | // own includes |
- | 26 | #include "ucl/ucl.h" |
|
- | 27 | #include "minilzo.h" |
|
26 | #include "buffer.h" |
28 | #include "buffer.h" |
27 | #include "sha512.h" |
29 | #include "sha512.h" |
28 | #include "ifsfile.h" |
30 | #include "ifsfile.h" |
29 | #include "elffile.h" |
31 | #include "elffile.h" |
30 | #include "utility.h" |
32 | #include "utility.h" |
Line 33... | Line 35... | ||
33 | // imported global variables |
35 | // imported global variables |
34 | extern int verbose_level; // from ifstool.c |
36 | extern int verbose_level; // from ifstool.c |
35 | 37 | ||
36 | 38 | ||
37 | // exported function prototypes |
39 | // exported function prototypes |
38 | int dump_ifs_info (const char *ifs_pathname, bool want_everything); // dumps detailed info about a particular IFS file on the standard output, returns 0 on success and >0 on error |
40 | int dump_ifs_info (const char *ifs_pathname, bool want_everything, bool hide_filename); // dumps detailed info about a particular IFS file on the standard output, returns 0 on success and >0 on error |
39 | int dump_ifs_contents (const char *ifs_pathname, const char *outdir); // dumps the IFS filesystem contents in outdir, returns 0 on success and >0 on error |
41 | int dump_ifs_contents (const char *ifs_pathname, const char *outdir); // dumps the IFS filesystem contents in outdir, returns 0 on success and >0 on error |
40 | int dump_file_hex (const char *pathname); // hexdump the content of pathname, returns 0 on success and != 0 on error |
42 | int dump_file_hex (const char *pathname); // hexdump the content of pathname, returns 0 on success and != 0 on error |
41 | 43 | ||
42 | 44 | ||
43 | // prototypes of local functions |
45 | // prototypes of local functions |
Line 149... | Line 151... | ||
149 | } |
151 | } |
150 | return (outstr); |
152 | return (outstr); |
151 | } |
153 | } |
152 | 154 | ||
153 | 155 | ||
154 | int dump_ifs_info (const char *ifs_pathname, bool want_everything) |
156 | int dump_ifs_info (const char *ifs_pathname, bool want_everything, bool hide_filename) |
155 | { |
157 | { |
156 | #define hex_printf(buf,size,...) do { \ |
158 | #define hex_printf(buf,size,...) do { \ |
157 | if (want_everything || ((size) <= 16 * 1024)) /* only print when it's not too big (up to 16 kb) */\ |
159 | if (want_everything || ((size) <= 16 * 1024)) /* only print when it's not too big (up to 16 kb) */\ |
158 | hex_fprintf (stdout, (buf), (size), 16, __VA_ARGS__); /* use 16 columns in hex output to stdout */ \ |
160 | hex_fprintf (stdout, (buf), (size), 16, __VA_ARGS__); /* use 16 columns in hex output to stdout */ \ |
159 | else { \ |
161 | else { \ |
Line 195... | Line 197... | ||
195 | image_trailer_v2_t *image_trailer_v2 = NULL; |
197 | image_trailer_v2_t *image_trailer_v2 = NULL; |
196 | size_t imagetrailer_offset = 0; |
198 | size_t imagetrailer_offset = 0; |
197 | fsentry_t **fsentries = NULL; // mallocated |
199 | fsentry_t **fsentries = NULL; // mallocated |
198 | size_t fsentry_count = 0; |
200 | size_t fsentry_count = 0; |
199 | fsentry_t *current_fsentry = NULL; |
201 | fsentry_t *current_fsentry = NULL; |
- | 202 | buffer_t decompression_dst; |
|
200 | char recorded_sha512[2 * SHA512_DIGEST_LENGTH + 1] = ""; |
203 | char recorded_sha512[2 * SHA512_DIGEST_LENGTH + 1] = ""; |
201 | char computed_sha512[2 * SHA512_DIGEST_LENGTH + 1] = ""; |
204 | char computed_sha512[2 * SHA512_DIGEST_LENGTH + 1] = ""; |
202 | size_t startupfile_blobsize = 0; |
205 | size_t startupfile_blobsize = 0; |
- | 206 | size_t compressed_blocksize; |
|
203 | void *reallocated_ptr; |
207 | void *reallocated_ptr; |
204 | bool is_foreign_endianness; |
208 | bool is_foreign_endianness; |
- | 209 | uint8_t *decompressor_out; |
|
- | 210 | uint8_t *decompressor_in; |
|
- | 211 | size_t decompressor_outlen; |
|
205 | size_t bootfile_blobsize = 0; |
212 | size_t bootfile_blobsize = 0; |
206 | size_t current_offset; |
213 | size_t current_offset; |
207 | size_t fsentry_index; |
214 | size_t fsentry_index; |
208 | size_t nearest_distance; |
215 | size_t nearest_distance; |
209 | size_t nearest_index; |
216 | size_t nearest_index; |
210 | size_t byte_index; |
217 | size_t byte_index; |
211 | uint32_t recorded_checksum; |
218 | uint32_t recorded_checksum; |
212 | uint32_t computed_checksum; |
219 | uint32_t computed_checksum; |
213 | buffer_t file; |
220 | buffer_t file; |
214 | time_t mtime; |
221 | time_t mtime; |
- | 222 | int cf; |
|
215 | 223 | ||
216 | // open and read IFS file |
224 | // open and read IFS file |
217 | if (!Buffer_ReadFromFile (&file, ifs_pathname)) |
225 | if (!Buffer_ReadFromFile (&file, ifs_pathname)) |
218 | DIE_WITH_EXITCODE (1, "can't open \"%s\" for reading: %s", ifs_pathname, strerror (errno)); |
226 | DIE_WITH_EXITCODE (1, "can't open \"%s\" for reading: %s", ifs_pathname, strerror (errno)); |
219 | 227 | ||
220 | printf ("QNX In-kernel Filesystem analysis produced by ifstool version " VERSION_FMT_YYYYMMDD "\n", VERSION_ARG_YYYYMMDD); |
228 | printf ("QNX In-kernel Filesystem analysis produced by ifstool version " VERSION_FMT_YYYYMMDD "\n", VERSION_ARG_YYYYMMDD); |
- | 229 | if (hide_filename) |
|
- | 230 | printf ("IFS file - size 0x%zx (%zd) bytes\n", file.size, file.size); |
|
- | 231 | else |
|
221 | printf ("IFS file \"%s\" - size 0x%zx (%zd) bytes\n", ifs_pathname, file.size, file.size); |
232 | printf ("IFS file \"%s\" - size 0x%zx (%zd) bytes\n", ifs_pathname, file.size, file.size); |
222 | 233 | ||
223 | // parse file from start to end |
234 | // parse file from start to end |
224 | current_offset = 0; |
235 | current_offset = 0; |
- | 236 | cf = STARTUP_HDR_FLAGS1_COMPRESS_NONE; |
|
225 | for (;;) |
237 | for (;;) |
226 | { |
238 | { |
227 | // does a startup header start here ? |
239 | // does a startup header start here ? |
- | 240 | if ((current_offset + sizeof (startup_header_t) < file.size) |
|
- | 241 | && (startup_header == NULL) |
|
228 |
|
242 | && (memcmp (&file.bytes[current_offset], "\xeb\x7e\xff\x00", 4) == 0)) |
229 | { |
243 | { |
230 | startupheader_offset = current_offset; |
244 | startupheader_offset = current_offset; |
231 | startup_header = (startup_header_t *) &file.bytes[startupheader_offset]; |
245 | startup_header = (startup_header_t *) &file.bytes[startupheader_offset]; |
232 | 246 | ||
233 | // layout: |
247 | // layout: |
Line 237... | Line 251... | ||
237 | 251 | ||
238 | printf ("\n"); |
252 | printf ("\n"); |
239 | printf ("Startup header at offset 0x%zx (%zd):\n", current_offset, current_offset); |
253 | printf ("Startup header at offset 0x%zx (%zd):\n", current_offset, current_offset); |
240 | printf (" signature = %02x %02x %02x %02x - good\n", startup_header->signature[0], startup_header->signature[1], startup_header->signature[2], startup_header->signature[3]); |
254 | printf (" signature = %02x %02x %02x %02x - good\n", startup_header->signature[0], startup_header->signature[1], startup_header->signature[2], startup_header->signature[3]); |
241 | printf (" version = 0x%04x (%d) - %s\n", startup_header->version, startup_header->version, (startup_header->version == 1 ? "looks good" : "???")); |
255 | printf (" version = 0x%04x (%d) - %s\n", startup_header->version, startup_header->version, (startup_header->version == 1 ? "looks good" : "???")); |
- | 256 | cf = startup_header->flags1 & STARTUP_HDR_FLAGS1_COMPRESS_MASK; |
|
242 | printf (" flags1 = 0x%02x (%s)\n", startup_header->flags1, describe_uint8 (startup_header->flags1, startupheader_flags1_strings)); |
257 | printf (" flags1 = 0x%02x (%s) - %s\n", startup_header->flags1, describe_uint8 (startup_header->flags1, startupheader_flags1_strings), (cf == STARTUP_HDR_FLAGS1_COMPRESS_NONE ? "uncompressed image" : (cf == STARTUP_HDR_FLAGS1_COMPRESS_ZLIB ? "Zlib-compressed image (non-bootable)" : (cf == STARTUP_HDR_FLAGS1_COMPRESS_LZO ? "LZO-compressed image" : (cf == STARTUP_HDR_FLAGS1_COMPRESS_UCL ? "UCL-compressed image" : "compressed image (unknown algorithm)"))))); |
243 | printf (" flags2 = 0x%02x (%s) - %s\n", startup_header->flags2, BINARY (startup_header->flags2), (startup_header->flags2 == 0 ? "looks good" : "???")); |
258 | printf (" flags2 = 0x%02x (%s) - %s\n", startup_header->flags2, BINARY (startup_header->flags2), (startup_header->flags2 == 0 ? "looks good" : "???")); |
244 | printf (" header_size = 0x%04x (%d) - %s\n", startup_header->header_size, startup_header->header_size, (startup_header->header_size == sizeof (startup_header_t) ? "looks good" : "BAD")); |
259 | printf (" header_size = 0x%04x (%d) - %s\n", startup_header->header_size, startup_header->header_size, (startup_header->header_size == sizeof (startup_header_t) ? "looks good" : "BAD")); |
245 | printf (" machine = 0x%04x (%d) - %s\n", startup_header->machine, startup_header->machine, (startup_header->machine == ELF_MACHINE_X86_64 ? "x86_64" : (startup_header->machine == ELF_MACHINE_AARCH64 ? "aarch64" : "unknown"))); |
260 | printf (" machine = 0x%04x (%d) - %s\n", startup_header->machine, startup_header->machine, (startup_header->machine == ELF_MACHINE_X86_64 ? "x86_64" : (startup_header->machine == ELF_MACHINE_AARCH64 ? "aarch64" : "unknown"))); |
246 | printf (" startup_vaddr = 0x%08x (%d) - virtual address to transfer to after IPL is done\n", startup_header->startup_vaddr, startup_header->startup_vaddr); |
261 | printf (" startup_vaddr = 0x%08x (%d) - virtual address to transfer to after IPL is done\n", startup_header->startup_vaddr, startup_header->startup_vaddr); |
247 | printf (" paddr_bias = 0x%08x (%d) - value to add to physical addresses to get an indirectable pointer value\n", startup_header->paddr_bias, startup_header->paddr_bias); |
262 | printf (" paddr_bias = 0x%08x (%d) - value to add to physical addresses to get an indirectable pointer value\n", startup_header->paddr_bias, startup_header->paddr_bias); |
248 | printf (" image_paddr = 0x%08x (%d) - physical address of image\n", startup_header->image_paddr, startup_header->image_paddr); |
263 | printf (" image_paddr = 0x%08x (%d) - physical address of image\n", startup_header->image_paddr, startup_header->image_paddr); |
249 | printf (" ram_paddr = 0x%08x (%d) - physical address of RAM to copy image to (startup_size bytes copied)\n", startup_header->ram_paddr, startup_header->ram_paddr); |
264 | printf (" ram_paddr = 0x%08x (%d) - physical address of RAM to copy image to (startup_size bytes copied)\n", startup_header->ram_paddr, startup_header->ram_paddr); |
250 | printf (" ram_size = 0x%08x (%d) - amount of RAM used by the startup program and executables in the fs\n", startup_header->ram_size, startup_header->ram_size); |
265 | printf (" ram_size = 0x%08x (%d) - amount of RAM used by the startup program and executables in the fs\n", startup_header->ram_size, startup_header->ram_size); |
251 | printf (" startup_size = 0x%08x (%d) - size of startup (never compressed) - %s\n", startup_header->startup_size, startup_header->startup_size, (current_offset + sizeof (image_header_t) + startup_header->startup_size + (startup_header->flags1 & STARTUP_HDR_FLAGS1_TRAILER_V2 ? sizeof (image_trailer_v2_t) : sizeof (image_trailer_v1_t)) < file.size ? "looks good" : "BAD (IFS file too short)")); |
266 | printf (" startup_size = 0x%08x (%d) - size of startup (never compressed) - %s\n", startup_header->startup_size, startup_header->startup_size, (current_offset + sizeof (image_header_t) + startup_header->startup_size + (startup_header->flags1 & STARTUP_HDR_FLAGS1_TRAILER_V2 ? sizeof (image_trailer_v2_t) : sizeof (image_trailer_v1_t)) < file.size ? "looks good" : "BAD (IFS file too short)")); |
252 | printf (" stored_size = 0x%08x (%d) - size of |
267 | printf (" stored_size = 0x%08x (%d) - stored size of image - %s\n", startup_header->stored_size, startup_header->stored_size, (startup_header->stored_size <= startup_header->ram_size ? "looks good" : "???")); |
253 | printf (" imagefs_paddr = 0x%08x (%d) - set by IPL when startup runs - %s\n", startup_header->imagefs_paddr, startup_header->imagefs_paddr, (startup_header->imagefs_paddr == 0 ? "looks good" : "??? should be zero")); |
268 | printf (" imagefs_paddr = 0x%08x (%d) - set by IPL when startup runs - %s\n", startup_header->imagefs_paddr, startup_header->imagefs_paddr, (startup_header->imagefs_paddr == 0 ? "looks good" : "??? should be zero")); |
254 | printf (" imagefs_size = 0x%08x (%d) - size of uncompressed imagefs\n", startup_header->imagefs_size, startup_header->imagefs_size); |
269 | printf (" imagefs_size = 0x%08x (%d) - size of uncompressed imagefs\n", startup_header->imagefs_size, startup_header->imagefs_size); |
255 | printf (" preboot_size = 0x%04x (%d) - size of loaded before header - %s\n", startup_header->preboot_size, startup_header->preboot_size, (startup_header->preboot_size == current_offset ? "looks good" : "???")); |
270 | printf (" preboot_size = 0x%04x (%d) - size of loaded before header - %s\n", startup_header->preboot_size, startup_header->preboot_size, (startup_header->preboot_size == current_offset ? "looks good" : "???")); |
256 | printf (" zero0 = 0x%04x (%d) - zeros - %s\n", startup_header->zero0, startup_header->zero0, (startup_header->zero0 == 0 ? "looks good" : "??? should be zero")); |
271 | printf (" zero0 = 0x%04x (%d) - zeros - %s\n", startup_header->zero0, startup_header->zero0, (startup_header->zero0 == 0 ? "looks good" : "??? should be zero")); |
257 | printf (" zero[0] = 0x%08x (%d) - zeros - %s\n", startup_header->zero[0], startup_header->zero[0], (startup_header->zero[0] == 0 ? "looks good" : "??? should be zero")); |
272 | printf (" zero[0] = 0x%08x (%d) - zeros - %s\n", startup_header->zero[0], startup_header->zero[0], (startup_header->zero[0] == 0 ? "looks good" : "??? should be zero")); |
Line 320... | Line 335... | ||
320 | 335 | ||
321 | current_offset += (startup_header->flags1 & STARTUP_HDR_FLAGS1_TRAILER_V2 ? sizeof (startup_trailer_v2_t) : sizeof (startup_trailer_v1_t)); // now reach the next segment |
336 | current_offset += (startup_header->flags1 & STARTUP_HDR_FLAGS1_TRAILER_V2 ? sizeof (startup_trailer_v2_t) : sizeof (startup_trailer_v1_t)); // now reach the next segment |
322 | } |
337 | } |
323 | 338 | ||
324 | // else does an image header start here ? |
339 | // else does an image header start here ? |
- | 340 | else if ((current_offset + sizeof (image_header_t) < file.size) |
|
- | 341 | && (image_header == NULL) |
|
325 |
|
342 | && ( ((cf == STARTUP_HDR_FLAGS1_COMPRESS_NONE) && (memcmp (&file.bytes[current_offset], "imagefs", 7) == 0)) |
- | 343 | || (cf != STARTUP_HDR_FLAGS1_COMPRESS_NONE) && (startup_header->imagefs_size > 0))) |
|
326 | { |
344 | { |
327 | imageheader_offset = current_offset; |
345 | imageheader_offset = current_offset; |
328 | image_header = (image_header_t *) &file.bytes[imageheader_offset]; |
346 | image_header = (image_header_t *) &file.bytes[imageheader_offset]; |
- | 347 | ||
- | 348 | // should we decompress it ? |
|
- | 349 | if (cf != STARTUP_HDR_FLAGS1_COMPRESS_NONE) |
|
- | 350 | { |
|
- | 351 | // it appears mkifs compresses data in blocks, prefixed by 2-byte block size in BIG ENDIAN |
|
- | 352 | Buffer_InitWithSize (&decompression_dst, startup_header->imagefs_size * 11 / 10); // mallocate and add 10% for safety |
|
- | 353 | decompression_dst.size = 0; |
|
- | 354 | ||
- | 355 | if (cf == STARTUP_HDR_FLAGS1_COMPRESS_UCL) |
|
- | 356 | ASSERT (ucl_init () == UCL_E_OK, "UCL library initialization failed -- please recompile this tool with less aggressive optimizations"); |
|
- | 357 | else if (cf == STARTUP_HDR_FLAGS1_COMPRESS_LZO) |
|
- | 358 | ASSERT (lzo_init () == LZO_E_OK, "LZO library initialization failed -- please recompile this tool with less aggressive optimizations"); |
|
- | 359 | else if (cf == STARTUP_HDR_FLAGS1_COMPRESS_ZLIB) |
|
- | 360 | { |
|
- | 361 | LOG_WARNING ("unimplemented compression scheme: zlib (FIXME)"); |
|
- | 362 | goto endofdata; |
|
- | 363 | } |
|
- | 364 | else |
|
- | 365 | { |
|
- | 366 | LOG_WARNING ("unsupported compression flags: 0x%2x", cf); |
|
- | 367 | goto endofdata; |
|
- | 368 | } |
|
- | 369 | ||
- | 370 | // run the compressed payload (the imagefs) through the right decompression algorithm |
|
- | 371 | for (;;) |
|
- | 372 | { |
|
- | 373 | compressed_blocksize = (file.bytes[current_offset + 0] << 8) | (file.bytes[current_offset + 1] << 0); // read block size word (in big engian) |
|
- | 374 | current_offset += 2; // skip it |
|
- | 375 | if (compressed_blocksize == 0) |
|
- | 376 | break; // a nil block size means end of stream is reached |
|
- | 377 | LOG_DEBUG ("about to decompress block of %zd bytes", compressed_blocksize); |
|
- | 378 | decompressor_in = &file.bytes[current_offset]; |
|
- | 379 | decompressor_out = &decompression_dst.bytes[decompression_dst.size]; |
|
- | 380 | decompressor_outlen = 0; |
|
- | 381 | ||
- | 382 | if (cf == STARTUP_HDR_FLAGS1_COMPRESS_UCL) |
|
- | 383 | { |
|
- | 384 | // UCL compression. NOTE: the decompressor function used in startup-x86 is "ucl_nrv2b_decompress_8 / ucl_nrv2b_decompress_le16 / ucl_nrv2b_decompress_le32" |
|
- | 385 | static ucl_uint ucl_outlen; // have a different variable because of pointer size mismatch |
|
- | 386 | if (ucl_nrv2b_decompress_8 (decompressor_in, (ucl_uint) compressed_blocksize, decompressor_out, &ucl_outlen, NULL) != UCL_E_OK) |
|
- | 387 | { |
|
- | 388 | LOG_WARNING ("this IFS file is corrupted (UCL decompression failed)"); |
|
- | 389 | goto endofdata; |
|
- | 390 | } |
|
- | 391 | decompressor_outlen = ucl_outlen; |
|
- | 392 | } |
|
- | 393 | else if (cf == STARTUP_HDR_FLAGS1_COMPRESS_LZO) |
|
- | 394 | { |
|
- | 395 | // LZO decompression. NOTE: mkifs uses the full LZO package, whereas I use minilzo. |
|
- | 396 | static lzo_uint lzo_outlen; // have a different variable because of pointer size mismatch |
|
- | 397 | if (lzo1x_decompress (decompressor_in, (lzo_uint) compressed_blocksize, decompressor_out, &lzo_outlen, NULL) != LZO_E_OK) |
|
- | 398 | { |
|
- | 399 | LOG_WARNING ("this IFS file is corrupted (UCL decompression failed)"); |
|
- | 400 | goto endofdata; |
|
- | 401 | } |
|
- | 402 | decompressor_outlen = lzo_outlen; |
|
- | 403 | } |
|
- | 404 | else if (cf == STARTUP_HDR_FLAGS1_COMPRESS_ZLIB) |
|
- | 405 | ; // TODO |
|
- | 406 | ||
- | 407 | current_offset += compressed_blocksize; |
|
- | 408 | decompression_dst.size += decompressor_outlen; |
|
- | 409 | } |
|
- | 410 | ||
- | 411 | LOG_INFO ("decompressed %zd bytes into %zd bytes\n", file.size - imageheader_offset, decompression_dst.size); |
|
- | 412 | ||
- | 413 | // now place the decompressed buffer in the payload at the imagefs offset |
|
- | 414 | ASSERT_WITH_ERRNO (Buffer_WriteBufferAt (&file, imageheader_offset, &decompression_dst)); |
|
- | 415 | current_offset = imageheader_offset; // jump back to where we put the uncompressed data |
|
- | 416 | file.size = imageheader_offset + decompression_dst.size; // update IFS data size |
|
- | 417 | ||
- | 418 | startup_header = (startup_header_t *) &file.bytes[startupheader_offset]; // fix the pointers that might have changed |
|
- | 419 | if (startup_header->flags1 & STARTUP_HDR_FLAGS1_TRAILER_V2) |
|
- | 420 | startup_trailer_v2 = (startup_trailer_v2_t *) &file.bytes[startuptrailer_offset]; |
|
- | 421 | else // old V1 trailer |
|
- | 422 | startup_trailer_v1 = (startup_trailer_v1_t *) &file.bytes[startuptrailer_offset]; |
|
- | 423 | image_header = (image_header_t *) &file.bytes[imageheader_offset]; // fix the pointers that might have changed |
|
- | 424 | } |
|
329 | 425 | ||
330 | // layout: |
426 | // layout: |
331 | // [IMAGE HEADER] |
427 | // [IMAGE HEADER] |
332 | // [image directory entries] |
428 | // [image directory entries] |
333 | // [smallest file blobs up to KERNEL] |
429 | // [smallest file blobs up to KERNEL] |