Jump to content
Search In
  • More options...
Find results that contain...
Find results in...
uhbooh

EXE hacking

Recommended Posts

VGA said:

Now why the hell would I ever use <x> I don't know but the important thing is that I can get it working if I want to. The OCD is strong with this one.


I think a lot of us empathise with that, I know I do.

Share this post


Link to post
VGA said:

What the hell? No, I don't want to do that :D


So, when you are using your dos machine, you would rather use boom or mbf than the vanilla exes?

Share this post


Link to post
Danfun64 said:

So, when you are using your dos machine, you would rather use boom or mbf than the vanilla exes?

I don't have a DOS machine since I was a kid :D

I use Dosbox. Slightly interesting note, I recently did a timedemo benchmarking in Dosbox (after setting the cycles to fixed 70000) to see if there was some difference in speed between doom 2 1.9, doom-plus, final doom executable from id anthology, that nr4tl hacked exe that xttl posted and doom2-plus with the DOS32a extender replacing dos4gw.

Disappointingly, they all timedemoed at around the same cycles, within statistical error margin. I then tested that new version of MBF 2.04 (vsync off, page flipping off and transparency off) and it timedemoed at around 10% less realtics than the others, pretty impressive.

Reading the developer's tests on real hardware, it seems that it is not faster but actually slower. It has to do with id's executables using that magical mode-x mode. And Dosbox obviously doesn't emulate that videocard updating ... thing faithfully enough.

Share this post


Link to post

Doom didn't use Mode X, although we'd all be a lot better off if it had (stupid non square pixels...)

Share this post


Link to post

Dosbox benchmarking...

From Scali of Vogons.org.

DOSBox isn't designed at all to be an accurate emulator of actual hardware. It just does everything 'as fast as possible'.
You could try PCem, it's not super-accurate, but at least it tries to emulate the actual cost of instructions and accesses to video memory and such, where you can select different CPUs, video interfaces etc to control the overall performance.


edit: on another note, real dos benchmarks of dos doom source ports can be found here (Not me).

Share this post


Link to post
Linguica said:

Doom didn't use Mode X, although we'd all be a lot better off if it had (stupid non square pixels...)

I don't *really* know what mode-x is but I just found the two places where I read about Doom 1.9 using it:

First here:
http://www.vogons.org/viewtopic.php?t=2131

Well there are some problems with that since cycles take a big impact if you run a game that uses the mode-x features of the VGA. You can see that with DOOM

This is posted by someone having a "DOSBox Author" tag.

Second here:
http://www.vogons.org/viewtopic.php?f=7&t=40699

Doom 1.9 original 42,2 FPS (Draws directly to mode-X video memory)

That's from a benchmark from germin, the author of the new unofficial release of MBF (2.04).

Share this post


Link to post

Not to go into details, but one of the most important aspects (pun intended) of Mode X is that it was 320x240, not 320x200. Doom ran in 320x200, so it wasn't in Mode X, QED.

Share this post


Link to post
Linguica said:

Not to go into details, but one of the most important aspects (pun intended) of Mode X is that it was 320x240, not 320x200. Doom ran in 320x200, so it wasn't in Mode X, QED.



AFAIK there were various 'Mode X' variants, with 320x200, 320x240 and 320x400.

But a 320x200 version of this definitely existed. About what *precisely* is named Mode X is up to debate, since these never were official terms.

Share this post


Link to post
Linguica said:

Doom didn't use Mode X, although we'd all be a lot better off if it had (stupid non square pixels...)


but dat 70Hz refresh rate...! At least I appreciated it very much back then. Playing games which used 320x240 or 640x480 modes vs. 320x200, 320x400 or 640x400 was annoying due to the flicker.

Also, unchained 320x200 VGA mode like what Doom uses is/was sometimes called Mode Y, apparently.

Share this post


Link to post

This chapter from the Abrash book is worth a read http://downloads.gamedev.net/pdf/gpbb/gpbb31.pdf

Edit, this one too (specifically about mode x) http://downloads.gamedev.net/pdf/gpbb/gpbb47.pdf

Note that Heretic/Hexen didn't use Mode 13H like Doom, which only needed it for the wipe effect iirc. Heretic and Hexen therefore benefited from square pixels.

Edit, wow I just stumbled across this old tutorial http://www.brackeen.com/vga/unchain.html , which is fun for me because that's the very first programming tutorial I ever attempted to follow, as a complete beginner, back in the late 90s.

Share this post


Link to post
xttl said:

but dat 70Hz refresh rate...!

320x240 probably ran at 60hz instead, right? Sigh... another reason why Carmack should have known better...

Share this post


Link to post
Graf Zahl said:

AFAIK there were various 'Mode X' variants, with 320x200, 320x240 and 320x400.

But a 320x200 version of this definitely existed. About what *precisely* is named Mode X is up to debate, since these never were official terms.

Yeah, I always referred to any of the tweaked, unchained VGA modes as "Mode X", but Abrash seems to have used that term only for the 320x240 mode. (Seems there was always ambiguity; I've got files from the early-to-mid 1990s that use it both ways: VGADOC4 uses it as a blanket term, while TWEAK16B uses it specifically...)

Jon said:

Note that Heretic/Hexen didn't use Mode 13H like Doom ...Heretic and Hexen therefore benefited from square pixels.

(Is this right? I thought the Raven games used untweaked Mode 13h. Either way I'm pretty sure they were also 320x200 and non-square.)

Jon said:

which only needed it for the wipe effect iirc.

I'm guessing (without a disassembly handy at the moment) that Doom also implemented low-detail mode by taking advantage of writing to two planes at once.

Share this post


Link to post
CODOR said:

(Is this right? I thought the Raven games used untweaked Mode 13h. Either way I'm pretty sure they were also 320x200 and non-square.)


I might be wrong. DOSBOX is outputting 320x200 for Heretic: SOTSR.

Share this post


Link to post
uhbooh said:

I'm aware that early versions of the EXE had random pitch shifts in the sound effects. What i meant was that, in all of the original EXEs, not just the early ones, DSPISTOL is played slightly faster and at a higher pitch when DSCHGUN is called. Source ports don't do this because they don't use the DMX sound library.


I think this is not quite right.

You are right that the chaingun is the only example of a sound effect defined as a link to another, and that it has a different base pitch in the source code. (src)

However, the code path for passing a sound effect through to the driver to be played doesn't change for linked sounds particularly, at least as far as we know, so the chaingun pitch, although the base pitch differs, is still ignored when the futzed the argument order for DMX.

I've just been doing some experiments and I cannot detect any pitch variation between the chaingun and the pistol in Doom or Doom 2 v1.9.

The base pitch is higher for doom v1.2, and so the mid-point of all the random pitch variations is higher than that for the pistol. I'm just confirming but I don't think we account for that properly in chocolate/crispy yet.

Share this post


Link to post

I don't really want to make a new thread for this, but while mapping the Final DOOM v2 EXE I just found out that the most recent versions of Doom actually have SFX support for 2 sound cards that you can't select in SETUP.EXE: Ensoniq SoundScape and "Crystal CODEC" / Windows Sound System compatibles.

Has this been documented anywhere yet? Unfortunately I cannot test whether this support really works since I don't have the hardware and DOSBox doesn't emulate either.

You need to edit default.cfg manually and set snd_sfxdevice to 10 for SoundScape or 11 for CODEC/WSS. SoundScape settings are read from an environment variable or an INI file pointed to by it (similar to GUS), for CODEC you need to set snd_sbport and snd_sbdma (yes, "sb", maybe it means "sound board" instead of "Sound Blaster"...) to the correct values yourself. Remember that the value for snd_sbport is given in decimal format.

EDIT: Just checked the EXEs from chungy's repo and Doom (2) v1.8 is the first version that supports these. French v1.8 however doesn't.

Share this post


Link to post

Weird, I was literally rereading this thread earlier today and thought "I wonder if xttl is still doing EXE hacking stuff."

Share this post


Link to post
xttl said:

I don't really want to make a new thread for this, but while mapping the Final DOOM v2 EXE I just found out that the most recent versions of Doom actually have SFX support for 2 sound cards that you can't select in SETUP.EXE: Ensoniq SoundScape and "Crystal CODEC" / Windows Sound System compatibles.

A while back i tried to get it working on Yamaha YMF718 card, which is WSS compatible. DMX detected it, but failed to initialize it.

Share this post


Link to post
nukeykt said:

A while back i tried to get it working on Yamaha YMF718 card, which is WSS compatible. DMX detected it, but failed to initialize it.


Oh well. I still have a Sound Galaxy 16 card (Aztech) lying somewhere which is also WSS compatible, but I'm not sure whether it works anymore and I don't currently have a '90s PC to put it into. Maybe I'll get to try it on someone else's PC soon.

Linguica said:

Weird, I was literally rereading this thread earlier today and thought "I wonder if xttl is still doing EXE hacking stuff."


Haven't done much at all since I was last posting actively here, hacking the original binaries has kind of lost its appeal for me since it's always a lot of effort for relatively little gain. I'm not sure how well PC DOOM works because I haven't ever tried to compile or use it myself, but I think that's the way to go for people out there who want a DOS DOOM binary compiled with Watcom and using the original sound code but still with some enhancements or bugfixes. I guess the alphas and beta (and console versions) could still be a interesting target for patching (and reverse engineering) though.

Currently I've been trying to figure out ways to make patching easier for myself so that I could perhaps stay motivated better. Ideally, I'd like to use C code compiled with Open Watcom for patching the binaries. I think this is doable but requires some work to design and write a tool to convert the OMF32 .obj files generated by wcl386 into an easier to handle format, and then to write a loader for the output of that tool which has to be patched into the game manually.

Share this post


Link to post
xttl said:

I think that's the way to go for people out there who want a DOS DOOM binary compiled with Watcom and using the original sound code but still with some enhancements or bugfixes.


PC DOOM uses the Apogee sound system. The files are named DMX, but it's only a wrapper for that sound system.

If you have the DMX source code that was leaked some time ago, I guess you can use it easily using this wrapper. (but it would be illegal to redistribute it)

The guy who had the DMX source code on his web site hosts his "illegal" Doom ports here:
https://bitbucket.org/maraakate/doomnew-for-dos
https://bitbucket.org/maraakate/heretic-for-dos

Share this post


Link to post

Yeah keeping everything legit is one reason to stick to patching the original EXE.

Are there features in DMX that aren't available with ASS? The biggest problem with the old DOS ports I had was that MIDI on FM cards always sounded like shit because nobody had figured out how to use DMX instrument defs with Allegro, and Allegro's softsynth (I think it was called digmid?) was too slow on my 486DX. I guess phase shifting (set DMXOPTION=-phase) for digital SFX could also be one?

What features would you like to see in a patch btw (besides the obvious like Doom+ limits and longtics support)? I remember Linguica suggesting target restoration from savegames and I already made a hack that supports NR4TL in DOS properly some years ago. Also I know someone who'd have use for MIDI output via serial port on his DOS/Win9x machine.

Share this post


Link to post
axdoom1 said:

PC DOOM uses the Apogee sound system. The files are named DMX, but it's only a wrapper for that sound system.

If you have the DMX source code that was leaked some time ago, I guess you can use it easily using this wrapper. (but it would be illegal to redistribute it)

The guy who had the DMX source code on his web site hosts his "illegal" Doom ports here:
https://bitbucket.org/maraakate/doomnew-for-dos
https://bitbucket.org/maraakate/heretic-for-dos

What is exactly is that port all about?

Share this post


Link to post

I don't know anything about ASS unfortunately. Using DMX is better, for purity and authenticity (if these things matter to you).

xttl said:

here's a work in progress. It is Final Doom Anthology exed patched with...


Your project is interesting and I would sure like to see it completed. I believe there would been dozens of such modified executable projects with new features if the Doom source code was never released. That's what happened with Zoo Tycoon and Starcraft 1 which both have huge fan base.

If I knew the assembly language, I would do a lot of changes to the executable. I have a list of over 100 changes that I would do (which I wrote over the lasts weeks, so some features repeat).

I would make a .crk file with the patches inside so people would be able to choose want they want to enable and apply the changes with CRACKER.EXE which can also be reverted. (so no need to add command line parameters)

That's a job for a monk or a purist (me), since the source code is available there is no really any point (except the legality of DMX). I understand you lost the appeal to do it.

VGA said:

What is exactly is that port all about?


Read this: https://github.com/chocolate-doom/chocolate-doom/issues/639#issuecomment-156088947

He says more stuff later in the thread. His Github username is "maraakate".

Share this post


Link to post
Randy87 said:

Good point, I'll edit this post with a link when Mediafire stops misbehaving.

Doom_IDA.7z

Thanks for this! I've been making one for Heretic for a while now, but progress is slow. I've got about half the action code pointers so far. It goes slow for me, as I try to label every jump/call/const something meaningful.

Share this post


Link to post

The Heretic source release comes with a .map file generated by the linker which matches the last released executable (v1.3). It's quite easy to write a program or script that reads map files and writes an IDC script file for IDA that uses MakeName to label everything for you (or you could even try to write an IDC script that parses the map file). Freeware IDA 5.0 supports IDC scripting if you're using that.

Also all Doom alphas and the press beta come with debugging symbols intact but WDUMP from Open Watcom doesn't read them, perhaps Watcom changed the format at some point in time and WDUMP doesn't support the older format anymore? I don't know. Fortunately it isn't too had to figure out the format enough to generate an IDC file:

#include <stdio.h>

int main (int argc, char **argv)
{
  FILE *fp;

  printf ("#include <idc.idc>\n\n"); 
  printf ("static main (void)\n{\n");

  fp = fopen ("newdoom.exe", "rb");
  //fseek (fp, 0x73A48, SEEK_SET);
  fseek (fp, 0x7483C, SEEK_SET);

  while (!feof(fp))
  {
    unsigned long int sym_offs;
    unsigned short int sym_seg, unknown;
    unsigned char sym_name_len;
    unsigned char sym_name[256];
    unsigned long segbases[2] = {0x10000, 0x50000};

    fread (&sym_offs, 4, 1, fp);
    fread (&sym_seg, 2, 1, fp);
    fread (&unknown, 2, 1, fp);
    fread (&sym_name_len, 1, 1, fp); 
    fread (sym_name, sym_name_len, 1, fp);
    sym_name[sym_name_len] = 0;

    if (sym_name_len <= 1)
      break;
      
    //if (sym_seg==1)
    //  sym_name[sym_name_len-1] = 0; // remove trailing underscore in CS

    printf ("  MakeName (0x%08lx, "%s");\n", segbases[sym_seg-1] + sym_offs, 
      sym_name );
  }

  printf ("}\n");
  return 0;
}

Share this post


Link to post

@xttl: We really ought to release that beta hack we were working on at some point ;)

Share this post


Link to post
xttl said:

The Heretic source release comes with a .map file generated by the linker which matches the last released executable (v1.3). It's quite easy to write a program or script that reads map files and writes an IDC script file for IDA that uses MakeName to label everything for you (or you could even try to write an IDC script that parses the map file). Freeware IDA 5.0 supports IDC scripting if you're using that.

Also all Doom alphas and the press beta come with debugging symbols intact but WDUMP from Open Watcom doesn't read them, perhaps Watcom changed the format at some point in time and WDUMP doesn't support the older format anymore? I don't know. Fortunately it isn't too had to figure out the format enough to generate an IDC file:

#include <stdio.h>

int main (int argc, char **argv)
{
  FILE *fp;

  printf ("#include <idc.idc>\n\n"); 
  printf ("static main (void)\n{\n");

  fp = fopen ("newdoom.exe", "rb");
  //fseek (fp, 0x73A48, SEEK_SET);
  fseek (fp, 0x7483C, SEEK_SET);

  while (!feof(fp))
  {
    unsigned long int sym_offs;
    unsigned short int sym_seg, unknown;
    unsigned char sym_name_len;
    unsigned char sym_name[256];
    unsigned long segbases[2] = {0x10000, 0x50000};

    fread (&sym_offs, 4, 1, fp);
    fread (&sym_seg, 2, 1, fp);
    fread (&unknown, 2, 1, fp);
    fread (&sym_name_len, 1, 1, fp); 
    fread (sym_name, sym_name_len, 1, fp);
    sym_name[sym_name_len] = 0;

    if (sym_name_len <= 1)
      break;
      
    //if (sym_seg==1)
    //  sym_name[sym_name_len-1] = 0; // remove trailing underscore in CS

    printf ("  MakeName (0x%08lx, "%s");\n", segbases[sym_seg-1] + sym_offs, 
      sym_name );
  }

  printf ("}\n");
  return 0;
}

Nice! I never considered that - thanks so much! These will both save a lot of time!

Quasar said:

@xttl: We really ought to release that beta hack we were working on at some point ;)

Yes, please! You guys did some fascinating and impressive work, with sound, with menus, levels, etc, etc! I am very eager to see it, when you're ready, of course. I am kinda disappointed that I've never found the time to look into it myself.

Share this post


Link to post
xttl said:

I don't really want to make a new thread for this, but while mapping the Final DOOM v2 EXE I just found out that the most recent versions of Doom actually have SFX support for 2 sound cards that you can't select in SETUP.EXE: Ensoniq SoundScape and "Crystal CODEC" / Windows Sound System compatibles.

Has this been documented anywhere yet? Unfortunately I cannot test whether this support really works since I don't have the hardware and DOSBox doesn't emulate either.

I've had a SoundScape for close to 15 years. Too bad I didn't discover this until recently. :-P (A friend got some surplus computers from a place he worked at and gave me a few of them, one of which was a big Gateway 2000 tower with what I assumed was a generic Sound Blaster clone in it. It's been sitting in my parents' basement until last Christmas when I finally decided to see what it was. I'm not sure exactly which model it is, possibly a SoundScape II; it's the same one linked to in this post on VOGONS.)

Turns out I wasn't far off with thinking it was a "generic Sound Blaster clone"; while its native abilities (48kHz, 16-bit, stereo) are pretty much what you'd expect from a mid-1990s card and its wavetable MIDI is pretty good (see here for some recordings including E1M1), it only emulated an SB 2.0 (44.1kHz, 8-bit, mono) and it had no FM synthesis whatsoever. (It pretended that it did but it filled in the sounds from the wavetable synth. Imagine how bad that would sound, and then realize that it's not even that good.) So having SoundScape support in vanilla Doom would've been nice back in the day, if only for wavetable music and stereo sound effects. (Does vanilla mix sounds in 16-bit?)

It's not in a computer right now but it's handy and I'll try it in one of my DOS boxes sometime this week. I also have at least a couple of WSS cards so I'll test those too, although one is a YMF718 and nukeykt already tried one of those and it didn't initialize (but other games seem somewhat flakey in their detection of these cards so you never know)...

Share this post


Link to post
On 3/3/2017 at 9:35 PM, xttl said:

You need to edit default.cfg manually and set snd_sfxdevice to 10 for SoundScape or 11 for CODEC/WSS. SoundScape settings are read from an environment variable or an INI file pointed to by it (similar to GUS), for CODEC you need to set snd_sbport and snd_sbdma (yes, "sb", maybe it means "sound board" instead of "Sound Blaster"...) to the correct values yourself. Remember that the value for snd_sbport is given in decimal format.

So I finally tried this. The SoundScape worked immediately without any changes (other than snd_sfxdevice); it picks up the INI file from the directory pointed to by the SNDSCAPE environment variable. Sound effects were in stereo, which shouldn't be possible without using the SoundScape interface (as I mentioned earlier, it only emulates a Sound Blaster 2.0 which is mono only).

 

I also have at least two WSS (CODEC) cards: a Yamaha Audician 32 (YMF718 based) and an Acer Magic S23A (CS4232 based). The Audician 32 worked once I set snd_sbport to 1332 (hex 0x534), although strangely it still gave the "CODEC.  The CODEC ain't responding." message during startup. I used SETUPSA.EXE (Yamaha's configuration software) to mute the card's Sound Blaster Pro 2 emulation, yet sound effects were still audible. The S23A also said "CODEC.  The CODEC ain't responding." but regardless of port, DMA, mixer settings or running/not running CS32WSS.EXE there was no audible output.

 

For what it's worth, Tyrian 2000 gives the same results when using its WSS driver. The Audician 32 works, the S23A doesn't. (Presumably the S23A's WSS implementation sucks. I seem to remember having issues with it in DOS when it was my main soundcard in the late 1990s.)

 

TL;DR: Doom has had Ensoniq SoundScape and (mostly) WSS/CODEC support since version 1.8...

Share this post


Link to post

Hello, I haven't been active here for a while, and I don't have anything big to release right now but I'm too happy to not bump this thread since I just finally got EXE patching using compiled C code working (after about two-three days on and off looking at and trying out things). There are limitations and the way I have to write the code is a bit strange and unwieldy, like this:

 

Spoiler

 


// this is overwritten by dll2bin based on the entry point in dll header
// watcom always puts it to the start of the code section
// (use -zc flag in wcc386, "place const data into the code segment")
const char *jumpbytes = "\xC4\xC0\xDA\xEF\xFF";

// use local variables and function parameters only!
// no global variables!

typedef struct
{
  void *mybase;
  void *csbase;
  void *dsbase;
}
vars_t;

typedef struct
{
  int (*open) (const char *fn, int mode, ...); // takes args via stack. seriously.
  int (*read) (int handle, void *buffer, int length);
  int (*close) (int handle);
  void *(*malloc) (int bytes);
  int (*printf) (const char *fmt, ...);
  void (*exit) (int returncode);
  int (*filelength) (int handle);
  int (*fopen) (const char *fn, const char *mode);
  int (*fclose) (int handle);
  int (*fscanf) (int handle, const char *fmt, ...);
  int (*sscanf) (const char *str, const char *fmt);
}
funcs_t;

static void patch_game_keys (vars_t *v, funcs_t *f)
{
  int handle;
  unsigned char *gamekeyp;
  const char *str_gkeys = "patching game keys, data @ %x, keyfile %s\n";
  const char *str_keyfile = "keys.cfg";
  const char *str_err = "cannot open keys.cfg\n";
  unsigned char keybuf[4];

  str_gkeys += (unsigned long)v->mybase;
  str_keyfile += (unsigned long)v->mybase;
  str_err += (unsigned long)v->mybase;

  gamekeyp = (unsigned char *)v->dsbase + 0x521c8;
  f->printf (str_gkeys, gamekeyp, str_keyfile);

  handle = f->open (str_keyfile, 0x200, 0);
  if (handle == -1)
  {
    f->printf (str_err);
    f->exit (66);
  }
  f->read (handle, keybuf, 4);
  f->close (handle);

  *gamekeyp = keybuf[0]; gamekeyp+=4; //forward
  *gamekeyp = keybuf[1]; gamekeyp+=4; //back
  *gamekeyp = keybuf[2]; gamekeyp+=4; //left
  *gamekeyp = keybuf[3];              //right

  return;
}

static void patch_autorun (vars_t *v, funcs_t *f)
{
  unsigned long *movep;
  const char *str_run = "patching move/turn speed values, data @ %x\n";

  str_run += (unsigned long)v->mybase;

  movep = (unsigned long *)v->dsbase + (0x521e8 / 4);

  f->printf (str_run, movep);

  // forwardmove
  *movep = *(movep+1); movep += 2;
  // sidemove
  *movep = *(movep+1); movep += 2;
  // angleturn
  *movep = *(movep+1);;

  return;
}

static void patch_platspeed (vars_t *v, funcs_t *f)
{
  unsigned char *platcodep;

  platcodep = (unsigned char *)v->csbase + 0x2eb60;
  *platcodep = 0x04;

  return;
}

// before call, asm loader sets: eax=mybase, edx=csbase, ebx=dsbase)
void start (void *mybase, void *csbase, void *dsbase)
{
  const char *str_hello1 = "\nHello from Stage2!\n";
  const char *str_hello2 = "mybase=%08x csbase=%08x dsbase=%08x\n\n";
  const char *str_end = "\n";
  vars_t v;
  funcs_t f;

  v.mybase = mybase;
  v.csbase = csbase;
  v.dsbase = dsbase;

      f.printf = (unsigned long) v.csbase + 0x42d40;
        f.exit = (unsigned long) v.csbase + 0x436ce;
        f.open = (unsigned long) v.csbase + 0x432f0;
        f.read = (unsigned long) v.csbase + 0x43551;
       f.close = (unsigned long) v.csbase + 0x43642;
      f.malloc = (unsigned long) v.csbase + 0x42f75;
  f.filelength = (unsigned long) v.csbase + 0x43e50;
      f.fscanf = (unsigned long) v.csbase + 0x437e1;
       f.fopen = (unsigned long) v.csbase + 0x42ed6;
      f.fclose = (unsigned long) v.csbase + 0x43151;
      f.sscanf = (unsigned long) v.csbase + 0x4328d;

  // you need to fix up all pointers to data inside this module like this
  str_hello1 += (unsigned long) v.mybase;
  str_hello2 += (unsigned long) v.mybase;
  str_end += (unsigned long) v.mybase;

  f.printf (str_hello1);
  f.printf (str_hello2, mybase, csbase, dsbase);
  //f.exit (66);

  patch_game_keys (&v,&f);
  patch_autorun (&v,&f);
  patch_platspeed (&v,&f);

  f.printf (str_end);
  return;
}

 

 

 

 

(that's a quick test I wrote right after I got this thing working for the press beta exe which patches movement keys based on a 4-byte keys.cfg file, makes the doomguy always run and changes plat movement speed to match release version)

 

Now the only thing I have to write in assembly and patch directly into the exe (while dealing with LE relocation crap getting in the way all the time) is a very simple and short loader, which just calls the open/read/close/malloc funcs originally linked into the binary to load a flat bin file from the disk into a memory buffer which contains some code that it can do a call into.

 

Spoiler

 


BITS 32

; overwrites D_TimingLoop, unrelocated load address in cs is 0x23778, on disk: 0x26578
%define ORIGIN 0x23778

; library function pointers for:
; newdoom.exe (512839 bytes, sha1 25497e84320a7496692fbe18d01e5302b97e063e)
libc_open		equ 0x432f0
libc_read		equ 0x43551
libc_close		equ 0x43642
libc_malloc		equ 0x42f75
libc_printf		equ 0x42d40
libc_exit		equ 0x436ce
libc_filelength		equ 0x43e50

;
; prepatched into data section
;
; I reuse the end of the error message string as the file name to fit this
; into a smaller space.
;
errmsgp		equ 0x56e40
filenamep	equ 0x56e4f

;
; prepatched into code section, over unused function D_TimingLoop @ 0x23778
; (on disk: 0x26578)
;
; 140 bytes available there, so make sure this stays under that amount assembled
;
org ORIGIN:

	pushad

	; first, calculate relocated cs base address
	call $+5			; call the next instruction to get EIP on stack, to calculate relocated cs base
	pop esi				;
	sub esi, dword (ORIGIN+6)	; subtract expected unrelocated address of the previous pop instruction

	; now ESI = CODE section offset after relocation
	; next, calculate the relocated ds base from any known reference to ds in the code

	mov edi, dword [esi+0x19a24]	; cs base + 0x19a24 = pointer to "DMXGUS.INI" from a mov instruction (in libDMX)
	sub edi, dword 0x506ca		; subtract expected unrelocated address of the string

	; now EDI = DATA section offset after relocation

	; try to open stage2.bin file			;
	push dword 0					;
	push dword 0x200 ; O_RDONLY | O_BINARY		;
	lea edx, [edi+filenamep]			;
	push edx					;
	call libc_open					;
	add esp, byte 12				;
	; now EAX = file handle, or -1 on failure	;
	cmp eax, dword -1				;
	je failed					;

	; get file length	;
	push eax 		; save handle for later
	call libc_filelength 	; will take handle in EAX, and return length in EAX
	; now EAX = file length	;

	; malloc a buffer					;
	push eax ; save length for later use also		;
	call libc_malloc					;
	; now EAX = pointer to buffer, or 0 on failure		;
	test eax,eax						;
	jz failed						;

	; read takes EAX=handle, EDX=buffer, EBX=length	;
	; and returns EAX=read bytes			;
	mov edx, eax					;
	mov eax, dword [esp+4]				;
	mov ebx, dword [esp]				;
	call libc_read					;
	; check read length				;
	cmp eax,dword [esp]				;
	jne failed					;

	; close file now		;
	mov eax, dword [esp+4]		;
	call libc_close			;

	; no need for handle/length anymore
	add esp, byte 8

	; stage2 from C compiler needs:
	mov eax, edx	; eax = mybasep;
	mov ebx, edi	; ebx = dsbasep;
	mov edx, esi	; edx = csbasep;

	call eax

	popad
	ret



failed:	lea eax, [edi+errmsgp+26]
	mov [eax], byte 0x0A	; overwrite first null for open call's filename with a newline, lol
	sub eax, 26
	push eax
	call libc_printf
	add esp, byte 4
	xor eax,eax
	dec eax		; return -1
	jmp libc_exit

 

 

 

 

A suitable stage2.bin file can currently be generated by using Open Watcom to compile and link a Win32/NT DLL file (with specific settings and limitations) and then running a hacky and kludgy tool I wrote in a few hours on it, which I am not going to release at least for the time being.

 

(PE is probably the nicest and friendliest to work with of the formats the OW toolchain can generate out of the box, relatively easy to parse and with good tools and specs available from the net. LEs suck, and last time I was working on this some years ago I made the mistake to only consider using the OMF32 object files the compiler makes for this instead of looking at linker output... they're so massively annoying and complex to parse I just gave up on the idea completely. And right now I can't seem to even find a spec on the web anymore which includes all of the OMF record types wcc386 generates, last time I think I did eventually find one...)

 

Btw. the binary is called stage2.bin because I am going to try at some point to use what I got so far to write a loader for real PE DLL or maybe even ELF files. So it's a "second stage loader".

 

Is it possible to post hidden (must click to expand) code snippets here?

 

I would have never bothered if this was going to be used just for some silly hacks for a game that's been open source for about 20 years now, but now I might even finish some of the hack projects (especially the Doom press beta hack) I started since it's going to be a lot less tedious work for me, at least if I can develop this thing further to the point where I can just compile and drop in replacements for whole fucntions from the original game code.

 

I've attached newdoom.exe with my stage1 loader patched in + a stage2.bin compiled from the above code if somebody wants to play the beta with good plat speed, keys, autorun and no date/password check. :P

 

 

Oh yeah, I've only tested it in DOSBox, I'm interested to hear if it works on real hardware too (but I see no reason why it wouldn't).

 

edit: forgot keys.cfg from attachment

pressbeta_hack.zip

Share this post


Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×