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] |