Herr Otto Partz says you're all nothing but pipsqueaks!

Main Menu

Show posts

This section allows you to view all posts made by this member. Note that you can only see posts made in areas you currently have access to.

Show posts Menu

Messages - clvn

Stunts Reverse Engineering / Re: bypassing load.exe
October 27, 2009, 04:11:00 AM
Quote from: Duplode on October 26, 2009, 11:25:24 PM
Quote from: BonzaiJoe on October 26, 2009, 10:52:48 PM
Forgive my ignorance, but what is the point of bypassing load.exe? What can be achieved with this utility?
If I understood correctly what Cas mentioned somewhere long ago, load.exe picks a number of code files (according for different video/sound rivers, etc.) and combines them into a single piece of code which is run as the game. Getting it off the way should make it easier to locate which parts of the executable(s) are responsible for which functions within the game - that is, doing reverse engineering on whatever is buried inside the code.

yes, stunpack+the first code snippet basically re-implement portions of load.exe required decompress and combine the game-executable to disk rather than executing it in-memory. i understand this step wasnt documented here before.

the utilitys use is solely for reverse engineering purposes. it creates a version of the game that is actually possible to disassemble - as is shown in the linked game.asm.

hopefully something more interesting than undocumented command line parameters will come out of this, but time will show.
Stunts Reverse Engineering / Re: bypassing load.exe
October 26, 2009, 10:22:23 PM
hello again!

ive put game.exe through idapro and worked through random portions of the disassembly. so far its been adhoc hacking, trying to figure out the general structure and flow of the game.

if anyones interested, heres the output game.asm so far: . also id be happy to share the .idb as well.

of the 500+ functions detected in the exe, about half of them are named roughly after their category or function. the others still have cryptic names like "sub_9F1_2564". the main()-function is right at the beginning of the file (after the struct declarations).

dunno if it is documented somewhere else, but according to the command line parsing code, the exe understands the following parameters:

/ns - no sound
/nb - parsed, but unused
/ssb - use soundblaster (ad15.drv) instead of pc speaker
/sXY - use driver XY15.drv instead of pc speaker (e.g /sad for soundblaster)
/h - sets bios video mode 4 (black screen here)
Stunts Reverse Engineering / Re: bypassing load.exe
October 20, 2009, 09:53:56 PM
some further analysis reveals the the output game.exe from the above program is compressed with exepack, as with load.exe.

to remove the copy protection, uncompress with unp and put a byte 0x1 at offset 0x2b3c :-)
Stunts Reverse Engineering / bypassing load.exe
October 19, 2009, 08:33:07 PM

using info on this forum, stunpack and bit of hacking, heres source code to a quick&dirty program that combines mcga.hdr, the uncompressed ega.cmn, mcga.cod and mcga.dif into a new game.exe. this new exe replaces load.exe/*.hdr/*.cmn/*.cod/*.dif.

made with msvc. some tweaks may be needed. enjoy!

#include <fstream>

void next_offset(unsigned short* arg0, unsigned short* arg2, unsigned long arg4) {
unsigned short var2;
arg4 += *arg0;
var2 = arg4 / 0x10;
*arg2 += var2;
*arg0 = arg4 - (var2 << 4);

bool apply_dif(const char* filename, char* bytes) {
std::ifstream fs;, std::ios::in | std::ios::binary);

if (!fs) return false;

unsigned short var8;
unsigned char val1;
unsigned short output_ofs = 0x0000;
unsigned short output_seg = 0x0000;//0x01A7;

if (output_ofs == 0)
output_seg -= 0x1000;


next_offset(&output_ofs, &output_seg, 0);

while (true) {*)&var8, sizeof(unsigned short));
if (var8 == 0) break; // eof

next_offset(&output_ofs, &output_seg, var8 & 0x7fff);

int pos = output_seg << 4 | output_ofs;
char* buffer = &bytes[pos];*)buffer, sizeof(unsigned char));*)&buffer[1], sizeof(unsigned char));

if ((var8 & 0x8000) != 0) {*)&buffer[2], sizeof(unsigned char));*)&buffer[3], sizeof(unsigned char));


return true;

size_t copy_binary(const char* filename, char* exeimage) {
std::ifstream fs;, std::ios::in | std::ios::binary);
if (!fs) return 0;
fs.seekg(0, SEEK_END);
size_t size = fs.tellg();
fs.seekg(0, SEEK_SET);, size);

return size;

void save_binary(std::string filename, char* image, int size) {
std::ofstream fs;, std::ios::out | std::ios::binary);
fs.write(image, size);

int main() {

char exehdr[30];

copy_binary("assets\\mcga.hdr", exehdr);

unsigned short bytes_in_last_page = *(unsigned short*)((char*)&exehdr[2]);
unsigned short pages_in_executable = *(unsigned short*)((char*)&exehdr[4]);
unsigned short relocation_offset = *(unsigned short*)((char*)&exehdr[24]);
unsigned short paragraphs_in_header = *(unsigned short*)((char*)&exehdr[8]);

int executable_size = (pages_in_executable * 512);
if (bytes_in_last_page > 0)
executable_size += -512 + bytes_in_last_page;

int header_size = paragraphs_in_header * 16;

char* exeimage = new char[executable_size];
memcpy(exeimage, exehdr, 30);

int size = copy_binary("assets\\ega.cmn", &exeimage[header_size]);
apply_dif("assets\\mcga.dif", &exeimage[header_size]);
copy_binary("assets\\mcga.cod", &exeimage[header_size + size]);

save_binary("game.exe", exeimage, executable_size);
return 0;