Saturday, May 19, 2012

Obstinate Overlays

I came to find out I wasn't quite as thoroughly done labeling all the functions in Legend of the Red Dragon assembly as I thought.  As I was going through the code in more detail, I found a call to a function in what looked like another broken stub.  I thought no problem, it must just link to one of the functions which I've already labeled, since I'd gone through all of the overlay segments already.  I just needed to trace down which function it was and create the JMP manually like before.

Nope!

After a bit of poking around, it turned out that the segment in which this Turbo Pascal stub was wanting to jump into wasn't loaded into IDA at all.  This meant somehow I had to manually load this segment in.  Luckily you can do that, with the Additional Binary File in the Load File menu.  First I had to find the unmangled Turbo Pascal stub in the EXE, since the stubs IDA can't straighten out aren't always the same as the original data in the EXE anymore.  Once that was found, I could calculate where the segment was in the LORD.OVR overlay file that I needed.  I then used this offset and length to load the section into IDA that I needed.

After loading this, I still had to create the segment again so that I could set the base address, which you apparently can't do when creating the segment in the Additional Binary dialog.  But if you make a new segment for the same memory area then it just replaces the other one, basically.  Then I had to set the assumed data segment.  But even after doing this, the segments in the Program Segmentation tab don't display DS properly.  So I dunno how to fix that, although it doesn't seem to matter.  I think that's just the default DS.

Then came the next challenge: the relocations.  I quickly noticed that there were calls all red and not linking to anywhere else.  I knew immediately that it was because there were no relocations applied, but I just wasn't sure how to go about fixing it.  My first step was to go back to the Turbo Pascal stub from the EXE and determine the size of the relocation section in the overlay (which is always directly below each segment).  I extracted that, and started trying to match up the first relocation to the first CALL in the assembly via IDA's hex editor.  Matched up perfectly.  Then I realized that I actually only needed to change the segment of each call manually to add 0x1000 to them, since that's IDA's overall base address or whatever.  But when you realize just how many calls you're going to have to manually set, you see what a huge pain in the ass that's about to become.

So I did some looking into the IDC script language which IDA uses.  Two functions are useful here:  Word(), and PatchWord().  I tested it out by manually putting together a script command to patch the first segment address to add 0x1000 to it, and it worked fine.  So, I wrote a little C app to convert the relocation table from the overlay into an IDC script, and pasted the lines in several at a time.  Worked like a charm!

Then I found ANOTHER broken stub and realized I was going to have to do this all over again.  So I opted to make my life a little easier.  I wrote another C app to scan the LORD.EXE and locate all of the overlay stubs, then using that information, extract each segment and relocation table into separate binary files, while printing out code and relocation sizes and all that as it goes.  I was then able to easily import the code chunk I needed, parse the relocation binary with my other little C app to make the relocation script, patch it, and done.  That segment went in much quicker.

I used my stub finder to determine that every stub was now in fact added into IDA.  So I proceeded to label those few functions which got added (related to DarkCloak Tavern as it turns out) and can now say I have nearly all of the game's assembly processed/labeled/etc.  Again.

This also indirectly resulted in setting me on a path to determine what a couple more of the settings in PLAYEXT.DAT are specifically, so it wasn't all bad!


p.s. The alternative to writing the relocation-to-IDC-script utility would have been one to just patch the segment directly before inserting it.  But since I'd already manually inserted the first one straight out of the overlay, I opted to just fix what was already there than try to do it again.  This was before I realized I was in fact going to have to do it a second time anyway for the other segment that was missing!

No comments:

Post a Comment