VeraCrypt
aboutsummaryrefslogtreecommitdiff
path: root/src/Setup/SelfExtract.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/Setup/SelfExtract.c')
-rw-r--r--src/Setup/SelfExtract.c1576
1 files changed, 788 insertions, 788 deletions
diff --git a/src/Setup/SelfExtract.c b/src/Setup/SelfExtract.c
index 42326efc..5129e991 100644
--- a/src/Setup/SelfExtract.c
+++ b/src/Setup/SelfExtract.c
@@ -1,788 +1,788 @@
-/*
- Derived from source code of TrueCrypt 7.1a, which is
- Copyright (c) 2008-2012 TrueCrypt Developers Association and which is governed
- by the TrueCrypt License 3.0.
-
- Modifications and additions to the original source code (contained in this file)
- and all other portions of this file are Copyright (c) 2013-2016 IDRIX
- and are governed by the Apache License 2.0 the full text of which is
- contained in the file License.txt included in VeraCrypt binary and source
- code distribution packages.
-*/
-
-#include "Tcdefs.h"
-
-#include "Inflate.h"
-#include "SelfExtract.h"
-#include "Wizard.h"
-#include "Setup.h"
-#include "Crc.h"
-#include "Endian.h"
-#include "Dlgcode.h"
-#include "Dir.h"
-#include "Language.h"
-#include "Resource.h"
-#include <tchar.h>
-#include <Strsafe.h>
-
-#ifndef SRC_POS
-#define SRC_POS (__FUNCTION__ ":" TC_TO_STRING(__LINE__))
-#endif
-
-#define OutputPackageFile L"VeraCrypt Setup " _T(VERSION_STRING) L".exe"
-
-#define MAG_START_MARKER "TCINSTRT"
-#define MAG_END_MARKER_OBFUSCATED "T/C/I/N/S/C/R/C"
-#define PIPE_BUFFER_LEN (4 * BYTES_PER_KB)
-
-unsigned char MagEndMarker [sizeof (MAG_END_MARKER_OBFUSCATED)];
-wchar_t DestExtractPath [TC_MAX_PATH];
-DECOMPRESSED_FILE Decompressed_Files [NBR_COMPRESSED_FILES];
-
-volatile char *PipeWriteBuf = NULL;
-volatile HANDLE hChildStdinWrite = INVALID_HANDLE_VALUE;
-unsigned char *DecompressedData = NULL;
-
-
-
-void SelfExtractStartupInit (void)
-{
- DeobfuscateMagEndMarker ();
-}
-
-
-// The end marker must be included in the self-extracting exe only once, not twice (used e.g.
-// by IsSelfExtractingPackage()) and that's why MAG_END_MARKER_OBFUSCATED is obfuscated and
-// needs to be deobfuscated using this function at startup.
-static void DeobfuscateMagEndMarker (void)
-{
- int i;
-
- for (i = 0; i < sizeof (MAG_END_MARKER_OBFUSCATED); i += 2)
- MagEndMarker [i/2] = MAG_END_MARKER_OBFUSCATED [i];
-
- MagEndMarker [i/2] = 0;
-}
-
-
-static void PkgError (wchar_t *msg)
-{
- MessageBox (NULL, msg, L"VeraCrypt", MB_ICONERROR | MB_SETFOREGROUND | MB_TOPMOST);
-}
-
-
-static void PkgWarning (wchar_t *msg)
-{
- MessageBox (NULL, msg, L"VeraCrypt", MB_ICONWARNING | MB_SETFOREGROUND | MB_TOPMOST);
-}
-
-
-static void PkgInfo (wchar_t *msg)
-{
- MessageBox (NULL, msg, L"VeraCrypt", MB_ICONINFORMATION | MB_SETFOREGROUND | MB_TOPMOST);
-}
-
-
-// Returns 0 if decompression fails or, if successful, returns the size of the decompressed data
-static int DecompressBuffer (char *out, char *in, int len)
-{
- return (DecompressDeflatedData (out, in, len)); // Inflate
-}
-
-
-static void __cdecl PipeWriteThread (void *len)
-{
- int sendBufSize = PIPE_BUFFER_LEN, bytesSent = 0;
- int bytesToSend = *((int *) len), bytesSentTotal = 0;
-
- if (PipeWriteBuf == NULL || (HANDLE) hChildStdinWrite == INVALID_HANDLE_VALUE)
- {
- PkgError (L"Failed sending data to the STDIN pipe");
- return;
- }
-
- while (bytesToSend > 0)
- {
- if (bytesToSend < PIPE_BUFFER_LEN)
- sendBufSize = bytesToSend;
-
- if (!WriteFile ((HANDLE) hChildStdinWrite, (char *) PipeWriteBuf + bytesSentTotal, sendBufSize, &bytesSent, NULL)
- || bytesSent == 0
- || bytesSent != sendBufSize)
- {
- PkgError (L"Failed sending data to the STDIN pipe");
- return;
- }
-
- bytesToSend -= bytesSent;
- bytesSentTotal += bytesSent;
- }
-
- // Closing the pipe causes the child process to stop reading from it
-
- if (!CloseHandle (hChildStdinWrite))
- {
- PkgError (L"Cannot close pipe");
- return;
- }
-}
-
-
-// Returns 0 if compression fails or, if successful, the size of the compressed data
-static int CompressBuffer (char *out, char *in, int len)
-{
- SECURITY_ATTRIBUTES securityAttrib;
- DWORD bytesReceived = 0;
- HANDLE hChildStdoutWrite = INVALID_HANDLE_VALUE;
- HANDLE hChildStdoutRead = INVALID_HANDLE_VALUE;
- HANDLE hChildStdinRead = INVALID_HANDLE_VALUE;
- STARTUPINFO startupInfo;
- PROCESS_INFORMATION procInfo;
- char pipeBuffer [PIPE_BUFFER_LEN];
- int res_len = 0;
- BOOL bGzipHeaderRead = FALSE;
- wchar_t szGzipCmd[64];
-
- ZeroMemory (&startupInfo, sizeof (startupInfo));
- ZeroMemory (&procInfo, sizeof (procInfo));
-
- // Pipe handle inheritance
- securityAttrib.bInheritHandle = TRUE;
- securityAttrib.nLength = sizeof (securityAttrib);
- securityAttrib.lpSecurityDescriptor = NULL;
-
- if (!CreatePipe (&hChildStdoutRead, &hChildStdoutWrite, &securityAttrib, 0))
- {
- PkgError (L"Cannot create STDOUT pipe.");
- return 0;
- }
- SetHandleInformation (hChildStdoutRead, HANDLE_FLAG_INHERIT, 0);
-
- if (!CreatePipe (&hChildStdinRead, &((HANDLE) hChildStdinWrite), &securityAttrib, 0))
- {
- PkgError (L"Cannot create STDIN pipe.");
- CloseHandle(hChildStdoutWrite);
- CloseHandle(hChildStdoutRead);
- return 0;
- }
- SetHandleInformation (hChildStdinWrite, HANDLE_FLAG_INHERIT, 0);
-
- // Create a child process that will compress the data
-
- startupInfo.wShowWindow = SW_HIDE;
- startupInfo.hStdInput = hChildStdinRead;
- startupInfo.hStdOutput = hChildStdoutWrite;
- startupInfo.cb = sizeof (startupInfo);
- startupInfo.hStdError = hChildStdoutWrite;
- startupInfo.dwFlags |= STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
-
- StringCchCopyW (szGzipCmd, ARRAYSIZE (szGzipCmd), L"gzip --best");
- if (!CreateProcess (NULL, szGzipCmd, NULL, NULL, TRUE, 0, NULL, NULL, &startupInfo, &procInfo))
- {
- PkgError (L"Error: Cannot run gzip.\n\nBefore you can create a self-extracting VeraCrypt package, you need to have the open-source 'gzip' compression tool placed in any directory in the search path for executable files (for example, in 'C:\\Windows\\').\n\nNote: gzip can be freely downloaded e.g. from www.gzip.org");
- CloseHandle(hChildStdoutWrite);
- CloseHandle(hChildStdoutRead);
- CloseHandle(hChildStdinRead);
- CloseHandle(hChildStdinWrite);
- return 0;
- }
-
- CloseHandle (procInfo.hProcess);
- CloseHandle (procInfo.hThread);
-
- // Start sending the uncompressed data to the pipe (STDIN)
- PipeWriteBuf = in;
- _beginthread (PipeWriteThread, PIPE_BUFFER_LEN * 2, (void *) &len);
-
- if (!CloseHandle (hChildStdoutWrite))
- {
- PkgError (L"Cannot close STDOUT write");
- CloseHandle(hChildStdoutRead);
- CloseHandle(hChildStdinRead);
- return 0;
- }
-
- bGzipHeaderRead = FALSE;
-
- // Read the compressed data from the pipe (sent by the child process to STDOUT)
- while (TRUE)
- {
- if (!ReadFile (hChildStdoutRead, pipeBuffer, bGzipHeaderRead ? PIPE_BUFFER_LEN : 10, &bytesReceived, NULL))
- break;
-
- if (bGzipHeaderRead)
- {
- memcpy (out + res_len, pipeBuffer, bytesReceived);
- res_len += bytesReceived;
- }
- else
- bGzipHeaderRead = TRUE; // Skip the 10-byte gzip header
- }
-
- CloseHandle(hChildStdoutRead);
- CloseHandle(hChildStdinRead);
- return res_len - 8; // A gzip stream ends with a CRC-32 hash and a 32-bit size (those 8 bytes need to be chopped off)
-}
-
-
-// Clears all bytes that change when an exe file is digitally signed, except the data that are appended.
-// If those bytes weren't cleared, CRC-32 checks would fail after signing.
-static void WipeSignatureAreas (char *buffer)
-{
- // Clear bytes 0x130-0x1ff
- memset (buffer + 0x130, 0, 0x200 - 0x130);
-}
-
-
-BOOL MakeSelfExtractingPackage (HWND hwndDlg, wchar_t *szDestDir)
-{
- int i, x;
- wchar_t inputFile [TC_MAX_PATH];
- wchar_t outputFile [TC_MAX_PATH];
- wchar_t szTmpFilePath [TC_MAX_PATH];
- unsigned char szTmp32bit [4] = {0};
- unsigned char *szTmp32bitPtr = szTmp32bit;
- unsigned char *buffer = NULL, *compressedBuffer = NULL;
- unsigned char *bufIndex = NULL;
- wchar_t tmpStr [2048];
- int bufLen = 0, compressedDataLen = 0, uncompressedDataLen = 0;
-
- x = wcslen (szDestDir);
- if (x < 2)
- goto err;
-
- if (szDestDir[x - 1] != L'\\')
- StringCbCatW (szDestDir, MAX_PATH, L"\\");
-
- GetModuleFileName (NULL, inputFile, ARRAYSIZE (inputFile));
-
- StringCchCopyW (outputFile, ARRAYSIZE(outputFile), szDestDir);
- StringCchCatW (outputFile, ARRAYSIZE(outputFile), OutputPackageFile);
-
- // Clone 'VeraCrypt Setup.exe' to create the base of the new self-extracting archive
-
- if (!TCCopyFile (inputFile, outputFile))
- {
- handleWin32Error (hwndDlg, SRC_POS);
- PkgError (L"Cannot copy 'VeraCrypt Setup.exe' to the package");
- goto err;
- }
-
- // Determine the buffer size needed for all the files and meta data and check if all required files exist
-
- bufLen = 0;
-
- for (i = 0; i < sizeof (szCompressedFiles) / sizeof (szCompressedFiles[0]); i++)
- {
- StringCbPrintfW (szTmpFilePath, sizeof(szTmpFilePath), L"%s%s", szDestDir, szCompressedFiles[i]);
-
- if (!FileExists (szTmpFilePath))
- {
- wchar_t tmpstr [1000];
-
- StringCbPrintfW (tmpstr, sizeof(tmpstr), L"File not found:\n\n'%s'", szTmpFilePath);
- if (_wremove (outputFile))
- StringCbCatW (tmpstr, sizeof(tmpstr), L"\nFailed also to delete package file");
- PkgError (tmpstr);
- goto err;
- }
-
- bufLen += (int) GetFileSize64 (szTmpFilePath);
-
- bufLen += 2; // 16-bit filename length
- bufLen += (wcslen(szCompressedFiles[i]) * sizeof (wchar_t)); // Filename
- bufLen += 4; // CRC-32
- bufLen += 4; // 32-bit file length
- }
-
- buffer = malloc (bufLen + 524288); // + 512K reserve
- if (buffer == NULL)
- {
- PkgError (L"Cannot allocate memory for uncompressed data");
- if (_wremove (outputFile))
- PkgError (L"Cannot allocate memory for uncompressed data.\nFailed also to delete package file");
- else
- PkgError (L"Cannot allocate memory for uncompressed data");
- goto err;
- }
-
-
- // Write the start marker
- if (!SaveBufferToFile (MAG_START_MARKER, outputFile, strlen (MAG_START_MARKER), TRUE, FALSE))
- {
- if (_wremove (outputFile))
- PkgError (L"Cannot write the start marker\nFailed also to delete package file");
- else
- PkgError (L"Cannot write the start marker");
- goto err;
- }
-
-
- bufIndex = buffer;
-
- // Copy all required files and their meta data to the buffer
- for (i = 0; i < sizeof (szCompressedFiles) / sizeof (szCompressedFiles[0]); i++)
- {
- DWORD tmpFileSize;
- unsigned char *tmpBuffer;
-
- StringCbPrintfW (szTmpFilePath, sizeof(szTmpFilePath), L"%s%s", szDestDir, szCompressedFiles[i]);
-
- tmpBuffer = LoadFile (szTmpFilePath, &tmpFileSize);
-
- if (tmpBuffer == NULL)
- {
- wchar_t tmpstr [1000];
-
- StringCbPrintfW (tmpstr, sizeof(tmpstr), L"Cannot load file \n'%s'", szTmpFilePath);
- if (_wremove (outputFile))
- StringCbCatW (tmpstr, sizeof(tmpstr), L"\nFailed also to delete package file");
- PkgError (tmpstr);
- goto err;
- }
-
- // Copy the filename length to the main buffer
- mputWord (bufIndex, (WORD) wcslen(szCompressedFiles[i]));
-
- // Copy the filename to the main buffer
- wmemcpy ((wchar_t*)bufIndex, szCompressedFiles[i], wcslen(szCompressedFiles[i]));
- bufIndex += (wcslen(szCompressedFiles[i]) * sizeof (wchar_t));
-
- // Compute CRC-32 hash of the uncompressed file and copy it to the main buffer
- mputLong (bufIndex, GetCrc32 (tmpBuffer, tmpFileSize));
-
- // Copy the file length to the main buffer
- mputLong (bufIndex, (unsigned __int32) tmpFileSize);
-
- // Copy the file contents to the main buffer
- memcpy (bufIndex, tmpBuffer, tmpFileSize);
- bufIndex += tmpFileSize;
-
- free (tmpBuffer);
- }
-
- // Calculate the total size of the uncompressed data
- uncompressedDataLen = (int) (bufIndex - buffer);
-
- // Write total size of the uncompressed data
- szTmp32bitPtr = szTmp32bit;
- mputLong (szTmp32bitPtr, (unsigned __int32) uncompressedDataLen);
- if (!SaveBufferToFile (szTmp32bit, outputFile, sizeof (szTmp32bit), TRUE, FALSE))
- {
- if (_wremove (outputFile))
- PkgError (L"Cannot write the total size of the uncompressed data.\nFailed also to delete package file");
- else
- PkgError (L"Cannot write the total size of the uncompressed data");
- goto err;
- }
-
- // Compress all the files and meta data in the buffer to create a solid archive
-
- // Test to make Coverity happy. It will always be false
- if (uncompressedDataLen >= (INT_MAX - 524288))
- {
- if (_wremove (outputFile))
- PkgError (L"Cannot allocate memory for compressed data.\nFailed also to delete package file");
- else
- PkgError (L"Cannot allocate memory for compressed data");
- goto err;
- }
-
- compressedBuffer = malloc (uncompressedDataLen + 524288); // + 512K reserve
- if (compressedBuffer == NULL)
- {
- if (_wremove (outputFile))
- PkgError (L"Cannot allocate memory for compressed data.\nFailed also to delete package file");
- else
- PkgError (L"Cannot allocate memory for compressed data");
- goto err;
- }
-
- compressedDataLen = CompressBuffer (compressedBuffer, buffer, uncompressedDataLen);
- if (compressedDataLen <= 0)
- {
- if (_wremove (outputFile))
- PkgError (L"Failed to compress the data.\nFailed also to delete package file");
- else
- PkgError (L"Failed to compress the data");
- goto err;
- }
-
- free (buffer);
- buffer = NULL;
-
- // Write the total size of the compressed data
- szTmp32bitPtr = szTmp32bit;
- mputLong (szTmp32bitPtr, (unsigned __int32) compressedDataLen);
- if (!SaveBufferToFile (szTmp32bit, outputFile, sizeof (szTmp32bit), TRUE, FALSE))
- {
- if (_wremove (outputFile))
- PkgError (L"Cannot write the total size of the compressed data.\nFailed also to delete package file");
- else
- PkgError (L"Cannot write the total size of the compressed data");
- goto err;
- }
-
- // Write the compressed data
- if (!SaveBufferToFile (compressedBuffer, outputFile, compressedDataLen, TRUE, FALSE))
- {
- if (_wremove (outputFile))
- PkgError (L"Cannot write compressed data to the package.\nFailed also to delete package file");
- else
- PkgError (L"Cannot write compressed data to the package");
- goto err;
- }
-
- // Write the end marker
- if (!SaveBufferToFile (MagEndMarker, outputFile, strlen (MagEndMarker), TRUE, FALSE))
- {
- if (_wremove (outputFile))
- PkgError (L"Cannot write the end marker.\nFailed also to delete package file");
- else
- PkgError (L"Cannot write the end marker");
- goto err;
- }
-
- free (compressedBuffer);
- compressedBuffer = NULL;
-
- // Compute and write CRC-32 hash of the entire package
- {
- DWORD tmpFileSize;
- char *tmpBuffer;
-
- tmpBuffer = LoadFile (outputFile, &tmpFileSize);
-
- if (tmpBuffer == NULL)
- {
- handleWin32Error (hwndDlg, SRC_POS);
- if (_wremove (outputFile))
- PkgError (L"Cannot load the package to compute CRC.\nFailed also to delete package file");
- else
- PkgError (L"Cannot load the package to compute CRC");
- goto err;
- }
-
- // Zero all bytes that change when the exe is digitally signed (except appended blocks).
- WipeSignatureAreas (tmpBuffer);
-
- szTmp32bitPtr = szTmp32bit;
- mputLong (szTmp32bitPtr, GetCrc32 (tmpBuffer, tmpFileSize));
- free (tmpBuffer);
-
- if (!SaveBufferToFile (szTmp32bit, outputFile, sizeof (szTmp32bit), TRUE, FALSE))
- {
- if (_wremove (outputFile))
- PkgError (L"Cannot write the total size of the compressed data.\nFailed also to delete package file");
- else
- PkgError (L"Cannot write the total size of the compressed data");
- goto err;
- }
- }
-
- StringCbPrintfW (tmpStr, sizeof(tmpStr), L"Self-extracting package successfully created (%s)", outputFile);
- PkgInfo (tmpStr);
- return TRUE;
-
-err:
- if (buffer)
- free (buffer);
- if (compressedBuffer)
- free (compressedBuffer);
-
- return FALSE;
-}
-
-
-// Verifies the CRC-32 of the whole self-extracting package (except the digital signature areas, if present)
-BOOL VerifyPackageIntegrity (void)
-{
- int fileDataEndPos = 0;
- int fileDataStartPos = 0;
- unsigned __int32 crc = 0;
- unsigned char *tmpBuffer;
- int tmpFileSize;
- wchar_t path [TC_MAX_PATH];
-
- GetModuleFileName (NULL, path, ARRAYSIZE (path));
-
- fileDataEndPos = (int) FindStringInFile (path, MagEndMarker, strlen (MagEndMarker));
- if (fileDataEndPos < 0)
- {
- Error ("DIST_PACKAGE_CORRUPTED", NULL);
- return FALSE;
- }
- fileDataEndPos--;
-
- fileDataStartPos = (int) FindStringInFile (path, MAG_START_MARKER, strlen (MAG_START_MARKER));
- if (fileDataStartPos < 0)
- {
- Error ("DIST_PACKAGE_CORRUPTED", NULL);
- return FALSE;
- }
- fileDataStartPos += strlen (MAG_START_MARKER);
-
-
- if (!LoadInt32 (path, &crc, fileDataEndPos + strlen (MagEndMarker) + 1))
- {
- Error ("CANT_VERIFY_PACKAGE_INTEGRITY", NULL);
- return FALSE;
- }
-
- // Compute the CRC-32 hash of the whole file (except the digital signature area, if present)
- tmpBuffer = LoadFile (path, &tmpFileSize);
-
- if (tmpBuffer == NULL)
- {
- Error ("CANT_VERIFY_PACKAGE_INTEGRITY", NULL);
- return FALSE;
- }
-
- // Zero all bytes that change when an exe is digitally signed (except appended blocks).
- WipeSignatureAreas (tmpBuffer);
-
- if (crc != GetCrc32 (tmpBuffer, fileDataEndPos + 1 + strlen (MagEndMarker)))
- {
- free (tmpBuffer);
- Error ("DIST_PACKAGE_CORRUPTED", NULL);
- return FALSE;
- }
-
- free (tmpBuffer);
-
- return TRUE;
-}
-
-
-// Determines whether we are a self-extracting package
-BOOL IsSelfExtractingPackage (void)
-{
- wchar_t path [TC_MAX_PATH];
-
- GetModuleFileName (NULL, path, ARRAYSIZE (path));
-
- return (FindStringInFile (path, MagEndMarker, strlen (MagEndMarker)) != -1);
-}
-
-
-static void FreeAllFileBuffers (void)
-{
- int fileNo;
-
- if (DecompressedData != NULL)
- {
- free (DecompressedData);
- DecompressedData = NULL;
- }
-
- for (fileNo = 0; fileNo < NBR_COMPRESSED_FILES; fileNo++)
- {
- Decompressed_Files[fileNo].fileName = NULL;
- Decompressed_Files[fileNo].fileContent = NULL;
- Decompressed_Files[fileNo].fileNameLength = 0;
- Decompressed_Files[fileNo].fileLength = 0;
- Decompressed_Files[fileNo].crc = 0;
- }
-}
-
-
-// Assumes that VerifyPackageIntegrity() has been used. Returns TRUE, if successful (otherwise FALSE).
-// Creates a table of pointers to buffers containing the following objects for each file:
-// filename size, filename (not null-terminated!), file size, file CRC-32, uncompressed file contents.
-// For details, see the definition of the DECOMPRESSED_FILE structure.
-BOOL SelfExtractInMemory (wchar_t *path)
-{
- int filePos = 0, fileNo = 0;
- int fileDataEndPos = 0;
- int fileDataStartPos = 0;
- int uncompressedLen = 0;
- int compressedLen = 0;
- unsigned char *compressedData = NULL;
- unsigned char *bufPos = NULL, *bufEndPos = NULL;
-
- FreeAllFileBuffers();
-
- fileDataEndPos = (int) FindStringInFile (path, MagEndMarker, strlen (MagEndMarker));
- if (fileDataEndPos < 0)
- {
- Error ("CANNOT_READ_FROM_PACKAGE", NULL);
- return FALSE;
- }
-
- fileDataEndPos--;
-
- fileDataStartPos = (int) FindStringInFile (path, MAG_START_MARKER, strlen (MAG_START_MARKER));
- if (fileDataStartPos < 0)
- {
- Error ("CANNOT_READ_FROM_PACKAGE", NULL);
- return FALSE;
- }
-
- fileDataStartPos += strlen (MAG_START_MARKER);
-
- filePos = fileDataStartPos;
-
- // Read the stored total size of the uncompressed data
- if (!LoadInt32 (path, &uncompressedLen, filePos))
- {
- Error ("CANNOT_READ_FROM_PACKAGE", NULL);
- return FALSE;
- }
-
- filePos += 4;
-
- // Read the stored total size of the compressed data
- if (!LoadInt32 (path, &compressedLen, filePos))
- {
- Error ("CANNOT_READ_FROM_PACKAGE", NULL);
- return FALSE;
- }
-
- filePos += 4;
-
- if (compressedLen != fileDataEndPos - fileDataStartPos - 8 + 1)
- {
- Error ("DIST_PACKAGE_CORRUPTED", NULL);
- }
-
- DecompressedData = malloc (uncompressedLen + 524288); // + 512K reserve
- if (DecompressedData == NULL)
- {
- Error ("ERR_MEM_ALLOC", NULL);
- return FALSE;
- }
-
- bufPos = DecompressedData;
- bufEndPos = bufPos + uncompressedLen - 1;
-
- compressedData = LoadFileBlock (path, filePos, compressedLen);
-
- if (compressedData == NULL)
- {
- free (DecompressedData);
- DecompressedData = NULL;
-
- Error ("CANNOT_READ_FROM_PACKAGE", NULL);
- return FALSE;
- }
-
- // Decompress the data
- if (DecompressBuffer (DecompressedData, compressedData, compressedLen) != uncompressedLen)
- {
- Error ("DIST_PACKAGE_CORRUPTED", NULL);
- goto sem_end;
- }
-
- while (bufPos <= bufEndPos && fileNo < NBR_COMPRESSED_FILES)
- {
- // Filename length
- Decompressed_Files[fileNo].fileNameLength = mgetWord (bufPos);
-
- // Filename
- Decompressed_Files[fileNo].fileName = (wchar_t*) bufPos;
- bufPos += (Decompressed_Files[fileNo].fileNameLength * sizeof (wchar_t));
-
- // CRC-32 of the file
- Decompressed_Files[fileNo].crc = mgetLong (bufPos);
-
- // File length
- Decompressed_Files[fileNo].fileLength = mgetLong (bufPos);
-
- // File content
- Decompressed_Files[fileNo].fileContent = bufPos;
- bufPos += Decompressed_Files[fileNo].fileLength;
-
- // Verify CRC-32 of the file (to verify that it didn't get corrupted while creating the solid archive).
- if (Decompressed_Files[fileNo].crc
- != GetCrc32 (Decompressed_Files[fileNo].fileContent, Decompressed_Files[fileNo].fileLength))
- {
- Error ("DIST_PACKAGE_CORRUPTED", NULL);
- goto sem_end;
- }
-
- fileNo++;
- }
-
- if (fileNo < NBR_COMPRESSED_FILES)
- {
- Error ("DIST_PACKAGE_CORRUPTED", NULL);
- goto sem_end;
- }
-
- free (compressedData);
- return TRUE;
-
-sem_end:
- FreeAllFileBuffers();
- free (compressedData);
- return FALSE;
-}
-
-
-void __cdecl ExtractAllFilesThread (void *hwndDlg)
-{
- int fileNo;
- BOOL bSuccess = FALSE;
- wchar_t packageFile [TC_MAX_PATH];
-
- InvalidateRect (GetDlgItem (GetParent (hwndDlg), IDD_INSTL_DLG), NULL, TRUE);
-
- ClearLogWindow (hwndDlg);
-
- GetModuleFileName (NULL, packageFile, ARRAYSIZE (packageFile));
-
- if (!(bSuccess = SelfExtractInMemory (packageFile)))
- goto eaf_end;
-
- if (mkfulldir (DestExtractPath, TRUE) != 0)
- {
- if (mkfulldir (DestExtractPath, FALSE) != 0)
- {
- wchar_t szTmp[TC_MAX_PATH];
-
- handleWin32Error (hwndDlg, SRC_POS);
- StringCbPrintfW (szTmp, sizeof(szTmp), GetString ("CANT_CREATE_FOLDER"), DestExtractPath);
- MessageBoxW (hwndDlg, szTmp, lpszTitle, MB_ICONHAND);
- bSuccess = FALSE;
- goto eaf_end;
- }
- }
-
- for (fileNo = 0; fileNo < NBR_COMPRESSED_FILES; fileNo++)
- {
- wchar_t fileName [TC_MAX_PATH] = {0};
- wchar_t filePath [TC_MAX_PATH] = {0};
-
- // Filename
- StringCchCopyNW (fileName, ARRAYSIZE(fileName), Decompressed_Files[fileNo].fileName, Decompressed_Files[fileNo].fileNameLength);
- StringCchCopyW (filePath, ARRAYSIZE(filePath), DestExtractPath);
- StringCchCatW (filePath, ARRAYSIZE(filePath), fileName);
-
- StatusMessageParam (hwndDlg, "EXTRACTING_VERB", filePath);
-
- // Write the file
- if (!SaveBufferToFile (
- Decompressed_Files[fileNo].fileContent,
- filePath,
- Decompressed_Files[fileNo].fileLength,
- FALSE, FALSE))
- {
- wchar_t szTmp[512];
-
- StringCbPrintfW (szTmp, sizeof (szTmp), GetString ("CANNOT_WRITE_FILE_X"), filePath);
- MessageBoxW (hwndDlg, szTmp, lpszTitle, MB_ICONERROR | MB_SETFOREGROUND | MB_TOPMOST);
- bSuccess = FALSE;
- goto eaf_end;
- }
- UpdateProgressBarProc ((int) (100 * ((float) fileNo / NBR_COMPRESSED_FILES)));
- }
-
-eaf_end:
- FreeAllFileBuffers();
-
- if (bSuccess)
- PostMessage (MainDlg, TC_APPMSG_EXTRACTION_SUCCESS, 0, 0);
- else
- PostMessage (MainDlg, TC_APPMSG_EXTRACTION_FAILURE, 0, 0);
-}
-
+/*
+ Derived from source code of TrueCrypt 7.1a, which is
+ Copyright (c) 2008-2012 TrueCrypt Developers Association and which is governed
+ by the TrueCrypt License 3.0.
+
+ Modifications and additions to the original source code (contained in this file)
+ and all other portions of this file are Copyright (c) 2013-2016 IDRIX
+ and are governed by the Apache License 2.0 the full text of which is
+ contained in the file License.txt included in VeraCrypt binary and source
+ code distribution packages.
+*/
+
+#include "Tcdefs.h"
+
+#include "Inflate.h"
+#include "SelfExtract.h"
+#include "Wizard.h"
+#include "Setup.h"
+#include "Crc.h"
+#include "Endian.h"
+#include "Dlgcode.h"
+#include "Dir.h"
+#include "Language.h"
+#include "Resource.h"
+#include <tchar.h>
+#include <Strsafe.h>
+
+#ifndef SRC_POS
+#define SRC_POS (__FUNCTION__ ":" TC_TO_STRING(__LINE__))
+#endif
+
+#define OutputPackageFile L"VeraCrypt Setup " _T(VERSION_STRING) L".exe"
+
+#define MAG_START_MARKER "TCINSTRT"
+#define MAG_END_MARKER_OBFUSCATED "T/C/I/N/S/C/R/C"
+#define PIPE_BUFFER_LEN (4 * BYTES_PER_KB)
+
+unsigned char MagEndMarker [sizeof (MAG_END_MARKER_OBFUSCATED)];
+wchar_t DestExtractPath [TC_MAX_PATH];
+DECOMPRESSED_FILE Decompressed_Files [NBR_COMPRESSED_FILES];
+
+volatile char *PipeWriteBuf = NULL;
+volatile HANDLE hChildStdinWrite = INVALID_HANDLE_VALUE;
+unsigned char *DecompressedData = NULL;
+
+
+
+void SelfExtractStartupInit (void)
+{
+ DeobfuscateMagEndMarker ();
+}
+
+
+// The end marker must be included in the self-extracting exe only once, not twice (used e.g.
+// by IsSelfExtractingPackage()) and that's why MAG_END_MARKER_OBFUSCATED is obfuscated and
+// needs to be deobfuscated using this function at startup.
+static void DeobfuscateMagEndMarker (void)
+{
+ int i;
+
+ for (i = 0; i < sizeof (MAG_END_MARKER_OBFUSCATED); i += 2)
+ MagEndMarker [i/2] = MAG_END_MARKER_OBFUSCATED [i];
+
+ MagEndMarker [i/2] = 0;
+}
+
+
+static void PkgError (wchar_t *msg)
+{
+ MessageBox (NULL, msg, L"VeraCrypt", MB_ICONERROR | MB_SETFOREGROUND | MB_TOPMOST);
+}
+
+
+static void PkgWarning (wchar_t *msg)
+{
+ MessageBox (NULL, msg, L"VeraCrypt", MB_ICONWARNING | MB_SETFOREGROUND | MB_TOPMOST);
+}
+
+
+static void PkgInfo (wchar_t *msg)
+{
+ MessageBox (NULL, msg, L"VeraCrypt", MB_ICONINFORMATION | MB_SETFOREGROUND | MB_TOPMOST);
+}
+
+
+// Returns 0 if decompression fails or, if successful, returns the size of the decompressed data
+static int DecompressBuffer (char *out, char *in, int len)
+{
+ return (DecompressDeflatedData (out, in, len)); // Inflate
+}
+
+
+static void __cdecl PipeWriteThread (void *len)
+{
+ int sendBufSize = PIPE_BUFFER_LEN, bytesSent = 0;
+ int bytesToSend = *((int *) len), bytesSentTotal = 0;
+
+ if (PipeWriteBuf == NULL || (HANDLE) hChildStdinWrite == INVALID_HANDLE_VALUE)
+ {
+ PkgError (L"Failed sending data to the STDIN pipe");
+ return;
+ }
+
+ while (bytesToSend > 0)
+ {
+ if (bytesToSend < PIPE_BUFFER_LEN)
+ sendBufSize = bytesToSend;
+
+ if (!WriteFile ((HANDLE) hChildStdinWrite, (char *) PipeWriteBuf + bytesSentTotal, sendBufSize, &bytesSent, NULL)
+ || bytesSent == 0
+ || bytesSent != sendBufSize)
+ {
+ PkgError (L"Failed sending data to the STDIN pipe");
+ return;
+ }
+
+ bytesToSend -= bytesSent;
+ bytesSentTotal += bytesSent;
+ }
+
+ // Closing the pipe causes the child process to stop reading from it
+
+ if (!CloseHandle (hChildStdinWrite))
+ {
+ PkgError (L"Cannot close pipe");
+ return;
+ }
+}
+
+
+// Returns 0 if compression fails or, if successful, the size of the compressed data
+static int CompressBuffer (char *out, char *in, int len)
+{
+ SECURITY_ATTRIBUTES securityAttrib;
+ DWORD bytesReceived = 0;
+ HANDLE hChildStdoutWrite = INVALID_HANDLE_VALUE;
+ HANDLE hChildStdoutRead = INVALID_HANDLE_VALUE;
+ HANDLE hChildStdinRead = INVALID_HANDLE_VALUE;
+ STARTUPINFO startupInfo;
+ PROCESS_INFORMATION procInfo;
+ char pipeBuffer [PIPE_BUFFER_LEN];
+ int res_len = 0;
+ BOOL bGzipHeaderRead = FALSE;
+ wchar_t szGzipCmd[64];
+
+ ZeroMemory (&startupInfo, sizeof (startupInfo));
+ ZeroMemory (&procInfo, sizeof (procInfo));
+
+ // Pipe handle inheritance
+ securityAttrib.bInheritHandle = TRUE;
+ securityAttrib.nLength = sizeof (securityAttrib);
+ securityAttrib.lpSecurityDescriptor = NULL;
+
+ if (!CreatePipe (&hChildStdoutRead, &hChildStdoutWrite, &securityAttrib, 0))
+ {
+ PkgError (L"Cannot create STDOUT pipe.");
+ return 0;
+ }
+ SetHandleInformation (hChildStdoutRead, HANDLE_FLAG_INHERIT, 0);
+
+ if (!CreatePipe (&hChildStdinRead, &((HANDLE) hChildStdinWrite), &securityAttrib, 0))
+ {
+ PkgError (L"Cannot create STDIN pipe.");
+ CloseHandle(hChildStdoutWrite);
+ CloseHandle(hChildStdoutRead);
+ return 0;
+ }
+ SetHandleInformation (hChildStdinWrite, HANDLE_FLAG_INHERIT, 0);
+
+ // Create a child process that will compress the data
+
+ startupInfo.wShowWindow = SW_HIDE;
+ startupInfo.hStdInput = hChildStdinRead;
+ startupInfo.hStdOutput = hChildStdoutWrite;
+ startupInfo.cb = sizeof (startupInfo);
+ startupInfo.hStdError = hChildStdoutWrite;
+ startupInfo.dwFlags |= STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
+
+ StringCchCopyW (szGzipCmd, ARRAYSIZE (szGzipCmd), L"gzip --best");
+ if (!CreateProcess (NULL, szGzipCmd, NULL, NULL, TRUE, 0, NULL, NULL, &startupInfo, &procInfo))
+ {
+ PkgError (L"Error: Cannot run gzip.\n\nBefore you can create a self-extracting VeraCrypt package, you need to have the open-source 'gzip' compression tool placed in any directory in the search path for executable files (for example, in 'C:\\Windows\\').\n\nNote: gzip can be freely downloaded e.g. from www.gzip.org");
+ CloseHandle(hChildStdoutWrite);
+ CloseHandle(hChildStdoutRead);
+ CloseHandle(hChildStdinRead);
+ CloseHandle(hChildStdinWrite);
+ return 0;
+ }
+
+ CloseHandle (procInfo.hProcess);
+ CloseHandle (procInfo.hThread);
+
+ // Start sending the uncompressed data to the pipe (STDIN)
+ PipeWriteBuf = in;
+ _beginthread (PipeWriteThread, PIPE_BUFFER_LEN * 2, (void *) &len);
+
+ if (!CloseHandle (hChildStdoutWrite))
+ {
+ PkgError (L"Cannot close STDOUT write");
+ CloseHandle(hChildStdoutRead);
+ CloseHandle(hChildStdinRead);
+ return 0;
+ }
+
+ bGzipHeaderRead = FALSE;
+
+ // Read the compressed data from the pipe (sent by the child process to STDOUT)
+ while (TRUE)
+ {
+ if (!ReadFile (hChildStdoutRead, pipeBuffer, bGzipHeaderRead ? PIPE_BUFFER_LEN : 10, &bytesReceived, NULL))
+ break;
+
+ if (bGzipHeaderRead)
+ {
+ memcpy (out + res_len, pipeBuffer, bytesReceived);
+ res_len += bytesReceived;
+ }
+ else
+ bGzipHeaderRead = TRUE; // Skip the 10-byte gzip header
+ }
+
+ CloseHandle(hChildStdoutRead);
+ CloseHandle(hChildStdinRead);
+ return res_len - 8; // A gzip stream ends with a CRC-32 hash and a 32-bit size (those 8 bytes need to be chopped off)
+}
+
+
+// Clears all bytes that change when an exe file is digitally signed, except the data that are appended.
+// If those bytes weren't cleared, CRC-32 checks would fail after signing.
+static void WipeSignatureAreas (char *buffer)
+{
+ // Clear bytes 0x130-0x1ff
+ memset (buffer + 0x130, 0, 0x200 - 0x130);
+}
+
+
+BOOL MakeSelfExtractingPackage (HWND hwndDlg, wchar_t *szDestDir)
+{
+ int i, x;
+ wchar_t inputFile [TC_MAX_PATH];
+ wchar_t outputFile [TC_MAX_PATH];
+ wchar_t szTmpFilePath [TC_MAX_PATH];
+ unsigned char szTmp32bit [4] = {0};
+ unsigned char *szTmp32bitPtr = szTmp32bit;
+ unsigned char *buffer = NULL, *compressedBuffer = NULL;
+ unsigned char *bufIndex = NULL;
+ wchar_t tmpStr [2048];
+ int bufLen = 0, compressedDataLen = 0, uncompressedDataLen = 0;
+
+ x = wcslen (szDestDir);
+ if (x < 2)
+ goto err;
+
+ if (szDestDir[x - 1] != L'\\')
+ StringCbCatW (szDestDir, MAX_PATH, L"\\");
+
+ GetModuleFileName (NULL, inputFile, ARRAYSIZE (inputFile));
+
+ StringCchCopyW (outputFile, ARRAYSIZE(outputFile), szDestDir);
+ StringCchCatW (outputFile, ARRAYSIZE(outputFile), OutputPackageFile);
+
+ // Clone 'VeraCrypt Setup.exe' to create the base of the new self-extracting archive
+
+ if (!TCCopyFile (inputFile, outputFile))
+ {
+ handleWin32Error (hwndDlg, SRC_POS);
+ PkgError (L"Cannot copy 'VeraCrypt Setup.exe' to the package");
+ goto err;
+ }
+
+ // Determine the buffer size needed for all the files and meta data and check if all required files exist
+
+ bufLen = 0;
+
+ for (i = 0; i < sizeof (szCompressedFiles) / sizeof (szCompressedFiles[0]); i++)
+ {
+ StringCbPrintfW (szTmpFilePath, sizeof(szTmpFilePath), L"%s%s", szDestDir, szCompressedFiles[i]);
+
+ if (!FileExists (szTmpFilePath))
+ {
+ wchar_t tmpstr [1000];
+
+ StringCbPrintfW (tmpstr, sizeof(tmpstr), L"File not found:\n\n'%s'", szTmpFilePath);
+ if (_wremove (outputFile))
+ StringCbCatW (tmpstr, sizeof(tmpstr), L"\nFailed also to delete package file");
+ PkgError (tmpstr);
+ goto err;
+ }
+
+ bufLen += (int) GetFileSize64 (szTmpFilePath);
+
+ bufLen += 2; // 16-bit filename length
+ bufLen += (wcslen(szCompressedFiles[i]) * sizeof (wchar_t)); // Filename
+ bufLen += 4; // CRC-32
+ bufLen += 4; // 32-bit file length
+ }
+
+ buffer = malloc (bufLen + 524288); // + 512K reserve
+ if (buffer == NULL)
+ {
+ PkgError (L"Cannot allocate memory for uncompressed data");
+ if (_wremove (outputFile))
+ PkgError (L"Cannot allocate memory for uncompressed data.\nFailed also to delete package file");
+ else
+ PkgError (L"Cannot allocate memory for uncompressed data");
+ goto err;
+ }
+
+
+ // Write the start marker
+ if (!SaveBufferToFile (MAG_START_MARKER, outputFile, strlen (MAG_START_MARKER), TRUE, FALSE))
+ {
+ if (_wremove (outputFile))
+ PkgError (L"Cannot write the start marker\nFailed also to delete package file");
+ else
+ PkgError (L"Cannot write the start marker");
+ goto err;
+ }
+
+
+ bufIndex = buffer;
+
+ // Copy all required files and their meta data to the buffer
+ for (i = 0; i < sizeof (szCompressedFiles) / sizeof (szCompressedFiles[0]); i++)
+ {
+ DWORD tmpFileSize;
+ unsigned char *tmpBuffer;
+
+ StringCbPrintfW (szTmpFilePath, sizeof(szTmpFilePath), L"%s%s", szDestDir, szCompressedFiles[i]);
+
+ tmpBuffer = LoadFile (szTmpFilePath, &tmpFileSize);
+
+ if (tmpBuffer == NULL)
+ {
+ wchar_t tmpstr [1000];
+
+ StringCbPrintfW (tmpstr, sizeof(tmpstr), L"Cannot load file \n'%s'", szTmpFilePath);
+ if (_wremove (outputFile))
+ StringCbCatW (tmpstr, sizeof(tmpstr), L"\nFailed also to delete package file");
+ PkgError (tmpstr);
+ goto err;
+ }
+
+ // Copy the filename length to the main buffer
+ mputWord (bufIndex, (WORD) wcslen(szCompressedFiles[i]));
+
+ // Copy the filename to the main buffer
+ wmemcpy ((wchar_t*)bufIndex, szCompressedFiles[i], wcslen(szCompressedFiles[i]));
+ bufIndex += (wcslen(szCompressedFiles[i]) * sizeof (wchar_t));
+
+ // Compute CRC-32 hash of the uncompressed file and copy it to the main buffer
+ mputLong (bufIndex, GetCrc32 (tmpBuffer, tmpFileSize));
+
+ // Copy the file length to the main buffer
+ mputLong (bufIndex, (unsigned __int32) tmpFileSize);
+
+ // Copy the file contents to the main buffer
+ memcpy (bufIndex, tmpBuffer, tmpFileSize);
+ bufIndex += tmpFileSize;
+
+ free (tmpBuffer);
+ }
+
+ // Calculate the total size of the uncompressed data
+ uncompressedDataLen = (int) (bufIndex - buffer);
+
+ // Write total size of the uncompressed data
+ szTmp32bitPtr = szTmp32bit;
+ mputLong (szTmp32bitPtr, (unsigned __int32) uncompressedDataLen);
+ if (!SaveBufferToFile (szTmp32bit, outputFile, sizeof (szTmp32bit), TRUE, FALSE))
+ {
+ if (_wremove (outputFile))
+ PkgError (L"Cannot write the total size of the uncompressed data.\nFailed also to delete package file");
+ else
+ PkgError (L"Cannot write the total size of the uncompressed data");
+ goto err;
+ }
+
+ // Compress all the files and meta data in the buffer to create a solid archive
+
+ // Test to make Coverity happy. It will always be false
+ if (uncompressedDataLen >= (INT_MAX - 524288))
+ {
+ if (_wremove (outputFile))
+ PkgError (L"Cannot allocate memory for compressed data.\nFailed also to delete package file");
+ else
+ PkgError (L"Cannot allocate memory for compressed data");
+ goto err;
+ }
+
+ compressedBuffer = malloc (uncompressedDataLen + 524288); // + 512K reserve
+ if (compressedBuffer == NULL)
+ {
+ if (_wremove (outputFile))
+ PkgError (L"Cannot allocate memory for compressed data.\nFailed also to delete package file");
+ else
+ PkgError (L"Cannot allocate memory for compressed data");
+ goto err;
+ }
+
+ compressedDataLen = CompressBuffer (compressedBuffer, buffer, uncompressedDataLen);
+ if (compressedDataLen <= 0)
+ {
+ if (_wremove (outputFile))
+ PkgError (L"Failed to compress the data.\nFailed also to delete package file");
+ else
+ PkgError (L"Failed to compress the data");
+ goto err;
+ }
+
+ free (buffer);
+ buffer = NULL;
+
+ // Write the total size of the compressed data
+ szTmp32bitPtr = szTmp32bit;
+ mputLong (szTmp32bitPtr, (unsigned __int32) compressedDataLen);
+ if (!SaveBufferToFile (szTmp32bit, outputFile, sizeof (szTmp32bit), TRUE, FALSE))
+ {
+ if (_wremove (outputFile))
+ PkgError (L"Cannot write the total size of the compressed data.\nFailed also to delete package file");
+ else
+ PkgError (L"Cannot write the total size of the compressed data");
+ goto err;
+ }
+
+ // Write the compressed data
+ if (!SaveBufferToFile (compressedBuffer, outputFile, compressedDataLen, TRUE, FALSE))
+ {
+ if (_wremove (outputFile))
+ PkgError (L"Cannot write compressed data to the package.\nFailed also to delete package file");
+ else
+ PkgError (L"Cannot write compressed data to the package");
+ goto err;
+ }
+
+ // Write the end marker
+ if (!SaveBufferToFile (MagEndMarker, outputFile, strlen (MagEndMarker), TRUE, FALSE))
+ {
+ if (_wremove (outputFile))
+ PkgError (L"Cannot write the end marker.\nFailed also to delete package file");
+ else
+ PkgError (L"Cannot write the end marker");
+ goto err;
+ }
+
+ free (compressedBuffer);
+ compressedBuffer = NULL;
+
+ // Compute and write CRC-32 hash of the entire package
+ {
+ DWORD tmpFileSize;
+ char *tmpBuffer;
+
+ tmpBuffer = LoadFile (outputFile, &tmpFileSize);
+
+ if (tmpBuffer == NULL)
+ {
+ handleWin32Error (hwndDlg, SRC_POS);
+ if (_wremove (outputFile))
+ PkgError (L"Cannot load the package to compute CRC.\nFailed also to delete package file");
+ else
+ PkgError (L"Cannot load the package to compute CRC");
+ goto err;
+ }
+
+ // Zero all bytes that change when the exe is digitally signed (except appended blocks).
+ WipeSignatureAreas (tmpBuffer);
+
+ szTmp32bitPtr = szTmp32bit;
+ mputLong (szTmp32bitPtr, GetCrc32 (tmpBuffer, tmpFileSize));
+ free (tmpBuffer);
+
+ if (!SaveBufferToFile (szTmp32bit, outputFile, sizeof (szTmp32bit), TRUE, FALSE))
+ {
+ if (_wremove (outputFile))
+ PkgError (L"Cannot write the total size of the compressed data.\nFailed also to delete package file");
+ else
+ PkgError (L"Cannot write the total size of the compressed data");
+ goto err;
+ }
+ }
+
+ StringCbPrintfW (tmpStr, sizeof(tmpStr), L"Self-extracting package successfully created (%s)", outputFile);
+ PkgInfo (tmpStr);
+ return TRUE;
+
+err:
+ if (buffer)
+ free (buffer);
+ if (compressedBuffer)
+ free (compressedBuffer);
+
+ return FALSE;
+}
+
+
+// Verifies the CRC-32 of the whole self-extracting package (except the digital signature areas, if present)
+BOOL VerifyPackageIntegrity (void)
+{
+ int fileDataEndPos = 0;
+ int fileDataStartPos = 0;
+ unsigned __int32 crc = 0;
+ unsigned char *tmpBuffer;
+ int tmpFileSize;
+ wchar_t path [TC_MAX_PATH];
+
+ GetModuleFileName (NULL, path, ARRAYSIZE (path));
+
+ fileDataEndPos = (int) FindStringInFile (path, MagEndMarker, strlen (MagEndMarker));
+ if (fileDataEndPos < 0)
+ {
+ Error ("DIST_PACKAGE_CORRUPTED", NULL);
+ return FALSE;
+ }
+ fileDataEndPos--;
+
+ fileDataStartPos = (int) FindStringInFile (path, MAG_START_MARKER, strlen (MAG_START_MARKER));
+ if (fileDataStartPos < 0)
+ {
+ Error ("DIST_PACKAGE_CORRUPTED", NULL);
+ return FALSE;
+ }
+ fileDataStartPos += strlen (MAG_START_MARKER);
+
+
+ if (!LoadInt32 (path, &crc, fileDataEndPos + strlen (MagEndMarker) + 1))
+ {
+ Error ("CANT_VERIFY_PACKAGE_INTEGRITY", NULL);
+ return FALSE;
+ }
+
+ // Compute the CRC-32 hash of the whole file (except the digital signature area, if present)
+ tmpBuffer = LoadFile (path, &tmpFileSize);
+
+ if (tmpBuffer == NULL)
+ {
+ Error ("CANT_VERIFY_PACKAGE_INTEGRITY", NULL);
+ return FALSE;
+ }
+
+ // Zero all bytes that change when an exe is digitally signed (except appended blocks).
+ WipeSignatureAreas (tmpBuffer);
+
+ if (crc != GetCrc32 (tmpBuffer, fileDataEndPos + 1 + strlen (MagEndMarker)))
+ {
+ free (tmpBuffer);
+ Error ("DIST_PACKAGE_CORRUPTED", NULL);
+ return FALSE;
+ }
+
+ free (tmpBuffer);
+
+ return TRUE;
+}
+
+
+// Determines whether we are a self-extracting package
+BOOL IsSelfExtractingPackage (void)
+{
+ wchar_t path [TC_MAX_PATH];
+
+ GetModuleFileName (NULL, path, ARRAYSIZE (path));
+
+ return (FindStringInFile (path, MagEndMarker, strlen (MagEndMarker)) != -1);
+}
+
+
+static void FreeAllFileBuffers (void)
+{
+ int fileNo;
+
+ if (DecompressedData != NULL)
+ {
+ free (DecompressedData);
+ DecompressedData = NULL;
+ }
+
+ for (fileNo = 0; fileNo < NBR_COMPRESSED_FILES; fileNo++)
+ {
+ Decompressed_Files[fileNo].fileName = NULL;
+ Decompressed_Files[fileNo].fileContent = NULL;
+ Decompressed_Files[fileNo].fileNameLength = 0;
+ Decompressed_Files[fileNo].fileLength = 0;
+ Decompressed_Files[fileNo].crc = 0;
+ }
+}
+
+
+// Assumes that VerifyPackageIntegrity() has been used. Returns TRUE, if successful (otherwise FALSE).
+// Creates a table of pointers to buffers containing the following objects for each file:
+// filename size, filename (not null-terminated!), file size, file CRC-32, uncompressed file contents.
+// For details, see the definition of the DECOMPRESSED_FILE structure.
+BOOL SelfExtractInMemory (wchar_t *path)
+{
+ int filePos = 0, fileNo = 0;
+ int fileDataEndPos = 0;
+ int fileDataStartPos = 0;
+ int uncompressedLen = 0;
+ int compressedLen = 0;
+ unsigned char *compressedData = NULL;
+ unsigned char *bufPos = NULL, *bufEndPos = NULL;
+
+ FreeAllFileBuffers();
+
+ fileDataEndPos = (int) FindStringInFile (path, MagEndMarker, strlen (MagEndMarker));
+ if (fileDataEndPos < 0)
+ {
+ Error ("CANNOT_READ_FROM_PACKAGE", NULL);
+ return FALSE;
+ }
+
+ fileDataEndPos--;
+
+ fileDataStartPos = (int) FindStringInFile (path, MAG_START_MARKER, strlen (MAG_START_MARKER));
+ if (fileDataStartPos < 0)
+ {
+ Error ("CANNOT_READ_FROM_PACKAGE", NULL);
+ return FALSE;
+ }
+
+ fileDataStartPos += strlen (MAG_START_MARKER);
+
+ filePos = fileDataStartPos;
+
+ // Read the stored total size of the uncompressed data
+ if (!LoadInt32 (path, &uncompressedLen, filePos))
+ {
+ Error ("CANNOT_READ_FROM_PACKAGE", NULL);
+ return FALSE;
+ }
+
+ filePos += 4;
+
+ // Read the stored total size of the compressed data
+ if (!LoadInt32 (path, &compressedLen, filePos))
+ {
+ Error ("CANNOT_READ_FROM_PACKAGE", NULL);
+ return FALSE;
+ }
+
+ filePos += 4;
+
+ if (compressedLen != fileDataEndPos - fileDataStartPos - 8 + 1)
+ {
+ Error ("DIST_PACKAGE_CORRUPTED", NULL);
+ }
+
+ DecompressedData = malloc (uncompressedLen + 524288); // + 512K reserve
+ if (DecompressedData == NULL)
+ {
+ Error ("ERR_MEM_ALLOC", NULL);
+ return FALSE;
+ }
+
+ bufPos = DecompressedData;
+ bufEndPos = bufPos + uncompressedLen - 1;
+
+ compressedData = LoadFileBlock (path, filePos, compressedLen);
+
+ if (compressedData == NULL)
+ {
+ free (DecompressedData);
+ DecompressedData = NULL;
+
+ Error ("CANNOT_READ_FROM_PACKAGE", NULL);
+ return FALSE;
+ }
+
+ // Decompress the data
+ if (DecompressBuffer (DecompressedData, compressedData, compressedLen) != uncompressedLen)
+ {
+ Error ("DIST_PACKAGE_CORRUPTED", NULL);
+ goto sem_end;
+ }
+
+ while (bufPos <= bufEndPos && fileNo < NBR_COMPRESSED_FILES)
+ {
+ // Filename length
+ Decompressed_Files[fileNo].fileNameLength = mgetWord (bufPos);
+
+ // Filename
+ Decompressed_Files[fileNo].fileName = (wchar_t*) bufPos;
+ bufPos += (Decompressed_Files[fileNo].fileNameLength * sizeof (wchar_t));
+
+ // CRC-32 of the file
+ Decompressed_Files[fileNo].crc = mgetLong (bufPos);
+
+ // File length
+ Decompressed_Files[fileNo].fileLength = mgetLong (bufPos);
+
+ // File content
+ Decompressed_Files[fileNo].fileContent = bufPos;
+ bufPos += Decompressed_Files[fileNo].fileLength;
+
+ // Verify CRC-32 of the file (to verify that it didn't get corrupted while creating the solid archive).
+ if (Decompressed_Files[fileNo].crc
+ != GetCrc32 (Decompressed_Files[fileNo].fileContent, Decompressed_Files[fileNo].fileLength))
+ {
+ Error ("DIST_PACKAGE_CORRUPTED", NULL);
+ goto sem_end;
+ }
+
+ fileNo++;
+ }
+
+ if (fileNo < NBR_COMPRESSED_FILES)
+ {
+ Error ("DIST_PACKAGE_CORRUPTED", NULL);
+ goto sem_end;
+ }
+
+ free (compressedData);
+ return TRUE;
+
+sem_end:
+ FreeAllFileBuffers();
+ free (compressedData);
+ return FALSE;
+}
+
+
+void __cdecl ExtractAllFilesThread (void *hwndDlg)
+{
+ int fileNo;
+ BOOL bSuccess = FALSE;
+ wchar_t packageFile [TC_MAX_PATH];
+
+ InvalidateRect (GetDlgItem (GetParent (hwndDlg), IDD_INSTL_DLG), NULL, TRUE);
+
+ ClearLogWindow (hwndDlg);
+
+ GetModuleFileName (NULL, packageFile, ARRAYSIZE (packageFile));
+
+ if (!(bSuccess = SelfExtractInMemory (packageFile)))
+ goto eaf_end;
+
+ if (mkfulldir (DestExtractPath, TRUE) != 0)
+ {
+ if (mkfulldir (DestExtractPath, FALSE) != 0)
+ {
+ wchar_t szTmp[TC_MAX_PATH];
+
+ handleWin32Error (hwndDlg, SRC_POS);
+ StringCbPrintfW (szTmp, sizeof(szTmp), GetString ("CANT_CREATE_FOLDER"), DestExtractPath);
+ MessageBoxW (hwndDlg, szTmp, lpszTitle, MB_ICONHAND);
+ bSuccess = FALSE;
+ goto eaf_end;
+ }
+ }
+
+ for (fileNo = 0; fileNo < NBR_COMPRESSED_FILES; fileNo++)
+ {
+ wchar_t fileName [TC_MAX_PATH] = {0};
+ wchar_t filePath [TC_MAX_PATH] = {0};
+
+ // Filename
+ StringCchCopyNW (fileName, ARRAYSIZE(fileName), Decompressed_Files[fileNo].fileName, Decompressed_Files[fileNo].fileNameLength);
+ StringCchCopyW (filePath, ARRAYSIZE(filePath), DestExtractPath);
+ StringCchCatW (filePath, ARRAYSIZE(filePath), fileName);
+
+ StatusMessageParam (hwndDlg, "EXTRACTING_VERB", filePath);
+
+ // Write the file
+ if (!SaveBufferToFile (
+ Decompressed_Files[fileNo].fileContent,
+ filePath,
+ Decompressed_Files[fileNo].fileLength,
+ FALSE, FALSE))
+ {
+ wchar_t szTmp[512];
+
+ StringCbPrintfW (szTmp, sizeof (szTmp), GetString ("CANNOT_WRITE_FILE_X"), filePath);
+ MessageBoxW (hwndDlg, szTmp, lpszTitle, MB_ICONERROR | MB_SETFOREGROUND | MB_TOPMOST);
+ bSuccess = FALSE;
+ goto eaf_end;
+ }
+ UpdateProgressBarProc ((int) (100 * ((float) fileNo / NBR_COMPRESSED_FILES)));
+ }
+
+eaf_end:
+ FreeAllFileBuffers();
+
+ if (bSuccess)
+ PostMessage (MainDlg, TC_APPMSG_EXTRACTION_SUCCESS, 0, 0);
+ else
+ PostMessage (MainDlg, TC_APPMSG_EXTRACTION_FAILURE, 0, 0);
+}
+