News:

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

Main Menu

bypassing load.exe

Started by clvn, October 19, 2009, 08:33:07 PM

Previous topic - Next topic

clvn

hi!

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;
fs.open(filename, 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;

output_ofs--;

next_offset(&output_ofs, &output_seg, 0);

while (true) {
fs.read((char*)&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];

fs.read((char*)buffer, sizeof(unsigned char));
fs.read((char*)&buffer[1], sizeof(unsigned char));

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


fs.close();

return true;
}

size_t copy_binary(const char* filename, char* exeimage) {
std::ifstream fs;
fs.open(filename, 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);

fs.read(exeimage, size);
fs.close();

return size;
}

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

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;
}



clvn

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 :-)

clvn

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: http://dl.getdropbox.com/u/213479/game.asm . 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)

BonzaiJoe

Hi clvn! And welcome.

Forgive my ignorance, but what is the point of bypassing load.exe? What can be achieved with this utility?
But we can't be quite sure.


Duplode

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.

As for me, I have no disassembly knowledge to be able to help, but highly appreciate the efforts anyway  :) Too bad Cas and the other hackers haven't been around lately...

clvn

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.

clvn

The little reverse engineering project has continued at full pace. Check out the latest .asm-dump from idapro:

http://dl.getdropbox.com/u/213479/game2.asm

While a lot of analysis remains, the disassembly now has many better-named functions and variables and a bunch of structs. The readability is much improved. Big chunks of the data segment was identified, including tables with mappings between track-tiles and 3D-shapes with rotation, materials, etc.

On a side note, a greater plan is starting to emerge. I've reconstructed enough of the resource manager and original memory layout to code a .trk-viewer-app under windows/d3d. Its pretty lame, so no betas, screenshots nor source code yet. It is meant as a testbed for analyzing and porting assembly from the disassembled stunts game executable. This way the vital parts of the game engine could be reimplemented in inline 32-bit x86 msvc-assembly with only minor changes. Further porting to C/C++ and other platforms would of course be for later.

There are approx 25000+ lines of code (out of 100000+) that are relevant to the core game engine and needs to be ported. So far only 1500 lines in 3 functions were ported in a couple of hours. There is work for at least a few weeks-to-months for somebody with a lot of spare time :)

zaqrack

absolutely stunning news. Thanks for the efforts!

Duplode

Quote from: clvn on November 01, 2009, 02:54:53 PM
While a lot of analysis remains, the disassembly now has many better-named functions and variables and a bunch of structs. The readability is much improved. Big chunks of the data segment was identified, including tables with mappings between track-tiles and 3D-shapes with rotation, materials, etc.

Quote from: clvn on November 01, 2009, 02:54:53 PM
It is meant as a testbed for analyzing and porting assembly from the disassembled stunts game executable. This way the vital parts of the game engine could be reimplemented in inline 32-bit x86 msvc-assembly with only minor changes. Further porting to C/C++ and other platforms would of course be for later.

I hope everyone can spare a moment for appreciating the immense significance of this stuff. It is the culmination of the hacking efforts done over all those years. It is really fantastic! There is so much to look at... if you excuse me, clvn, I will start with two kinda trivial questions, coming from someone who knows almost nothing about disassembly:

1. With the information you have already dissected is it possible to locate the materials table and the colour palette(s) used to build it?

2. After locating materials and palettes, how hard would it be to make a patch for modifying the default colours of sky and ground? Or, more ambitiously, to substitute materials entirely?

clvn

Quote from: Duplode on November 01, 2009, 07:57:58 PM
1. With the information you have already dissected is it possible to locate the materials table and the colour palette(s) used to build it?

2. After locating materials and palettes, how hard would it be to make a patch for modifying the default colours of sky and ground? Or, more ambitiously, to substitute materials entirely?

well, this depends.. of course there is the 768 bytes "!pal"-structure in sdmain.vsh. thats the global 256-color palette used throughout the entire game. tweaking it may have unexpected side effects though.

from what ive learned so far, it is possible to tweak hard coded material assignments for all the individual tile types. e.g render a normal road as icy road, or rotate, move or replace a shape with another one. this could be done before, but not without modifying the 3d files themselves. but the ground and the sky are handled in special ways, and i cant tell which color indexes are used for those.

also, there should indeed be a material index table in there somewhere. it has mappings between the 3d shape materials/paintjobs and the global "!pal" palette. i've ripped some stuff from stressed in order to get the colors in my d3d-rendering correct, but havent located this in the disassembly either.

dstien

Holy crack! Excellent work, clvn. I didn't notice this thread until now.

To further elaborate on BonzaiJoe's question, having a single, uncompressed EXE file makes static code analysis a breeze. By translating the game back to human-readable C code we can:

  • See exactly how game resources are parsed.
  • See what causes the many collision detection and physics bugs.
  • Port the code to modern architectures and operating systems.
  • Port the code to exotic platforms like handheld devices, gaming consoles and web browsers.
  • Extend the game with new features and eye-candy while preserving the eccentric physics we all love.

If we could make the manual decompilation process a collaborative effort it'll speed up the job. The collabREate approach looks interesting.

BonzaiJoe

Quote from: dstien on November 03, 2009, 08:35:58 AM
Holy crack! Excellent work, clvn. I didn't notice this thread until now.

To further elaborate on BonzaiJoe's question, having a single, uncompressed EXE file makes static code analysis a breeze. By translating the game back to human-readable C code we can:

  • See exactly how game resources are parsed.
  • See what causes the many collision detection and physics bugs.
  • Port the code to modern architectures and operating systems.
  • Port the code to exotic platforms like handheld devices, gaming consoles and web browsers.
  • Extend the game with new features and eye-candy while preserving the eccentric physics we all love.

If we could make the manual decompilation process a collaborative effort it'll speed up the job. The collabREate approach looks interesting.

Well that sounds wonderful! Good work clvn :)
But we can't be quite sure.


clvn

Quote from: dstien on November 03, 2009, 08:35:58 AM
If we could make the manual decompilation process a collaborative effort it'll speed up the job. The collabREate approach looks interesting.
ooh, collabreate looks like a good tool for sharing the effort, considering a regular versioning tool wont work with idapros .idb-file.

im gonna have to try and set up collabreate in a local vm for testing. alas i dont have access to a suitable public server. if anyone here wants to set up a collabreate-server for the task, ill support it for sure.

llm

hi clvn

first: thank you for reactivating the reverse engeneering subject :-)

i can't create the game.exe with your program - i get an access violation in apply_dif
after serveral runs of the while loop - i think your break condition does not met with my data
what game version did you use?

ciao llm

clvn

hello!

Quote from: llm on November 12, 2009, 12:24:02 PM
i can't create the game.exe with your program - i get an access violation in apply_dif
after serveral runs of the while loop - i think your break condition does not met with my data
what game version did you use?

it says stunts version 1.1, feb 12 1991.

most obvious point of failure i can think of is not uncompressing the datafiles with stunpack in advance. dunno.

for convenience, heres a zip with the vs project, including the final game.exe both uncompressed and cracked;
http://dl.dropbox.com/u/213479/execombiner.zip