├── .gitignore
├── .gitmodules
├── GetBootmanagerVersion.cpp
├── GetBootmanagerVersion.h
├── README.md
├── bmzip.cpp
├── bmzip.sln
├── bmzip.vcxproj
└── bmzip.vcxproj.filters
/.gitignore:
--------------------------------------------------------------------------------
1 | *.lib
2 | x86
3 | x64
4 |
5 | # Compiled Object files
6 | *.slo
7 | *.lo
8 | *.o
9 |
10 | # Compiled Dynamic libraries
11 | *.so
12 |
13 | # Compiled Static libraries
14 | *.lai
15 | *.la
16 | *.a
17 |
--------------------------------------------------------------------------------
/.gitmodules:
--------------------------------------------------------------------------------
1 | [submodule "ms-compression"]
2 | path = ms-compression
3 | url = git@github.com:coderforlife/ms-compress.git
4 |
--------------------------------------------------------------------------------
/GetBootmanagerVersion.cpp:
--------------------------------------------------------------------------------
1 | // bmzip: program for compressing and decompressing the bootmgr file
2 | // Copyright (C) 2012 Jeffrey Bush jeff@coderforlife.com
3 | //
4 | // This program is free software: you can redistribute it and/or modify
5 | // it under the terms of the GNU General Public License as published by
6 | // the Free Software Foundation, either version 3 of the License, or
7 | // (at your option) any later version.
8 | //
9 | // This library is distributed in the hope that it will be useful,
10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | // GNU General Public License for more details.
13 | //
14 | // You should have received a copy of the GNU General Public License
15 | // along with this program. If not, see .
16 |
17 | #include "GetBootmanagerVersion.h"
18 |
19 | // Modified from PEDataTypes.h, PEFile.cpp, PEVersion.h, and PEVersion.cpp in pe-file project: https://github.com/coderforlife/pe-file/
20 | // Only reads the version resource from the mini PE file in the bootmgr
21 |
22 | #ifdef _MSC_VER
23 | #pragma warning(disable : 4201 4480) // nonstandard extension used: [nameless struct/union | specifying underlying type for enum]
24 | #endif
25 |
26 | #if defined(_MSC_VER) && _MSC_VER <= 1500
27 | typedef unsigned __int8 uint8_t;
28 | typedef unsigned __int16 uint16_t;
29 | typedef unsigned __int32 uint32_t;
30 | typedef unsigned __int64 uint64_t;
31 | typedef __int8 int8_t;
32 | typedef __int16 int16_t;
33 | typedef __int32 int32_t;
34 | typedef __int64 int64_t;
35 | #else
36 | #include
37 | #endif
38 |
39 | #include
40 | #include
41 |
42 | #ifndef ARRAYSIZE
43 | #define ARRAYSIZE(a) sizeof(a)/sizeof(a[0])
44 | #endif
45 |
46 | template inline static size_t roundUpTo(size_t x) { size_t mod = x % MULT; return (mod == 0) ? x : (x + MULT - mod); }
47 | template<> inline size_t roundUpTo<2>(size_t x) { return (x + 1) & ~0x1; }
48 | template<> inline size_t roundUpTo<4>(size_t x) { return (x + 3) & ~0x3; }
49 |
50 | #pragma region Resource Finding Structures and Code
51 | #include "pshpack2.h"
52 | struct DOSHeader { // IMAGE_DOS_HEADER - DOS .EXE header
53 | const static uint16_t SIGNATURE = 0x5A4D; // MZ
54 |
55 | uint16_t e_magic; // Magic number
56 | uint16_t e_cblp; // Bytes on last page of file
57 | uint16_t e_cp; // Pages in file
58 | uint16_t e_crlc; // Relocations
59 | uint16_t e_cparhdr; // Size of header in paragraphs
60 | uint16_t e_minalloc; // Minimum extra paragraphs needed
61 | uint16_t e_maxalloc; // Maximum extra paragraphs needed
62 | uint16_t e_ss; // Initial (relative) SS value
63 | uint16_t e_sp; // Initial SP value
64 | uint16_t e_csum; // Checksum
65 | uint16_t e_ip; // Initial IP value
66 | uint16_t e_cs; // Initial (relative) CS value
67 | uint16_t e_lfarlc; // File address of relocation table
68 | uint16_t e_ovno; // Overlay number
69 | uint16_t e_res[4]; // Reserved words
70 | uint16_t e_oemid; // OEM identifier (for e_oeminfo)
71 | uint16_t e_oeminfo; // OEM information; e_oemid specific
72 | uint16_t e_res2[10]; // Reserved words
73 | int32_t e_lfanew; // File address of new exe header
74 | };
75 | #include "poppack.h"
76 | struct FileHeader { // IMAGE_FILE_HEADER
77 | enum CharacteristicFlags : uint16_t { // IMAGE_FILE_* - FLAGS
78 | RELOCS_STRIPPED = 0x0001, // Relocation info stripped from file.
79 | EXECUTABLE_IMAGE = 0x0002, // File is executable (i.e. no unresolved external references).
80 | LINE_NUMS_STRIPPED = 0x0004, // Line numbers stripped from file.
81 | LOCAL_SYMS_STRIPPED = 0x0008, // Local symbols stripped from file.
82 | AGGRESIVE_WS_TRIM = 0x0010, // Aggressively trim working set
83 | LARGE_ADDRESS_AWARE = 0x0020, // App can handle >2gb addresses
84 | BYTES_REVERSED_LO = 0x0080, // Bytes of machine word are reversed.
85 | MACHINE_32BIT = 0x0100, // 32 bit word machine.
86 | DEBUG_STRIPPED = 0x0200, // Debugging info stripped from file in .DBG file
87 | REMOVABLE_RUN_FROM_SWAP = 0x0400, // If Image is on removable media, copy and run from the swap file.
88 | NET_RUN_FROM_SWAP = 0x0800, // If Image is on Net, copy and run from the swap file.
89 | SYSTEM = 0x1000, // System File.
90 | DLL = 0x2000, // File is a DLL.
91 | UP_SYSTEM_ONLY = 0x4000, // File should only be run on a UP machine
92 | BYTES_REVERSED_HI = 0x8000, // Bytes of machine word are reversed.
93 | };
94 | enum MachineType : uint16_t { // IMAGE_FILE_MACHINE_*
95 | Unknown = 0,
96 | I386 = 0x014c, // Intel 386.
97 | R3000 = 0x0162, // MIPS little-endian, 0x160 big-endian
98 | R4000 = 0x0166, // MIPS little-endian
99 | R10000 = 0x0168, // MIPS little-endian
100 | WCEMIPSV2 = 0x0169, // MIPS little-endian WCE v2
101 | ALPHA = 0x0184, // Alpha_AXP
102 | SH3 = 0x01a2, // SH3 little-endian
103 | SH3DSP = 0x01a3,
104 | SH3E = 0x01a4, // SH3E little-endian
105 | SH4 = 0x01a6, // SH4 little-endian
106 | SH5 = 0x01a8, // SH5
107 | ARM = 0x01c0, // ARM Little-Endian
108 | THUMB = 0x01c2,
109 | AM33 = 0x01d3,
110 | POWERPC = 0x01F0, // IBM PowerPC Little-Endian
111 | POWERPCFP = 0x01f1,
112 | IA64 = 0x0200, // Intel 64
113 | MIPS16 = 0x0266, // MIPS
114 | ALPHA64 = 0x0284, // ALPHA64
115 | MIPSFPU = 0x0366, // MIPS
116 | MIPSFPU16 = 0x0466, // MIPS
117 | AXP64 = ALPHA64,
118 | TRICORE = 0x0520, // Infineon
119 | CEF = 0x0CEF,
120 | EBC = 0x0EBC, // EFI Byte Code
121 | AMD64 = 0x8664, // AMD64 (K8)
122 | M32R = 0x9041, // M32R little-endian
123 | CEE = 0xC0EE,
124 | };
125 |
126 | MachineType Machine;
127 | uint16_t NumberOfSections;
128 | uint32_t TimeDateStamp;
129 | uint32_t PointerToSymbolTable;
130 | uint32_t NumberOfSymbols;
131 | uint16_t SizeOfOptionalHeader;
132 | CharacteristicFlags Characteristics;
133 | };
134 | struct OptionalHeader { // IMAGE_OPTIONAL_HEADER_*
135 | static const uint16_t SIGNATURE32 = 0x10b;
136 | static const uint16_t SIGNATURE64 = 0x20b;
137 |
138 | uint16_t Magic;
139 | uint8_t MajorLinkerVersion;
140 | uint8_t MinorLinkerVersion;
141 | uint32_t SizeOfCode;
142 | uint32_t SizeOfInitializedData;
143 | uint32_t SizeOfUninitializedData;
144 | uint32_t AddressOfEntryPoint;
145 | uint32_t BaseOfCode;
146 | union {
147 | struct
148 | {
149 | uint32_t BaseOfData;
150 | uint32_t ImageBase32;
151 | };
152 | uint64_t ImageBase64;
153 | };
154 | uint32_t SectionAlignment;
155 | uint32_t FileAlignment;
156 | uint16_t MajorOperatingSystemVersion;
157 | uint16_t MinorOperatingSystemVersion;
158 | uint16_t MajorImageVersion;
159 | uint16_t MinorImageVersion;
160 | uint16_t MajorSubsystemVersion;
161 | uint16_t MinorSubsystemVersion;
162 | uint32_t Win32VersionValue;
163 | uint32_t SizeOfImage;
164 | uint32_t SizeOfHeaders;
165 | uint32_t CheckSum;
166 | };
167 | struct NTHeaders { // IMAGE_NT_HEADERS_*
168 | static const uint32_t SIGNATURE = 0x00004550; // PE00
169 | uint32_t Signature;
170 | struct FileHeader FileHeader;
171 | struct OptionalHeader OptionalHeader;
172 | };
173 | struct SectionHeader { // IMAGE_SECTION_HEADER
174 | enum CharacteristicFlags : uint32_t { // IMAGE_SCN_* - FLAGS
175 | //Reserved: TYPE_REG = 0x00000000,
176 | //Reserved: TYPE_DSECT = 0x00000001,
177 | //Reserved: TYPE_NOLOAD = 0x00000002,
178 | //Reserved: TYPE_GROUP = 0x00000004,
179 | TYPE_NO_PAD = 0x00000008,
180 | //Reserved: TYPE_COPY = 0x00000010,
181 |
182 | CNT_CODE = 0x00000020, // Section contains code.
183 | CNT_INITIALIZED_DATA = 0x00000040, // Section contains initialized data.
184 | CNT_UNINITIALIZED_DATA = 0x00000080, // Section contains uninitialized data.
185 |
186 | LNK_OTHER = 0x00000100,
187 | LNK_INFO = 0x00000200, // Section contains comments or some other type of information.
188 | //Reserved: TYPE_OVER = 0x00000400,
189 | LNK_REMOVE = 0x00000800, // Section contents will not become part of image.
190 | LNK_COMDAT = 0x00001000, // Section contents comdat.
191 |
192 | //Reserved: = 0x00002000,
193 | //Obsolete: MEM_PROTECTED = 0x00004000,
194 | NO_DEFER_SPEC_EXC = 0x00004000, // Reset speculative exceptions handling bits in the TLB entries for this section.
195 | GPREL = 0x00008000, // Section content can be accessed relative to GP
196 | MEM_FARDATA = 0x00008000,
197 | //Obsolete: MEM_SYSHEAP = 0x00010000,
198 | MEM_PURGEABLE = 0x00020000,
199 | MEM_16BIT = 0x00020000,
200 | MEM_LOCKED = 0x00040000,
201 | MEM_PRELOAD = 0x00080000,
202 |
203 | ALIGN_1BYTES = 0x00100000,
204 | ALIGN_2BYTES = 0x00200000,
205 | ALIGN_4BYTES = 0x00300000,
206 | ALIGN_8BYTES = 0x00400000,
207 | ALIGN_16BYTES = 0x00500000, // Default alignment if no others are specified.
208 | ALIGN_32BYTES = 0x00600000,
209 | ALIGN_64BYTES = 0x00700000,
210 | ALIGN_128BYTES = 0x00800000,
211 | ALIGN_256BYTES = 0x00900000,
212 | ALIGN_512BYTES = 0x00A00000,
213 | ALIGN_1024BYTES = 0x00B00000,
214 | ALIGN_2048BYTES = 0x00C00000,
215 | ALIGN_4096BYTES = 0x00D00000,
216 | ALIGN_8192BYTES = 0x00E00000,
217 | //Unused: = 0x00F00000,
218 | ALIGN_MASK = 0x00F00000,
219 |
220 | LNK_NRELOC_OVFL = 0x01000000, // Section contains extended relocations.
221 | MEM_DISCARDABLE = 0x02000000, // Section can be discarded.
222 | MEM_NOT_CACHED = 0x04000000, // Section is not cacheable.
223 | MEM_NOT_PAGED = 0x08000000, // Section is not pageable.
224 | MEM_SHARED = 0x10000000, // Section is shareable.
225 | MEM_EXECUTE = 0x20000000, // Section is executable.
226 | MEM_READ = 0x40000000, // Section is readable.
227 | MEM_WRITE = 0x80000000, // Section is writeable.
228 |
229 | TLS_SCALE_INDEX = 0x00000001, // Tls index is scaled
230 | };
231 |
232 | char Name[8];
233 | uint32_t VirtualSize; // or PhysicalAddress
234 | uint32_t VirtualAddress;
235 | uint32_t SizeOfRawData;
236 | uint32_t PointerToRawData;
237 | uint32_t PointerToRelocations;
238 | uint32_t PointerToLinenumbers;
239 | uint16_t NumberOfRelocations;
240 | uint16_t NumberOfLinenumbers;
241 | CharacteristicFlags Characteristics;
242 | };
243 | struct ResourceDirectory { // IMAGE_RESOURCE_DIRECTORY
244 | uint32_t Characteristics;
245 | uint32_t TimeDateStamp;
246 | uint16_t MajorVersion;
247 | uint16_t MinorVersion;
248 | uint16_t NumberOfNamedEntries;
249 | uint16_t NumberOfIdEntries;
250 | // IMAGE_RESOURCE_DIRECTORY_ENTRY DirectoryEntries[];
251 | };
252 | struct ResourceDirectoryEntry { // IMAGE_RESOURCE_DIRECTORY_ENTRY
253 | union {
254 | struct {
255 | uint32_t NameOffset:31;
256 | uint32_t NameIsString:1;
257 | };
258 | uint32_t Name;
259 | uint16_t Id;
260 | };
261 | union {
262 | uint32_t OffsetToData;
263 | struct {
264 | uint32_t OffsetToDirectory:31;
265 | uint32_t DataIsDirectory:1;
266 | };
267 | };
268 | };
269 | struct ResourceDataEntry { // IMAGE_RESOURCE_DATA_ENTRY
270 | uint32_t OffsetToData;
271 | uint32_t Size;
272 | uint32_t CodePage;
273 | uint32_t Reserved;
274 | };
275 | static const unsigned char* GetVersionResource(const unsigned char* data) {
276 | // Load and check headers
277 | const DOSHeader *dosh = (DOSHeader*)data;
278 | if (dosh->e_magic != DOSHeader::SIGNATURE) { return NULL; }
279 | int32_t peOffset = dosh->e_lfanew;
280 | const NTHeaders *nth = (NTHeaders*)(data+peOffset);
281 | if (nth->Signature != NTHeaders::SIGNATURE) { return NULL; }
282 | const FileHeader* header = &nth->FileHeader; // identical for 32 and 64 bits
283 | const OptionalHeader* opt = &nth->OptionalHeader;
284 | bool is64bit = !(header->Characteristics & FileHeader::MACHINE_32BIT);
285 | if ((is64bit && opt->Magic != OptionalHeader::SIGNATURE64) || (!is64bit && opt->Magic != OptionalHeader::SIGNATURE32)) { return NULL; }
286 |
287 | // Get the RSRC section
288 | const SectionHeader *sections = (SectionHeader*)(data+peOffset+sizeof(uint32_t)+sizeof(FileHeader)+header->SizeOfOptionalHeader);
289 | const SectionHeader *rsrcSect = NULL;
290 | for (uint16_t i = 0; i < header->NumberOfSections; ++i)
291 | if (strncmp(sections[i].Name, ".rsrc", ARRAYSIZE(sections[i].Name)) == 0) { rsrcSect = sections+i; break; }
292 | if (!rsrcSect || rsrcSect->PointerToRawData == 0 || rsrcSect->SizeOfRawData == 0) { return NULL; }
293 |
294 | // Get the resource within the RSRC section
295 | const unsigned char* rsrc = data + rsrcSect->PointerToRawData;
296 | const ResourceDirectory *dir = (ResourceDirectory*)rsrc;
297 | const ResourceDirectoryEntry *entry = (ResourceDirectoryEntry*)(dir+1);
298 | const ResourceDataEntry *dataEntry = (ResourceDataEntry*)(rsrc+entry->OffsetToData);
299 | return ((dir->NumberOfIdEntries + dir->NumberOfNamedEntries) < 1 || entry->DataIsDirectory) ? NULL : rsrc+dataEntry->OffsetToData-rsrcSect->VirtualAddress;
300 | }
301 | #pragma endregion
302 |
303 | #pragma region Version Parsing Structures and Code
304 | Version::Version() : Minor(0), Major(0), Revision(0), Build(0) { }
305 | struct SmallVersion { uint16_t Minor, Major; };
306 | struct FileVersionBasicInfo {
307 | static const uint32_t SIGNATURE = 0xFEEF04BD;
308 |
309 | static FileVersionBasicInfo* Get(void* ver);
310 |
311 | uint32_t Signature;
312 | SmallVersion StrucVersion;
313 | Version FileVersion;
314 | Version ProductVersion;
315 |
316 | typedef enum _FileFlags : uint32_t { // FLAGS
317 | DEBUG = 0x00000001,
318 | PRERELEASE = 0x00000002,
319 | PATCHED = 0x00000004,
320 | PRIVATEBUILD = 0x00000008,
321 | INFOINFERRED = 0x00000010,
322 | SPECIALBUILD = 0x00000020,
323 | } Flags;
324 | Flags FileFlagsMask;
325 | Flags FileFlags;
326 |
327 | typedef enum _OS : uint32_t { // FLAGS, kinda
328 | UNKNOWN_OS = 0x00000000,
329 |
330 | DOS = 0x00010000,
331 | OS216 = 0x00020000,
332 | OS232 = 0x00030000,
333 | NT = 0x00040000,
334 |
335 | WINDOWS16 = 0x00000001,
336 | PM16 = 0x00000002,
337 | PM32 = 0x00000003,
338 | WINDOWS32 = 0x00000004,
339 |
340 | DOS_WINDOWS16 = 0x00010001,
341 | DOS_WINDOWS32 = 0x00010004,
342 | OS216_PM16 = 0x00020002,
343 | OS232_PM32 = 0x00030003,
344 | NT_WINDOWS32 = 0x00040004,
345 | } OS;
346 | OS FileOS;
347 |
348 | typedef enum _Type : uint32_t {
349 | UNKNOWN_TYPE = 0x00000000,
350 | APP = 0x00000001,
351 | DLL = 0x00000002,
352 | DRV = 0x00000003,
353 | FONT = 0x00000004,
354 | VXD = 0x00000005,
355 | STATIC_LIB = 0x00000007,
356 | } Type;
357 | Type FileType;
358 |
359 | typedef enum _SubType : uint32_t {
360 | UNKNOWN_SUB_TYPE = 0x00000000,
361 |
362 | DRV_PRINTER = 0x00000001,
363 | DRV_KEYBOARD = 0x00000002,
364 | DRV_LANGUAGE = 0x00000003,
365 | DRV_DISPLAY = 0x00000004,
366 | DRV_MOUSE = 0x00000005,
367 | DRV_NETWORK = 0x00000006,
368 | DRV_SYSTEM = 0x00000007,
369 | DRV_INSTALLABLE = 0x00000008,
370 | DRV_SOUND = 0x00000009,
371 | DRV_COMM = 0x0000000A,
372 | DRV_VERSIONED_PRINTER = 0x0000000C,
373 |
374 | FONT_RASTER = 0x00000001,
375 | FONT_VECTOR = 0x00000002,
376 | FONT_TRUETYPE = 0x00000003,
377 | } SubType;
378 | SubType FileSubtype;
379 |
380 | uint64_t FileDate;
381 | };
382 | struct Block32 {
383 | uint16_t size; // size including key, value, and children
384 | uint16_t val_size;
385 | uint16_t type; // 0x0000 for a binary value, 0x0001 for a string value
386 | const wchar_t* key;
387 | const unsigned char* value;
388 | //std::vector children;
389 | };
390 | static const FileVersionBasicInfo *GetVersionInfo(const unsigned char* ver) {
391 | const uint16_t* words = (const uint16_t*)ver;
392 | Block32 root = { words[0], words[1], words[2], (const wchar_t*)(words+3) };
393 | root.value = ver + roundUpTo(3 * sizeof(uint16_t) + (wcslen(root.key) + 1) * sizeof(wchar_t));
394 | if (wcscmp(root.key, L"VS_VERSION_INFO") != 0 || root.type != 0x0000 || root.val_size != 52) { return NULL; } // error!
395 | const FileVersionBasicInfo *v = (FileVersionBasicInfo*)root.value;
396 | if (v->Signature != FileVersionBasicInfo::SIGNATURE || v->StrucVersion.Major != 1 || v->StrucVersion.Minor != 0) { return NULL; } // error!
397 | return v;
398 | }
399 | #pragma endregion
400 |
401 | const Version GetBootmanagerVersion(const void* data) {
402 | const unsigned char* ver = GetVersionResource((unsigned char*)data);
403 | if (!ver) { return Version(); }
404 | const FileVersionBasicInfo *fvi = GetVersionInfo(ver);
405 | if (!fvi) { return Version(); }
406 | return fvi->FileVersion;
407 | }
408 |
--------------------------------------------------------------------------------
/GetBootmanagerVersion.h:
--------------------------------------------------------------------------------
1 | // bmzip: program for compressing and decompressing the bootmgr file
2 | // Copyright (C) 2012 Jeffrey Bush jeff@coderforlife.com
3 | //
4 | // This program is free software: you can redistribute it and/or modify
5 | // it under the terms of the GNU General Public License as published by
6 | // the Free Software Foundation, either version 3 of the License, or
7 | // (at your option) any later version.
8 | //
9 | // This library is distributed in the hope that it will be useful,
10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | // GNU General Public License for more details.
13 | //
14 | // You should have received a copy of the GNU General Public License
15 | // along with this program. If not, see .
16 |
17 | #ifndef GET_BOOTMANAGER_VERSION_H
18 | #define GET_BOOTMANAGER_VERSION_H
19 |
20 | struct Version {
21 | Version();
22 | unsigned short Minor, Major, Revision, Build;
23 | };
24 |
25 | const Version GetBootmanagerVersion(const void* data);
26 |
27 | #endif
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | bmzip
2 | =====
3 |
4 | Decompresses and compresses the Windows bootmgr (Vista, 7, and 8)
--------------------------------------------------------------------------------
/bmzip.cpp:
--------------------------------------------------------------------------------
1 | // bmzip: program for compressing and decompressing the bootmgr file
2 | // Copyright (C) 2012 Jeffrey Bush jeff@coderforlife.com
3 | //
4 | // This program is free software: you can redistribute it and/or modify
5 | // it under the terms of the GNU General Public License as published by
6 | // the Free Software Foundation, either version 3 of the License, or
7 | // (at your option) any later version.
8 | //
9 | // This library is distributed in the hope that it will be useful,
10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | // GNU General Public License for more details.
13 | //
14 | // You should have received a copy of the GNU General Public License
15 | // along with this program. If not, see .
16 |
17 | #define _CRT_SECURE_NO_WARNINGS
18 |
19 | #include
20 | #include
21 | #include
22 | #include
23 |
24 | #include "GetBootmanagerVersion.h"
25 | #include "ms-compression\compression.h"
26 |
27 | typedef unsigned char byte;
28 | typedef byte* bytes;
29 | typedef const byte const_byte;
30 | typedef const_byte* const_bytes;
31 |
32 | static bytes read_all(const TCHAR* filepath, size_t* size)
33 | {
34 | size_t l, len;
35 | bytes b, b0;
36 | FILE* f = _tfopen(filepath, _T("rb"));
37 | if (f == NULL) { /* error! */ return NULL; }
38 | if (fseek(f, 0L, SEEK_END) || (*size = len = ftell(f)) == -1 || fseek(f, 0L, SEEK_SET) || (b0 = b = (bytes)malloc(len)) == NULL) { /* error! */ fclose(f); return NULL; }
39 | while ((l = fread(b, sizeof(byte), len, f)) > 0 && (len -= l) > 0) { b += l; }
40 | fclose(f);
41 | if (len > 0) { /* error! */ free(b0); b0 = NULL; }
42 | return b0;
43 | }
44 |
45 | static int write_all(const TCHAR* filepath, bytes b, size_t size)
46 | {
47 | size_t l;
48 | FILE* f = _tfopen(filepath, _T("wb"));
49 | if (f == NULL) { /* error! */ return 0; }
50 | while ((l = fwrite(b, sizeof(byte), size, f)) > 0 && (size-=l) > 0) { b += l; }
51 | fflush(f);
52 | fclose(f);
53 | if (size > 0) { /* error! */ return 0; }
54 | return 1;
55 | }
56 |
57 | static int append_all(const TCHAR* filepath, bytes b, size_t size)
58 | {
59 | size_t l;
60 | FILE* f = _tfopen(filepath, _T("ab"));
61 | if (f == NULL) { /* error! */ return 0; }
62 | while ((l = fwrite(b, sizeof(byte), size, f)) > 0 && (size-=l) > 0) { b += l; }
63 | fflush(f);
64 | fclose(f);
65 | if (size > 0) { /* error! */ return 0; }
66 | return 1;
67 | }
68 |
69 | typedef struct _BM_DATA
70 | {
71 | unsigned int signature;
72 | unsigned int compressed_size;
73 | unsigned int uncompressed_size;
74 | unsigned int offset;
75 | } BM_DATA;
76 |
77 | const unsigned int bmLZNT1 = 0x49434D42; // BMCI
78 | const unsigned int bmXpressHuff = 0x48584D42; // BMXH
79 |
80 | static BM_DATA* find_bm_data(bytes in, bytes in_end)
81 | {
82 | BM_DATA* bm_data;
83 | while ((in = (bytes)memchr(in, 'B', in_end - in - 3)) != NULL && *(unsigned int*)in != bmLZNT1 && *(unsigned int*)in != bmXpressHuff) { ++in; }
84 | bm_data = (BM_DATA*)in;
85 | return in == NULL || (in + bm_data->offset + bm_data->compressed_size > in_end) ? NULL : bm_data;
86 | }
87 | static void print_version(BM_DATA* bm_data)
88 | {
89 | // Check the mini program between here and the compressed data that contains version information
90 | Version v = GetBootmanagerVersion((void*)(bm_data+1));
91 | if (v.Major != 0 || v.Minor != 0 || v.Build != 0 || v.Revision != 0)
92 | _tprintf(_T("Version: %hu.%hu.%hu.%hu\n"), v.Major, v.Minor, v.Build, v.Revision);
93 | else
94 | _tprintf(_T("Version: Unknown\n"));
95 | }
96 | static CompressionFormat get_format(BM_DATA* bm_data)
97 | {
98 | switch (bm_data->signature)
99 | {
100 | case bmLZNT1: _tprintf(_T("Compression Method: LZNT1\n")); return COMPRESSION_LZNT1;
101 | case bmXpressHuff: _tprintf(_T("Compression Method: XPRESS Huffman\n")); return COMPRESSION_XPRESS_HUFF;
102 | }
103 | return (CompressionFormat)-1;
104 | }
105 |
106 | static int bm_decomp(const TCHAR* in_file, const TCHAR* out_file)
107 | {
108 | size_t in_size, out_size;
109 | bytes in, out;
110 | BM_DATA *bm_data;
111 |
112 | if ((in = read_all(in_file, &in_size)) == NULL) { /* error! */ _ftprintf(stderr, _T("Failed to read input file '%s'\n"), in_file); return -1; }
113 | if ((bm_data = find_bm_data(in, in+in_size)) == NULL) { /* error! not found */ _ftprintf(stderr, _T("Failed to find the boot manager compression signature in file '%s'\n"), in_file); return -2; }
114 | print_version(bm_data);
115 | if ((out = (bytes)malloc(bm_data->uncompressed_size)) == NULL) { /* error! */ _ftprintf(stderr, _T("Failed to allocate %u bytes for decompression\n"), bm_data->uncompressed_size); return -3; }
116 | if ((out_size = decompress(get_format(bm_data), ((bytes)bm_data) + bm_data->offset, bm_data->compressed_size, out, bm_data->uncompressed_size)) != bm_data->uncompressed_size) { /* error! */ _ftprintf(stderr, _T("Failed to decompress data: %u\n"), errno); return -4; }
117 | if (!write_all(out_file, out, out_size)) { /* error! */ _ftprintf(stderr, _T("Failed to save decompressed file to '%s'\n"), out_file); return -5; }
118 |
119 | // TODO: free()
120 |
121 | return 0;
122 | }
123 |
124 | static int bm_comp(const TCHAR* in_file, const TCHAR* out_file)
125 | {
126 | size_t in_size, out_size;
127 | bytes in, out, out_data;
128 | BM_DATA *bm_data;
129 |
130 | if ((in = read_all(in_file, &in_size)) == NULL) { /* error! */ _ftprintf(stderr, _T("Failed to read input file '%s'\n"), in_file); return -1; }
131 | if ((out = read_all(out_file, &out_size)) == NULL) { /* error! */ _ftprintf(stderr, _T("Failed to read output file '%s' - it must be a bootmgr file\n"), out_file); return -1; }
132 | if ((bm_data = find_bm_data(out, out+out_size)) == NULL) { /* error! not found */ _ftprintf(stderr, _T("Failed to find the boot manager compression signature in file '%s' - it must be a bootmgr file\n"), out_file); return -2; }
133 | print_version(bm_data);
134 | bm_data->uncompressed_size = in_size;
135 | if ((out_data = (bytes)malloc(2*in_size)) == NULL) { /* error! */ _ftprintf(stderr, _T("Failed to allocate %u bytes for compression\n"), 2*in_size); return -3; }
136 | if ((out_size = compress(get_format(bm_data), in, in_size, out_data, 2*in_size)) == 0) { /* error! */ _ftprintf(stderr, _T("Failed to compress data: %u\n"), errno); return -4; }
137 | bm_data->compressed_size = out_size;
138 | out_data[out_size++] = 0;
139 | if (!write_all(out_file, out, ((bytes)bm_data) + bm_data->offset - out)) { /* error! */ _ftprintf(stderr, _T("Failed to save compressed file to '%s'\n"), out_file); return -5; }
140 | if (!append_all(out_file, out_data, out_size)) { /* error! */ _ftprintf(stderr, _T("Failed to save compressed file to '%s'\n"), out_file); return -5; }
141 |
142 | // TODO: free()
143 |
144 | return 0;
145 | }
146 |
147 | static void usage(_TCHAR* prog)
148 | {
149 | _tprintf(_T("To extract bootmgr.exe:\n"));
150 | _tprintf(_T(" %s bootmgr bootmgr.exe\n"), prog);
151 | _tprintf(_T(" The bootmgr file must be a complete bootmgr file and bootmgr.exe is overwritten\n"));
152 | _tprintf(_T("\n"));
153 | _tprintf(_T("To compress bootmgr.exe\n"));
154 | _tprintf(_T(" %s /c bootmgr.exe bootmgr\n"), prog);
155 | _tprintf(_T(" The bootmgr file must be a complete bootmgr file and is modified with the input file\n"));
156 | _tprintf(_T("\n"));
157 | }
158 |
159 | int _tmain(int argc, _TCHAR* argv[])
160 | {
161 | bool compress;
162 |
163 | _tprintf(_T("bmzip Copyright (C) 2012 Jeffrey Bush \n"));
164 | _tprintf(_T("This program comes with ABSOLUTELY NO WARRANTY;\n"));
165 | _tprintf(_T("This is free software, and you are welcome to redistribute it\n"));
166 | _tprintf(_T("under certain conditions;\n"));
167 | _tprintf(_T("See http://www.gnu.org/licenses/gpl.html for more details.\n"));
168 | _tprintf(_T("\n"));
169 |
170 | compress = argc > 1 && _tcslen(argv[1]) == 2 && (argv[1][0] == _T('-') || argv[1][0] == _T('/')) && (argv[1][1] == _T('c') || argv[1][1] == _T('C'));
171 | if (!compress && argc == 3) return bm_decomp(argv[1], argv[2]);
172 | else if (compress && argc == 4) return bm_comp(argv[2], argv[3]);
173 | usage(argv[0]);
174 | return 1;
175 | }
176 |
--------------------------------------------------------------------------------
/bmzip.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 11.00
3 | # Visual Studio 2010
4 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "bmzip", "bmzip.vcxproj", "{0F9707C1-E6D7-47EE-96B8-63908B286501}"
5 | ProjectSection(ProjectDependencies) = postProject
6 | {2221E871-BAC6-4A25-BC2E-2749F8EDDD70} = {2221E871-BAC6-4A25-BC2E-2749F8EDDD70}
7 | EndProjectSection
8 | EndProject
9 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ms-compress-library", "ms-compression\ms-compress-library.vcxproj", "{2221E871-BAC6-4A25-BC2E-2749F8EDDD70}"
10 | EndProject
11 | Global
12 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
13 | Debug|Win32 = Debug|Win32
14 | Debug|x64 = Debug|x64
15 | Debug-Lib|Win32 = Debug-Lib|Win32
16 | Debug-Lib|x64 = Debug-Lib|x64
17 | Release|Win32 = Release|Win32
18 | Release|x64 = Release|x64
19 | Release-Lib|Win32 = Release-Lib|Win32
20 | Release-Lib|x64 = Release-Lib|x64
21 | EndGlobalSection
22 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
23 | {0F9707C1-E6D7-47EE-96B8-63908B286501}.Debug|Win32.ActiveCfg = Debug|Win32
24 | {0F9707C1-E6D7-47EE-96B8-63908B286501}.Debug|Win32.Build.0 = Debug|Win32
25 | {0F9707C1-E6D7-47EE-96B8-63908B286501}.Debug|x64.ActiveCfg = Debug|x64
26 | {0F9707C1-E6D7-47EE-96B8-63908B286501}.Debug|x64.Build.0 = Debug|x64
27 | {0F9707C1-E6D7-47EE-96B8-63908B286501}.Debug-Lib|Win32.ActiveCfg = Debug-Lib|Win32
28 | {0F9707C1-E6D7-47EE-96B8-63908B286501}.Debug-Lib|Win32.Build.0 = Debug-Lib|Win32
29 | {0F9707C1-E6D7-47EE-96B8-63908B286501}.Debug-Lib|x64.ActiveCfg = Debug-Lib|x64
30 | {0F9707C1-E6D7-47EE-96B8-63908B286501}.Debug-Lib|x64.Build.0 = Debug-Lib|x64
31 | {0F9707C1-E6D7-47EE-96B8-63908B286501}.Release|Win32.ActiveCfg = Release|Win32
32 | {0F9707C1-E6D7-47EE-96B8-63908B286501}.Release|Win32.Build.0 = Release|Win32
33 | {0F9707C1-E6D7-47EE-96B8-63908B286501}.Release|x64.ActiveCfg = Release|x64
34 | {0F9707C1-E6D7-47EE-96B8-63908B286501}.Release|x64.Build.0 = Release|x64
35 | {0F9707C1-E6D7-47EE-96B8-63908B286501}.Release-Lib|Win32.ActiveCfg = Release-Lib|Win32
36 | {0F9707C1-E6D7-47EE-96B8-63908B286501}.Release-Lib|Win32.Build.0 = Release-Lib|Win32
37 | {0F9707C1-E6D7-47EE-96B8-63908B286501}.Release-Lib|x64.ActiveCfg = Release-Lib|x64
38 | {0F9707C1-E6D7-47EE-96B8-63908B286501}.Release-Lib|x64.Build.0 = Release-Lib|x64
39 | {2221E871-BAC6-4A25-BC2E-2749F8EDDD70}.Debug|Win32.ActiveCfg = Debug|Win32
40 | {2221E871-BAC6-4A25-BC2E-2749F8EDDD70}.Debug|Win32.Build.0 = Debug|Win32
41 | {2221E871-BAC6-4A25-BC2E-2749F8EDDD70}.Debug|x64.ActiveCfg = Debug|x64
42 | {2221E871-BAC6-4A25-BC2E-2749F8EDDD70}.Debug|x64.Build.0 = Debug|x64
43 | {2221E871-BAC6-4A25-BC2E-2749F8EDDD70}.Debug-Lib|Win32.ActiveCfg = Debug-Lib|Win32
44 | {2221E871-BAC6-4A25-BC2E-2749F8EDDD70}.Debug-Lib|Win32.Build.0 = Debug-Lib|Win32
45 | {2221E871-BAC6-4A25-BC2E-2749F8EDDD70}.Debug-Lib|x64.ActiveCfg = Debug-Lib|x64
46 | {2221E871-BAC6-4A25-BC2E-2749F8EDDD70}.Debug-Lib|x64.Build.0 = Debug-Lib|x64
47 | {2221E871-BAC6-4A25-BC2E-2749F8EDDD70}.Release|Win32.ActiveCfg = Release|Win32
48 | {2221E871-BAC6-4A25-BC2E-2749F8EDDD70}.Release|Win32.Build.0 = Release|Win32
49 | {2221E871-BAC6-4A25-BC2E-2749F8EDDD70}.Release|x64.ActiveCfg = Release|x64
50 | {2221E871-BAC6-4A25-BC2E-2749F8EDDD70}.Release|x64.Build.0 = Release|x64
51 | {2221E871-BAC6-4A25-BC2E-2749F8EDDD70}.Release-Lib|Win32.ActiveCfg = Release-Lib|Win32
52 | {2221E871-BAC6-4A25-BC2E-2749F8EDDD70}.Release-Lib|Win32.Build.0 = Release-Lib|Win32
53 | {2221E871-BAC6-4A25-BC2E-2749F8EDDD70}.Release-Lib|x64.ActiveCfg = Release-Lib|x64
54 | {2221E871-BAC6-4A25-BC2E-2749F8EDDD70}.Release-Lib|x64.Build.0 = Release-Lib|x64
55 | EndGlobalSection
56 | GlobalSection(SolutionProperties) = preSolution
57 | HideSolutionNode = FALSE
58 | EndGlobalSection
59 | EndGlobal
60 |
--------------------------------------------------------------------------------
/bmzip.vcxproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug-Lib
6 | Win32
7 |
8 |
9 | Debug-Lib
10 | x64
11 |
12 |
13 | Debug
14 | Win32
15 |
16 |
17 | Debug
18 | x64
19 |
20 |
21 | Release-Lib
22 | Win32
23 |
24 |
25 | Release-Lib
26 | x64
27 |
28 |
29 | Release
30 | Win32
31 |
32 |
33 | Release
34 | x64
35 |
36 |
37 |
38 | {0F9707C1-E6D7-47EE-96B8-63908B286501}
39 | Win32Proj
40 | bmzip
41 |
42 |
43 |
44 | Application
45 | true
46 | Unicode
47 |
48 |
49 | Application
50 | true
51 | Unicode
52 |
53 |
54 | Application
55 | true
56 | Unicode
57 |
58 |
59 | Application
60 | true
61 | Unicode
62 |
63 |
64 | Application
65 | false
66 | true
67 | Unicode
68 |
69 |
70 | Application
71 | false
72 | true
73 | Unicode
74 |
75 |
76 | Application
77 | false
78 | true
79 | Unicode
80 |
81 |
82 | Application
83 | false
84 | true
85 | Unicode
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 | true
117 | $(SolutionDir)x86\$(Configuration)\
118 | x86\$(Configuration)\
119 |
120 |
121 | true
122 | $(SolutionDir)x86\$(Configuration)\
123 | x86\$(Configuration)\
124 |
125 |
126 | true
127 |
128 |
129 | true
130 |
131 |
132 | false
133 | $(SolutionDir)x86\$(Configuration)\
134 | x86\$(Configuration)\
135 |
136 |
137 | false
138 | $(SolutionDir)x86\$(Configuration)\
139 | x86\$(Configuration)\
140 |
141 |
142 | false
143 |
144 |
145 | false
146 |
147 |
148 |
149 |
150 |
151 | Level4
152 | Disabled
153 | WIN32;_DEBUG;_CONSOLE;COMPRESSION_API_DLL;%(PreprocessorDefinitions)
154 |
155 |
156 | Console
157 | true
158 | MSCompression.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
159 | $(OutDir)
160 |
161 |
162 |
163 |
164 |
165 |
166 | Level4
167 | Disabled
168 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)
169 |
170 |
171 | Console
172 | true
173 | MSCompression.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
174 | $(OutDir)
175 |
176 |
177 |
178 |
179 |
180 |
181 | Level4
182 | Disabled
183 | WIN32;_DEBUG;_CONSOLE;COMPRESSION_API_DLL;%(PreprocessorDefinitions)
184 |
185 |
186 | Console
187 | true
188 | MSCompression.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
189 | $(OutDir)
190 |
191 |
192 |
193 |
194 |
195 |
196 | Level4
197 | Disabled
198 | WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)
199 |
200 |
201 | Console
202 | true
203 | MSCompression.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
204 | $(OutDir)
205 |
206 |
207 |
208 |
209 | Level4
210 |
211 |
212 | MaxSpeed
213 | true
214 | true
215 | WIN32;NDEBUG;_CONSOLE;COMPRESSION_API_DLL;%(PreprocessorDefinitions)
216 | MultiThreaded
217 |
218 |
219 | Console
220 | false
221 | true
222 | true
223 | MSCompression.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
224 | $(OutDir)
225 |
226 |
227 |
228 |
229 | Level4
230 |
231 |
232 | MaxSpeed
233 | true
234 | true
235 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
236 | MultiThreaded
237 |
238 |
239 | Console
240 | false
241 | true
242 | true
243 | MSCompression.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
244 | $(OutDir)
245 |
246 |
247 |
248 |
249 | Level4
250 |
251 |
252 | MaxSpeed
253 | true
254 | true
255 | WIN32;NDEBUG;_CONSOLE;COMPRESSION_API_DLL;%(PreprocessorDefinitions)
256 | MultiThreaded
257 |
258 |
259 | Console
260 | false
261 | true
262 | true
263 | MSCompression.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
264 | $(OutDir)
265 |
266 |
267 |
268 |
269 | Level4
270 |
271 |
272 | MaxSpeed
273 | true
274 | true
275 | WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)
276 | MultiThreaded
277 |
278 |
279 | Console
280 | false
281 | true
282 | true
283 | MSCompression.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)
284 | $(OutDir)
285 |
286 |
287 |
288 |
289 |
290 |
291 |
292 |
293 |
294 |
295 |
296 |
297 |
--------------------------------------------------------------------------------
/bmzip.vcxproj.filters:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx
7 |
8 |
9 | {93995380-89BD-4b04-88EB-625FBE52EBFB}
10 | h;hpp;hxx;hm;inl;inc;xsd
11 |
12 |
13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01}
14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms
15 |
16 |
17 |
18 |
19 | Source Files
20 |
21 |
22 | Source Files
23 |
24 |
25 |
26 |
27 | Header Files
28 |
29 |
30 |
--------------------------------------------------------------------------------