I am trying to reverse some DOS game in IDA pro (5.0 demo). I get stuck when it tries to load the overlay file. Is it possible to load the 2nd executable into the original namespace?

It has already setup the video, interrupt, and some jump tables for common routines.

I think I tried this years ago, and just dumped the full 1meg of ram via DosBox. It broke the segments etc however.

seg001:0672                 mov     ax, bx
seg001:0674                 sub     ax, offset string_of_space ;
seg001:0677                 mov     byte_108CA, al
seg001:067A                 mov     bx, offset param_block
seg001:067D                 mov     dx, cs:filename
seg001:0682                 mov     ax, 4B00h
seg001:0685                 mov     cs:saved_ss, ss
seg001:068A                 mov     cs:saved_sp, sp
seg001:068F                 int     21h             ; DOS - 2+ - LOAD OR EXECUTE     (EXEC)
seg001:068F                                         ; DS:DX -> ASCIZ filename
seg001:068F                                         ; ES:BX -> parameter block
seg001:068F                                         ; AL = subfunc: load & execute     program
seg001:0691                 cli
seg001:0692                 mov     ss, cs:saved_ss
seg001:0697                 assume ss:nothing
seg001:0697                 mov     sp, cs:saved_sp
  • 3
    Do you want to (static) analyze, or (dynamic) debug the file(s)? Since the 2nd program gets loaded by the dos exec call, it's being run in it's own context, and with a bit of luck, doesn't use the 1st one much, so you can just make a second project of it. – Guntram Blohm May 18 '14 at 14:47

Pending a native IDA solution, I could solve this for myself with a C program that used the following procedure:

  1. Read the base executable into memory;
  2. Read the overlay into memory. Note that this is a regular executable, in its own right.
  3. In the base executable, adjust the following EXE header items:
    a. set bytes_in_last_block to 0,
    b. add the blocks_in_file from the overlay to the base's,
    c. add the num_relocs from the overlay to the base's.
  4. Calculate the new executable size; this is the total number of blocks_in_file * 512 - original_header_paragraphs*16. You need this number for the new stack segment ss.
  5. The new header_paragraphs size - that is, the original one plus the relocations from the overlay - is going to be reloc_table_offset + 4*num_relocs. Make sure to round up to paragraph size, 16.

At this point the new header should be complete. Write it to a new file. The main executable's relocation table should be unchanged, and you can write it as well.

The overlay's relocation table then needs to be adjusted.

The relocation table itself contains a segment:offset pair for each relocation that points into the binary executable image to the position where a zero-based segment value is stored (i.e., the value for "the first segment" would be 0000h, and when loaded, the actual segment is added to this value).

Since you added data to the executable part, you need to adjust the linear offset into the file; add the size of the original executable code (which should be rounded upwards to a 512-byte long page). Read the segment at this position, add the size of the original executable code in paragraphs, and write it back. Then add the size of the original executable code to the segment part of the original relocation. Do this for each relocation in the overlay's table.

After adjusting the overlay's relocation table, write this to your output file, immediately followed by the original executable's data (which is totally unchanged). Then add the changed overlay data to the output file.

One thing to note is that the executable I tested with (only one!) stored a very small stack in the executable as well. I cannot tell if that's usual or not; I had to remove the saved stack from the 'main' code, and add it again after the combined main code + overlay code.

Important note!

This procedure worked for me because the program I tested it on uses dynamically-loaded overlays. The main program loads the overlay and copies a number of data and code addresses into the main dseg segment. After that, it calls the overlaid code through these pointers. The overlaid code used ds "as usual", it simply used the main's dseg.

Of course, now the "initialization" routine did not get called, these pointers to the overlaid routines are uninitialized and you have to find out manually what gets copied to where. But at least all code can be loaded into IDA in one go.

Will it still run?

Of course it will. The main code calls LOAD/EXEC, the overlay gets loaded, pointers get copied, and All is Well. The only thing is that the main executable is suddenly a whole lot larger .. but that extra part is never seen nor used by the original code. (Naturally, the main executable may now be so large that there is no more memory left to load overlays.)
The purpose of this exercise was not to remove the need to load the overlays, only to be able to disassemble the entire thing as one binary.

You can download the C source here: http://www.jongware.com/binaries/combine_exe_ovl.zip
- be warned, it's a pretty dirty hackish piece of code, so it comes with no warranties.

Your Answer

