Roll Your Own Error Messages

This forum is for discussions on how to edit what can not be edited through the txt files, needless to say this isn't about battle net hacking.

Moderators: Nefarius, Havvoric

Post Reply

0
No votes
 
Total votes: 0

User avatar
Myhrginoc
Retired Admin
Cherub
Posts: 12062
Joined: Sat May 25, 2002 7:28 am
Location: Percussion U

Hand-picked

Roll Your Own Error Messages

Post by Myhrginoc » Mon May 27, 2002 9:16 pm

While trying to wrestle the extra DLL into shape, I ran across an interesting technique. Fog.dll is, among other things, the exception handler for D2. You can have your code produce D2-style error messages, and even record them in the debug file for you! This is useful if you want to test for out-of-bounds conditions and function call failures (especially system functions).

The function Fog #10023 (and several similar functions) sets it all up for you. You need Ollydbg for this, a PE header dump utility, and perhaps the hex editor of your choice. I used Matt Pietrek's DumpPE utility and Hex Workshop, but there are several out there for each application.

Use the PE header dump utility to make a listing of the DLL's PE header. Look up the Image Base, this number is the preferred loading address for the DLL. All offsets are added to this number to get the absolute memory location if the DLL is loaded without relocations. (Example: for D2Game.dll it is 0x6FC30000.) We will need this number later.

Now we need to find where the DLL stores the import address for Fog #10023. Scan down the list until you get to the Import Address Table. Look for the line that gives you an offset for Fog #10023. In D2Game v1.09d the offset is 0xD0BD0. Add that number to the image base. In our example, 0x6FC30000 + 0xD0BD0 = 0x6FD00BD0.

The next thing we need to find is the jump table location for the DLL imports. In Blizzard DLLs this is usually located in a block of asm code where every line is FF 25 a.k.a. jmp dword ptr ds:[location]. In D2Game v1.09d this jump table begins at offset 0xC49B0. Scrolling down the list we find the jump for Fog #10023 starts at offset 0xC5B5C. Add this offset to the image base. Again with our example, 0x6FC30000 + 0xC5B5C = 0x6FCF5B5C. This is the number we will call when we ask for the error-handling function.

Now look for the Section Table in the PE dump. We want the section named ".rdata", to get three important numbers. The first number is the actual space used by the existing data ("Virtual Size"). The second number is the offset where this data begins ("Virtual Address"). The third number is the file space reserved for this section ("Raw Data Size"), it should always be larger than the first number.

We will be adding new data in the form of string messages in the space between the end of data and the beginning of the next section. To do this, add the first and second numbers together, then start your error messages there. Make sure there is at least one 00 byte between your data and any original data, and you start at the offset equal to the sum of those two numbers—even if there are a bunch of 00 bytes before that offset. Type in the ASCII codes for two lines, with a trailing 00 after each line. (D2 uses null-terminated strings.) Make note of the offset for the first character of each line! Example error message:

Code: Select all

C:\Myhrginoc\Projects\Diablo II\D2Extra\D2Extra.asm
Load != 0x6F700000  DLL Failed to load at required base address.
You will note I didn't put in any line numbers, that comes later. The next step is to find the offset of your last trailing 00 byte. Add one to that number and write it down. Go back to the PE header, and find that first number. You will change this number to be the result of subtracting the offset you wrote down and the second number. So if you started with the three numbers being 0x6033, 0xD0000, 0x7000, and you added 170 bytes of message text, the new first number would be 0x60DD.

You now should have two offset number for your error text and the image base number at hand. Add each offset separately to the image base using hex arithmetic to get the absolute values of the error text pointers.

Start a game and attach Ollydbg to it. Check that the various addresses you calculated do indeed point where you think they should. In particular, note that the jump table location now shows Fog.#10023 instead of some address.

Now go to the code section you want to error-trap. (I am assuming this is your own custom code.) After whatever trap test you make, put this in the exception path:

push {dword} <---------------------------------------- see below
push {pointer to first error text line}
push {pointer to second error text line}
call {address of jump table instruction for Fog #10023}

So far I haven't said boo about the line numbers that come with D2 error messages. Line numbers are pretty much irrelevant since we aren't referring to the source code. You can use any valid dword number you want, and that is what get pushed first in the code segment above.

What does this look like for D2Game.dll? Something like:

push 13
push 6FD06033
push 6FD0607E
call 6FCF5B5C <--- gets changed by Ollydbg to call <jmp.&fog.#10023>

One strong caution about relocations. D2 DLLs are based at very unusual locations and almost never relocate. So it is relatively safe to directly address locations with absolute addressing. But if your DLL does get relocated, absolute addresses get hosed. There is another section in the dll called .reloc, this contains the data for all fixups Windows does to a relocated DLL. But we just added two references (the error text pointers) which will not appear in the relocation table! So if your DLL gets relocated, the resulting text would be garbage. Or would it? It so happens, when Ollydbg assembles an instruction for you, it does some behind-the-scene calculations on offsets. So when you look at your new code, the only references you have to fix up are indirect references such as generated by "dword ptr ds:[6FD00BD0]" operands. And in this case, happily, we didn't make any. But if the function we wanted was not in the jump table (such as a system call) then we would have to make an indirect call to the Import Address Table ourselves, and we would need a fixup added to the relocation table.

Postscript: Here is a link to a thread on what each DLL does in the system. It doesn't mention that fog.dll is also the exception handler.
Do the right thing. It will gratify some people and astonish the rest.
~ Mark Twain
Run Diablo II in any version for mods: tutorial
The Terms of Service!! Know them, abide by them, and enjoy the forums at peace.
The Beginner's Guide v1.4: (MS Word | PDF) || Mod Running Scripts || TFW: Awakening

User avatar
Alkalund
Retired Admin
Throne
Posts: 7597
Joined: Sun May 26, 2002 5:54 pm
Location: Toronto, Ontario, Canada
Contact:

Hand-picked

Post by Alkalund » Wed May 29, 2002 4:08 am

Heheh Myhrginoc, I just wanted to say that I read this "horror", the whole thing :) ;)

All I can say is that this looks very... interesting, and useful. Sorry for the lack of technical comments, but almost all of my assembly knowledge is based on 'absorbing' bits of knowledge here an there, I'm assimilating things slowly here... :)

Jarulf
Junior Member
Champion of the Light
Posts: 346
Joined: Sun May 26, 2002 9:20 am

Hand-picked

Re: Roll Your Own Error Messages

Post by Jarulf » Tue Jun 04, 2002 10:17 am

[quote=Myhrginoc"]
Postscript: Here is a [url=https://d2mods.info/ubb/Forum33/HTML/000044.html][color=cyan]link[/color][/url] to a thread on what each DLL does in the system. It doesn't mention that fog.dll is also the exception handler.[/quote]

fog is perhaps best described as a dll where they keep common function functions that is not game related. Other things you find there are bit manipulating functions (to pack data on bit level as oposed to byte level), memory allocation and deallocation functions (fog.273d for example is a memory allocation function and I think 273e (or 273c don't remember which one) frees such allocated memory). There are probably other similary non game related stuff in there used by the rest of the code. The file probably got named by the sme guy that named storm or something :)

User avatar
Myhrginoc
Retired Admin
Cherub
Posts: 12062
Joined: Sat May 25, 2002 7:28 am
Location: Percussion U

Hand-picked

Post by Myhrginoc » Wed Jun 05, 2002 12:42 am

No doubt, there are many more functions than the ones that pop up error messages. One of these days I need to build a function inventory. But first, the extra dll! This project has gone on far too long already.

By the way Jarulf, does BB code mess up on your browser? Otherwise, you might go into your profile and turn BB code always on. Then you won't show all of our tags when you quote us.
Do the right thing. It will gratify some people and astonish the rest.
~ Mark Twain
Run Diablo II in any version for mods: tutorial
The Terms of Service!! Know them, abide by them, and enjoy the forums at peace.
The Beginner's Guide v1.4: (MS Word | PDF) || Mod Running Scripts || TFW: Awakening

User avatar
Myhrginoc
Retired Admin
Cherub
Posts: 12062
Joined: Sat May 25, 2002 7:28 am
Location: Percussion U

Hand-picked

Post by Myhrginoc » Mon Nov 11, 2002 4:55 am

I am going to return to an old topic for an interesting addition I came up with today. As we all know, there are many assertions scattered throughout the code that give cryptic advice at best. It would be really helpful if the assertion bothered to let you know which record from a bin (txt) file might be causing trouble. It so happens it is not difficult to add that information to a new assertion, although adding it to existing assertions requires moving code around.

Code: Select all

6F7AB300    8BDC                MOV EBX,ESP
6F7AB302    83C3 08             ADD EBX,8
6F7AB305    68 996E7F6F         PUSH 6F7F6E99                   ; ASCII "].index <= message_table.EOF"
6F7AB30A    52                  PUSH EDX
6F7AB30B    68 846E7F6F         PUSH 6F7F6E84                   ; ASCII "filter_table.record["
6F7AB310    68 B66E7F6F         PUSH 6F7F6EB6                   ; ASCII "%s%u%s"
6F7AB315    53                  PUSH EBX
6F7AB316    FF15 14D2DB6F       CALL NEAR [DWORD DS:<&USER32.ws>; USER32.wsprintfA
6F7AB31C    83C4 14             ADD ESP,14
6F7AB31F    68 99B20A00         PUSH 0AB299
6F7AB324    68 006E7F6F         PUSH 6F7F6E00                   ; ASCII "C:\Myhrginoc\Diablo II\D2Extra\MessageUnit"
6F7AB329    53                  PUSH EBX
6F7AB32A    E8 3F550000         CALL 6F7B086E                   ; JMP to Fog.#10023
6F7AB32F    83C4 0C             ADD ESP,0C
6F7AB332    6A FF               PUSH -1
6F7AB334    FF15 CC6F7F6F       CALL NEAR [DWORD DS:6F7F6FCC]   ; D2Lang.6FC14999
In this sample, which is for a new function in D2Extra, I am modifying the standard assertion to include the record number in the bottom line. The code works like this: first start by assigning a buffer pointer (in EBX here, but the method isn't important). Then split your bottom text line and provide a format string, and pass these pieces to wsprintfA. Take the resulting string and run it through Fog.10023 as shown previously. Here I have inserted a record number, stored in EDX, which sits in the middle of the error line. So I cut the line in half; the format string %s%d%s shows how the number (%d) sits between two strings (%s). Now I borrow the call to wsprintfA from D2Common, since D2Extra doesn't have it already, and that function can be indirectly referenced at D2Common.6FDBD214. I then feed the output buffer (EBX) to the Fog.10023 call. Finally, I borrow an internal call from D2Lang.dll to get the exit code, since D2Extra doesn't have the Visual C++ Runtime Library. The result looks like:

Assertion Failure
Location : C:\Myhrginoc\Diablo II\D2Extra\MessageUnit, line #701081
Expression : filter_table.record[3].index <= message_table.EOF


indicating in this case that the third record has a problem.
Do the right thing. It will gratify some people and astonish the rest.
~ Mark Twain
Run Diablo II in any version for mods: tutorial
The Terms of Service!! Know them, abide by them, and enjoy the forums at peace.
The Beginner's Guide v1.4: (MS Word | PDF) || Mod Running Scripts || TFW: Awakening

Post Reply

Return to “Code Editing”