From be75f39fb105a6a685d2a682cd16cb12fb29efcd Mon Sep 17 00:00:00 2001 From: Ann Priestman <apriestman@basistech.com> Date: Mon, 6 Feb 2017 09:41:38 -0500 Subject: [PATCH] Add image writer path to makeAddImageProcess Cleanup --- bindings/java/jni/dataModel_SleuthkitJNI.cpp | 34 - bindings/java/jni/dataModel_SleuthkitJNI.h | 8 - .../sleuthkit/datamodel/Examples/Sample.java | 2 +- .../sleuthkit/datamodel/SleuthkitCase.java | 6 +- .../org/sleuthkit/datamodel/SleuthkitJNI.java | 21 +- .../org/sleuthkit/datamodel/BottomUpTest.java | 2 +- .../datamodel/DataModelTestSuite.java | 2 +- tsk/auto/auto.cpp | 3 - tsk/img/img_writer.cpp | 817 +++++++++--------- tsk/img/img_writer.h | 5 +- tsk/img/raw.c | 7 +- tsk/img/vhd.c | 3 + 12 files changed, 421 insertions(+), 489 deletions(-) diff --git a/bindings/java/jni/dataModel_SleuthkitJNI.cpp b/bindings/java/jni/dataModel_SleuthkitJNI.cpp index 806ec806a..c8c556b80 100644 --- a/bindings/java/jni/dataModel_SleuthkitJNI.cpp +++ b/bindings/java/jni/dataModel_SleuthkitJNI.cpp @@ -1184,9 +1184,6 @@ Java_org_sleuthkit_datamodel_SleuthkitJNI_runAddImgNat(JNIEnv * env, } else { tskAuto->disableImageWriter(); - setThrowTskCoreError(env, - "runAddImgNat: Disabling image writer."); - return; } // Add the data source. @@ -2162,34 +2159,3 @@ JNIEXPORT jboolean JNICALL Java_org_sleuthkit_datamodel_SleuthkitJNI_isImageSupp return (jboolean) result; } - -/* - * Enable image writing during ingest - * @param env pointer to java environment this was called from - * @param obj the java object this was called from - * @param directoryJ directory to store the image in - * @param baseNameJ base name for the new image - * @return 0 if successful, -1 otherwise - */ -JNIEXPORT jint JNICALL -Java_org_sleuthkit_datamodel_SleuthkitJNI_enableImageWriterNat (JNIEnv * env, jclass obj, - jlong a_img_info, jstring directoryJ, jstring baseNameJ) { - - TSK_IMG_INFO *img_info = castImgInfo(env, a_img_info); - if (img_info == 0) { - //exception already set - return -1; - } - - TSK_TCHAR directoryT[1024]; - toTCHAR(env, directoryT, 1024, directoryJ); - - TSK_TCHAR baseNameT[1024]; - toTCHAR(env, baseNameT, 1024, baseNameJ); - - if (TSK_ERR == tsk_img_writer_create_from_dir(img_info, directoryT, baseNameT)) { - return -1; - } - - return 0; -} diff --git a/bindings/java/jni/dataModel_SleuthkitJNI.h b/bindings/java/jni/dataModel_SleuthkitJNI.h index 0f1a0094f..74b4c7808 100644 --- a/bindings/java/jni/dataModel_SleuthkitJNI.h +++ b/bindings/java/jni/dataModel_SleuthkitJNI.h @@ -407,14 +407,6 @@ JNIEXPORT jstring JNICALL Java_org_sleuthkit_datamodel_SleuthkitJNI_getCurDirNat JNIEXPORT jboolean JNICALL Java_org_sleuthkit_datamodel_SleuthkitJNI_isImageSupportedNat (JNIEnv *, jclass, jstring); -/* - * Class: org_sleuthkit_datamodel_SleuthkitJNI - * Method: enableImageWriterNat - * Signature: (JLjava/lang/String;Ljava/lang/String;)I - */ -JNIEXPORT jint JNICALL Java_org_sleuthkit_datamodel_SleuthkitJNI_enableImageWriterNat - (JNIEnv *, jclass, jlong, jstring, jstring); - #ifdef __cplusplus } #endif diff --git a/bindings/java/src/org/sleuthkit/datamodel/Examples/Sample.java b/bindings/java/src/org/sleuthkit/datamodel/Examples/Sample.java index 6fc7b8224..3f6620ae5 100755 --- a/bindings/java/src/org/sleuthkit/datamodel/Examples/Sample.java +++ b/bindings/java/src/org/sleuthkit/datamodel/Examples/Sample.java @@ -43,7 +43,7 @@ public static void run(String imagePath) { // initialize the case with an image String timezone = ""; - AddImageProcess process = sk.makeAddImageProcess(timezone, true, false); + AddImageProcess process = sk.makeAddImageProcess(timezone, true, false, ""); ArrayList<String> paths = new ArrayList<String>(); paths.add(imagePath); try { diff --git a/bindings/java/src/org/sleuthkit/datamodel/SleuthkitCase.java b/bindings/java/src/org/sleuthkit/datamodel/SleuthkitCase.java index 40c2536d4..ffb0642a9 100755 --- a/bindings/java/src/org/sleuthkit/datamodel/SleuthkitCase.java +++ b/bindings/java/src/org/sleuthkit/datamodel/SleuthkitCase.java @@ -1223,12 +1223,14 @@ public static SleuthkitCase newCase(String databaseName, CaseDbConnectionInfo in * unallocated space in the image. * @param noFatFsOrphans Set to true to skip processing orphan files of FAT * file systems. + * @param imageWriterPath Path that a copy of the image should be written to. + * Use empty string to disable image writing * * @return Object that encapsulates control of adding an image via the * SleuthKit native code layer. */ - public AddImageProcess makeAddImageProcess(String timezone, boolean addUnallocSpace, boolean noFatFsOrphans) { - return this.caseHandle.initAddImageProcess(timezone, addUnallocSpace, noFatFsOrphans); + public AddImageProcess makeAddImageProcess(String timezone, boolean addUnallocSpace, boolean noFatFsOrphans, String imageWriterPath) { + return this.caseHandle.initAddImageProcess(timezone, addUnallocSpace, noFatFsOrphans, imageWriterPath); } /** diff --git a/bindings/java/src/org/sleuthkit/datamodel/SleuthkitJNI.java b/bindings/java/src/org/sleuthkit/datamodel/SleuthkitJNI.java index 5961cdbdb..a546ca927 100644 --- a/bindings/java/src/org/sleuthkit/datamodel/SleuthkitJNI.java +++ b/bindings/java/src/org/sleuthkit/datamodel/SleuthkitJNI.java @@ -168,12 +168,15 @@ long addImageInfo(long deviceObjId, List<String> imageFilePaths, String timeZone * unallocated space. * @param skipFatFsOrphans Pass true to skip processing of orphan files * for FAT file systems. + * @param imageWriterPath Path that a copy of the image should be written to. + * Use empty string to disable image writing * * @return An object that can be used to exercise fine-grained control * of the process of adding the image to the case database. */ - AddImageProcess initAddImageProcess(String timeZone, boolean addUnallocSpace, boolean skipFatFsOrphans) { - return new AddImageProcess(timeZone, addUnallocSpace, skipFatFsOrphans); + //AddImageProcess initAddImageProcess(String timeZone, boolean addUnallocSpace, boolean skipFatFsOrphans) { + AddImageProcess initAddImageProcess(String timeZone, boolean addUnallocSpace, boolean skipFatFsOrphans, String imageWriterPath) { + return new AddImageProcess(timeZone, addUnallocSpace, skipFatFsOrphans, imageWriterPath); } /** @@ -185,6 +188,7 @@ public class AddImageProcess { private final String timeZone; private final boolean addUnallocSpace; private final boolean skipFatFsOrphans; + private final String imageWriterPath; private volatile long tskAutoDbPointer; /** @@ -196,11 +200,14 @@ public class AddImageProcess { * unallocated space. * @param skipFatFsOrphans Pass true to skip processing of orphan * files for FAT file systems. + * @param imageWriterPath Path that a copy of the image should be written to. + * Use empty string to disable image writing */ - private AddImageProcess(String timeZone, boolean addUnallocSpace, boolean skipFatFsOrphans) { + private AddImageProcess(String timeZone, boolean addUnallocSpace, boolean skipFatFsOrphans, String imageWriterPath) { this.timeZone = timeZone; this.addUnallocSpace = addUnallocSpace; this.skipFatFsOrphans = skipFatFsOrphans; + this.imageWriterPath = imageWriterPath; tskAutoDbPointer = 0; } @@ -236,7 +243,7 @@ public void run(String deviceId, String[] imageFilePaths) throws TskCoreExceptio } //runAddImgNat(tskAutoDbPointer, deviceId, imageFilePaths, imageFilePaths.length, timeZone); - runAddImgNat(tskAutoDbPointer, deviceId, imageHandle, timeZone, "C:\\cygwin\\home\\apriestman\\Work\\autopsy\\vhdTesting\\tskOutput\\autopsyVHD3.vhd"); + runAddImgNat(tskAutoDbPointer, deviceId, imageHandle, timeZone, imageWriterPath); } /** @@ -988,10 +995,6 @@ public static long findDeviceSize(String devPath) throws TskCoreException { public static boolean isImageSupported(String imagePath){ return isImageSupportedNat(imagePath); } - - public static int enableImageWriter(long imgHandle, String directory, String baseName){ - return enableImageWriterNat(imgHandle, directory, baseName); - } private static native String getVersionNat(); @@ -1092,7 +1095,5 @@ public static int enableImageWriter(long imgHandle, String directory, String bas private static native String getCurDirNat(long process); private static native boolean isImageSupportedNat(String imagePath); - - private static native int enableImageWriterNat(long imgHandle, String directory, String baseName); } diff --git a/bindings/java/test/org/sleuthkit/datamodel/BottomUpTest.java b/bindings/java/test/org/sleuthkit/datamodel/BottomUpTest.java index 349e22236..96684cb85 100644 --- a/bindings/java/test/org/sleuthkit/datamodel/BottomUpTest.java +++ b/bindings/java/test/org/sleuthkit/datamodel/BottomUpTest.java @@ -80,7 +80,7 @@ public void testBottomUpDiff() { SleuthkitCase sk = SleuthkitCase.newCase(dbPath); String timezone = ""; title = title + DataModelTestSuite.BTTMUP + ".txt"; - SleuthkitJNI.CaseDbHandle.AddImageProcess process = sk.makeAddImageProcess(timezone, true, false); + SleuthkitJNI.CaseDbHandle.AddImageProcess process = sk.makeAddImageProcess(timezone, true, false, ""); try { process.run(imagePaths.toArray(new String[imagePaths.size()])); } catch (TskDataException ex) { diff --git a/bindings/java/test/org/sleuthkit/datamodel/DataModelTestSuite.java b/bindings/java/test/org/sleuthkit/datamodel/DataModelTestSuite.java index 7bb4a3981..66d00e391 100644 --- a/bindings/java/test/org/sleuthkit/datamodel/DataModelTestSuite.java +++ b/bindings/java/test/org/sleuthkit/datamodel/DataModelTestSuite.java @@ -115,7 +115,7 @@ public static void createOutput(String outputPath, String tempDirPath, List<Stri SleuthkitCase sk = SleuthkitCase.newCase(dbPath); String timezone = ""; - SleuthkitJNI.CaseDbHandle.AddImageProcess process = sk.makeAddImageProcess(timezone, true, false); + SleuthkitJNI.CaseDbHandle.AddImageProcess process = sk.makeAddImageProcess(timezone, true, false, ""); try { process.run(imagePaths.toArray(new String[imagePaths.size()])); } catch (TskDataException ex) { diff --git a/tsk/auto/auto.cpp b/tsk/auto/auto.cpp index 95e298fd2..0a57a040e 100644 --- a/tsk/auto/auto.cpp +++ b/tsk/auto/auto.cpp @@ -81,10 +81,7 @@ uint8_t closeImage(); m_internalOpen = true; - enableImageWriter("C:\\cygwin\\home\\apriestman\\Work\\autopsy\\vhdTesting\\tskOutput\\newTest.vhd"); m_img_info = tsk_img_open(a_numImg, a_images, a_imgType, a_sSize); - tsk_img_writer_create(m_img_info, m_imageWriterPath); - //tsk_img_writer_create_from_dir(m_img_info, L"C:\\cygwin\\home\\apriestman\\Work\\autopsy\\vhdTesting\\tskOutput", a_images[0]); if (m_img_info) return 0; else diff --git a/tsk/img/img_writer.cpp b/tsk/img/img_writer.cpp index 85b268258..decc00a53 100644 --- a/tsk/img/img_writer.cpp +++ b/tsk/img/img_writer.cpp @@ -24,378 +24,371 @@ #include <winioctl.h> #endif -/* This is a little lower than the actual maximum size for the VHD */ -#define VHD_MAX_IMAGE_SIZE 2000000000000 -#define VHD_DEFAULT_BLOCK_SIZE 0x200000 +#define VHD_MAX_IMAGE_SIZE 2000000000000 /* VHD_MAX_IMAGE_SIZE is a little lower than the actual maximum size for the VHD */ +#define VHD_DEFAULT_BLOCK_SIZE 0x200000 /* This needs to be 0x200000 to load the VHD in Windows */ #define VHD_SECTOR_SIZE 0x200 #define VHD_FOOTER_LENGTH 0x200 #define VHD_DISK_HEADER_LENGTH 0x400 TSK_RETVAL_ENUM writeFooter(TSK_IMG_WRITER* writer); -// TEMP LOGGING +// TEMP LOGGING TEMP char messageBuffer[0x2000]; char logBuffer[0x2000]; void openLogFile(TSK_IMG_WRITER * writer); void writeLogFile(TSK_IMG_WRITER * writer, const char * message) { - if (writer->logFileHandle == 0) { - // Open it back up - openLogFile(writer); - } - time_t ltime; /* calendar time */ - ltime = time(NULL); /* get current cal time */ - sprintf(logBuffer, "%s : ", asctime(localtime(<ime))); - strcat(logBuffer, message); - - DWORD bytesWritten; - if (FALSE == WriteFile(writer->logFileHandle, logBuffer, - strlen(logBuffer), &bytesWritten, NULL)) { - int lastError = GetLastError(); - tsk_error_reset(); - tsk_error_set_errno(TSK_ERR_IMG_WRITE); - tsk_error_set_errstr("writeLogFile: error writing log", - lastError); - } + if (writer->logFileHandle == 0) { + // Open it back up + openLogFile(writer); + } + time_t ltime; /* calendar time */ + ltime = time(NULL); /* get current cal time */ + sprintf(logBuffer, "%s : ", asctime(localtime(<ime))); + strcat(logBuffer, message); + + DWORD bytesWritten; + if (FALSE == WriteFile(writer->logFileHandle, logBuffer, + strlen(logBuffer), &bytesWritten, NULL)) { + int lastError = GetLastError(); + tsk_error_reset(); + tsk_error_set_errno(TSK_ERR_IMG_WRITE); + tsk_error_set_errstr("writeLogFile: error writing log", + lastError); + } } void openLogFile(TSK_IMG_WRITER * writer) { - writer->logFileHandle = CreateFile(L"C:\\cygwin\\home\\apriestman\\Work\\autopsy\\vhdTesting\\tskOutput\\tskLog.txt", FILE_APPEND_DATA, - FILE_SHARE_READ, NULL, OPEN_ALWAYS, 0, - NULL); - if (writer->logFileHandle == INVALID_HANDLE_VALUE) { - tsk_fprintf(stderr, "Error opening VHD!!!"); // temp - fflush(stderr); - int lastError = (int)GetLastError(); - writer->outputFileHandle = 0; /* so we don't close it next time */ - tsk_error_reset(); - tsk_error_set_errno(TSK_ERR_IMG_OPEN); - tsk_error_set_errstr("openLogFile: file %d", lastError); - } - writeLogFile(writer, "Opened log file\n"); + writer->logFileHandle = CreateFile(L"C:\\cygwin\\home\\apriestman\\Work\\autopsy\\vhdTesting\\tskOutput\\tskLog.txt", FILE_APPEND_DATA, + FILE_SHARE_READ, NULL, OPEN_ALWAYS, 0, + NULL); + if (writer->logFileHandle == INVALID_HANDLE_VALUE) { + tsk_fprintf(stderr, "Error opening VHD!!!"); // temp + fflush(stderr); + int lastError = (int)GetLastError(); + writer->outputFileHandle = 0; /* so we don't close it next time */ + tsk_error_reset(); + tsk_error_set_errno(TSK_ERR_IMG_OPEN); + tsk_error_set_errstr("openLogFile: file %d", lastError); + } + writeLogFile(writer, "Opened log file\n"); } +// END TEMP LOGGING +/* + * Considering the buffer to be an array of bits, get the entry at + * the given index. + */ +static bool getBit(unsigned char * buffer, TSK_OFF_T index) { + unsigned char b = buffer[index / 8]; + return (b >> (7 - (index % 8)) & 0x01) == 1; +} - -bool getBit(unsigned char * buffer, TSK_OFF_T index) { - unsigned char b = buffer[index / 8]; - return (b >> (7 - (index % 8)) & 0x01) == 1; +/* + * Considering the buffer to be an array of bits, set the entry at + * the given index. + */ +static void setBit(unsigned char * buffer, TSK_OFF_T index, bool val) { + unsigned char b = buffer[index / 8]; + unsigned char mask = 0xff ^ (1 << (7 - (index % 8))); + b = (b & mask) | (val << (7 - (index % 8))); + buffer[index / 8] = b; } -void setBit(unsigned char * buffer, TSK_OFF_T index, bool val) { - if (tsk_verbose) { - //tsk_fprintf(stderr, "setBit: Setting bit 0x%x to %d\n", index, val); - //fflush(stderr); - } - unsigned char b = buffer[index / 8]; - unsigned char mask = 0xff ^ (1 << (7 - (index % 8))); - b = (b & mask) | (val << (7 - (index % 8))); - buffer[index / 8] = b; +/* + * Move the file pointer to the given offset (relative the beginning of the file) + */ +static TSK_RETVAL_ENUM seekToOffset(TSK_IMG_WRITER * writer, TSK_OFF_T offset) { + LARGE_INTEGER li; + li.QuadPart = offset; + + li.LowPart = SetFilePointer(writer->outputFileHandle, li.LowPart, + &li.HighPart, FILE_BEGIN); + + if ((li.LowPart == INVALID_SET_FILE_POINTER) && + (GetLastError() != NO_ERROR)) { + int lastError = (int)GetLastError(); + tsk_error_reset(); + tsk_error_set_errno(TSK_ERR_IMG_SEEK); + tsk_error_set_errstr("img_writer::seekToOffset: offset %" PRIuOFF " seek - %d", + offset, + lastError); + return TSK_ERR; + } + return TSK_OK; } -TSK_RETVAL_ENUM seekToOffset(TSK_IMG_WRITER * writer, TSK_OFF_T offset) { - LARGE_INTEGER li; - li.QuadPart = offset; - - li.LowPart = SetFilePointer(writer->outputFileHandle, li.LowPart, - &li.HighPart, FILE_BEGIN); - - if ((li.LowPart == INVALID_SET_FILE_POINTER) && - (GetLastError() != NO_ERROR)) { - int lastError = (int)GetLastError(); - tsk_error_reset(); - tsk_error_set_errno(TSK_ERR_IMG_SEEK); - tsk_error_set_errstr("img_writer::seekToOffset: offset %" PRIuOFF " seek - %d", - offset, - lastError); - return TSK_ERR; - } - return TSK_OK; +/* + * Move the file pointer from the current location + */ +static TSK_RETVAL_ENUM seekAhead(TSK_IMG_WRITER * writer, TSK_OFF_T dist) { + LARGE_INTEGER li; + li.QuadPart = dist; + + li.LowPart = SetFilePointer(writer->outputFileHandle, li.LowPart, + &li.HighPart, FILE_CURRENT); + + if ((li.LowPart == INVALID_SET_FILE_POINTER) && + (GetLastError() != NO_ERROR)) { + int lastError = (int)GetLastError(); + tsk_error_reset(); + tsk_error_set_errno(TSK_ERR_IMG_SEEK); + tsk_error_set_errstr("img_writer::seekAhead: offset %" PRIuOFF " seek - %d", + dist, + lastError); + return TSK_ERR; + } + return TSK_OK; } -TSK_RETVAL_ENUM seekAhead(TSK_IMG_WRITER * writer, TSK_OFF_T dist) { - LARGE_INTEGER li; - li.QuadPart = dist; - - li.LowPart = SetFilePointer(writer->outputFileHandle, li.LowPart, - &li.HighPart, FILE_CURRENT); - - if ((li.LowPart == INVALID_SET_FILE_POINTER) && - (GetLastError() != NO_ERROR)) { - int lastError = (int)GetLastError(); - tsk_error_reset(); - tsk_error_set_errno(TSK_ERR_IMG_SEEK); - tsk_error_set_errstr("img_writer::seekAhead: offset %" PRIuOFF " seek - %d", - dist, - lastError); - return TSK_ERR; - } - return TSK_OK; +/* + * Use the sector bitmap to determine whether we're done writing data to a given block + */ +static void checkIfBlockIsFinished(TSK_IMG_WRITER* writer, TSK_OFF_T blockNum) { + + /* The final block may not contain the full number of sectors */ + unsigned int nSectors; + if ((blockNum == writer->totalBlocks - 1) && (writer->imageSize % writer->blockSize != 0)) { + nSectors = (writer->imageSize % writer->blockSize) / VHD_SECTOR_SIZE; + } + else { + nSectors = writer->sectorsPerBlock; + } + + unsigned char * sectBitmap = writer->blockToSectorBitmap[blockNum]; + for (unsigned int i = 0; i < nSectors; i++) { + if (false == getBit(sectBitmap, i)) { + /* At least one sector has not been written */ + return; + } + } + + /* Mark the block as finished and free the memory for its sector bitmap */ + writer->blockStatus[blockNum] = IMG_WRITER_BLOCK_STATUS_FINISHED; + if (writer->blockToSectorBitmap[blockNum] != NULL) { + free(writer->blockToSectorBitmap[blockNum]); + writer->blockToSectorBitmap[blockNum] = NULL; + } } -void checkIfBlockIsFinished(TSK_IMG_WRITER* writer, TSK_OFF_T blockNum) { +/* + * Add a buffer of data to a previously started block in the VHD + */ +static TSK_RETVAL_ENUM addToExistingBlock(TSK_IMG_WRITER* writer, TSK_OFF_T addr, char *buffer, + size_t len, TSK_OFF_T blockNum) { + + if (tsk_verbose) { + tsk_fprintf(stderr, "addToExistingBlock: Adding data to existing block 0x%x\n", blockNum); + fflush(stderr); + } - /* This may not ever mark the last block as finished - need to work on that */ + /* Seek to where this buffer should start in the image */ + if (TSK_OK != seekToOffset(writer, VHD_SECTOR_SIZE * TSK_OFF_T(writer->blockToSectorNumber[blockNum]) + writer->sectorBitmapLength + + (addr % writer->blockSize))) { + return TSK_ERR; + } - unsigned char * sectBitmap = writer->blockToSectorBitmap[blockNum]; - for (int i = 0; i < writer->sectorsPerBlock; i++) { - if (false == getBit(sectBitmap, i)) { - /* At least one sector has not been written */ - return; - } - } + /* Copy each sector that isn't already there */ + for (size_t inputOffset = 0; inputOffset < len; inputOffset += VHD_SECTOR_SIZE) { + uint32_t currentSector = uint32_t((addr % writer->blockSize + inputOffset) / VHD_SECTOR_SIZE); - /* Mark the block as finished and free the memory for its sector bitmap */ - writer->blockStatus[blockNum] = IMG_WRITER_BLOCK_STATUS_FINISHED; - if (writer->blockToSectorBitmap[blockNum] != NULL) { - free(writer->blockToSectorBitmap[blockNum]); - } + if (getBit(writer->blockToSectorBitmap[blockNum], currentSector)) { + if (TSK_OK != seekAhead(writer, VHD_SECTOR_SIZE)) { + return TSK_ERR; + } + } + else { + + DWORD bytesWritten; + if (FALSE == WriteFile(writer->outputFileHandle, &(buffer[inputOffset]), VHD_SECTOR_SIZE, + &bytesWritten, NULL)) { + int lastError = GetLastError(); + tsk_error_reset(); + tsk_error_set_errno(TSK_ERR_IMG_WRITE); + tsk_error_set_errstr("addToExistingBlock: error writing sector", + lastError); + return TSK_ERR; + } + setBit(writer->blockToSectorBitmap[blockNum], currentSector, true); + } + } -} + /* Update the sector bitmap */ + if (TSK_OK != seekToOffset(writer, VHD_SECTOR_SIZE * TSK_OFF_T(writer->blockToSectorNumber[blockNum]))) { + return TSK_ERR; + } + + DWORD bytesWritten; + if (FALSE == WriteFile(writer->outputFileHandle, writer->blockToSectorBitmap[blockNum], + writer->sectorBitmapArrayLength, &bytesWritten, NULL)) { + int lastError = GetLastError(); + tsk_error_reset(); + tsk_error_set_errno(TSK_ERR_IMG_WRITE); + tsk_error_set_errstr("addToExistingBlock: error writing sector", + lastError); + return TSK_ERR; + } -TSK_RETVAL_ENUM addToExistingBlock(TSK_IMG_WRITER* writer, TSK_OFF_T addr, char *buffer, - size_t len, TSK_OFF_T blockNum) { - - if (tsk_verbose) { - tsk_fprintf(stderr, "addToExistingBlock: Adding data to existing block 0x%x\n", blockNum); - fflush(stderr); - } - - /* Seek to where this buffer should start in the image */ - if (TSK_OK != seekToOffset(writer, writer->blockToOffset[blockNum] + writer->sectorBitmapLength + - (addr % writer->blockSize))) { - return TSK_ERR; - } - - /* Copy each sector that isn't already there */ - for (TSK_OFF_T inputOffset = 0; inputOffset < len; inputOffset += VHD_SECTOR_SIZE) { - uint32_t currentSector = (addr % writer->blockSize + inputOffset) / VHD_SECTOR_SIZE; - - if (getBit(writer->blockToSectorBitmap[blockNum], currentSector)) { - if (TSK_OK != seekAhead(writer, VHD_SECTOR_SIZE)) { - return TSK_ERR; - } - } - else { - - DWORD bytesWritten; - if (FALSE == WriteFile(writer->outputFileHandle, &(buffer[inputOffset]), VHD_SECTOR_SIZE, - &bytesWritten, NULL)) { - int lastError = GetLastError(); - tsk_error_reset(); - tsk_error_set_errno(TSK_ERR_IMG_WRITE); - tsk_error_set_errstr("addToExistingBlock: error writing sector", - lastError); - return TSK_ERR; - } - setBit(writer->blockToSectorBitmap[blockNum], currentSector, true); - } - } - - /* Update the sector bitmap */ - if (TSK_OK != seekToOffset(writer, writer->blockToOffset[blockNum])) { - return TSK_ERR; - } - - DWORD bytesWritten; - if (FALSE == WriteFile(writer->outputFileHandle, writer->blockToSectorBitmap[blockNum], - writer->sectorBitmapArrayLength, &bytesWritten, NULL)) { - int lastError = GetLastError(); - tsk_error_reset(); - tsk_error_set_errno(TSK_ERR_IMG_WRITE); - tsk_error_set_errstr("addToExistingBlock: error writing sector", - lastError); - return TSK_ERR; - } - - return TSK_OK; + return TSK_OK; } -TSK_RETVAL_ENUM addNewBlock(TSK_IMG_WRITER* writer, TSK_OFF_T addr, char *buffer, size_t len, TSK_OFF_T blockNum) { - - if (tsk_verbose) { - tsk_fprintf(stderr, "addNewBlock: Adding new block 0x%x\n", blockNum); - fflush(stderr); - } - - writer->blockStatus[blockNum] = IMG_WRITER_BLOCK_STATUS_ALLOC; - writer->blockToOffset[blockNum] = writer->nextDataOffset; - - if (tsk_verbose) { - tsk_fprintf(stderr, "addNewBlock: Allocating memory\n fullBuffer length: 0x%x\n sectorBitmap length: 0x%x\n completedSectors length: 0x%x\n", - writer->blockSize, writer->sectorBitmapLength, writer->sectorBitmapArrayLength); - fflush(stderr); - } - char * fullBuffer = (char *)tsk_malloc(writer->blockSize * sizeof(char)); - char * sectorBitmap = (char *)tsk_malloc(writer->sectorBitmapLength * sizeof(char)); - unsigned char * completedSectors = (unsigned char *)tsk_malloc(((writer->sectorBitmapArrayLength) * sizeof(char))); - - /* Create the full new block and record the sectors written */ - if (tsk_verbose) { - tsk_fprintf(stderr, "addNewBlock: Writing sector bitmap and full buffer. len = 0x%x\n", len); - fflush(stderr); - } - TSK_OFF_T startingOffset = addr % writer->blockSize; - for (size_t i = 0; i < len; i++) { - - if (((startingOffset + i) % VHD_SECTOR_SIZE) == 0) { - TSK_OFF_T currentSector = (startingOffset + i) / VHD_SECTOR_SIZE; - setBit(completedSectors, currentSector, true); - if (tsk_verbose) { - tsk_fprintf(stderr, "addNewBlock: Setting sectorBitmap[%d] to completedSectors[%d]\n", - currentSector / 8, currentSector / 8); - fflush(stderr); - } - sectorBitmap[currentSector / 8] = completedSectors[currentSector / 8]; - } - - if (tsk_verbose) { - //tsk_fprintf(stderr, "addNewBlock: Setting fullBuffer[0x%x] to buffer[0x%x]\n", - // startingOffset + i, i); - //fflush(stderr); - } - fullBuffer[startingOffset + i] = buffer[i]; - } - writer->blockToSectorBitmap[blockNum] = completedSectors; - - if (tsk_verbose) { - tsk_fprintf(stderr, "addNewBlock: Sector bitmap"); - for (int i = 0; i < writer->sectorBitmapArrayLength; i++) { - if (i % 16 == 0) { - tsk_fprintf(stderr, "\n"); - } - tsk_fprintf(stderr, "%02x ", completedSectors[i]); - } - fflush(stderr); - } - - /* Prepare the new block offset */ - TSK_OFF_T nextDataOffsetSector = writer->nextDataOffset / VHD_SECTOR_SIZE; - unsigned char newBlockOffset[4]; - newBlockOffset[0] = (nextDataOffsetSector >> 24) & 0xff; - newBlockOffset[1] = (nextDataOffsetSector >> 16) & 0xff; - newBlockOffset[2] = (nextDataOffsetSector >> 8) & 0xff; - newBlockOffset[3] = nextDataOffsetSector & 0xff; - - /* Write the new offset to the BAT */ - if (TSK_OK != seekToOffset(writer, writer->batOffset + 4 * blockNum)) { - return TSK_ERR; - } - DWORD bytesWritten; - if (FALSE == WriteFile(writer->outputFileHandle, newBlockOffset, 4, &bytesWritten, NULL)) { - int lastError = GetLastError(); - tsk_error_reset(); - tsk_error_set_errno(TSK_ERR_IMG_WRITE); - tsk_error_set_errstr("addNewBlock: error writing BAT entry", - lastError); - return TSK_ERR; - } - - /* Write the sector bitmap and the data */ - if (TSK_OK != seekToOffset(writer, writer->nextDataOffset)) { - return TSK_ERR; - } - if (FALSE == WriteFile(writer->outputFileHandle, sectorBitmap, writer->sectorBitmapLength, &bytesWritten, NULL)) { - int lastError = GetLastError(); - tsk_error_reset(); - tsk_error_set_errno(TSK_ERR_IMG_WRITE); - tsk_error_set_errstr("addNewBlock: error writing sector bitmap", - lastError); - return TSK_ERR; - } - if (FALSE == WriteFile(writer->outputFileHandle, fullBuffer, writer->blockSize, &bytesWritten, NULL)) { - int lastError = GetLastError(); - tsk_error_reset(); - tsk_error_set_errno(TSK_ERR_IMG_WRITE); - tsk_error_set_errstr("addNewBlock: error writing block data", - lastError); - return TSK_ERR; - } - - writer->nextDataOffset += writer->sectorBitmapLength + writer->blockSize; - - /* Always add the footer on to make it a valid VHD */ - writeFooter(writer); - - free(fullBuffer); - free(sectorBitmap); - - return TSK_OK; +/* + * Add a new block to the VHD and copy in the buffer + */ +static TSK_RETVAL_ENUM addNewBlock(TSK_IMG_WRITER* writer, TSK_OFF_T addr, char *buffer, size_t len, TSK_OFF_T blockNum) { + + if (tsk_verbose) { + tsk_fprintf(stderr, "addNewBlock: Adding new block 0x%x\n", blockNum); + fflush(stderr); + } + + writer->blockStatus[blockNum] = IMG_WRITER_BLOCK_STATUS_ALLOC; + + /* Given the max size of the VHD, the sector number will always fit in four bytes */ + writer->blockToSectorNumber[blockNum] = uint32_t(writer->nextDataOffset / VHD_SECTOR_SIZE); + + char * fullBuffer = (char *)tsk_malloc(writer->blockSize * sizeof(char)); + char * sectorBitmap = (char *)tsk_malloc(writer->sectorBitmapLength * sizeof(char)); + unsigned char * completedSectors = (unsigned char *)tsk_malloc(((writer->sectorBitmapArrayLength) * sizeof(char))); + + /* Create the full new block and record the sectors written */ + TSK_OFF_T startingOffset = addr % writer->blockSize; + for (size_t i = 0; i < len; i++) { + + /* Update the sector bitmap */ + if (((startingOffset + i) % VHD_SECTOR_SIZE) == 0) { + TSK_OFF_T currentSector = (startingOffset + i) / VHD_SECTOR_SIZE; + setBit(completedSectors, currentSector, true); + sectorBitmap[currentSector / 8] = completedSectors[currentSector / 8]; + } + + fullBuffer[startingOffset + i] = buffer[i]; + } + writer->blockToSectorBitmap[blockNum] = completedSectors; + + /* Prepare the new block offset - this is stored in big-endian order */ + TSK_OFF_T nextDataOffsetSector = writer->nextDataOffset / VHD_SECTOR_SIZE; + unsigned char newBlockOffset[4]; + newBlockOffset[0] = (nextDataOffsetSector >> 24) & 0xff; + newBlockOffset[1] = (nextDataOffsetSector >> 16) & 0xff; + newBlockOffset[2] = (nextDataOffsetSector >> 8) & 0xff; + newBlockOffset[3] = nextDataOffsetSector & 0xff; + + /* Write the new offset to the BAT */ + if (TSK_OK != seekToOffset(writer, writer->batOffset + 4 * blockNum)) { + return TSK_ERR; + } + DWORD bytesWritten; + if (FALSE == WriteFile(writer->outputFileHandle, newBlockOffset, 4, &bytesWritten, NULL)) { + int lastError = GetLastError(); + tsk_error_reset(); + tsk_error_set_errno(TSK_ERR_IMG_WRITE); + tsk_error_set_errstr("addNewBlock: error writing BAT entry", + lastError); + return TSK_ERR; + } + + /* Write the sector bitmap and the data */ + if (TSK_OK != seekToOffset(writer, writer->nextDataOffset)) { + return TSK_ERR; + } + if (FALSE == WriteFile(writer->outputFileHandle, sectorBitmap, writer->sectorBitmapLength, &bytesWritten, NULL)) { + int lastError = GetLastError(); + tsk_error_reset(); + tsk_error_set_errno(TSK_ERR_IMG_WRITE); + tsk_error_set_errstr("addNewBlock: error writing sector bitmap", + lastError); + return TSK_ERR; + } + if (FALSE == WriteFile(writer->outputFileHandle, fullBuffer, writer->blockSize, &bytesWritten, NULL)) { + int lastError = GetLastError(); + tsk_error_reset(); + tsk_error_set_errno(TSK_ERR_IMG_WRITE); + tsk_error_set_errstr("addNewBlock: error writing block data", + lastError); + return TSK_ERR; + } + + /* Update the offset where the next block will start */ + writer->nextDataOffset += writer->sectorBitmapLength + writer->blockSize; + + /* Always add the footer on to make it a valid VHD */ + writeFooter(writer); + + free(fullBuffer); + free(sectorBitmap); + + return TSK_OK; } -TSK_RETVAL_ENUM addBlock(TSK_IMG_WRITER* writer, TSK_OFF_T addr, char *buffer, size_t len) { - TSK_OFF_T blockNum = addr / writer->blockSize; +/* + * Add a buffer that fits in a single block of the VHD + */ +static TSK_RETVAL_ENUM addBlock(TSK_IMG_WRITER* writer, TSK_OFF_T addr, char *buffer, size_t len) { + TSK_OFF_T blockNum = addr / writer->blockSize; - if (writer->blockStatus[blockNum] == IMG_WRITER_BLOCK_STATUS_FINISHED){ - return TSK_OK; - } + if (writer->blockStatus[blockNum] == IMG_WRITER_BLOCK_STATUS_FINISHED){ + return TSK_OK; + } - if (writer->blockStatus[blockNum] == IMG_WRITER_BLOCK_STATUS_ALLOC) { - addToExistingBlock(writer, addr, buffer, len, blockNum); - } - else { - addNewBlock(writer, addr, buffer, len, blockNum); - } + if (writer->blockStatus[blockNum] == IMG_WRITER_BLOCK_STATUS_ALLOC) { + addToExistingBlock(writer, addr, buffer, len, blockNum); + } + else { + addNewBlock(writer, addr, buffer, len, blockNum); + } - /* Check whether the block is now done */ - checkIfBlockIsFinished(writer, blockNum); + /* Check whether the block is now done */ + checkIfBlockIsFinished(writer, blockNum); - return TSK_OK; + return TSK_OK; } +/* + * Add a buffer to the VHD. The buffer can span multiple blocks. + * @param writer Image writer object + * @param addr Offset in the original image where the data starts + * @param buffer The data to copy + * @param len Length of the data (this must be a multiple of the sector size) + */ static TSK_RETVAL_ENUM tsk_img_writer_add(TSK_IMG_WRITER* writer, TSK_OFF_T addr, char *buffer, size_t len) { #ifndef TSK_WIN32 - return TSK_ERR; + return TSK_ERR; #else - if (tsk_verbose) { - tsk_fprintf(stderr, - "tsk_img_writer_add: Adding data at offset: %" - PRIuOFF " len: %" PRIuOFF "\n", addr, - (TSK_OFF_T)len); - } - - sprintf(messageBuffer, "tsk_img_writer_add: addr: 0x%llx len: 0x%llx\n", addr, len); - writeLogFile(writer, messageBuffer); - - if (writer->outputFileHandle == 0) { - writeLogFile(writer, "tsk_img_writer_add: outputFileHandle is closed"); - } - - /* This should never happen, but best to check */ - if (addr % VHD_SECTOR_SIZE != 0) { - return TSK_ERR; - } - - if ((addr / writer->blockSize) == ((addr + len) / writer->blockSize)) { - /* The buffer is contained in a single block */ - if (tsk_verbose) { - tsk_fprintf(stderr, "tsk_img_writer_add: Data fits in one block (0x%x)", (addr / writer->blockSize)); - } - return addBlock(writer, addr, buffer, len); - } - else { - /* The buffer spans two blocks */ - - - TSK_OFF_T firstPartLength = writer->blockSize - (addr % writer->blockSize); - - if (tsk_verbose) { - tsk_fprintf(stderr, "tsk_img_writer_add: Data spans two blocks (0x%x and 0x%x)\n", - (addr / writer->blockSize), ((addr + len) / writer->blockSize)); - tsk_fprintf(stderr, "tsk_img_writer_add: first part len: 0x%llx\n", firstPartLength); - tsk_fprintf(stderr, "tsk_img_writer_add: second part len: 0x%llx\n", addr % writer->blockSize); - } - addBlock(writer, addr, buffer, firstPartLength); - if (addr + firstPartLength < writer->imageSize) { - addBlock(writer, addr + firstPartLength, buffer + firstPartLength, (addr + len) % writer->blockSize); - } - } - - return TSK_OK; + if (tsk_verbose) { + tsk_fprintf(stderr, + "tsk_img_writer_add: Adding data at offset: %" + PRIuOFF " len: %" PRIuOFF "\n", addr, + (TSK_OFF_T)len); + } + + /* This should never happen, but best to check */ + if (addr % VHD_SECTOR_SIZE != 0) { + return TSK_ERR; + } + + if ((addr / writer->blockSize) == ((addr + len) / writer->blockSize)) { + /* The buffer is contained in a single block */ + return addBlock(writer, addr, buffer, len); + } + else { + /* The buffer spans two blocks */ + TSK_OFF_T firstPartLength = writer->blockSize - (addr % writer->blockSize); + addBlock(writer, addr, buffer, firstPartLength); + if (addr + firstPartLength < writer->imageSize) { + addBlock(writer, addr + firstPartLength, buffer + firstPartLength, (addr + len) % writer->blockSize); + } + } + + return TSK_OK; #endif } +/* + * Close the image writer and free its memory + * @param writer Image writer object + */ static TSK_RETVAL_ENUM tsk_img_writer_close(TSK_IMG_WRITER* img_writer) { #ifndef TSK_WIN32 return TSK_ERR; @@ -404,22 +397,58 @@ static TSK_RETVAL_ENUM tsk_img_writer_close(TSK_IMG_WRITER* img_writer) { tsk_fprintf(stderr, "tsk_img_writer_close: Closing image writer"); } - writeLogFile(img_writer, "Closing image writer"); - + if (img_writer->outputFileHandle != 0) { CloseHandle(img_writer->outputFileHandle); img_writer->outputFileHandle = 0; - - /* TODO: Free the data */ } - if (img_writer->logFileHandle != 0) { - CloseHandle(img_writer->logFileHandle); - img_writer->logFileHandle = 0; - } + + /* Free the memory */ + if (img_writer->blockToSectorNumber != NULL) { + free(img_writer->blockToSectorNumber); + img_writer->blockToSectorNumber = NULL; + } + + if (img_writer->blockStatus != NULL) { + free(img_writer->blockStatus); + img_writer->blockStatus = NULL; + } + + if (img_writer->blockToSectorBitmap != NULL) { + for (uint32_t i = 0; i < img_writer->totalBlocks; i++) { + if (img_writer->blockToSectorBitmap[i] != NULL) { + free(img_writer->blockToSectorBitmap[i]); + } + } + free(img_writer->blockToSectorBitmap); + img_writer->blockToSectorBitmap = NULL; + } + + if (img_writer->footer != NULL) { + free(img_writer->footer); + img_writer->footer = NULL; + } + + if (img_writer->fileName != NULL) { + free(img_writer->fileName); + img_writer->fileName = NULL; + } + + + // TEMP TEMP TEMP + if (img_writer->logFileHandle != 0) { + CloseHandle(img_writer->logFileHandle); + img_writer->logFileHandle = 0; + } return TSK_OK; #endif } + +/* + * NOT IMPLENTED YET - Will go through the image and manually read and copy any missing sectors + * @param writer Image writer object + */ static TSK_RETVAL_ENUM tsk_img_writer_finish_image(TSK_IMG_WRITER* img_writer) { #ifndef TSK_WIN32 return TSK_ERR; @@ -439,7 +468,7 @@ static TSK_RETVAL_ENUM tsk_img_writer_finish_image(TSK_IMG_WRITER* img_writer) { * Will write val as an nBytes-long value to the buffer at the given offset. * Byte ordering is big endian */ -void addIntToBuffer(unsigned char * buffer, int offset, TSK_OFF_T val, int nBytes) { +static void addIntToBuffer(unsigned char * buffer, int offset, TSK_OFF_T val, int nBytes) { for (int i = 0; i < nBytes; i++) { buffer[offset + i] = (val >> (8 * (nBytes - 1 - i))) & 0xff; } @@ -448,7 +477,7 @@ void addIntToBuffer(unsigned char * buffer, int offset, TSK_OFF_T val, int nByte /* * Utility function to write strings to the VHD headers. */ -void addStringToBuffer(unsigned char * buffer, int offset, char const * str, int nBytes) { +static void addStringToBuffer(unsigned char * buffer, int offset, char const * str, int nBytes) { for (int i = 0; i < nBytes; i++) { buffer[offset + i] = str[i]; } @@ -458,7 +487,7 @@ void addStringToBuffer(unsigned char * buffer, int offset, char const * str, int * Calculate the checksum for the header. It's the one's complement of the sum of * all the bytes (apart from the checksum) */ -uint32_t generateChecksum(unsigned char * buffer, int len) { +static uint32_t generateChecksum(unsigned char * buffer, int len) { uint32_t sum = 0; for (int i = 0; i < len; i++) { @@ -473,7 +502,7 @@ uint32_t generateChecksum(unsigned char * buffer, int len) { * Will write to the current file position. * Save it so we only have to generate it once. */ -TSK_RETVAL_ENUM writeFooter(TSK_IMG_WRITER* writer) { +static TSK_RETVAL_ENUM writeFooter(TSK_IMG_WRITER* writer) { if (writer->footer == NULL) { writer->footer = (unsigned char *)tsk_malloc(VHD_FOOTER_LENGTH * sizeof(unsigned char)); @@ -520,8 +549,7 @@ TSK_RETVAL_ENUM writeFooter(TSK_IMG_WRITER* writer) { addIntToBuffer(writer->footer, 8, 2, 4); // Features addIntToBuffer(writer->footer, 0xc, 0x10000, 4); // File format version addIntToBuffer(writer->footer, 0x10, 0x200, 8); // Data offset - // 0x18 is a four byte timestamp - leave blank (or maybe not...) - addIntToBuffer(writer->footer, 0x18, 0x200a44cf, 4); + // 0x18 is a four byte timestamp - ok to leave blank addStringToBuffer(writer->footer, 0x1c, "win ", 4); // Creator app addIntToBuffer(writer->footer, 0x20, 0x60001, 4); // Creator version addStringToBuffer(writer->footer, 0x24, "Wi2k", 4); // Creator host OS @@ -531,12 +559,7 @@ TSK_RETVAL_ENUM writeFooter(TSK_IMG_WRITER* writer) { addIntToBuffer(writer->footer, 0x3a, heads, 1); // Geometry addIntToBuffer(writer->footer, 0x3b, sectorsPerTrack, 1); // Geometry addIntToBuffer(writer->footer, 0x3c, 3, 4); // Disk type - - // Maybe we need the UUID to be set to something? - addIntToBuffer(writer->footer, 0x44, 0xde08e6bb, 4);// UUID1 - addIntToBuffer(writer->footer, 0x48, 0xf7684142, 4); - addIntToBuffer(writer->footer, 0x4c, 0x938758ea, 4); - addIntToBuffer(writer->footer, 0x50, 0x77385e49, 4); + // Bytes 0x44 to 0x54 are a UUID, which is ok to leave blank addIntToBuffer(writer->footer, 0x40, generateChecksum(writer->footer, VHD_FOOTER_LENGTH), 4); // Checksum } @@ -556,7 +579,7 @@ TSK_RETVAL_ENUM writeFooter(TSK_IMG_WRITER* writer) { /* * Write the dynamic disk header to the file */ -TSK_RETVAL_ENUM writeDynamicDiskHeader(TSK_IMG_WRITER * writer) { +static TSK_RETVAL_ENUM writeDynamicDiskHeader(TSK_IMG_WRITER * writer) { unsigned char * diskHeader = (unsigned char *)malloc(VHD_DISK_HEADER_LENGTH * sizeof(unsigned char)); for (int i = 0; i < VHD_DISK_HEADER_LENGTH; i++) { diskHeader[i] = 0; @@ -587,50 +610,23 @@ TSK_RETVAL_ENUM writeDynamicDiskHeader(TSK_IMG_WRITER * writer) { /* * Create and initailize the TSK_IMG_WRITER struct and save reference in img_info, * then write the headers to the output file + * @param img_info the TSK_IMG_INFO object + * @param outputFileName path to the VHD */ -TSK_RETVAL_ENUM tsk_img_writer_create_from_dir(TSK_IMG_INFO * img_info, const TSK_TCHAR * directory, - const TSK_TCHAR * basename) { - -#ifndef TSK_WIN32 - return TSK_ERR; -#else - if (tsk_verbose) { - tsk_fprintf(stderr, - "tsk_img_writer_create: Creating image writer in directory %" PRIttocTSK" with basename %" PRIttocTSK"\n", - directory, basename); - fflush(stderr); - } - - /* Set up the output file */ - size_t len = TSTRLEN(directory) + TSTRLEN(basename) + 10; - TSK_TCHAR * outputFileName = (TSK_TCHAR *)malloc(len * sizeof(TSK_TCHAR)); - TSTRNCPY(outputFileName, directory, TSTRLEN(directory) + 1); - TSTRNCAT(outputFileName, _TSK_T("\\"), 2); - TSTRNCAT(outputFileName, basename, TSTRLEN(basename) + 1); - TSTRNCAT(outputFileName, _TSK_T(".vhd"), 5); - if (tsk_verbose) { - tsk_fprintf(stderr, - "tsk_img_writer_create: Output file: %" PRIttocTSK"\n", outputFileName); - fflush(stderr); - } - - return tsk_img_writer_create(img_info, outputFileName); -#endif -} - -/* -* Create and initailize the TSK_IMG_WRITER struct and save reference in img_info, -* then write the headers to the output file -*/ TSK_RETVAL_ENUM tsk_img_writer_create(TSK_IMG_INFO * img_info, const TSK_TCHAR * outputFileName) { #ifndef TSK_WIN32 - return TSK_ERR; + return TSK_ERR; #else if (tsk_verbose) { tsk_fprintf(stderr, "tsk_img_writer_create: Creating image writer in %" PRIttocTSK"\n", outputFileName); - fflush(stderr); + } + + /* Everything will break if the buffers coming in are larger than the block + size (i.e., they could span three blocks instead of just two)*/ + if (TSK_IMG_INFO_CACHE_LEN > VHD_DEFAULT_BLOCK_SIZE) { + return TSK_ERR; } IMG_RAW_INFO* raw_info = (IMG_RAW_INFO *)img_info; @@ -650,8 +646,8 @@ TSK_RETVAL_ENUM tsk_img_writer_create(TSK_IMG_INFO * img_info, const TSK_TCHAR * writer->close = tsk_img_writer_close; writer->finish_image = tsk_img_writer_finish_image; - writer->fileName = (TSK_TCHAR*)tsk_malloc((TSTRLEN(outputFileName) + 1) * sizeof(TCHAR)); - TSTRNCPY(writer->fileName, outputFileName, TSTRLEN(outputFileName) + 1); + writer->fileName = (TSK_TCHAR*)tsk_malloc((TSTRLEN(outputFileName) + 1) * sizeof(TCHAR)); + TSTRNCPY(writer->fileName, outputFileName, TSTRLEN(outputFileName) + 1); /* Calculation time */ writer->imageSize = raw_info->img_info.size; @@ -664,22 +660,20 @@ TSK_RETVAL_ENUM tsk_img_writer_create(TSK_IMG_INFO * img_info, const TSK_TCHAR * writer->totalBlocks++; } writer->sectorsPerBlock = writer->blockSize / VHD_SECTOR_SIZE; - writer->sectorBitmapArrayLength = writer->sectorsPerBlock / 8; - if (writer->sectorBitmapArrayLength % 8 != 0) { - writer->sectorBitmapArrayLength++; - } - writer->sectorBitmapLength = writer->sectorBitmapArrayLength; - if (0 != writer->sectorBitmapLength % VHD_SECTOR_SIZE) { - writer->sectorBitmapLength += VHD_SECTOR_SIZE - (writer->sectorBitmapLength % VHD_SECTOR_SIZE); - } + writer->sectorBitmapArrayLength = writer->sectorsPerBlock / 8; + if (writer->sectorBitmapArrayLength % 8 != 0) { + writer->sectorBitmapArrayLength++; + } + writer->sectorBitmapLength = writer->sectorBitmapArrayLength; + if (0 != writer->sectorBitmapLength % VHD_SECTOR_SIZE) { + writer->sectorBitmapLength += VHD_SECTOR_SIZE - (writer->sectorBitmapLength % VHD_SECTOR_SIZE); + } /* TODO: Decide what to do if the file already exisits. For now, always overwrite */ writer->outputFileHandle = CreateFile(writer->fileName, FILE_WRITE_DATA, FILE_SHARE_READ, NULL, CREATE_ALWAYS, 0, NULL); if (writer->outputFileHandle == INVALID_HANDLE_VALUE) { - tsk_fprintf(stderr, "Error opening VHD!!!"); // temp - fflush(stderr); int lastError = (int)GetLastError(); writer->outputFileHandle = 0; /* so we don't close it next time */ tsk_error_reset(); @@ -689,31 +683,24 @@ TSK_RETVAL_ENUM tsk_img_writer_create(TSK_IMG_INFO * img_info, const TSK_TCHAR * return TSK_ERR; } - if (tsk_verbose) { - tsk_fprintf(stderr, "tsk_img_writer_create: Writing VHD headers"); - fflush(stderr); - } - /* Write the backup copy of the footer */ TSK_RETVAL_ENUM retval = writeFooter(writer); if (retval != TSK_OK) { return retval; } + + /* Write the dynamic disk header */ retval = writeDynamicDiskHeader(writer); if (retval != TSK_OK) { return retval; } - if (tsk_verbose) { - tsk_fprintf(stderr, "tsk_img_writer_create: Writing block allocation table"); - fflush(stderr); - } - /* Write the (empty) Block Allocation Table */ + /* Write the (empty) Block Allocation Table. Each entry is 4 bytes*/ writer->batOffset = VHD_FOOTER_LENGTH + VHD_DISK_HEADER_LENGTH; uint32_t batLengthOnDisk = 4 * writer->totalBlocks; - if ((batLengthOnDisk % 0x200) != 0) { + if ((batLengthOnDisk % VHD_SECTOR_SIZE) != 0) { /* Pad out to the next sector boundary */ - batLengthOnDisk += (0x200 - ((4 * writer->totalBlocks) % 0x200)); + batLengthOnDisk += (VHD_SECTOR_SIZE - ((4 * writer->totalBlocks) % VHD_SECTOR_SIZE)); } DWORD bytesWritten; @@ -733,20 +720,10 @@ TSK_RETVAL_ENUM tsk_img_writer_create(TSK_IMG_INFO * img_info, const TSK_TCHAR * /* Offset for the first data block - 0x600 bytes for the two headers plus the BAT length*/ writer->nextDataOffset = 0x600 + batLengthOnDisk; - if (tsk_verbose) { - tsk_fprintf(stderr, "VHD data:\n imageSize: %x\n blockSize: %x\n totalBlocks: %x\n sectorBitmapLength: %x\n ", - writer->imageSize, writer->blockSize, writer->totalBlocks, writer->sectorBitmapLength); - tsk_fprintf(stderr, " sectorBitmapInMemory: %x\n sectorsPerBlock: %x\n", - writer->sectorBitmapArrayLength, writer->sectorsPerBlock); - fflush(stderr); - - } - - /* Initialze all the bookkeeping arrays */ - writer->blockStatus = (IMG_WRITER_BLOCK_STATUS_ENUM*)tsk_malloc(writer->totalBlocks * sizeof(IMG_WRITER_BLOCK_STATUS_ENUM)); - - writer->blockToOffset = (TSK_OFF_T*)tsk_malloc(writer->totalBlocks * sizeof(TSK_OFF_T)); - writer->blockToSectorBitmap = (unsigned char **)tsk_malloc(writer->totalBlocks * sizeof(unsigned char *)); + /* Initialze all the bookkeeping arrays */ + writer->blockStatus = (IMG_WRITER_BLOCK_STATUS_ENUM*)tsk_malloc(writer->totalBlocks * sizeof(IMG_WRITER_BLOCK_STATUS_ENUM)); + writer->blockToSectorNumber = (uint32_t*)tsk_malloc(writer->totalBlocks * sizeof(uint32_t)); + writer->blockToSectorBitmap = (unsigned char **)tsk_malloc(writer->totalBlocks * sizeof(unsigned char *)); return TSK_OK; #endif diff --git a/tsk/img/img_writer.h b/tsk/img/img_writer.h index e421e020c..dac6a69e5 100644 --- a/tsk/img/img_writer.h +++ b/tsk/img/img_writer.h @@ -19,9 +19,6 @@ #ifdef __cplusplus extern "C" { #endif - - TSK_RETVAL_ENUM tsk_img_writer_create_from_dir(TSK_IMG_INFO* img_info, const TSK_TCHAR * directory, - const TSK_TCHAR * basename); TSK_RETVAL_ENUM tsk_img_writer_create(TSK_IMG_INFO* img_info, const TSK_TCHAR * outputPath); enum IMG_WRITER_BLOCK_STATUS_ENUM { @@ -54,7 +51,7 @@ extern "C" { HANDLE logFileHandle; IMG_WRITER_BLOCK_STATUS_ENUM* blockStatus; - TSK_OFF_T* blockToOffset; + uint32_t* blockToSectorNumber; unsigned char ** blockToSectorBitmap; TSK_RETVAL_ENUM(*add)(TSK_IMG_WRITER* img_writer, TSK_OFF_T addr, char *buffer, size_t len); diff --git a/tsk/img/raw.c b/tsk/img/raw.c index 1ddcded72..a3d85123a 100644 --- a/tsk/img/raw.c +++ b/tsk/img/raw.c @@ -359,6 +359,8 @@ raw_close(TSK_IMG_INFO * img_info) #ifdef TSK_WIN32 if (raw_info->img_writer != NULL) { raw_info->img_writer->close(raw_info->img_writer); + free(raw_info->img_writer); + raw_info->img_writer = NULL; } #endif @@ -759,11 +761,6 @@ tsk_img_malloc(size_t a_len) void tsk_img_free(void *a_ptr) { - IMG_RAW_INFO *rawInfo = (IMG_RAW_INFO *)a_ptr; - if (rawInfo->img_writer != NULL) { - free(rawInfo->img_writer); - rawInfo->img_writer = NULL; - } TSK_IMG_INFO *imgInfo = (TSK_IMG_INFO *) a_ptr; imgInfo->tag = 0; free(imgInfo); diff --git a/tsk/img/vhd.c b/tsk/img/vhd.c index ba45fedc1..864aa0167 100644 --- a/tsk/img/vhd.c +++ b/tsk/img/vhd.c @@ -202,6 +202,7 @@ vhdi_open(int a_num_img, } // Check the file signature before we call the library open #if defined( TSK_WIN32 ) + tsk_fprintf(stderr, "Trying to open file: %s\n", vhdi_info->img_info.images[0]); if( libvhdi_check_file_signature_wide((const wchar_t *) vhdi_info->img_info.images[0], &vhdi_error ) != 1 ) #else if( libvhdi_check_file_signature((const char *) vhdi_info->images[0], &vhdi_error) != 1) @@ -214,6 +215,8 @@ vhdi_open(int a_num_img, tsk_error_set_errstr("vhdi_open file: %" PRIttocTSK ": Error checking file signature for image (%s)", a_images[0], error_string); + + tsk_fprintf(stderr, "VHD error string: %s\n", error_string); // temp temp libvhdi_error_free(&vhdi_error); tsk_img_free(vhdi_info); -- GitLab