├── .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 | --------------------------------------------------------------------------------