Debugging and Patching Star Trek Armada I – Part 1 of 3

Making Armada Work On Modern Systems
(a.k.a. A Partial Guide to Ollydbg)

Being a professional in the Computer Science field, I don’t have that much time for video games anymore. As a result, when I choose to play games, I typically prefer to take a trip down memory lane and play something from my childhood. One of my favorite games is Star Trek Armada I. Unfortunately, Star Trek Armada I is rather poorly written (from a reliability standpoint) and generally doesn’t play very well (if at all) on most modern Windows systems. I could switch over to Star Trek Armada II, but I much prefer the original game for various design reasons.

Fortunately, modern IT professionals (and amateurs, in my case) are armed with a swath of debugging and reverse engineering tools, with which we can correct some of Star Trek Armada’s shortcomings. So, without further ado, let’s get started!

Platform Specs & Prerequisite Tools

My system’s specifications:

  • Windows 7 Ultimate x64 SP1
  • Dell XPS 1640 (yes, pretty old now, I know)
    • Intel Core 2 Duo P8600 (2.4 GHz)
    • 4 GB RAM
    • ATI Mobility Radeon HD 3670
  • A secondary monitor (necessary for fullscreen debugging).

I installed the following tools before beginning my little reverse engineering escapade:

  • Notepad++
  • DirectX SDK (I used the June 2010 version) – Gives us the DirectX Control Panel which can be helpful for enabling multi-monitor debugging.
  • Ollydbg 2
  • Tiny Hexer

You’ll only need these tools if you are following along. I’ll make all of my final patches available (as a diff) at the end of the “part 3” blog entry.

For the Record – Installing Star Trek Armada

I took the following steps to install Star Trek Armada:

  1. Installed Star Trek Armada I from CD. The installer worked “as-is.”
  2. Patched STA to version 1.2 using the Armadaupdate.exe updater file.
    1. File size: 3868183 bytes
    2. sha1 hash: a0621a7a431e60138893492d67425251c36df7e5
    3. sha256 hash: f3aa1bb6236e9709b05afa8a66ba545b22553f87a5d985c2df17ebef67d9a9e6
  3. Installed the STA map editor file by extracting Qedit from the Armada file and copying it to the STA installation folder.
    1. (Zip) file size: 70723 bytes
    2. (Zip) sha1 hash: 00114b10dd5f35c78a4ec78a3692e7f0576f2148
    3. (Zip) sha256 hash: 18a049760510c5fe2a1b555f72fa8d7181f67d655c33301a561a9d4a34de2cdb
  4. Installed STA_MapEdit.exe into the STA installation folder. This is a simple custom-built program that helps launch the STA map editor with the correct flags. If you’re following along, you can safely skip this step.
    1. file size: 1703936 bytes
    2. sha1 hash: 2170c8ad9e92ff5ababc86ae6356cd02c8993d28
    3. sha256 hash: beeacf1cce813ad6ae21aef4082897cadbd19d608b716a48fb6df030767f60a1
  5. Copied in a modified RTS_CFG.h config file that improves the end-user experience. Target: STA installation folder.
    • Modified value of “float OVERVIEW_INIT_ZOOM” to 1.0
    • Modified value of “float OVERVIEW_INIT_HEIGHT” to 700.0
    • (These two entries start the game zoomed out to its maximum point; helpful if your keyboard doesn’t have a number pad.)
    • Added new line “int GIVE_ALL_MISSIONS=1;” to end of file.
    • (This entry enables all missions in the game.)
  6. Copied in the gbholeg.odf file to the <STA Installation>\Addon folder. (This un-hides the “cloak” power icon on the Romulan Phoenix ships.)

With the above complete, I was ready to play!

Fix #1 – “Insufficient Memory”

Running Armada.exe, I was quickly greeted with the encouraging “splash” screen of the game loading, but then received the following error:

Clicking OK, the game quit. Bummer.

From experience, I know that these kinds of checks are caused by the typical programming error of using the C++ “int” data type instead of the C++ “size_t” data type when checking the amount of available RAM in the system. Since my system has more than 2 GB of available RAM (the maximum positive size of the int data type), the memory check code will return a negative number instead of a positive one. Programmers: take heed; you should ALMOST NEVER be using signed data types.

So, let’s break into Ollydbg and see if we can find and get rid of this buggy check. Steps taken:

  1. Ran Ollydbg as administrator.
  2. Opened Armada.exe.
  3. Ran Armada.exe inside Ollydbg.
  4. Upon error message box appearing, clicked the “pause” button inside Ollydbg.
  5. Clicked the OK button in error message box. Ollydbg regained the now-paused program at the next instruction after the MessageBoxA Win32 API call:


Looking at the disassembly of the code near the current instruction pointer, we can see the error message text being loaded onto the stack as a parameter, the call to MessageBoxA(), and finally the call to the Microsoft C Runtime’s exit() function (which is terminating the program). Also, notice that the particular subroutine containing these instructions is fairly short and that the call to MessageBoxA is (relatively) near the beginning of the routine. As a result, it’s likely that the faulty decision logic is actually one routine earlier on the call stack. So, let’s use ollydbg’s stack window to jump to one routine earlier in the program:



Aha! Now we are getting close. Notice the call to the GlobalMemoryStatus() function near the start of this routine. This is likely where the faulty decision logic exists.

Now, we COULD take the time to “fix” the broken logic. Alternatively, we can be lazy and simply patch out the error routine. Let’s be lazy!

We’ll patch out “PUSH 0”, “CALL 00442EB0”, and “ADD ESP, 4”. This requires using the “assemble” feature of Ollydbg multiple times until all bytes of these 3 instructions are replaced with 0x90 (NOP).


Now, let’s export our changes from memory to a new Armada.exe version!



Finally, we copy our exported file into to Armada installation folder and we’re done!

Fix #2 – System Path Stack Trash

Okay, with our fix #1 in place, let’s give this another go!


Well, the loading process made it a bit further this time; the splash screen disappeared and the screen flickered multiple times prior to the error appearing. Let’s re-run the game inside Ollydbg and see if we can figure anything out. (Note: For this to work, it was necessary to enable a second monitor so that the game could go fullscreen while Ollydbg was running.)

Breaking in at the right time with Olly is easy in this case – we simply wait for the game to crash and Olly will pause execution for us:


Hmm. This is strange. The disassembly (code) view is entirely empty. This means that Ollydbg is really confused about what’s going on here. Let’s look at the stack more closely. (In the above screenshot, I’ve stretched the bottom stack viewer pane over the top disassembly view.)

Notice the “Access Violation when reading 0x62696c5c” error message. Looking at the stack, we can see this same value immediately above the current stack pointer. Most probably, a RET instruction was executed that caused the program to attempt to return to this memory location which caused the access violation. Come to think of it, Olly is having trouble providing ANY information about the stack…why could that be?

Notice that the stack currently contains a set of readable strings – the current system path!  At this point, we can guess that an overflow of a stack-stored buffer is occurring due to excessive length of our currently-configured system path. This is certainly bad programming on the part of the STA developers and stems from an incorrect assumption that the system path will not exceed a certain character length. While we could attempt to (partially) correct the program by increasing the stack space allocated to the path buffer(s) on the stack, the easiest fix is to remove some unnecessary stuff from our system path to make it fit in the miscreant buffer.

The change made to our system, we log out and log back on (necessary to refresh the path in running executables). Running Armada.exe again, we are greeted with the main menu of the game!


Part 1 – Conclusion

In summary, with a little knowledge of debugging and the help of the great Ollydbg, it’s actually pretty easy to get old games working on modern systems. In part 2 of this mini-series, we’ll take our debugging efforts one step further to correcting the game’s faulty timing logic!  In part 3, we’ll enable multiplayer saves and I’ll provide a copy of the fixes made in all three articles of this series.

One comment

  1. due date says:

    For some reason QueryPerformanceCounter calls seem to be being optimized away… Er, hey compiler, I need that result!

Leave a Reply

Your email address will not be published. Required fields are marked *