#include <stdio.h>
#include <conio.h>
#include <Windows.h>
BOOL
ReadFileAlign(
HANDLE
hFile,
LPVOID
lpBuffer,
DWORD
nNumberOfBytesToRead,
LPDWORD
lpNumberOfBytesRead)
{
DWORD
dwRead = 0;
DWORD
nAlignedSize = (nNumberOfBytesToRead / 512 + (nNumberOfBytesToRead % 512 ? 1 : 0)) * 512;
PUCHAR
buffer = (
PUCHAR
)
malloc
(nAlignedSize);
if
(!ReadFile(hFile, buffer, nAlignedSize, &dwRead, NULL))
{
*lpNumberOfBytesRead = 0;
return
FALSE;
}
memcpy
(lpBuffer, buffer, nNumberOfBytesToRead);
*lpNumberOfBytesRead = nNumberOfBytesToRead;
free
(buffer);
return
TRUE;
}
BOOL
IsEmptySector(
LPVOID
Buffer)
{
for
(
UINT
i = 0; i < 512; i++)
{
if
(*((
PUCHAR
)Buffer + i))
{
return
FALSE;
}
}
return
TRUE;
}
#pragma pack(push, 1)
typedef
struct
_MFT_SEGMENT_REFERENCE {
ULONG
SegmentNumberLowPart;
USHORT
SegmentNumberHighPart;
USHORT
SequenceNumber;
} MFT_SEGMENT_REFERENCE, *PMFT_SEGMENT_REFERENCE;
typedef
MFT_SEGMENT_REFERENCE FILE_REFERENCE, *PFILE_REFERENCE;
typedef
struct
_MULTI_SECTOR_HEADER {
UCHAR
Signature[4];
USHORT
UpdateSequenceArrayOffset;
USHORT
UpdateSequenceArraySize;
} MULTI_SECTOR_HEADER, *PMULTI_SECTOR_HEADER;
typedef
struct
_FILE_RECORD_SEGMENT_HEADER {
MULTI_SECTOR_HEADER MultiSectorHeader;
ULONGLONG
Reserved1;
USHORT
SequenceNumber;
USHORT
Reserved2;
USHORT
FirstAttributeOffset;
USHORT
Flags;
ULONG
Reserved3[2];
FILE_REFERENCE BaseFileRecordSegment;
USHORT
Reserved4;
} FILE_RECORD_SEGMENT_HEADER, *PFILE_RECORD_SEGMENT_HEADER;
typedef
enum
_ATTRIBUTE_TYPE_CODE {
ATTR_STANDARD_INFORMATION = 0x10,
ATTR_ATTRIBUTE_LIST = 0x20,
ATTR_FILE_NAME = 0x30,
ATTR_OBJECT_ID = 0x40,
ATTR_VOLUME_NAME = 0x60,
ATTR_VOLUME_INFORMATION = 0x70,
ATTR_DATA = 0x80,
ATTR_INDEX_ROOT = 0x90,
ATTR_INDEX_ALLOCATION = 0xA0,
ATTR_BITMAP = 0xB0,
ATTR_REPARSE_POINT = 0xC0,
ATTR_END = 0xFFFFFFFF
} ATTRIBUTE_TYPE_CODE;
#define RESIDENT_FORM 0x00
#define NONRESIDENT_FORM 0x01
typedef
ULONGLONG
VCN;
#define FILE_NAME_INDEX_PRESENT 0x10000000
typedef
struct
_ATTRIBUTE_RECORD_HEADER {
ATTRIBUTE_TYPE_CODE TypeCode;
ULONG
RecordLength;
UCHAR
FormCode;
UCHAR
NameLength;
USHORT
NameOffset;
USHORT
Flags;
USHORT
Instance;
union
{
struct
{
ULONG
ValueLength;
USHORT
ValueOffset;
UCHAR
Reserved[2];
} Resident;
struct
{
VCN LowestVcn;
VCN HighestVcn;
USHORT
MappingPairsOffset;
UCHAR
Reserved[6];
LONGLONG
AllocatedLength;
LONGLONG
FileSize;
LONGLONG
ValidDataLength;
LONGLONG
TotalAllocated;
} Nonresident;
} Form;
} ATTRIBUTE_RECORD_HEADER, *PATTRIBUTE_RECORD_HEADER;
typedef
struct
_FILE_NAME_ATTRIBUTE {
FILE_REFERENCE ParentDirectory;
UCHAR
Reserved[0x30];
ULONG
FileAttributes;
ULONG
AlignmentOrReserved;
UCHAR
FileNameLength;
UCHAR
Flags;
WCHAR
FileName[1];
} FILE_NAME_ATTRIBUTE, *PFILE_NAME_ATTRIBUTE;
typedef
struct
_BIOS_PARAMETER_BLOCK
{
UINT16 BytesPerSector;
UCHAR
SectorsPerCluster;
UINT16 ReservedSectors;
UCHAR
Fats;
UINT16 RootEntries;
UINT16 Sectors;
UCHAR
Media;
UINT16 SectorsPerFat;
UINT16 SectorsPerTrack;
UINT16 Heads;
UINT32
HiddenSectors;
UINT32
LargeSectors;
} BIOS_PARAMETER_BLOCK, *PBIOS_PARAMETER_BLOCK;
typedef
struct
_NTFS_BOOT_SECTOR
{
UCHAR
JmpCode[3];
char
OemID[8];
BIOS_PARAMETER_BLOCK PackedBpb;
UCHAR
Unused[4];
UINT64
NumberSectors;
UINT64
MftStartLcn;
UINT64
Mft2StartLcn;
UCHAR
ClustersPerFileRecordSegment;
UCHAR
Reserved0[3];
UCHAR
DefaultClustersPerIndexAllocationBuffer;
UCHAR
Reserved1[3];
UINT64
SerialNumber;
UINT32
Checksum;
UCHAR
BootStrap[426];
UINT16 RecordEndSign;
} NTFS_BOOT_SECTOR, *PNTFS_BOOT_SECTOR;
#pragma pack(pop)
unsigned
char
BootmgrCode[426] = {
0xFA, 0x33, 0xC0, 0x8E, 0xD0, 0xBC, 0x00, 0x7C, 0xFB, 0x68, 0xC0, 0x07, 0x1F, 0x1E, 0x68, 0x66,
0x00, 0xCB, 0x88, 0x16, 0x0E, 0x00, 0x66, 0x81, 0x3E, 0x03, 0x00, 0x4E, 0x54, 0x46, 0x53, 0x75,
0x15, 0xB4, 0x41, 0xBB, 0xAA, 0x55, 0xCD, 0x13, 0x72, 0x0C, 0x81, 0xFB, 0x55, 0xAA, 0x75, 0x06,
0xF7, 0xC1, 0x01, 0x00, 0x75, 0x03, 0xE9, 0xDD, 0x00, 0x1E, 0x83, 0xEC, 0x18, 0x68, 0x1A, 0x00,
0xB4, 0x48, 0x8A, 0x16, 0x0E, 0x00, 0x8B, 0xF4, 0x16, 0x1F, 0xCD, 0x13, 0x9F, 0x83, 0xC4, 0x18,
0x9E, 0x58, 0x1F, 0x72, 0xE1, 0x3B, 0x06, 0x0B, 0x00, 0x75, 0xDB, 0xA3, 0x0F, 0x00, 0xC1, 0x2E,
0x0F, 0x00, 0x04, 0x1E, 0x5A, 0x33, 0xDB, 0xB9, 0x00, 0x20, 0x2B, 0xC8, 0x66, 0xFF, 0x06, 0x11,
0x00, 0x03, 0x16, 0x0F, 0x00, 0x8E, 0xC2, 0xFF, 0x06, 0x16, 0x00, 0xE8, 0x4B, 0x00, 0x2B, 0xC8,
0x77, 0xEF, 0xB8, 0x00, 0xBB, 0xCD, 0x1A, 0x66, 0x23, 0xC0, 0x75, 0x2D, 0x66, 0x81, 0xFB, 0x54,
0x43, 0x50, 0x41, 0x75, 0x24, 0x81, 0xF9, 0x02, 0x01, 0x72, 0x1E, 0x16, 0x68, 0x07, 0xBB, 0x16,
0x68, 0x52, 0x11, 0x16, 0x68, 0x09, 0x00, 0x66, 0x53, 0x66, 0x53, 0x66, 0x55, 0x16, 0x16, 0x16,
0x68, 0xB8, 0x01, 0x66, 0x61, 0x0E, 0x07, 0xCD, 0x1A, 0x33, 0xC0, 0xBF, 0x0A, 0x13, 0xB9, 0xF6,
0x0C, 0xFC, 0xF3, 0xAA, 0xE9, 0xFE, 0x01, 0x90, 0x90, 0x66, 0x60, 0x1E, 0x06, 0x66, 0xA1, 0x11,
0x00, 0x66, 0x03, 0x06, 0x1C, 0x00, 0x1E, 0x66, 0x68, 0x00, 0x00, 0x00, 0x00, 0x66, 0x50, 0x06,
0x53, 0x68, 0x01, 0x00, 0x68, 0x10, 0x00, 0xB4, 0x42, 0x8A, 0x16, 0x0E, 0x00, 0x16, 0x1F, 0x8B,
0xF4, 0xCD, 0x13, 0x66, 0x59, 0x5B, 0x5A, 0x66, 0x59, 0x66, 0x59, 0x1F, 0x0F, 0x82, 0x16, 0x00,
0x66, 0xFF, 0x06, 0x11, 0x00, 0x03, 0x16, 0x0F, 0x00, 0x8E, 0xC2, 0xFF, 0x0E, 0x16, 0x00, 0x75,
0xBC, 0x07, 0x1F, 0x66, 0x61, 0xC3, 0xA1, 0xF6, 0x01, 0xE8, 0x09, 0x00, 0xA1, 0xFA, 0x01, 0xE8,
0x03, 0x00, 0xF4, 0xEB, 0xFD, 0x8B, 0xF0, 0xAC, 0x3C, 0x00, 0x74, 0x09, 0xB4, 0x0E, 0xBB, 0x07,
0x00, 0xCD, 0x10, 0xEB, 0xF2, 0xC3, 0x0D, 0x0A, 0x41, 0x20, 0x64, 0x69, 0x73, 0x6B, 0x20, 0x72,
0x65, 0x61, 0x64, 0x20, 0x65, 0x72, 0x72, 0x6F, 0x72, 0x20, 0x6F, 0x63, 0x63, 0x75, 0x72, 0x72,
0x65, 0x64, 0x00, 0x0D, 0x0A, 0x42, 0x4F, 0x4F, 0x54, 0x4D, 0x47, 0x52, 0x20, 0x69, 0x73, 0x20,
0x63, 0x6F, 0x6D, 0x70, 0x72, 0x65, 0x73, 0x73, 0x65, 0x64, 0x00, 0x0D, 0x0A, 0x50, 0x72, 0x65,
0x73, 0x73, 0x20, 0x43, 0x74, 0x72, 0x6C, 0x2B, 0x41, 0x6C, 0x74, 0x2B, 0x44, 0x65, 0x6C, 0x20,
0x74, 0x6F, 0x20, 0x72, 0x65, 0x73, 0x74, 0x61, 0x72, 0x74, 0x0D, 0x0A, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x8A, 0x01, 0xA7, 0x01, 0xBF, 0x01, 0x00, 0x00
};
unsigned
char
NtldrCode[426] = {
0xFA, 0x33, 0xC0, 0x8E, 0xD0, 0xBC, 0x00, 0x7C, 0xFB, 0xB8, 0xC0, 0x07, 0x8E, 0xD8, 0xE8, 0x16,
0x00, 0xB8, 0x00, 0x0D, 0x8E, 0xC0, 0x33, 0xDB, 0xC6, 0x06, 0x0E, 0x00, 0x10, 0xE8, 0x53, 0x00,
0x68, 0x00, 0x0D, 0x68, 0x6A, 0x02, 0xCB, 0x8A, 0x16, 0x24, 0x00, 0xB4, 0x08, 0xCD, 0x13, 0x73,
0x05, 0xB9, 0xFF, 0xFF, 0x8A, 0xF1, 0x66, 0x0F, 0xB6, 0xC6, 0x40, 0x66, 0x0F, 0xB6, 0xD1, 0x80,
0xE2, 0x3F, 0xF7, 0xE2, 0x86, 0xCD, 0xC0, 0xED, 0x06, 0x41, 0x66, 0x0F, 0xB7, 0xC9, 0x66, 0xF7,
0xE1, 0x66, 0xA3, 0x20, 0x00, 0xC3, 0xB4, 0x41, 0xBB, 0xAA, 0x55, 0x8A, 0x16, 0x24, 0x00, 0xCD,
0x13, 0x72, 0x0F, 0x81, 0xFB, 0x55, 0xAA, 0x75, 0x09, 0xF6, 0xC1, 0x01, 0x74, 0x04, 0xFE, 0x06,
0x14, 0x00, 0xC3, 0x66, 0x60, 0x1E, 0x06, 0x66, 0xA1, 0x10, 0x00, 0x66, 0x03, 0x06, 0x1C, 0x00,
0x66, 0x3B, 0x06, 0x20, 0x00, 0x0F, 0x82, 0x3A, 0x00, 0x1E, 0x66, 0x6A, 0x00, 0x66, 0x50, 0x06,
0x53, 0x66, 0x68, 0x10, 0x00, 0x01, 0x00, 0x80, 0x3E, 0x14, 0x00, 0x00, 0x0F, 0x85, 0x0C, 0x00,
0xE8, 0xB3, 0xFF, 0x80, 0x3E, 0x14, 0x00, 0x00, 0x0F, 0x84, 0x61, 0x00, 0xB4, 0x42, 0x8A, 0x16,
0x24, 0x00, 0x16, 0x1F, 0x8B, 0xF4, 0xCD, 0x13, 0x66, 0x58, 0x5B, 0x07, 0x66, 0x58, 0x66, 0x58,
0x1F, 0xEB, 0x2D, 0x66, 0x33, 0xD2, 0x66, 0x0F, 0xB7, 0x0E, 0x18, 0x00, 0x66, 0xF7, 0xF1, 0xFE,
0xC2, 0x8A, 0xCA, 0x66, 0x8B, 0xD0, 0x66, 0xC1, 0xEA, 0x10, 0xF7, 0x36, 0x1A, 0x00, 0x86, 0xD6,
0x8A, 0x16, 0x24, 0x00, 0x8A, 0xE8, 0xC0, 0xE4, 0x06, 0x0A, 0xCC, 0xB8, 0x01, 0x02, 0xCD, 0x13,
0x0F, 0x82, 0x19, 0x00, 0x8C, 0xC0, 0x05, 0x20, 0x00, 0x8E, 0xC0, 0x66, 0xFF, 0x06, 0x10, 0x00,
0xFF, 0x0E, 0x0E, 0x00, 0x0F, 0x85, 0x6F, 0xFF, 0x07, 0x1F, 0x66, 0x61, 0xC3, 0xA0, 0xF8, 0x01,
0xE8, 0x09, 0x00, 0xA0, 0xFB, 0x01, 0xE8, 0x03, 0x00, 0xFB, 0xEB, 0xFE, 0xB4, 0x01, 0x8B, 0xF0,
0xAC, 0x3C, 0x00, 0x74, 0x09, 0xB4, 0x0E, 0xBB, 0x07, 0x00, 0xCD, 0x10, 0xEB, 0xF2, 0xC3, 0x0D,
0x0A, 0x41, 0x20, 0x64, 0x69, 0x73, 0x6B, 0x20, 0x72, 0x65, 0x61, 0x64, 0x20, 0x65, 0x72, 0x72,
0x6F, 0x72, 0x20, 0x6F, 0x63, 0x63, 0x75, 0x72, 0x72, 0x65, 0x64, 0x00, 0x0D, 0x0A, 0x4E, 0x54,
0x4C, 0x44, 0x52, 0x20, 0x69, 0x73, 0x20, 0x6D, 0x69, 0x73, 0x73, 0x69, 0x6E, 0x67, 0x00, 0x0D,
0x0A, 0x4E, 0x54, 0x4C, 0x44, 0x52, 0x20, 0x69, 0x73, 0x20, 0x63, 0x6F, 0x6D, 0x70, 0x72, 0x65,
0x73, 0x73, 0x65, 0x64, 0x00, 0x0D, 0x0A, 0x50, 0x72, 0x65, 0x73, 0x73, 0x20, 0x43, 0x74, 0x72,
0x6C, 0x2B, 0x41, 0x6C, 0x74, 0x2B, 0x44, 0x65, 0x6C, 0x20, 0x74, 0x6F, 0x20, 0x72, 0x65, 0x73,
0x74, 0x61, 0x72, 0x74, 0x0D, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x83, 0xA0, 0xB3, 0xC9, 0x00, 0x00
};
BOOL
ReadSector(
HANDLE
hDisk,
ULONGLONG
Sector,
LPVOID
Buffer)
{
LARGE_INTEGER Offset = { 0 }, NewOffset = { 0 };
Offset.QuadPart = Sector * 512;
SetFilePointerEx(hDisk, Offset, &NewOffset, FILE_BEGIN);
DWORD
dwRead;
if
(!ReadFile(hDisk, Buffer, 512, &dwRead, NULL) || dwRead < 512)
{
fprintf
(stderr,
"Read sector error: %llu\n"
, Sector);
return
FALSE;
}
return
TRUE;
}
LONGLONG
ParseFileFirstCluster(
const
PUCHAR
FileRecord)
{
PFILE_RECORD_SEGMENT_HEADER pHeader = (PFILE_RECORD_SEGMENT_HEADER)FileRecord;
PATTRIBUTE_RECORD_HEADER pAttr = (PATTRIBUTE_RECORD_HEADER)((
PUCHAR
)pHeader + pHeader->FirstAttributeOffset);
while
(pAttr->TypeCode != ATTR_END)
{
ATTRIBUTE_TYPE_CODE typeCode = pAttr->TypeCode;
if
(pAttr->FormCode)
{
if
(typeCode == ATTR_DATA)
{
PUCHAR
dataRun = (
PUCHAR
)pAttr + pAttr->Form.Nonresident.MappingPairsOffset;
LONGLONG
LCN = 0;
ULONGLONG
VCN = 0;
while
(*dataRun)
{
UCHAR
lengthBytes = *dataRun & 0x0F;
UCHAR
offsetBytes = *dataRun >> 4;
dataRun++;
LONGLONG
length = 0;
memcpy
(&length, dataRun, lengthBytes);
dataRun += lengthBytes;
LONGLONG
lcnOffset = 0;
if
(offsetBytes)
{
if
(dataRun[offsetBytes - 1] & 0x80)
lcnOffset = -1;
memcpy
(&lcnOffset, dataRun, offsetBytes);
dataRun += offsetBytes;
}
LCN += lcnOffset;
return
lcnOffset == 0 ? 0 : LCN;
VCN += length;
}
}
}
pAttr = (PATTRIBUTE_RECORD_HEADER)((
PUCHAR
)pAttr + pAttr->RecordLength);
}
return
-1;
}
BOOL
ProcessVolume(
HANDLE
hDisk,
ULONGLONG
StartSector,
ULONGLONG
TotalSectors,
BOOL
IsBootmgr,
LPCWSTR
FileName)
{
printf
(
"Hidden sectors: %llu\n"
, StartSector - 1);
ULONGLONG
MftMirrStart = StartSector;
char
buf[1024];
for
(; MftMirrStart < TotalSectors; MftMirrStart++)
{
printf
(
"\rSearching $MFTMirr sector %llu/%llu..."
, MftMirrStart, TotalSectors);
if
(!ReadSector(hDisk, MftMirrStart, buf))
{
continue
;
}
unsigned
char
Magic[5] = { 0x46, 0x49, 0x4C, 0x45, 0x30 };
if
(!
memcmp
(buf, Magic, 5))
{
printf
(
"\nFound $MFTMirr start sector: %llu\n"
, MftMirrStart);
break
;
}
}
if
(MftMirrStart == TotalSectors)
{
printf
(
"\n$MFTMirr sector not found. This is not a vaild NTFS partition.\n"
);
return
FALSE;
}
if
(!ReadSector(hDisk, MftMirrStart + 2, buf) || !ReadSector(hDisk, MftMirrStart + 3, buf + 512))
{
printf
(
"Critical sector read failed, could not recovery this partition.\n"
);
return
FALSE;
}
ULONGLONG
MftMirrStartCluster = ParseFileFirstCluster((
PUCHAR
)buf);
if
(MftMirrStartCluster == -1)
{
printf
(
"Could not get $MFTMirr start cluster.\n"
);
return
FALSE;
}
printf
(
"$MFTMirr start cluster: %llu\n"
, MftMirrStartCluster);
DWORD
SectorsPerCluster = (MftMirrStart - StartSector + 1) / MftMirrStartCluster;
printf
(
"Sectors per cluster: %d\n"
, SectorsPerCluster);
if
(!ReadSector(hDisk, MftMirrStart, buf) || !ReadSector(hDisk, MftMirrStart + 1, buf + 512))
{
printf
(
"Critical sector read failed, could not recovery this partition.\n"
);
return
FALSE;
}
ULONGLONG
MftStartCluster = ParseFileFirstCluster((
PUCHAR
)buf);
if
(MftStartCluster == -1)
{
printf
(
"Could not get $MFT start cluster.\n"
);
return
FALSE;
}
printf
(
"$MFT start cluster: %llu\n"
, MftStartCluster);
NTFS_BOOT_SECTOR bootsect;
memcpy
(bootsect.JmpCode,
"\xEB\x52\x90"
, 3);
memcpy
(bootsect.OemID,
"NTFS "
, 8);
bootsect.PackedBpb.BytesPerSector = 512;
bootsect.PackedBpb.SectorsPerCluster = SectorsPerCluster;
bootsect.PackedBpb.ReservedSectors = 0;
bootsect.PackedBpb.Fats = 0;
bootsect.PackedBpb.RootEntries = 0;
bootsect.PackedBpb.Sectors = 0;
bootsect.PackedBpb.Media = 0xF8;
bootsect.PackedBpb.SectorsPerFat = 0;
bootsect.PackedBpb.SectorsPerTrack = 63;
bootsect.PackedBpb.Heads = 255;
bootsect.PackedBpb.HiddenSectors = StartSector - 1;
bootsect.PackedBpb.LargeSectors = 0;
memcpy
(bootsect.Unused,
"\x80\x00\x80\x00"
, 4);
bootsect.NumberSectors = TotalSectors - StartSector + 1;
bootsect.MftStartLcn = MftStartCluster;
bootsect.Mft2StartLcn = MftMirrStartCluster;
bootsect.ClustersPerFileRecordSegment = 0xF6;
memcpy
(bootsect.Reserved0,
"\x00\x00\x00"
, 3);
bootsect.DefaultClustersPerIndexAllocationBuffer = SectorsPerCluster > 8 ? 0xF4 : 1;
memcpy
(bootsect.Reserved1,
"\x00\x00\x00"
, 3);
bootsect.SerialNumber = 1ull *
rand
() *
rand
() *
rand
() *
rand
();
bootsect.Checksum = 0;
memcpy
(bootsect.BootStrap, IsBootmgr ? BootmgrCode : NtldrCode, 426);
bootsect.RecordEndSign = 0xAA55;
HANDLE
hFile = CreateFileW(FileName, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if
(hFile == INVALID_HANDLE_VALUE)
{
printf
(
"Failed to open output file.\n"
);
return
TRUE;
}
DWORD
dwWrite;
if
(!WriteFile(hFile, &bootsect, 512, &dwWrite, NULL))
{
printf
(
"Failed to write output file.\n"
);
CloseHandle(hFile);
return
TRUE;
}
CloseHandle(hFile);
printf
(
"Boot sector saved to file: %ls\n"
, FileName);
return
TRUE;
}
BOOL
UpdatePartSize(
LPCWSTR
FileName,
ULONGLONG
NumberSectors)
{
HANDLE
hFile = CreateFileW(FileName, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if
(hFile == INVALID_HANDLE_VALUE)
{
printf
(
"Failed to open output file.\n"
);
return
FALSE;
}
NTFS_BOOT_SECTOR bootsect;
DWORD
dwRead;
if
(!ReadFile(hFile, &bootsect, 512, &dwRead, NULL))
{
printf
(
"Failed to read output file.\n"
);
CloseHandle(hFile);
return
FALSE;
}
CloseHandle(hFile);
hFile = CreateFileW(FileName, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if
(hFile == INVALID_HANDLE_VALUE)
{
printf
(
"Failed to open output file.\n"
);
return
FALSE;
}
bootsect.NumberSectors = NumberSectors;
DWORD
dwWrite;
if
(!WriteFile(hFile, &bootsect, 512, &dwWrite, NULL))
{
printf
(
"Failed to write output file.\n"
);
CloseHandle(hFile);
return
FALSE;
}
CloseHandle(hFile);
printf
(
"Partition size updated, boot sector saved to file: %ls\n"
, FileName);
return
TRUE;
}
void
hexdump(
LPCVOID
buf,
DWORD
len)
{
const
char
*p = (
const
char
*)buf;
for
(
DWORD
i = 0; i < len; i++)
{
printf
(
"%.2X "
, (
UCHAR
)p[i]);
if
((i + 1) % 16 == 0)
{
printf
(
"| "
);
for
(
DWORD
j = i - 15; j <= i; j++)
{
if
(isprint(p[j]))
printf
(
"%c"
, p[j]);
else
printf
(
"."
);
}
printf
(
"\n"
);
}
}
printf
(
"\n"
);
}
int
main()
{
printf
(
"Please input the disk id: "
);
int
DiskId;
scanf_s(
"%d"
, &DiskId);
WCHAR
DiskName[MAX_PATH];
swprintf_s(DiskName, L
"\\\\.\\PhysicalDrive%d"
, DiskId);
HANDLE
hDisk = CreateFile(DiskName, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if
(hDisk == INVALID_HANDLE_VALUE)
{
printf
(
"Failed to open the disk.\n"
);
return
1;
}
DISK_GEOMETRY_EX DiskInfo;
DWORD
dwRet = 0;
if
(!DeviceIoControl(hDisk, IOCTL_DISK_GET_DRIVE_GEOMETRY_EX, NULL, 0, &DiskInfo,
sizeof
(DiskInfo), &dwRet, NULL))
{
printf
(
"Failed to get disk geometry.\n"
);
return
1;
}
ULONGLONG
TotalSectors = DiskInfo.DiskSize.QuadPart / 512;
DWORD
SectorsPerCylinder = DiskInfo.Geometry.SectorsPerTrack * DiskInfo.Geometry.TracksPerCylinder;
ULONGLONG
TotalCylinders = DiskInfo.Geometry.Cylinders.QuadPart;
printf
(
"Total sectors = %llu\n"
, TotalSectors);
printf
(
"Total cylinders = %llu\n"
, TotalCylinders);
printf
(
"Sectors per cylinder = %d\n"
, SectorsPerCylinder);
ULONGLONG
StartCylinder = 0;
ULONGLONG
LastStartSector = -1;
char
lastbuf[512];
memset
(lastbuf, 0x22,
sizeof
(lastbuf));
char
*buf = (
char
*)
malloc
(SectorsPerCylinder * 512);
for
(; StartCylinder < TotalCylinders; StartCylinder++)
{
printf
(
"\rSearching cylinder %llu/%llu..."
, StartCylinder, TotalCylinders);
ULONGLONG
CurSector = StartCylinder * SectorsPerCylinder;
LARGE_INTEGER Offset = { 0 }, NewOffset = { 0 };
Offset.QuadPart = CurSector * 512;
SetFilePointerEx(hDisk, Offset, &NewOffset, FILE_BEGIN);
DWORD
SectorsRead = min(SectorsPerCylinder, TotalSectors - CurSector);
DWORD
BytesRead = SectorsRead * 512;
if
(!ReadFile(hDisk, buf, BytesRead, &dwRet, NULL) || dwRet < BytesRead)
{
fprintf
(stderr,
"\nRead cylinder error: %llu\n"
, StartCylinder);
memset
(lastbuf, 0x22,
sizeof
(lastbuf));
continue
;
}
unsigned
char
Magic1[16] = { 0x07, 0x00, 0x42, 0x00, 0x4F, 0x00, 0x4F, 0x00, 0x54, 0x00, 0x4D, 0x00, 0x47, 0x00, 0x52, 0x00 };
unsigned
char
Magic2[16] = { 0x05, 0x00, 0x4E, 0x00, 0x54, 0x00, 0x4C, 0x00, 0x44, 0x00, 0x52, 0x00, 0x04, 0x00, 0x24, 0x00 };
for
(
DWORD
i = 0; i < SectorsRead; i++)
{
BOOL
IsBootmgr = !
memcmp
(buf + i * 512, Magic1, 16);
BOOL
IsNtldr = !
memcmp
(buf + i * 512, Magic2, 16);
if
(IsEmptySector(i == 0 ? lastbuf : buf + (i - 1) * 512) && (IsBootmgr || IsNtldr))
{
ULONGLONG
StartSector = CurSector + i;
printf
(
"\nFound boot code in sector %llu\n"
, StartSector);
WCHAR
filename[MAX_PATH];
swprintf_s(filename, L
"PBR_Sector_%llu.bin"
, StartSector - 1);
ProcessVolume(hDisk, StartSector, TotalSectors, IsBootmgr, filename);
if
(LastStartSector != -1)
{
swprintf_s(filename, L
"PBR_Sector_%llu.bin"
, LastStartSector);
UpdatePartSize(filename, StartSector - 1 - LastStartSector - 1);
}
LastStartSector = StartSector - 1;
}
}
memcpy
(lastbuf, buf + (SectorsRead - 1) * 512,
sizeof
(lastbuf));
}
CloseHandle(hDisk);
printf
(
"\nSearch completed, press any key to exit...\n"
);
_getch();
return
0;
}