Microsoft EXEPACK
Format type | Compression algorithm |
---|---|
Type | Stream |
I/O unit size | 1-bit |
Games |
Microsoft EXEPACK is a an executable file compressor used by several classic games.
EXEPACK compression could be added to a program by LINK.EXE /EXEPACK switch or by invoking EXEPACK.EXE utility, that was distributed with MASM.
Tools
- exepack
- https://www.bamsoftware.com/software/exepack/
- Open Source (Public Domain), updated 2022.
- Rust-based, can unpack or pack executables with the exepack algorithm, very deeply tested with many versions of the Microsoft Linker and standalone exepack
- The most mature and superior option for handling EXEPACK files.
- unEXEPACK
- https://github.com/w4kfu/unEXEPACK
- https://w4kfu.github.io/unEXEPACK/
- Source available (license unknown), updated 2019.
- Written in portable C, supports multiple formats.
- Second best option.
- unexepack
- https://sourceforge.net/p/openkb/code/ci/master/tree/src/tools/unexepack.c
- Open Source (Public Domain), updated 2013.
- Written in C, created as part of OpenKB engine for King's Bounty, only supports one format, has a bug when processing certain packed relocation tables.
- UNP (aka unp411)
- https://bencastricum.nl/unp/
- Source available (license unknown), updated 1995.
- Supports many compression formats besides EXEPACK.
- DOS assembly which works by setting breakpoints, running the target executable's own decompression algorithm, then dumping the contents of the uncompressed EXE from memory. Only works in DOS environment.
- UNPACK
- http://www.tbcnet.com/~clive/unpack.zip (archived)
- http://www.tbcnet.com/~clive/vcomwinp.html (archived)
- Closed source, free for non-commercial use only, updated 1996.
- DOS program written by Clive Turvey.
Games using EXEPACK
Some games utilize EXEPACK as an inner layer of their compression:
Game list extracted from Total DOS Collection
Games packed with EXEPACK
- 1869 (1992) by Max Design
- A10 Tank Killer (1989) by Dynamix
- Ace Of Aces (1987) by Accolade
- Alien Attack (1997) by Eldon Martin
- Alien Syndrome (1987) by Sega Entertainment Inc
- A Nightmare on Elm Street (1989) by Westwood Associates
- Aspetra (1996) by Zonarware
- Ballrace (1988) by Carl Mclawhorn
- Barbarian II Dungeons Of Drax (1988) by Epyx
- Bards Tale Construction Set the (1991) by Interplay
- Battle Of Austerlitz (1989) by Cornerstone Software Inc
- Beetlejuice In Skeletons In The Closet (1990) by Hi Tech Expressions Inc
- Beyond Columns (1990) by Sega Entertainment Inc
- Bible Builder (1992) by Everbright
- Big Sea (1994) by Starbyte
- Bravo Romeo Delta (1993) by Frankennstein
- Bugs Bunny Hare Brained The (1990) by Hi Tech Expressions Inc
- California Games (1987) by Epyx
- California Games II (1990) by Epyx
- Captain Comic II (1990) by Michael Denio
- Chessmaster 2100 (1988) by Software Toolworks
- Das Boot (1990) by Three Sixty Pacific
- Don't Go Alone (1989) by Accolade
- Ega Roids (1986) by Designer Software
- Elite (1985) by Firebird Software Ltd
- Fantasy Pinball (1994) by 21st Century Entertainment
- Fantasy World Dizzy (1990) by Codemasters
- Fort Apache (1992)
- Greens 1.01 (1992) by Microprose Software Inc
- Gunship 2000 (1990,1991) by Microprose Software Inc
- Highway Patrol II (1989) by Titus Interactive
- Humans 3 (1996) by Imagitec Design
- Indianapolis 500: The Simulation (1989) by Papyrus Design Group
- License To Kill (1989) by Domark
- Mario Teaches Typing (1992) by Interplay
- Mean Mini Golf (1992) by Johnathon Lexa
- Mega Man (1990) by Hi Tech Expressions Inc
- Mega Man 3 (1992) by Hi Tech Expressions Inc
- Pc Bowl (1983) by Bareware Systems
- Pc Starglider 2 (1988) by Argonaut Software
- Pinball Dreams (1992) by 21st Century Entertainment
- Pinball Fantasies (1992) by 21st Century Entertainment
- Pyramid Of Egypt (1989) by Softdisk Publishing
- Rocket Ranger (1988) by Cinemaware Corporation
- Romance Of The Three Kingdoms II (1990) by Koei Co Ltd
- Star Fleet II Krellan Commander (1989) by Interstel
- Star Trek 5 The Final Frontier (1989) by Mindscape Inc
- Street Rod 2 The Next Generation (1991) by California Dreams
- Tower Toppler (1987) by Us Gold
- Trek Trivia (1988) by Apogee Software Ltd
- Ultimate Gin (1993) by Accidential Software
- World Trophy Soccer (1989) by Novotrade
- Stunts (1990) by Distinctive Software, Inc.
Very large list of games that use EXEPACK: https://w4kfu.github.io/unEXEPACK/files/exepack_list.html
File Format
offset length purpose 0 0x1C DOS exe header ??? ??? packed exe 0x12 unpacker vars (EXEPACK variables, see below) 0x105 unpacker code 0x16 string "Packed file is corrupt" ??? packed reloc table (see below for more information) offset to packed exe = header * 16 (from exe header) length of packed exe = CS:IP (from exe header) length of packed reloc table = exepack_size - dest_len (from exepack variables)
EXEPACK variables
Variables used by the exepack unpacker (all except mem_start are pre-initialized):
Data type | Name | Description |
---|---|---|
UINT16LE | real_IP | real start address (offset) |
UINT16LE | real_CS | real start address (offset) |
UINT16LE | mem_start | start of the exe in memory (segment) |
UINT16LE | exepack_size | size of unpacker vars + unpacker code + error string + packed reloc table in bytes |
UINT16LE | real_SP | real stack (offset) |
UINT16LE | real_SS | real stack (segment) |
UINT16LE | dest_len | destination of the unpacker code (in paragraphs, relative to start of exe in memory) |
UINT16LE | skip_len | number of paragraphs between packed exe and unpacker variables + 1 |
UINT16LE | signature | "RB" (magic number of exepacked files) |
Relocation Table
packed relocation table = section_0, section_1, ..., section_0xf section = number_of_entries [can be zero], set of entry [can be empty] number_of_entries = unsigned word (16 bits) entry = unsigned word (16 bits) An entry in section n patches the segment value at: 0x1000*n + entry (relative to the start of the exe in memory)
Decompression algorithm
The exepack unpacker first copies itself to the location stored in dest_len. (the value in dest_len also equals the unpacked exe's size in paragraphs). It then executes a retf to the new location and starts unpacking. The unpacking algorithm works like this:
int srcPos; /* start at the end of the packed exe, because the unpacker works downwards */
int dstPos;
int commandByte, lengthWord, fillByte;
/* skip all 0xff bytes (they're just padding to make the packed exe's size a multiple of 16 */
while (*srcPos == 0xff) {
srcPos--;
}
/* unpack */
do {
commandByte = *(srcPos--);
switch (commandByte & 0xFE) {
/* (byte)value (word)length (byte)0xb0 */
/* writes a run of <length> bytes with a value of <value> */
case 0xb0:
lengthWord = (*(srcPos--))*0x100;
lengthWord += *(srcPos--);
fillByte = *(srcPos--);
for (i = 0; i < lengthWord; i++) {
*(dstPos--) = fillByte;
}
break;
/* (word)length (byte)0xb2 */
/* copies the next <length> bytes */
case 0xb2:
lengthWord = (*(srcPos--))*0x100;
lengthWord += *(srcPos--);
for (i = 0; i < lengthWord; i++) {
*(dstPos--) = *(srcPos--);
}
break;
/* unknown command */
default:
printf("Unknown command %x at position %x\n", commandByte, srcPos);
exit(1);
break;
}
} while ((commandByte & 1) != 1); /* lowest bit set => last block */
Notes:
- The sizes of both the packed exe and the unpacked exe are multiples of 16
- The unpacker code unpacks the exe onto itself, i.e. the unpacked exe has the same starting address (in memory) as the packed exe (in memory).
Credits
This information was adopted from http://cvs.z88dk.org/cgi-bin/viewvc.cgi/xu4/doc/avatarExepacked.txt?revision=1.1&root=zxu4&view=markup by aowen. The source page said:
Please send additions, corrections and feedback to this e-mail address: Remove space + vowels from "marc winterrowd" and append "at yahoo dot com"