Skip to content

Instantly share code, notes, and snippets.

@Sebbyastian
Created August 29, 2018 21:59
Show Gist options
  • Save Sebbyastian/308d911cf1c7a5924852e4f2f3f345db to your computer and use it in GitHub Desktop.
Save Sebbyastian/308d911cf1c7a5924852e4f2f3f345db to your computer and use it in GitHub Desktop.
ddv
#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