Created
August 29, 2018 21:59
-
-
Save Sebbyastian/308d911cf1c7a5924852e4f2f3f345db to your computer and use it in GitHub Desktop.
ddv
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <assert.h> | |
#include <limits.h> | |
#include <stdio.h> | |
#include <stdint.h> | |
#include <stdlib.h> | |
#include <string.h> | |
#include <Windows.h> | |
#define _tmain main | |
#define TCHAR char | |
#define _stprintf sprintf | |
#define _tprintf printf | |
#define _T | |
#define _tcslen strlen | |
void banner(void) | |
{ puts("DESTRUCTIVE DISK VERIFIER"); | |
puts("-------------------------"); | |
} | |
void usage(char const *header) | |
{ fprintf(stderr, "%s; usage: ./ddv \"drive path\"\n" + !header * 4, header); | |
exit(EXIT_FAILURE); | |
} | |
int _tmain(int argc, TCHAR **argv) | |
{ banner(); | |
if (argc <= 1) { usage("insufficient argument/s"); } | |
TCHAR filename[_tcslen(argv[1]) + 5]; | |
_stprintf(filename, _T("\\\\.\\%s"), argv[1]); | |
HANDLE file = CreateFile(filename, GENERIC_READ | GENERIC_WRITE | |
, FILE_SHARE_READ | FILE_SHARE_WRITE | |
, NULL | |
, OPEN_EXISTING | |
, FILE_FLAG_NO_BUFFERING | FILE_FLAG_WRITE_THROUGH | |
, NULL); | |
if (file == INVALID_HANDLE_VALUE) { usage("invalid filename"); } | |
DISK_GEOMETRY geom; | |
if (!DeviceIoControl(file, IOCTL_DISK_GET_DRIVE_GEOMETRY | |
, NULL, 0 | |
, &geom | |
, sizeof geom | |
, &(DWORD){42} // why do I need this shit?! Microsoft... | |
, NULL)) { usage("DeviceIoControl error"); } | |
long long unsigned total = geom.BytesPerSector; | |
total *= ULLONG_MAX / total >= geom.SectorsPerTrack ? geom.SectorsPerTrack : 0; | |
total *= ULLONG_MAX / total >= geom.TracksPerCylinder ? geom.TracksPerCylinder : 0; | |
total *= ULLONG_MAX / total >= geom.Cylinders.QuadPart ? geom.Cylinders.QuadPart : 0; | |
_tprintf("%s claims:\n" | |
"\tcylinders: %llu\n" | |
"\ttrack/cyl: %lu\n" | |
"\tsec/track: %lu\n" | |
"\tbytes/sec: %lu\n" | |
"\ttotal: %llu%s (%lluB)\n", argv[1] | |
, (long long unsigned) geom.Cylinders.QuadPart | |
, (long unsigned) geom.TracksPerCylinder | |
, (long unsigned) geom.SectorsPerTrack | |
, (long unsigned) geom.BytesPerSector | |
, total / (1ULL << 40) ? total / (1ULL << 40) | |
: total / (1ULL << 30) ? total / (1ULL << 30) | |
: total / (1ULL << 20) ? total / (1ULL << 20) | |
: total / (1ULL << 10) ? total / (1ULL << 10) | |
: total | |
, total / (1ULL << 40) ? "TB" | |
: total / (1ULL << 30) ? "GB" | |
: total / (1ULL << 20) ? "MB" | |
: total / (1ULL << 10) ? "KB" | |
: "B" | |
, total); | |
time_t tick = time(NULL); | |
unsigned int seed = tick; | |
unsigned char sector[geom.BytesPerSector]; // note for future use: sector size was 512 for me, \ | |
but we should probably allocate it as there's a \ | |
chance it may be greater than stack size... | |
int line_length = 0; | |
memset(sector, 0, sizeof sector); | |
_tprintf(_T("Disk verification will result in DESTRUCTION OF DATA! Continue? [y/n] ")); | |
fflush(stdout); | |
if (tolower(getchar()) != 'y') { goto cleanup; } | |
srand(seed); | |
total /= geom.Cylinders.QuadPart; | |
for (long long unsigned cyl = 0; cyl < geom.Cylinders.QuadPart; cyl++) | |
{ if (time(NULL) - tick) | |
{ tick = time(NULL); | |
for (size_t x = 0; x < line_length; x++) { fputc('\b', stdout); } | |
for (size_t x = 0; x < line_length; x++) { fputc(' ', stdout); } | |
for (size_t x = 0; x < line_length; x++) { fputc('\b', stdout); } | |
line_length = printf("Writing to cylinder %llu", cyl); | |
fflush(stdout); | |
} | |
unsigned int hi, lo = rand(); | |
do | |
{ hi = rand(); | |
} while (hi >= RAND_MAX - RAND_MAX % total); | |
// sometimes the location we select to write to is on the boundary of a boarder. In that case \ | |
we should wrap the end of the write around to the beginning of the sector. Hence 2x memcpy. | |
size_t pivot = hi % sizeof sector + sizeof lo >= sizeof sector | |
? (sizeof sector + sizeof lo) % sizeof sector | |
: sizeof lo; | |
memcpy(sector, (unsigned char *) &lo + pivot, sizeof lo - pivot); | |
memcpy(sector + hi % sizeof sector, &lo, pivot); | |
long long unsigned offset = total * cyl + hi - hi % sizeof sector; | |
if (SetFilePointer(file, offset, &(LONG){offset >> 32}, FILE_BEGIN) == INVALID_SET_FILE_POINTER) | |
{ TCHAR *message = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL | |
, GetLastError() | |
, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT) | |
, (void *) &message | |
, 0 | |
, NULL) | |
? message | |
: NULL; | |
for (size_t x = 0; x < line_length; x++) { putc('\b', stdout); } | |
for (size_t x = 0; x < line_length; x++) { putc(' ', stdout); } | |
for (size_t x = 0; x < line_length; x++) { putc('\b', stdout); } line_length = 0; | |
_tprintf("Seek failure at cylinder %llu; error message follows:\n", cyl); | |
_tprintf("%s\n", message ? message : "unknown error"); | |
LocalFree(message); | |
goto cleanup; | |
} | |
if (!WriteFile(file, sector, sizeof sector, &(DWORD){0}, NULL)) | |
{ TCHAR *message = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL | |
, GetLastError() | |
, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT) | |
, (void *) &message | |
, 0 | |
, NULL) | |
? message | |
: NULL; | |
for (size_t x = 0; x < line_length; x++) { putc('\b', stdout); } | |
for (size_t x = 0; x < line_length; x++) { putc(' ', stdout); } | |
for (size_t x = 0; x < line_length; x++) { putc('\b', stdout); } line_length = 0; | |
_tprintf("Write failure at cylinder %llu; error message follows:\n", cyl); | |
_tprintf("%s\n", message ? message : "unknown error"); | |
LocalFree(message); | |
break; | |
} | |
} | |
srand(seed); | |
for (long long unsigned cyl = 0; cyl < geom.Cylinders.QuadPart; cyl++) | |
{ if (time(NULL) - tick) | |
{ tick = time(NULL); | |
for (size_t x = 0; x < line_length; x++) { fputc('\b', stdout); } | |
for (size_t x = 0; x < line_length; x++) { fputc(' ', stdout); } | |
for (size_t x = 0; x < line_length; x++) { fputc('\b', stdout); } | |
line_length = printf("Reading from cylinder %llu", cyl); | |
fflush(stdout); | |
} | |
unsigned int hi, lo = rand(); | |
do | |
{ hi = rand(); | |
} while (hi >= RAND_MAX - RAND_MAX % total); | |
size_t pivot = hi % sizeof sector + sizeof lo >= sizeof sector | |
? (sizeof sector + sizeof lo) % sizeof sector | |
: sizeof lo; | |
//memcpy(sector, (unsigned char *) &lo + pivot, sizeof lo - pivot); | |
//memcpy(sector + hi % sizeof sector, &lo, pivot); | |
long long unsigned offset = total * cyl + hi - hi % sizeof sector; | |
if (SetFilePointer(file, offset, &(LONG){offset >> 32}, FILE_BEGIN) == INVALID_SET_FILE_POINTER) | |
{ TCHAR *message = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL | |
, GetLastError() | |
, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT) | |
, (void *) &message | |
, 0 | |
, NULL) | |
? message | |
: NULL; | |
for (size_t x = 0; x < line_length; x++) { putc('\b', stdout); } | |
for (size_t x = 0; x < line_length; x++) { putc(' ', stdout); } | |
for (size_t x = 0; x < line_length; x++) { putc('\b', stdout); } line_length = 0; | |
_tprintf("Seek failure at cylinder %llu; error message follows:\n", cyl); | |
_tprintf("%s\n", message ? message : "unknown error"); | |
LocalFree(message); | |
goto cleanup; | |
} | |
if (!ReadFile(file, sector, sizeof sector, &(DWORD){0}, NULL)) | |
{ TCHAR *message = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL | |
, GetLastError() | |
, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT) | |
, (void *) &message | |
, 0 | |
, NULL) | |
? message | |
: NULL; | |
for (size_t x = 0; x < line_length; x++) { putc('\b', stdout); } | |
for (size_t x = 0; x < line_length; x++) { putc(' ', stdout); } | |
for (size_t x = 0; x < line_length; x++) { putc('\b', stdout); } line_length = 0; | |
_tprintf("Read failure at cylinder %llu; error message follows:\n", cyl); | |
_tprintf("%s\n", message ? message : "unknown error"); | |
LocalFree(message); | |
goto cleanup; | |
} | |
if (memcmp(sector, (unsigned char *) &lo + pivot, sizeof lo - pivot) || memcmp(sector + hi % sizeof sector, &lo, pivot)) | |
{ for (size_t x = 0; x < line_length; x++) { putc('\b', stdout); } | |
for (size_t x = 0; x < line_length; x++) { putc(' ', stdout); } | |
for (size_t x = 0; x < line_length; x++) { putc('\b', stdout); } line_length = 0; | |
_tprintf("Invalid signature at cylinder %llu\n", cyl); | |
} | |
} | |
cleanup: | |
CloseHandle(file); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment