SkillAgentSearch skills...

F1DP

An engine patcher for the MS-DOS version of Fallout 1 including patches from Crafty's sFall1/sFall, High-Res patch, TeamX, and Fallout Fixt

Install / Use

/learn @Edw590/F1DP
About this skill

Quality Score

0/100

Supported Platforms

Universal

README

Fallout 1 DOS Patcher (F1DP)

An engine patcher for the MS-DOS version of Fallout 1 including patches from Crafty's sFall1/sFall, High-Res patch, TeamX, and Fallout Fixt

Download

To download, go to Releases.

Introduction

Hi everyone. I've decided to attempt to port all patches made to the Windows version of Fallout 1 to the MS-DOS one. Some Windows patches are DLL mods, and even if DOS recognizes DLLs with help of extenders or whatever it is, the DLL code is for the Windows version only (but anyway, I've no idea how to load and even program a DLL, at least yet). So I've went around that, and this way, those who need to play with the DOS version like me for whatever reason can enjoy the patches that the Windows version players can.

This repository contains the code for everything involved with F1DP:

  • the Installer, in C (a CLion project - it was written first in Go, which is much less troublesome, but I rewrote it in C so that I can compile with Watcom and run it on DOS);
  • the Patcher, in C and Inline-Assembly (a CLion project);
  • and the Loader, in Assembly (a file compiled from Sublime Text 3 using MASM 9.0 and using the compilation assistant and Sublime Text stuff from this repository of mine: https://github.com/DADi590/Chrome-Dino-Game-in-Assembly).

Small note about the naming: I know it's kind of awful. But I'm not sure of a better naming. The Installer installs only the Loader into the game EXE. The Patcher comes in its own file. But the project is (or was) called Fallout 1 DOS Patcher (best name I came up with). So I've reduced the name to F1DP, and now I can say F1DP Patcher more normally (don't think too much about it... xD).

History of ideas for this to work

Notes:

  • The versions are in the opposite order - the first is in the end.
  • They are big texts, but which explain everything that went through my head to get everything to be how it is, however that is.

HT Editor

Btw, a very useful program I used to analyze the Fallout EXE file: HT Editor. Along with random documentation I found about the LE EXE header, the program allowed me to decently analyze and edit the file without 34 headaches of doing it on a hex editor (also it has more information that I couldn't find on the documentations I found about the header - there's much more on LX than on LE). Love the program. Links for it: https://hte.sourceforge.net or https://github.com/sebastianbiallas/ht. I thank the author for it!

<details> <summary><h3>Second version</h3></summary>

Carrying on from the last thing I said on the first version, I did find out a way to go around editing the relocations table. I got the idea from @xttl user from the Doomworld forum, more precisely this thread: https://www.doomworld.com/forum/topic/86380-exe-hacking (thank you infinitely for posting your knowledge there). This was an AMAZING find and I loved the idea. The idea there is to load a BIN file with binary instructions, then jump to it and execute the instructions. The only thing permanently patched in the EXE (by editing the EXE with a hex editor) is the loader. When the game starts, it loads the patch file and executes the instructions. After that, it comes back to the game and unloads the patch from memory. Inside the patch, there could be only simple patches, like patching a number or a call to NOPs, for example. No adding new functions or strings or other things. There could not be any strings on it or global variables. Nothing outside the functions. So an idea I had first to go around having no strings was to allocate on the stack space for the characters and then assign char by char, index by index manually --> awful, but worked 😂.

Still, I tried to think on ideas to improve that, and seems all worked! Spoiler: the patches execute like a DLL and I can patch dynamically, and go from the EXE to the patch and back to the EXE and mention strings in the patch and modify them and whatever is needed, just like is done with Crafty's sFall1 mod. Took me some work to get to this though xD. I'll just more or less copy what I wrote on the mentioned forum.

Patch explanation

The first 12 bytes of the BIN file are to store the version of the patch (or the type, I haven't seen too much of that yet), and code and data segments address (these last 2 are put there by the loader - the loader must also provide in a register the address of the allocated code block to store the BIN file's contents). The last 4 bytes of the 16 are for anything else I'd need. The rest is a full copy of the Fallout1DOSPatches LE EXE starting from the code segment until the end of the file --> copy and paste, just that.

The code generated by the compiler for the C project comes with absolute references, expecting to be corrected when the EXE is loaded (relocations). So I can't rely on ANY absolute references produced by the compiler. Then the idea is to patch those references before they are needed! The patch patches itself with correct values only known at run-time (reads its own memory and patches it self XD ahahah), and then does whatever it wants with the new values - like patching the EXE with CALLs and JMPs to inside the patch...!

How is this done? I use Luck! So far my points have been very high on it! I use something I called a Special Number, which is a sequence of 4 bytes that can never appear anywhere else than where I put them in code myself. For example, there's 0x78563412 (which is 12 34 56 78 in Little Endian, the one used on x86). That one is used for the Loader to know where the code begins (4 bytes after finding that sequence of bytes on the file). But the real usage of these numbers is to replace them as I mentioned in the other paragraph. So there are variations, like 0x79563412 (there are more though), which is replaced by the code section address of the game each time the Patcher starts. How does it replace all of the occurrences without replacing the one that is used to compare? I've put a parameter on the function which is a constant: 0x70563412, and internally it uses offsets to that constant value. So 0x09000000, which summed with the constant gives the 0x79563412, which is then used to compare. Luckily Watcom doesn't optimize that even with all optimizations at maximum. If these byte sequences appear anywhere else, code corruption will happen, so Luck is involved with this idea ahah. It kind of seems to be some sort of relocations, but without a table (and seems to be w orking very well so far!).

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 an idea I had of main function parameter to know which sub-function 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 (with "%d", also in the data segment) in 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 (like on Craft's sFall1) 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! I load, let it be loaded, access stuff from inside its memory space, call its functions with references to the EXE's functions, whatever else is needed. At least for a beginner on these things seems to be wow ahahah.

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 (the block one - the base of everything else) 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 (2 days without touching on it, I think, while I'd find about these things).

Update: now the loader is writing the BIN file length on the 4th 4 bytes of the BIN file (only in memory, nothing permanent). That's required to know up to what address to look up when the pathces patches itself. The patcher patches itself as soon as it starts now (now I mean really when it starts - a direct call after the jump), and the rest of the code has all the values needed already ready for use. That way I don't need to pass the addresses as parameters to every function of the file. Seems that all really works, so cool!

</details> <details> <summary><h3>First version</h3></summary>

How I've been doing this

I've been checking this repository: https://github.com/Aramatheus/sfall_1. It has the sFall1 1.20 source with small modifications from Sduibek (Fallout Fixt's creator). If this one gets working well, I go over to sFall1 1.3 entirely by Crafty and then (or right to) 1.7.6. There's also version 1.8, but there's no

View on GitHub
GitHub Stars20
CategoryDevelopment
Updated1mo ago
Forks2

Languages

C

Security Score

95/100

Audited on Feb 4, 2026

No findings