diff --git a/tsk/img/raw.c b/tsk/img/raw.c index 861e1ff8db7334336c306e60e40aab344fb1b2d0..97d2c6da26b7e88b785c6daceb372e636541a7fd 100755 --- a/tsk/img/raw.c +++ b/tsk/img/raw.c @@ -39,7 +39,6 @@ #define S_IFDIR __S_IFDIR #endif - /** * \internal * Read from one of the multiple files in a split set of disk images. @@ -124,6 +123,7 @@ raw_read_segment(IMG_RAW_INFO * raw_info, int idx, char *buf, #ifdef TSK_WIN32 { + // Default to the values that were passed in TSK_OFF_T offset_to_read = rel_offset; size_t len_to_read = len; @@ -134,6 +134,7 @@ raw_read_segment(IMG_RAW_INFO * raw_info, int idx, char *buf, // read some extra data. if ((offset_to_read % raw_info->img_info.sector_size != 0) && (TSTRNCMP(raw_info->img_info.images[idx], _TSK_T("\\\\.\\"), 4) == 0)) { + //printf("\n#### Adjusting read offset: original 0x%llx\n", offset_to_read); offset_to_read = (offset_to_read / raw_info->img_info.sector_size) * raw_info->img_info.sector_size; len_to_read += raw_info->img_info.sector_size; // this length will already be a multiple of sector size sector_aligned_buf = (char *)tsk_malloc(len_to_read); @@ -158,6 +159,13 @@ raw_read_segment(IMG_RAW_INFO * raw_info, int idx, char *buf, if ((li.LowPart == INVALID_SET_FILE_POINTER) && (GetLastError() != NO_ERROR)) { + printf("### FAIL: 0x%llx\n", offset_to_read); + fflush(stdout); + //printf("\n### Error seeking in raw read\n"); + //printf(" offset: 0x%llx\n", offset_to_read); + //printf(" sector size: 0x%x\n", raw_info->img_info.sector_size); + //printf(" path: %S\n", raw_info->img_info.images[idx]); + //fflush(stdout); if (sector_aligned_buf != NULL) { free(sector_aligned_buf); } @@ -170,9 +178,12 @@ raw_read_segment(IMG_RAW_INFO * raw_info, int idx, char *buf, lastError); return -1; } + printf("### PASS: 0x%llx\n", offset_to_read); + fflush(stdout); cimg->seek_pos = offset_to_read; } + //For physical drive when the buffer is larger than remaining data, // WinAPI ReadFile call returns -1 //in this case buffer of exact length must be passed to ReadFile @@ -630,6 +641,127 @@ get_size(const TSK_TCHAR * a_file, uint8_t a_is_winobj) return size; } +#ifdef TSK_WIN32 +/** +* \internal +* Test seeking to the given offset and then reading. +* @return 1 if the read is successful, 0 if not +*/ +static int +test_sector_read(HANDLE file_handle, TSK_OFF_T offset, DWORD len, char * buf) { + printf("### test_sector_read - offset: 0x%llx\n", offset); + fflush(stdout); + LARGE_INTEGER li; + li.QuadPart = offset; + + // Seek to the given offset + li.LowPart = SetFilePointer(file_handle, li.LowPart, + &li.HighPart, FILE_BEGIN); + if ((li.LowPart == INVALID_SET_FILE_POINTER) && + (GetLastError() != NO_ERROR)) { + printf("### failed seek\n"); + fflush(stdout); + return 0; + } + + // Read a byte at the given offset + DWORD nread; + if (FALSE == ReadFile(file_handle, buf, len, &nread, NULL)) { + printf("### failed read (read returned FALSE) %d\n", GetLastError()); + return 0; + } + if (nread != offset) { + printf("### failed read (nread incorrect - 0x%x bytes read)\n", nread); + fflush(stdout); + return 0; + } + printf("### success\n"); + fflush(stdout); + return 1; +} + +/** + * Attempts to calculate the actual sector size needed for reading the image. + * If successful, the calculated sector size will be stored in raw_info. If it + * fails the sector_size field will not be updated. +*/ +void +find_sector_size(IMG_RAW_INFO * raw_info, const TSK_TCHAR * image_name, TSK_OFF_T first_seg_size) { + unsigned int max_sector_size = 4096; + HANDLE file_handle = CreateFile(image_name, FILE_READ_DATA, + FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, + NULL); + if (file_handle == INVALID_HANDLE_VALUE) { + if (tsk_verbose) { + tsk_fprintf(stderr, + "find_sector_size: failed to open image \"%" PRIttocTSK "\"\n", image_name); + } + return; + } + printf("Opened image file\n"); + fflush(stdout); + + // First test whether we need to align on sector boundaries + char * buf = malloc(max_sector_size); + int needs_sector_alignment = 0; + if (first_seg_size > raw_info->img_info.sector_size) { + if (test_sector_read(file_handle, 1, raw_info->img_info.sector_size, buf)) { + needs_sector_alignment = 0; + } + else { + needs_sector_alignment = 1; + } + } + + // If reading a sector starting at offset 1 failed, the assumption is that we have a device + // that requires reads to be sector-aligned. + if (needs_sector_alignment) { + printf("### Attempting to find sector size...\n"); + // Start at 512 and double up to max_sector_size (4096) + unsigned int sector_size = 512; + if (raw_info->img_info.sector_size > 512) { + sector_size = raw_info->img_info.sector_size; + } + printf(" Starting sector size: 0x%x\n", sector_size); + fflush(stdout); + + while (sector_size <= max_sector_size) { + // If we don't have enough data to do the test just leave it as the last value + if (first_seg_size < sector_size * 2) { + printf(" Not enough data to test sector size 0x%x\n", sector_size); + fflush(stdout); + break; + } + + if (test_sector_read(file_handle, sector_size, sector_size, buf)) { + // Found a valid sector size + printf(" Sector size 0x%x looks good!\n", sector_size); + if (tsk_verbose) { + tsk_fprintf(stderr, + "find_sector_size: using sector size %d\n", sector_size); + } + raw_info->img_info.sector_size = sector_size; + + if (file_handle != 0) { + CloseHandle(file_handle); + } + free(buf); + return; + } + sector_size *= 2; + } + if (tsk_verbose) { + tsk_fprintf(stderr, + "find_sector_size: failed to determine correct sector size. Reverting to default %d\n", raw_info->img_info.sector_size); + } + free(buf); + } + + if (file_handle != 0) { + CloseHandle(file_handle); + } +} +#endif /** * \internal @@ -661,9 +793,6 @@ raw_open(int a_num_img, const TSK_TCHAR * const a_images[], img_info->close = raw_close; img_info->imgstat = raw_imgstat; - img_info->sector_size = 512; - if (a_ssize) - img_info->sector_size = a_ssize; raw_info->is_winobj = 0; #if defined(TSK_WIN32) || defined(__CYGWIN__) @@ -683,6 +812,27 @@ raw_open(int a_num_img, const TSK_TCHAR * const a_images[], return NULL; } + /* Set the sector size using the first image file or the given parameter*/ + img_info->sector_size = 512; +#ifdef TSK_WIN32 + /* On Windows, figure out the actual sector size if one was not given. + * This is to prevent problems reading from devices later. */ + if (a_ssize) { + printf("Using given sector size %d\n", a_ssize); + fflush(stdout); + img_info->sector_size = a_ssize; + } + else { + printf("Calculating sector size\n"); + fflush(stdout); + find_sector_size(raw_info, a_images[0], first_seg_size); + } +#else + if (a_ssize) + img_info->sector_size = a_ssize; +#endif + + /* see if there are more of them... */ if ((a_num_img == 1) && (raw_info->is_winobj == 0)) { if ((raw_info->img_info.images =