diff --git a/tsk/base/tsk_base_i.h b/tsk/base/tsk_base_i.h index 4506b93e3902189ae746893131681110d3c4712f..d797872970258687defd25d9930089de7fa60a1e 100644 --- a/tsk/base/tsk_base_i.h +++ b/tsk/base/tsk_base_i.h @@ -67,6 +67,9 @@ extern "C" { uint16_t); extern uint8_t tsk_guess_end_u32(TSK_ENDIAN_ENUM *, uint8_t *, uint32_t); + extern uint8_t tsk_guess_end_u64(TSK_ENDIAN_ENUM *, uint8_t *, + uint64_t); + /** \internal * Read a 16-bit unsigned value. diff --git a/tsk/base/tsk_endian.c b/tsk/base/tsk_endian.c index fb75250e6e66948858d6c955fbbcdccd9ca8f84c..a69bdcbf265aa35b05eda5842ba790e71116da20 100644 --- a/tsk/base/tsk_endian.c +++ b/tsk/base/tsk_endian.c @@ -74,3 +74,29 @@ tsk_guess_end_u32(TSK_ENDIAN_ENUM * flag, uint8_t * x, uint32_t val) return 1; } + +/** \internal + * same idea as tsk_guess_end_u16 except that val is a 64-bit value + * +* @param flag Pointer to location where proper endian flag should be stored. +* @param x Pointer to array of bytes to analyze. +* @param val Target value to compare to +* @returns 1 if match cannot be made, 0 if it can. + */ +uint8_t +tsk_guess_end_u64(TSK_ENDIAN_ENUM * flag, uint8_t * x, uint64_t val) +{ + /* try little */ + if (tsk_getu64(TSK_LIT_ENDIAN, x) == val) { + *flag = TSK_LIT_ENDIAN; + return 0; + } + + /* ok, big now */ + if (tsk_getu64(TSK_BIG_ENDIAN, x) == val) { + *flag = TSK_BIG_ENDIAN; + return 0; + } + + return 1; +} diff --git a/tsk/fs/tsk_fs_i.h b/tsk/fs/tsk_fs_i.h index 58df7e96f478c8b5c6c105b2124abf1f3acb46e7..ee15e2734e60ab63bf4695f1cf4ddee4e972fc70 100644 --- a/tsk/fs/tsk_fs_i.h +++ b/tsk/fs/tsk_fs_i.h @@ -239,6 +239,8 @@ extern "C" { tsk_guess_end_u16(&(fs->endian), (x), (mag)) #define tsk_fs_guessu32(fs, x, mag) \ tsk_guess_end_u32(&(fs->endian), (x), (mag)) +#define tsk_fs_guessu64(fs, x, mag) \ + tsk_guess_end_u64(&(fs->endian), (x), (mag)) #ifdef __cplusplus } #endif /* */ diff --git a/tsk/vs/gpt.c b/tsk/vs/gpt.c index 22754c193bf2e03b54ec4f3381f315e3f816c587..9ff999089b7becf5aa8071a3ab04fb300282370a 100644 --- a/tsk/vs/gpt.c +++ b/tsk/vs/gpt.c @@ -22,7 +22,7 @@ * It is loaded into the internal sorted list */ static uint8_t -gpt_load_table(TSK_VS_INFO * vs) +gpt_load_table(TSK_VS_INFO * vs, GPT_LOCATION_ENUM gpt_type) { gpt_head *head; gpt_entry *ent; @@ -32,68 +32,94 @@ gpt_load_table(TSK_VS_INFO * vs) char *safe_str, *head_str, *tab_str, *ent_buf; ssize_t cnt; char *sect_buf; - TSK_DADDR_T taddr = vs->offset / vs->block_size + GPT_PART_SOFFSET; TSK_DADDR_T max_addr = (vs->img_info->size - vs->offset) / vs->block_size; // max sector + TSK_DADDR_T gpt_relative_addr; + TSK_DADDR_T gpt_absolute_addr; + + if(gpt_type == PRIMARY_TABLE){ + gpt_relative_addr = GPT_PART_SOFFSET + 1; + gpt_absolute_addr = vs->offset / vs->block_size + GPT_PART_SOFFSET + 1; + } else { + gpt_relative_addr = ((vs->img_info->size - vs->offset) / vs->block_size) - 1; + gpt_absolute_addr = (vs->img_info->size / vs->block_size) - 1; + } if (tsk_verbose) tsk_fprintf(stderr, "gpt_load_table: Sector: %" PRIuDADDR "\n", - taddr); + gpt_absolute_addr); if ((sect_buf = tsk_malloc(vs->block_size)) == NULL) return 1; - dos_part = (dos_sect *) sect_buf; - cnt = tsk_vs_read_block - (vs, GPT_PART_SOFFSET, sect_buf, vs->block_size); - /* if -1, then tsk_errno is already set */ - if (cnt != vs->block_size) { - if (cnt >= 0) { - tsk_error_reset(); - tsk_error_set_errno(TSK_ERR_VS_READ); + if(gpt_type == PRIMARY_TABLE){ + TSK_DADDR_T dos_sect_relative_addr = GPT_PART_SOFFSET; + TSK_DADDR_T dos_sect_absolute_addr = vs->offset / vs->block_size + GPT_PART_SOFFSET; + dos_part = (dos_sect *) sect_buf; + + cnt = tsk_vs_read_block + (vs, dos_sect_relative_addr, sect_buf, vs->block_size); + /* if -1, then tsk_errno is already set */ + if (cnt != vs->block_size) { + if (cnt >= 0) { + tsk_error_reset(); + tsk_error_set_errno(TSK_ERR_VS_READ); + } + tsk_error_set_errstr2 + ("Error reading DOS safety partition table in Sector: %" + PRIuDADDR, dos_sect_absolute_addr); + free(sect_buf); + return 1; } - tsk_error_set_errstr2 - ("Error reading DOS safety partition table in Sector: %" - PRIuDADDR, taddr); - free(sect_buf); - return 1; - } - /* Sanity Check */ - if (tsk_vs_guessu16(vs, dos_part->magic, DOS_MAGIC)) { - tsk_error_reset(); - tsk_error_set_errno(TSK_ERR_VS_MAGIC); - tsk_error_set_errstr - ("Missing DOS safety partition (invalid magic) (Sector: %" - PRIuDADDR ")", taddr); - free(sect_buf); - return 1; - } + /* Sanity Check */ + if (tsk_vs_guessu16(vs, dos_part->magic, DOS_MAGIC)) { + tsk_error_reset(); + tsk_error_set_errno(TSK_ERR_VS_MAGIC); + tsk_error_set_errstr + ("Missing DOS safety partition (invalid magic) (Sector: %" + PRIuDADDR ")", dos_sect_absolute_addr); + free(sect_buf); + return 1; + } - if (dos_part->ptable[0].ptype != GPT_DOS_TYPE) { - tsk_error_reset(); - tsk_error_set_errno(TSK_ERR_VS_MAGIC); - tsk_error_set_errstr - ("Missing DOS safety partition (invalid type in table: %d)", - dos_part->ptable[0].ptype); - free(sect_buf); - return 1; + if (dos_part->ptable[0].ptype != GPT_DOS_TYPE) { + tsk_error_reset(); + tsk_error_set_errno(TSK_ERR_VS_MAGIC); + tsk_error_set_errstr + ("Missing DOS safety partition (invalid type in table: %d)", + dos_part->ptable[0].ptype); + free(sect_buf); + return 1; + } } /* Read the GPT header */ head = (gpt_head *) sect_buf; cnt = tsk_vs_read_block - (vs, GPT_PART_SOFFSET + 1, sect_buf, vs->block_size); + (vs, gpt_relative_addr, sect_buf, vs->block_size); if (cnt != vs->block_size) { if (cnt >= 0) { tsk_error_reset(); tsk_error_set_errno(TSK_ERR_VS_READ); } tsk_error_set_errstr2("GPT Header structure in Sector: %" - PRIuDADDR, taddr + 1); + PRIuDADDR, gpt_absolute_addr); free(sect_buf); return 1; } + /* Do the endianness test for the secondary table since the test in the dos safety table was skipped */ + if(gpt_type == SECONDARY_TABLE){ + if (tsk_vs_guessu64(vs, head->signature, GPT_HEAD_SIG)) { + tsk_error_reset(); + tsk_error_set_errno(TSK_ERR_VS_MAGIC); + tsk_error_set_errstr("GPT Header: %" PRIx64, tsk_getu64(vs->endian, + &head->signature)); + free(sect_buf); + return 1; + } + } + if (tsk_getu64(vs->endian, &head->signature) != GPT_HEAD_SIG) { tsk_error_reset(); tsk_error_set_errno(TSK_ERR_VS_MAGIC); @@ -109,21 +135,22 @@ gpt_load_table(TSK_VS_INFO * vs) return 1; } - snprintf(safe_str, 16, "Safety Table"); - if (NULL == tsk_vs_part_add(vs, (TSK_DADDR_T) 0, (TSK_DADDR_T) 1, - TSK_VS_PART_FLAG_META, safe_str, -1, -1)) { - free(sect_buf); - return 1; + if(gpt_type == PRIMARY_TABLE){ + snprintf(safe_str, 16, "Safety Table"); + if (NULL == tsk_vs_part_add(vs, (TSK_DADDR_T) 0, (TSK_DADDR_T) 1, + TSK_VS_PART_FLAG_META, safe_str, -1, -1)) { + free(sect_buf); + return 1; + } } - if ((head_str = tsk_malloc(16)) == NULL) { free(sect_buf); return 1; } snprintf(head_str, 16, "GPT Header"); - if (NULL == tsk_vs_part_add(vs, (TSK_DADDR_T) 1, + if (NULL == tsk_vs_part_add(vs, gpt_relative_addr, (TSK_DADDR_T) ((tsk_getu32(vs->endian, &head->head_size_b) + (vs->block_size - 1)) / vs->block_size), TSK_VS_PART_FLAG_META, @@ -303,7 +330,7 @@ tsk_vs_gpt_open(TSK_IMG_INFO * img_info, TSK_DADDR_T offset) vs->close = gpt_close; /* Load the partitions into the sorted list */ - if (gpt_load_table(vs)) { + if (gpt_load_table(vs, PRIMARY_TABLE)) { int found = 0; if (tsk_verbose) tsk_fprintf(stderr, "gpt_open: Trying other sector sizes\n"); @@ -315,7 +342,7 @@ tsk_vs_gpt_open(TSK_IMG_INFO * img_info, TSK_DADDR_T offset) tsk_fprintf(stderr, "gpt_open: Trying sector size: %d\n", vs->block_size); - if (gpt_load_table(vs)) { + if (gpt_load_table(vs, PRIMARY_TABLE)) { vs->block_size *= 2; continue; } @@ -324,8 +351,33 @@ tsk_vs_gpt_open(TSK_IMG_INFO * img_info, TSK_DADDR_T offset) } if (found == 0) { - gpt_close(vs); - return NULL; + /* Look for the secondary GPT at the end of the image */ + if (tsk_verbose) + tsk_fprintf(stderr, "gpt_open: Trying secondary table\n"); + vs->block_size = img_info->sector_size; + if(gpt_load_table(vs, SECONDARY_TABLE)){ + + /* Try other sector sizes again */ + vs->block_size = 512; + while (vs->block_size <= 8192) { + if (tsk_verbose) + tsk_fprintf(stderr, "gpt_open: Trying secondary table sector size: %d\n", + vs->block_size); + + if (gpt_load_table(vs, SECONDARY_TABLE)) { + vs->block_size *= 2; + continue; + } + found = 1; + break; + } + + if(found == 0){ + gpt_close(vs); + return NULL; + } + } + } } diff --git a/tsk/vs/tsk_gpt.h b/tsk/vs/tsk_gpt.h index b265bcc2bc4400f02aa6c58d33ab20fc72a3045a..81a09b0474a28086b0a32b01e1326cbeb84b9501 100644 --- a/tsk/vs/tsk_gpt.h +++ b/tsk/vs/tsk_gpt.h @@ -57,6 +57,11 @@ extern "C" { uint8_t name[72]; /* name in unicode */ } gpt_entry; + typedef enum { + PRIMARY_TABLE, + SECONDARY_TABLE, + } GPT_LOCATION_ENUM; + #ifdef __cplusplus } diff --git a/tsk/vs/tsk_vs_i.h b/tsk/vs/tsk_vs_i.h index cb2c5aeeb818b0ac8d17eb70a311f5bcfb9733ad..910657692c41e160bda965603742d1ce663d8e7e 100644 --- a/tsk/vs/tsk_vs_i.h +++ b/tsk/vs/tsk_vs_i.h @@ -41,4 +41,8 @@ extern void tsk_vs_part_free(TSK_VS_INFO *); #define tsk_vs_guessu32(vs, x, mag) \ tsk_guess_end_u32(&(vs->endian), (x), (mag)) + +#define tsk_vs_guessu64(vs, x, mag) \ + tsk_guess_end_u64(&(vs->endian), (x), (mag)) + #endif