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

EXE hacking

Recommended Posts

55 minutes ago, Redneckerz said:

PPS: This is also a completely off-beat case ofcourse. 32 MB under DOS is enough to support insane things like BTSX, and i can't think of a Vanilla WAD that pushes more than that. But who knows. Doom64 with 64 MB heap? Doom128? :P

Well, it's more meant for those vanilla WADs that do rub the zone memory a certain way, as well as limit-removing WADs that can go way beyond that. I'd imagine 64MB is probably doable without adding bytes, since it's still 2 digits (I could be completely wrong, I'm just speculating here). Honestly I wouldn't know how to do that though, since all the stuff I've done so far is changing values to ones that already exist in other EXE hacks.)

 

I think next I'm going to take a closer look at AV.EXE included with Alien Vendetta, so I can see where they changed the par times. Honestly that would be AWESOME if we could see that put into Dehacked Special Edition some day.

Share this post


Link to post
12 minutes ago, OpenRift said:

Well, it's more meant for those vanilla WADs that do rub the zone memory a certain way, as well as limit-removing WADs that can go way beyond that. I'd imagine 64MB is probably doable without adding bytes, since it's still 2 digits (I could be completely wrong, I'm just speculating here). Honestly I wouldn't know how to do that though, since all the stuff I've done so far is changing values to ones that already exist in other EXE hacks.)

That means there is a challenge there, no? :P

Quote

 

I think next I'm going to take a closer look at AV.EXE included with Alien Vendetta, so I can see where they changed the par times. Honestly that would be AWESOME if we could see that put into Dehacked Special Edition some day.

I can give some background regarding that because those par time edits were done in a seperate array. The name of the person who actually did this edit escapes me at the moment, though.

 

Cleimos is another one of those odd releases that essentially does what DeHacked does but standalone, called CLEIMSET. Described at the Wiki.

 

There are more obscure examples, like Doom Hockey. This is a very early (1994) example that does the following:

  • Comes with a pre-Dehacked binary patch, PATCH.HKY, which is utitlizing an executable called HACK.EXE. PATCH.HKY is generated by a utility called Hex Hacker 1.01 and which will ''patch''/rename the Doom engine to NORMAL.EXE, utilizing similar methods like DoomHack. It is a pre-DeHacked, pre-DeusF form of patching. The WAD is utilizing a voodoo doll as a puck to implement a new game mode.

Ottawa University (Or OTTAWAU) is another such WAD that does a lot of dirty hacking, as is Castle Phobos (generates a unique, Doom 1.666 based executable)

Share this post


Link to post
1 minute ago, Redneckerz said:

I can give some background regarding that because those par time edits were done in a seperate array. The name of the person who actually did this edit escapes me at the moment, though.

I'm dumb, so I don't know what an array is. Would editing this array be as simple as changing byte values or would this mean some more complicated stuff?

 

Also looking at the AV text file, Kim AndrŠ Malde aka Mutator did the par time edits.

Share this post


Link to post
1 minute ago, OpenRift said:

I'm dumb, so I don't know what an array is. Would editing this array be as simple as changing byte values or would this mean some more complicated stuff?

Array's as i understand them are rather large code table where things can be defined. Given that AV is a rather old release, i reckon that array was defined as such. Since its byte values, i guess it could be changed?

 

Above is just an educated guess though. I can just about read a hex value, nothing more. Your crk's are informative though!

1 minute ago, OpenRift said:

Also looking at the AV text file, Kim AndrŠ Malde aka Mutator did the par time edits.

There ya go. That's the name that escaped me (I remembered Kim, nothing else haha)

Share this post


Link to post

Alright, so I figured out how to edit the par times, it's a lot simpler than I thought. The only caveat being that you can't set the par time above 59:59, as it will just display "SUCKS" where the time's supposed to be, akin to how if the player's time reaches 1 hour, it will says "TIME SUCKS" instead of the actual time. 

 

The following hexadecimal offsets are where the par time data starts (starting with E1M1/MAP01).

The Ultimate Doom: 0009ADC4 
Doom II: 00099C34
Final Doom: 0009AE38

 

The value at those addresses are 1E by default, which equals 30, as all the first levels in each executable have a par time of 30 seconds.

Share this post


Link to post

Hey guys, I just want to check in that UDOOM32 and FDOOM32 are the final (or at least, final-ish) of these limit-raising hacked EXEs? Do they have full Dehacked support? Just asking this stuff because I'd like to include them in the Big Vanilla Wad Pack. DOOM32.EXE has a big detailed textfile, and DOOMP.exe (which will be replaced) at least has a little txt explaining what the old limits were and what they've been raised to. Could you possibly make TXT files up for the new variants as well? I just don't want them to be uncredited, that's all. Something as simple as a document with the names of every contributor and all the raised limits would be more than sufficient!

Share this post


Link to post
2 hours ago, Doomkid said:

Hey guys, I just want to check in that UDOOM32 and FDOOM32 are the final (or at least, final-ish) of these limit-raising hacked EXEs?

FDoom32 does not raise all limits like DoomP. I believe MAXOPENINGS was not raised? I have the exact details on PC, on mobile now.

 

And UDoom32 has a wiki page. What, you thought otherwise? :P I was wondering when you would ask these things for the BVWP.

2 hours ago, Doomkid said:

Do they have full Dehacked support? Just asking this stuff because I'd like to include them in the Big Vanilla Wad Pack.

UDoom32 should be the same as DoomP at least.

2 hours ago, Doomkid said:

DOOM32.EXE has a big detailed textfile, and DOOMP.exe (which will be replaced) at least has a little txt explaining what the old limits were and what they've been raised to.

Doom32 is more complete tho because of the increased lump stack, heapsize and OPL. Still waiting on UDOOMHACK to be finalized by @xttl... :)

2 hours ago, Doomkid said:

Could you possibly make TXT files up for the new variants as well? I just don't want them to be uncredited, that's all. Something as simple as a document with the names of every contributor and all the raised limits would be more than sufficient!

For UDoom32 see the wiki page. I have not put up FDoom32 yet because its not fully compatible with DoomP.

 

I suppose FDoomSP could be there. Its just Final Doom with increased save game limits.

Share this post


Link to post

Thank you! I'll just include a full copy of the information on the Wiki page as the info.

Share this post


Link to post

Ok, so this might come off as insanely anal - but the one thing that's missing from Doom32.exe that I really wish it had is the ability to change skies on continuous play. The patched version of the Final Doom EXE (found here - DOOM2EXE_IdAnthologyPatch.zip) does have this feature, and also works perfectly with DeHackEd 3.0a "special edition" by xttl. I tried playing Doom2 (not final Doom) and everything seemed to work perfectly, and even many Doom2 mods with .DEH files worked exactly as they should, despite not being for Final Doom.

 

The only issue I could see with this is very occasional demo de-syncs due to the bouncing lost soul effect (which isn't in the "real" doom2 v1.9) but I seriously doubt serious/competitive Doomers are going to be using this EXE to submit demos to the DSDA anyway..

 

As much wadding & modding as I've done, I've never actually hacked the EXE in the traditional sense - so I have no idea how to go about this, but I do have a feeling other vanilla enthusiasts might enjoy having that damn "skies never update" bug fixed in a true-vanilla EXE, and if it means bouncing lost souls come with it, then so be it. I just wanted to put this idea here, so maybe OpenRift or someone else inclined towards EXE hacking could see it, or maybe lead me in the right direction..!

Share this post


Link to post
11 hours ago, Doomkid said:

Ok, so this might come off as insanely anal - but the one thing that's missing from Doom32.exe that I really wish it had is the ability to change skies on continuous play. The patched version of the Final Doom EXE (found here - DOOM2EXE_IdAnthologyPatch.zip) does have this feature, and also works perfectly with DeHackEd 3.0a "special edition" by xttl. I tried playing Doom2 (not final Doom) and everything seemed to work perfectly, and even many Doom2 mods with .DEH files worked exactly as they should, despite not being for Final Doom.

 

The only issue I could see with this is very occasional demo de-syncs due to the bouncing lost soul effect (which isn't in the "real" doom2 v1.9) but I seriously doubt serious/competitive Doomers are going to be using this EXE to submit demos to the DSDA anyway..

 

As much wadding & modding as I've done, I've never actually hacked the EXE in the traditional sense - so I have no idea how to go about this, but I do have a feeling other vanilla enthusiasts might enjoy having that damn "skies never update" bug fixed in a true-vanilla EXE, and if it means bouncing lost souls come with it, then so be it. I just wanted to put this idea here, so maybe OpenRift or someone else inclined towards EXE hacking could see it, or maybe lead me in the right direction..!

Honestly, I got no idea. I could've sworn that AXDOOMER's doom-patcher fixes this issue, but checking the github page, I guess not. Honestly, this would be kind of a cool feature to have baked into a "real" doom2 1.9 EXE. I got no idea how to do that though. What I would want the most is probably a tutti-frutti fix, because that's a really common problem that occurs with limit-removing WADs, since people are most likely doing their testing with Crispy Doom anyway, which fixes that, so mappers would never even know. 

Share this post


Link to post

So little update since last time I posted here:

 

I figured out how to to get custom par times for vanilla, and made a little guide on how to do that!

 

Also, I've recently been messing around with making custom EXEs for HacX and Rekkr (for v1.16, Sunken Land doesn't work in DOS for some reason, despite working in Chocolate).

 

For HacX, I've added the custom quit messages found in the IWAD's LANGUAGE lump. For whatever reason, it there never was any custom par times (it specified par times in the MAPINFO lump, but they're identical to the vanilla par times), so I just left those alone.

 

For REKKR, I was able to change both quit messages and par times, as well as removing all text string references to Doom via dehacked, similar to how HacX's dehacked patch does it, which makes it feel more like its own thing.

 

In addition to those, I've also made some Hex edited versions of the SERSETUP, IPXSETUP, and SETUP EXEs with proper labelling for the respective games.

 

I'm not sure if I'm ready to upload the REKKR package yet, but I'll probably upload the HacX package soon.

Share this post


Link to post

I'm looking forward for these! I've beeing playing some games on DOSBox recently and REKKR with a proper stand-alone presentation will be an awesome addition (The same for HacX).

Share this post


Link to post

@xttl Hi. I just created an account here to say thank you. For a beginner on reverse engineering like me, seems this thread should probably be archived ahah (I'll do it on my own way at least). So THANK YOU!!! I'm messing with Fallout 1 DOS EXE (which is also a Linear Executable LE EXE) and this was exactly what I needed to know!!! I can now patch functions in run-time because of this idea of giving the function the addresses of the segments!!!

 

I had just found out what relocations were and then I understood the reason why it was working on the PC and not on the tablet (didn't seem to make much logic until I learned this). I was thinking in making some automated tool to add things to the relocation table, but then I found this piece of gold. So, thank you again.

 

On 12/7/2018 at 4:45 PM, xttl said:

Well, now I finally looked at the linker output instead and in the end it turned out it isn't difficult at all to make this work at least on the level seen in the previous post. It's really fortunate that Open Watcom can make PE DLLs if you select the win95 or nt target, it's such a nice and easy format to parse compared to OMF32 or LE/LX, and then I just had to figure out ways to work around the fact that I don't have any kind of runtime dynamic rebasing loader yet in the C code. I cannot really replace ingame functions from compiled code yet though, because how would I pass the pointers to the vars/funcs structs to some code that isn't called from the start function without resorting to doing something silly, like storing them to some fixed address in low DOS memory, video memory or elsewhere where I could maybe get away with it, for later access?

About this, I just wanted to give you (and/or to anyone else) an idea, which I don't know if you already thought of or not (in case you're still at this though - I read the entire thread, so no idea if you're still on this or not). The idea is very simple actually, and seems to have worked here. As a start I'm doing something which came to my mind (and that I believe you mentioned around the thread, no idea where? Or I'm confusing with something else), which is to write on the code section the 3 addresses: the allocated block address, the code section address, and the data section address. Then, every time before you call the functions in the external file, before calling the function you want, push the ESI and EDI, call the next instruction, you just need to do:

call    $+5
pop     esi
mov     esi, [esi+offset from the previous instruction to where the Code section address is]
mov     edi, [esi+IDA offset to where the Data section address is]
call    [esi+IDA offset to where the allocated block address is]

Or if you want to go to somewhere specific, put add edx, [whatever] after the last mov.

This way I was able to patch a string address from the allocated block code! First time I patched stuff in run-time ahah.

 

[Btw, I'm thinking in just appending to the end of the EXE, which if I remember correctly, won't do anything bad because the header says the last page ends at a specific place and then everything else is just ignored(?). And this way I don't need to have another file around. I know where the the last page ends, so I can put everything else on the allocated block.]

 

Note: I'm storing the addresses in the code section because I don't know which parts of the data section are not used. And there are about 3k null bytes in the last code section page, so I extended the section and started writing there. I also still need to set the section as writable. I haven't done it and it still works (like it did with you as you wrote somewhere here). Not sure why though (the loaders don't like to read!?), but ok.

 

Thank you again! You just spared me a LOT of work moving the EXE contents down to add bytes to the tables and other awful stuff (and gave me some more ideas to the pack in case I ever need again ahah). Seems "DLL injection" works here xD (kind of). Never messed with that (yet, at least), but I think that's how it works, if I'm not mistaken.

 

EDIT: I think one can even do something like this.

Spoiler

...
loader:
(...)
; Supposing ESI containing the Code section address, EDI the Data section address, and EDX the allocated block address
mov     [edx], esi ; First store the Code section address for faster access(?)
mov     [edx+4], edi ; Second store the Data section address (the 2nd to be more called)
; The third 4 bytes will also be needed to store the original ESI each time an external function is called,
; which is the least one to be used - only on the function return, hopefully.
(...)
...
call    codecave1
...
ext_funcs_prep:
push    eax ; Save the external file parameter
call    $+5
pop     eax
lea     eax, [eax+fixed offset from the previous instruction to where the allocated block address is]
mov     [eax+8], esi ; Save the original ESI
xchg    esi, eax ; Store the block address in ESI (useful to the external functions)

pop     eax ; Here we have the external file parameter again
add     eax, [esi+12+eax]
jmp     eax
; Or in case it's a function parameter, no EAX on the ADD
...
codecave1:
push    eax
; Below, a number to sum to the allocated block address or a function number so a main external function can call
; the correct function (in my opinion, if it can be done which I think it can unless I'm missing something, it's
; more general and easier in case you change the functions on the external file, along with their side)
mov     eax, 123489h
jmp     ext_funcs_prep
...

 

This way you just need to CALL codecave or JMP to it (where you choose which function to execute on the external file or do other things, for example), and then only use JMPs here on the code above so when you RETurn from the external file (if it was a CALL), you go directly to where you were when you called codecave. Or you can just JMP to the codecave and keep the stack anyway (and then just use a JMP to where you want, though it must be with an absolute address with the Code section address help). Just don't forget of POPing EAX inside the function you called so the stack (and the register) can get back to normal.

 

No idea if this is still useful for here xD, but in case it is, it's here.

 

EDIT 2: actually one can just store the address of the allocated block address and keep the Code section and Data section addresses in the beginning of the block too. If I'm not missing anything, that would save using either ESI or EDI. Only one would be needed (to store the block address). You'd have more instructions to go on memory get the addresses though, but one more register would be available. I've edited the code to have this idea in mind. When you leave the external file, you need to reset the ESI register through the allocated block. This way the stack remains intact (less bugs and less hating life? xD).

 

EDIT 3: to answer another thing, you can have the loader wherever you want, not just on some specific place. You just need to have it in a fixed place (as it should anyway), and then subtract the IDA address from the address after the call instruction. I'm doing that right now. I call the loader from more or less the beginning of main() with a call, and inside I figure out where I am (same idea as I said above, just applied to the loader).

 

EDIT 5: I think one could even get the patcher to patch itself xD. Would make the code above and the need to call that function every time a hack is needed, not needed at all. When the patcher is first called, it patches itself, so next times when it gets called from the functions, it already has the correct addresses on it. I'll try to go this route (seems simpler).

Edited by DADi590

Share this post


Link to post

@DADi590

 

I don't know if you've already found out about it, but some time ago a proper hacker going by the name kgsws figured out a way to get code exec from a PWAD at map load time in vanilla Doom (with some suitably corrupted map data), and developed a simple "framework" (if you can call it that) for patching the game with compiled C code so that this exploit could be more easily used to do some interesting and even flashy stuff from a PWAD.

 

See this thread

 

Also see this github repo https://github.com/kgsws/doom_ace and especially this branch https://github.com/kgsws/doom_ace/tree/doom2_ace

 

The last linked example patches the game in memory to add (limited) ZDoom DECORATE support to it, but of course you could even replace the whole game in memory if you wanted to, or conversely only do some much smaller changes.

 

Might be worth looking into it, at least if you don't mind using gcc instead of Open Watcom to compile your code and the AT&T syntax for x86 asm GNU tools insist on sticking with. :P It seems you'll also have to write small asm wrappers for all functions from the main game binary your patch code calls, at least if the binary was built using the fast register-based calling convention (up to 4 args passed via regs, it seems gcc simply cannot be easily told to do this) Watcom offers. Does Fallout have some stack pushes before pretty much every function call, or just before printf & friends and some other rare exceptions?

 

Instead of exploiting the game and putting the loader code in the REJECT lump of a map, just permanently patch the provided loader code into the game binary and adapt it slightly where necessary (as in read the code blob from somewhere other than a PWAD lump).

 

I know if I ever return (unlikely any time soon) to tinkering around with this crap I'll just take kgsws' stuff and be done with it.

 

16 hours ago, DADi590 said:

[Btw, I'm thinking in just appending to the end of the EXE, which if I remember correctly, won't do anything bad because the header says the last page ends at a specific place and then everything else is just ignored(?). And this way I don't need to have another file around. I know where the the last page ends, so I can put everything else on the allocated block.]

 

 

Yes, anything you attach to the end of the EXE file should be completely ignored by the loader in DOS4GW (or workalike) unless you make some corresponding LE header edits.
 

Edited by xttl

Share this post


Link to post

Ah then it's no longer needed. No problem, at least shared the idea xD.

 

With a quick overview, the idea of the hack seems to be so that it's not needed to patch the EXE? Or the main idea is another one? If it's to remove patching (and since I cannot use that exploit because it's for Doom(?)), then is there any difference between your original approach and the one you just described? (Because I still have to permanently patch and have wrappers) If it's not really about this, never mind. I'll have to properly read the loader code some time and understand what's happening there decently. Will have a look for sure though! Will save the link along with the patches on my PC. Thank you!

 

AT&T syntax is kind of awful for me, but if it's needed, required and mandatory 😂, what can I do ahahah. Fallout seems to have everything passed on registers, except when there's a string involved (then its address gets pushed into the stack). So might mean hard way ahah.

 

[I don't follow Doom things at all (never even played any Doom ahah), so I didn't know about that or anything else anyway. Some day I'll play a game to see what that's all about, but for now I haven't done it yet.]

 

PS: about what you said of using wrappers to every function call. (Why do you say that btw? Sorry, I didn't get it. If it's just a call, why have a wrapper, and btw doing what inside?) The EDIT 5 of my previous message (about which I've been thinking all day ahahah) seem to have a way of me not having to need any wrapper, or actually even needing to store anything in the code segment at all.

 

The loader calls the BIN file on a place of the main external function. That function reads the block itself and patches all absolute references according to the given code and data section addresses. After that, it actually patches the EXE with the values that were just patched on it --> the patch patches itself before it can patch the EXE ahahah. Not sure if this works, but in my head it seems to. This way I wouldn't need to store the block address (I won't need it anymore), or the code and data section addresses. Only if I want to free() the block in the exit (will have to see how bad it is if I don't free it... On Windows would be fine, on DOS might not be, but still, one just would have to restart the VM after exiting the game and that's it, I guess).

 

EDIT: FYI, I just found out GCC can understand Intel x86 syntax if you give this compiling flag: -masm=intel (https://stackoverflow.com/questions/199966).

 

 

 

EDIT 2: IT WORKS!!!!!! The patch is patching itself!!! I've managed to call a function that calls printf() and exit() from inside the external code without giving that function ANYthing at all!!!!! No need for any wrappers it seems!!! Just made my life easier xD aside from having learned a bit more!!! (Unless there are alternatives? So far this is the only way I've seen without needing wrappers for every patch function call. At least without some exploit or something(?)).

 

EDIT 3: also, if what I just thought works, one can have global variables and strings placed in whatever segment!!! No more local variables-only thing nor creating strings on the stack with manual assignment with chars by index (awful ahahah) nor code-segment-only programming or whatever limitations!!!! Just make a normal program with normal flags and all shouod work! Will test this tomorrow...

Edited by DADi590

Share this post


Link to post

So, in case it's useful to know here, this really seems to be possible! (In case this wasn't already known? At least in this thread I didn't see that, but no idea about other places - I don't follow Doom things, because I never played, at least yet.) Finished testing now. The patch patches itself to have the correct addresses, and then patches the EXE (calls, jumps, other values, anything) and when you call the patch's functions from the EXE, you don't need to pass any parameters!

 

The contents of the BIN file remain in memory so that the EXE can jump or call or read its contents wherever it wants. It can jump or call to the EXE functions, and if inside the BIN file those functions need references to the EXE, they have them all already and there's no need to pass parameters. Just do the patch normally without thinking in passing parameters specifically for segment addresses and other stuff (not even my idea of function parameter to know which one to execute --> the EXE just calls the functions on the BIN file, because the patch patches the EXE's jumps and calls to go to the BIN file functions).

 

One can also have global variables/strings and use the data segment and whatever segment is needed and the code will run just fine. I haven't made any patches to the EXE yet, but I've been testing from the call to the patch from the loader. The test function I'm using is a naked function and I pass no parameters to it at all. I managed to call printf from it to print a string in the EXE's data segment ("FALLOUT %p.%p") with the code and data segment addresses as parameters, print a "Hi!" string in the data segment of the BIN file, print a global int value in the BIN file's data segment (with "%d", also on the BIN file's data segment), then increment it and print it again, and call exit(), and all worked perfectly!!! (Being printf() and exit() functions from inside the EXE.)

 

I can also call the EXE's functions from C. I made C functions with the same signature as the original standard ones with an Assembly implementation and I opened a file, read its contents to a local C variable and closed the file. In this case I can even put the patches to be choosable inside an INI file and let people edit the file easily to choose which patches they want applied!

 

So I think this can be used exactly like DLL injection! You load it, let it be loaded, access stuff from inside its memory space, call its functions with references to the EXE's functions, whatever else you want. Not sure if this has any use here though, but at least for a beginner on these things seems to be wow ahahah. I'll still have to check the loader on the repo though. But I'll leave that to later as I'm having too much fun/excitement finding out these things right now ahah.

 

PS: this doesn't mess on how the BIN file is loaded to memory. It just needs to pass 3 addresses in 3 registers or pass one of them and store the others in the block and the rest it's however the loader is implemented. I haven't touched the loader since I began trying  these things. It's still loading as I left it 2 days ago or something.

 

Update: just wanted to add a week later that it's no longer PoC. I'm patching a game function call to an external function. That function uses data and other functions from the game EXE. It also uses 2 external strings. I pass no parameters to it and I use only EDI to calculate all relocations, and I push and pop it every time (or if EDI is already in use, then ESI - 2 registers not much used and that are not used in Watcom's calling convention, and btw, EDI seems to be the less used one of the 2). All works perfectly! More ahead I'll have an external function calling another external function. And that will also work. If it's useful, I'm publising the code here: https://github.com/Edw590/F1DP.

 

Thank you again xttl for all your published knowledge!!!

 

EDIT: I made improvements to the explanation (no idea how many, it was months ago) in the GitHub link I've put above.

Edited by Edw590

Share this post


Link to post
On 5/26/2021 at 10:39 PM, OpenRift said:

Final Doom

fdoom32.zip

The Ultimate Doom

udoom32.zip

 

UDOOM32 also comes with all the limit increases seen in Doom-plus.

 

FDOOM32's heapsize increase should be especially helpful on Urania, because I know that one can have zone memory issues if you try to save in certain situations (not like a savegame size limit overflow), akin to some points in Back to Saturn X Episode 2.

Hi, I applied a patch for sound pitch on FDoom32 and after that I can't save in the game. It just crashes. In the dosbox, the console displays an error: DYNX86: can’t run code in this page!

 

Patch for sound pitch:

56A88: 58FEFFFF[E9CA000000]128B6B
5DAC8: DE8B[54]240889[CB]833D

Share this post


Link to post
On 5/25/2022 at 7:17 AM, Angel Of Nemesis said:

Hi, I applied a patch for sound pitch on FDoom32 and after that I can't save in the game. It just crashes. In the dosbox, the console displays an error: DYNX86: can’t run code in this page!

 

Patch for sound pitch:

56A88: 58FEFFFF[E9CA000000]128B6B
5DAC8: DE8B[54]240889[CB]833D

Can't really help you with that, I don't even know how to re-enable that sort of thing anyway.

 

EDIT: For those who are having savegame issues in DOSBox, set your memsize to 63 in your .conf file, this should allow you to save the game without issue. (so sorry for the year and a half late reply lol)

Edited by OpenRift

Share this post


Link to post
On 5/26/2021 at 3:39 PM, OpenRift said:

[...]

Final Doom

fdoom32.zip

The Ultimate Doom

udoom32.zip

[...]

 

On 5/25/2022 at 7:17 AM, Angel Of Nemesis said:

Hi, I applied a patch for sound pitch on FDoom32 and after that I can't save in the game. It just crashes. In the dosbox, the console displays an error: DYNX86: can’t run code in this page!

 

Patch for sound pitch:

56A88: 58FEFFFF[E9CA000000]128B6B
5DAC8: DE8B[54]240889[CB]833D

 

You were off by four bytes. Here is a table of the two series of bytes to be replaced (+ their offsets) for all versions starting with v1.666:
 

v1.666 D1   510EF
v1.666 D2   510DF
v1.7/v1.7a  510CF
v1.8/v1.9   5628C
v1.9u       5648C
v1.9f       56A8C

8B 59 1A 8B 71 ->
E9 CA 00 00 00   

  
v1.666 D1   5728A
v1.666 D2   5727A
v1.7/v1.7a  5726A
v1.8/v1.9   5D2CA
v1.9u       5D4CA
v1.9f       5DACA

5C 24 08 89 CA ->
54 24 08 89 CB  

 

Some notes:

  • the execs for v1.666 are different for D1 and D2
  • v1.7 and v1.7a are D2-only
  • v1.8 and v1.9 for D1 and D2 are all the same exec
  • v1.9u is Ultimate Doom
  • the offsets for v1.9f are good for both Final Doom versions as the execs are the same length
  • the v1.4-v1.6 betas don't have those two sequences of bytes, so some more disassembling needs to be done
Edited by Never_Again : added notes

Share this post


Link to post

DISABLE Q KEY DURING RECORDING

v1.0      : 4DE62          
v1.1      : 4F19E                        v1.9u disassembly 
v1.2      : 4DCD1           
v1.4      : 58186          cseg01:00031910 G_WriteDemoTiccmd proc near
v1.5      : 5A546          cseg01:00031910   push    ebx
v1.6      : 5AF96          cseg01:00031911   push    ecx
v1.666    : 5D776 D2       cseg01:00031912   push    edx
v1.666    : 5D86C D1       cseg01:00031913   mov     ebx, dword_9B74C
v1.7a     : 5D776          cseg01:00031919   mov     edx, eax
v1.8/v1.9 : 638F6          cseg01:0003191B   cmp     dword_9AE18, 0
v1.9u     : 63B36 ———————> cseg01:00031922   jz      short loc_31929
v1.9f     : 64416          cseg01:00031924   call    G_CheckDemoStatus
v1.9fa    : 64456

74 05 E8 ->
EB 05 E8

Based on @axdoomer's collection of hacks doom-patcher and extended to cover all versions. A disassembly extract is included to illustrate what this does. And what it does is replace the jump-if-zero operand with an unconditional jmp thus skipping the G_CheckDemoStatus check.

Share this post


Link to post

REMAP ANY1 KEY TO ANY OTHER

 

v1.9

Spoiler

899DD  ESC         1B   │   899F8  ENTER       71   │   89A14  ALT         B8
899DE  1           31   │   899F9  CTRL        9D   │   89A15  SPACE       20
899DF  2           32   │   899FA  A           61   │   89A17  F1          BB
899E0  3           33   │   899FB  S           73   │   89A18  F2          BC
899E1  4           34   │   899FC  D           64   │   89A19  F3          BD
899E2  5           35   │   899FD  F           66   │   89A1A  F4          BE
899E3  6           36   │   899FE  G           67   │   89A1B  F5          BF
899E4  7           37   │   899FF  H           68   │   89A1C  F6          C0
899E5  8           38   │   89A00  J           6A   │   89A1D  F7          C1
899E6  9           39   │   89A01  K           6B   │   89A1E  F8          C2
899E7  0           30   │   89A02  L           6C   │   89A1F  F9          C3
899E8  -           2D   │   89A03  ;           3B   │   89A20  F10         C4
899E9  =           3D   │   89A04  APOSTROPHE  27   │   89A23  HOME        C7
899EA  BACKSPACE   7F   │   89A05  ~           60   │   89A25  PGUP        C9
899EB  TAB         09   │   89A07  \           5C   │   89A26  NUMPAD-     2D
899EC  Q           71   │   89A08  Z           7A   │   89A28  NUMPAD5     35
899ED  W           77   │   89A09  X           78   │   8AC2A  NUMPAD+     2B
899EE  E           65   │   89A0A  C           63   │   8AC2B  END         CF
899EF  R           72   │   89A0B  V           76   │   89A2D  PGDN        D1
899F0  T           74   │   89A0C  B           62   │   89A2E  INS         D2
899F1  Y           79   │   89A0D  N           6E   │   89A2F  DEL         D3
899F2  U           75   │   89A0E  M           6D   │   89A33  F11         D7
899F3  I           69   │   89A0F  COMMA       2C   │   89A34  F12         D8
899F4  O           6F   │   89A10  PERIOD      2E   │
899F5  P           70   │   89A11  /           2F   │
899F6  [           5B   │   89A12  RSHIFT      B6   │
899F7  ]           5D   │   89A13  NUMPAD*     2A   │

 

 

v1.9u

Spoiler

8ABDD  ESC         1B   │   8ABF8  ENTER       0D   │   8AC14  ALT         B8
8ABDE  1           31   │   8ABF9  CTRL        9D   │   8AC15  SPACE       20
8ABDF  2           32   │   8ABFA  A           61   │   8AC17  F1          BB
8ABE0  3           33   │   8ABFB  S           73   │   8AC18  F2          BC
8ABE1  4           34   │   8ABFC  D           64   │   8AC19  F3          BD
8ABE2  5           35   │   8ABFD  F           66   │   8AC1A  F4          BE
8ABE3  6           36   │   8ABFE  G           67   │   8AC1B  F5          BF
8ABE4  7           37   │   8ABFF  H           68   │   8AC1C  F6          C0
8ABE5  8           38   │   8AC00  J           6A   │   8AC1D  F7          C1
8ABE6  9           39   │   8AC01  K           6B   │   8AC1E  F8          C2
8ABE7  0           30   │   8AC02  L           6C   │   8AC1F  F9          C3
8ABE8  -           2D   │   8AC03  ;           3B   │   8AC20  F10         C4
8ABE9  =           3D   │   8AC04  APOSTROPHE  27   │   8AC23  HOME        C7
8ABEA  BACKSPACE   7F   │   8AC05  ~           60   │   8AC25  PGUP        C9
8ABEB  TAB         09   │   8AC07  \           5C   │   8AC26  NUMPAD-     2D
8ABEC  Q           71   │   8AC08  Z           7A   │   8AC28  NUMPAD5     35
8ABED  W           77   │   8AC09  X           78   │   8AC2A  NUMPAD+     2B
8ABEE  E           65   │   8AC0A  C           63   │   8AC2B  END         CF
8ABEF  R           72   │   8AC0B  V           76   │   8AC2D  PGDN        D1
8ABF0  T           74   │   8AC0C  B           62   │   8AC2E  INS         D2
8ABF1  Y           79   │   8AC0D  N           6E   │   8AC2F  DEL         D3
8ABF2  U           75   │   8AC0E  M           6D   │   8AC33  F11         D7
8ABF3  I           69   │   8AC0F  COMMA       2C   │   8AC34  F12         D8
8ABF4  O           6F   │   8AC10  PERIOD      2E   │
8ABF5  P           70   │   8AC11  /           2F   │
8ABF6  [           5B   │   8AC12  RSHIFT      B6   │
8ABF7  ]           5D   │   8AC13  NUMPAD*     2A   │

 

 

v1.9f

Spoiler

8B1DD  ESC         1B   │   8B1F8  ENTER       71   │   8B214  ALT         B8
8B1DE  1           31   │   8B1F9  CTRL        9D   │   8B215  SPACE       20
8B1DF  2           32   │   8B1FA  A           61   │   8B217  F1          BB
8B1E0  3           33   │   8B1FB  S           73   │   8B218  F2          BC
8B1E1  4           34   │   8B1FC  D           64   │   8B219  F3          BD
8B1E2  5           35   │   8B1FD  F           66   │   8B21A  F4          BE
8B1E3  6           36   │   8B1FE  G           67   │   8B21B  F5          BF
8B1E4  7           37   │   8B1FF  H           68   │   8B21C  F6          C0
8B1E5  8           38   │   8B200  J           6A   │   8B21D  F7          C1
8B1E6  9           39   │   8B201  K           6B   │   8B21E  F8          C2
8B1E7  0           30   │   8B202  L           6C   │   8B21F  F9          C3
8B1E8  -           2D   │   8B203  ;           3B   │   8B220  F10         C4
8B1E9  =           3D   │   8B204  APOSTROPHE  27   │   8B223  HOME        C7
8B1EA  BACKSPACE   7F   │   8B205  ~           60   │   8B225  PGUP        C9
8B1EB  TAB         09   │   8B207  \           5C   │   8B226  NUMPAD-     2D
8B1EC  Q           71   │   8B208  Z           7A   │   8B228  NUMPAD5     35
8B1ED  W           77   │   8B209  X           78   │   8B22A  NUMPAD+     2B
8B1EE  E           65   │   8B20A  C           63   │   8B22B  END         CF
8B1EF  R           72   │   8B20B  V           76   │   8B22D  PGDN        D1
8B1F0  T           74   │   8B20C  B           62   │   8B22E  INS         D2
8B1F1  Y           79   │   8B20D  N           6E   │   8B22F  DEL         D3
8B1F2  U           75   │   8B20E  M           6D   │   8B233  F11         D7
8B1F3  I           69   │   8B20F  COMMA       2C   │   8B234  F12         D8
8B1F4  O           6F   │   8B210  PERIOD      2E   │
8B1F5  P           70   │   8B211  /           2F   │
8B1F6  [           5B   │   8B212  RSHIFT      B6   │
8B1F7  ]           5D   │   8B213  NUMPAD*     2A   │

 

 

Format: offset (in hex) - key - default value (in hex)

 

v1.0  77435 (-125A8)   │   v1.6          7FF6D (-9A70)
v1.1  74F11 (-14ACC)   │   v1.666/v1.7a  8436D (-5670)
v1.2  74B21 (-14EBC)   │   v1.8/v1.9     899DD
v1.4  7CC2D (-CDB0)    │   v1.9u         8ABDD
v1.5  7F86D (-A170)    │   v1.9f         8B1DD

And this is the list of offsets to the start of the keymap for all versions, sourced from the scantokey array (i_ibm.c).

 

The negative numbers are the difference between that version and v1.9. So if you want, for example, to find the offset for the tilde (~) key in v1.1 you take tilde's v1.9 offset (from the first table above) and subtract v1.1's number in parenthesis from it: 89A05 - 14ACC == 74F39. That byte's value should be 0x60. Change that to 0x71 to quit recording demos with, or to 0x09 to switch to the automap. And so on.

 

The array is 128 bytes long, with 82 key assignments; the rest is null bytes. Of the assigned keys five resisted all my attempts at remapping them:

89A06  LSHIFT      FE
89A24  UPARROW     AD
89A27  LEFTARROW   AC
89A29  RIGHTARROW  AE
89A2C  DOWNARROW   AF

Ditto for the rest of the NUMPAD keys, PRNTSCR and SCROLLOCK.

And then there's a peculiar case of the null byte immediately after the F10 key:

89A21  PAUSE/NUMLOCK 00

Changing that byte from 0x00 produces interesting results. For example, set it to 0x71. Now you can quit recording with the PAUSE key, with no pause added to the demo. Or you could use NUMLOCK, except that you'll need to press it twice if the NUMLOCK is ON. Set the byte to 0x09 and now switching to the automap will pause the game until you switch back to the normal view. Accessing the automap with the NUMLOCK key is even more bizarre: the first press makes the game alternate rapidly between the normal view and the automap; the second press settles the view on the automap. Another press and the flutter is back, etc. Worth a look, but probably too quirky for regular use.

 

Multiple keys can be set to the same action. To disable a key set its byte to 0x00. Watch out for unexpected side effects. Like, if you swap the pistol and the BFG keys then entering IDCLEV17 in D2 will take you to MAP12 instead of MAP17.

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
×