Solved offsets for eqgame.exe 09-09-2003 import to IDA

A forum for feature requests/discussions and user submitted patches that improve MQ2

Moderator: MacroQuest Developers

Lax
We're not worthy!
We're not worthy!
Posts: 3524
Joined: Thu Oct 17, 2002 1:01 pm
Location: ISBoxer
Contact:

Solved offsets for eqgame.exe 09-09-2003 import to IDA

Post by Lax » Fri Oct 03, 2003 9:26 pm

There are several thousand offsets solved!

Download: http://medlem.spray.se/eqmule/eqgame-9-9-2003.zip
Extract .IDC file to some directory.
Run IDA, load eqgame.exe from 9-9-2003
Hit F2 to run IDC script (or select from file menu)
Load .IDC file
Wait as it completes (might take a minute or two, but not too long)

and you there you have the currently solved offsets!
Lax Lacks
Master of MQ2 Disaster
Purveyor of premium, EULA-safe MMORPG Multiboxing Software
* Multiboxing with ISBoxer: Quick Start Video
* EQPlayNice, WinEQ 2.0

Lax
We're not worthy!
We're not worthy!
Posts: 3524
Joined: Thu Oct 17, 2002 1:01 pm
Location: ISBoxer
Contact:

Post by Lax » Sat Oct 04, 2003 8:51 am

If nobody comments I'll keep it to myself next patch ;)
Lax Lacks
Master of MQ2 Disaster
Purveyor of premium, EULA-safe MMORPG Multiboxing Software
* Multiboxing with ISBoxer: Quick Start Video
* EQPlayNice, WinEQ 2.0

User avatar
ap50
a snow griffon
a snow griffon
Posts: 425
Joined: Sun Aug 18, 2002 2:29 pm

Post by ap50 » Sat Oct 04, 2003 11:04 am

Insert suitable Image here.

Just gotta find a copy of IDA now to have a look.
[color=yellow][size=92][b]Just because you're paranoid, it doesn't mean everyone isn't out to get you![/b][/size][/color]

Amadeus
The Maestro
The Maestro
Posts: 2036
Joined: Sat Jun 29, 2002 3:51 pm

Post by Amadeus » Sat Oct 04, 2003 11:53 am

Lax,

That's incredibly cool and neat and I'm about -| |- far from understanding what I'm looking at ;)

Maybe we could take an example....

CBuffWindow_Activate() is at offset 00401DE9 and length 0000003A according to the functions window.

now in the IDA view I see this:

Code: Select all

.text:00401DE9 ; ¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦ S U B R O U T I N E ¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦
.text:00401DE9 
.text:00401DE9 
.text:00401DE9 CBuffWindow__Activate proc near         ; CODE XREF: ExecuteCmd+2031p
.text:00401DE9                 mov     eax, __pctype
.text:00401DEE                 test    eax, eax
.text:00401DF0                 jz      short locret_401E22
.text:00401DF2                 cmp     byte ptr [eax+138h], 0
.text:00401DF9                 jz      short loc_401E07
.text:00401DFB                 mov     edx, [eax]
.text:00401DFD                 mov     ecx, eax
.text:00401DFF                 call    dword ptr [edx+84h]
.text:00401E05                 jmp     short loc_401E17
.text:00401E07 ; --------------------------------------------------------
.text:00401E07 
.text:00401E07 loc_401E07:          ; CODE XREF: CBuffWindow__Activate+10j
.text:00401E07                 call    CStoryWnd__ShowAuto
.text:00401E0C                 mov     ecx, __pctype
.text:00401E12                 call    CChatManager__Activate
.text:00401E17 
.text:00401E17 loc_401E17:           ; CODE XREF: CBuffWindow__Activate+1Cj
.text:00401E17                 mov     ecx, __pctype
.text:00401E1D                 jmp     CSidlScreenWnd__StoreIniVis
.text:00401E22 ; --------------------------------------------------------
.text:00401E22 
.text:00401E22 locret_401E22:       ; CODE XREF: CBuffWindow__Activate+7j
.text:00401E22                 retn
.text:00401E22 CBuffWindow__Activate endp

So....what now? Or, maybe you could just provide an example with a subroutine that you KNOW does something cool. Or, I suppose I could check in the MQ source as well with some of the assembly type functions that we already have.. ...but, would be interesting to see something done brand new from this new incredible resource!!


or...maybe this one would be a bit less complex than the one before as an example:

Code: Select all

.text:0045F87A ; ¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦ S U B R O U T I N E ¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦
.text:0045F87A 
.text:0045F87A 
.text:0045F87A EQPlayer__Levitating proc near   ; CODE XREF: EQ_Character__RemovePCAffectex+26Ep
.text:0045F87A                 cmp     byte ptr [ecx+16Ch], 0
.text:0045F881                 jnz     short loc_45F8A0
.text:0045F883                 mov     ecx, [ecx+120h]
.text:0045F889                 test    ecx, ecx
.text:0045F88B                 jz      short loc_45F8A0
.text:0045F88D                 push    0
.text:0045F88F                 push    1
.text:0045F891                 push    39h
.text:0045F893                 call    EQ_Character__TotalSpellAffects
.text:0045F898                 test    eax, eax
.text:0045F89A                 jz      short loc_45F8A0
.text:0045F89C                 xor     eax, eax
.text:0045F89E                 inc     eax
.text:0045F89F                 retn
.text:0045F8A0 ; -----------------------------------------------------------
.text:0045F8A0 
.text:0045F8A0 loc_45F8A0:         ; CODE XREF: EQPlayer__Levitating+7j
.text:0045F8A0                                         ; EQPlayer__Levitating+11j ...
.text:0045F8A0                 xor     eax, eax
.text:0045F8A2                 retn
.text:0045F8A2 EQPlayer__Levitating endp
.text:0045F8A2 
.text:0045F8A3 

Lax
We're not worthy!
We're not worthy!
Posts: 3524
Joined: Thu Oct 17, 2002 1:01 pm
Location: ISBoxer
Contact:

Post by Lax » Sat Oct 04, 2003 2:39 pm

CEverQuest__dsp_chat is WriteChatColor, knock yourself out ;)

The whole point of this is that it identifies many functions and offsets based on the old ones, and severely reduces the amount of time it takes to figure out what's going on in the newer executables (let alone find the required offsets if needed)
Lax Lacks
Master of MQ2 Disaster
Purveyor of premium, EULA-safe MMORPG Multiboxing Software
* Multiboxing with ISBoxer: Quick Start Video
* EQPlayNice, WinEQ 2.0

Amadeus
The Maestro
The Maestro
Posts: 2036
Joined: Sat Jun 29, 2002 3:51 pm

Post by Amadeus » Sat Oct 04, 2003 3:06 pm

I suppose it's just hopeless if you don't know assembly very well to make any sense of it...I was hoping to find some function that was fairly simple and learn to manipulate it and figure out how it works.

I have an old thread of sprite's that talks about MoveMoney(), and I found that in the IDA ...but I have no idea how he came up with this:

Code: Select all


VOID CoinStuff(PSPAWNINFO pChar, PCHAR szLine) 
{ 
   DWORD DROPCOIN = 0x004DEE5E; 
   __asm { 
         push 0x0000000; // Always 0 
         push 0x0000064; // Amount 
         push 0x0000001; // Destination Coin Type: 0 = Platinum, 1 = Gold, 2 = Silver, 3 = Copper 
         push 0x0000000; // Source Coin Type: 0 = Platinum, 1 = Gold, 2 = Silver, 3 = Copper 
         push 0x0000000; // Coin Destination? 0 = cursor, 1 = inventory, 2 = bank 
         mov ecx, dword ptr 0x0077b858; 
         push 0x0000001; // Coin Source? 0 = cursor, 1 = inventory, 2 = bank 
         call dword ptr [DROPCOIN]; 
      } 
} 
Based upon what I'm seeing in the IDA....first of all, it's a hell of a lot longer and more complicated looking to me....

User avatar
Kint
a hill giant
a hill giant
Posts: 208
Joined: Thu Mar 13, 2003 3:36 am

Post by Kint » Sat Oct 04, 2003 3:40 pm

the potential sounds huge, I'll just have to find me IDA =p

nice work

kaz
a ghoul
a ghoul
Posts: 103
Joined: Tue Jan 14, 2003 4:09 am

Post by kaz » Sat Oct 04, 2003 11:40 pm

Lax,

amazing work. this is incredibly usefull

kaz
a ghoul
a ghoul
Posts: 103
Joined: Tue Jan 14, 2003 4:09 am

Post by kaz » Sat Oct 04, 2003 11:42 pm

Amadeus wrote:I suppose it's just hopeless if you don't know assembly very well to make any sense of it...I was hoping to find some function that was fairly simple and learn to manipulate it and figure out how it works.

I have an old thread of sprite's that talks about MoveMoney(), and I found that in the IDA ...but I have no idea how he came up with this:

Code: Select all


VOID CoinStuff(PSPAWNINFO pChar, PCHAR szLine) 
{ 
   DWORD DROPCOIN = 0x004DEE5E; 
   __asm { 
         push 0x0000000; // Always 0 
         push 0x0000064; // Amount 
         push 0x0000001; // Destination Coin Type: 0 = Platinum, 1 = Gold, 2 = Silver, 3 = Copper 
         push 0x0000000; // Source Coin Type: 0 = Platinum, 1 = Gold, 2 = Silver, 3 = Copper 
         push 0x0000000; // Coin Destination? 0 = cursor, 1 = inventory, 2 = bank 
         mov ecx, dword ptr 0x0077b858; 
         push 0x0000001; // Coin Source? 0 = cursor, 1 = inventory, 2 = bank 
         call dword ptr [DROPCOIN]; 
      } 
} 
Based upon what I'm seeing in the IDA....first of all, it's a hell of a lot longer and more complicated looking to me....
Amadeus,

this is just an example of how to call the eq MoveMoney function with hardcoded arguments, it is not the actual function.

Amadeus
The Maestro
The Maestro
Posts: 2036
Joined: Sat Jun 29, 2002 3:51 pm

Post by Amadeus » Sun Oct 05, 2003 12:36 am

Kaz,

I'll worship you for a whole week if you'll post a nice little walkthrough for one of the real functions found using IDA and Lax's stuff :)

Sincerely,
Amadeus

kaz
a ghoul
a ghoul
Posts: 103
Joined: Tue Jan 14, 2003 4:09 am

Post by kaz » Sun Oct 05, 2003 1:37 am

ok I will attempt to explain one for you :)

using this function

Code: Select all

.text:0045F87A ; ¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦ S U B R O U T I N E ¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦¦ 
.text:0045F87A 
.text:0045F87A 
.text:0045F87A EQPlayer__Levitating proc near   ; CODE XREF: EQ_Character__RemovePCAffectex+26Ep 
.text:0045F87A                 cmp     byte ptr [ecx+16Ch], 0 
.text:0045F881                 jnz     short loc_45F8A0 
.text:0045F883                 mov     ecx, [ecx+120h] 
.text:0045F889                 test    ecx, ecx 
.text:0045F88B                 jz      short loc_45F8A0 
.text:0045F88D                 push    0 
.text:0045F88F                 push    1 
.text:0045F891                 push    39h 
.text:0045F893                 call    EQ_Character__TotalSpellAffects 
.text:0045F898                 test    eax, eax 
.text:0045F89A                 jz      short loc_45F8A0 
.text:0045F89C                 xor     eax, eax 
.text:0045F89E                 inc     eax 
.text:0045F89F                 retn 
.text:0045F8A0 ; ----------------------------------------------------------- 
.text:0045F8A0 
.text:0045F8A0 loc_45F8A0:         ; CODE XREF: EQPlayer__Levitating+7j 
.text:0045F8A0                                         ; EQPlayer__Levitating+11j ... 
.text:0045F8A0                 xor     eax, eax 
.text:0045F8A2                 retn 
.text:0045F8A2 EQPlayer__Levitating endp 
.text:0045F8A2 
.text:0045F8A3 
ok first of all this is a member function of the class EQPlayer, called Levitating which takes no arguments and returns an int (or maybe bool)

so the C++ code might look something like :

Code: Select all

bool 
EQPlayer::Levitating(void)
{
  .........
}
with any class based member function the this pointer is stored in register ecx and with all functions, if there is a return value it is stored in eax.

so we begin this function with

Code: Select all

cmp     byte ptr [ecx+16Ch], 0
jnz       short loc_45F8A0
which means something like :

Code: Select all

if (this->someDataMember != 0) {
   goto exit;
}

the asm code is followed by

Code: Select all

mov     ecx, [ecx+120h]
test      ecx, ecx
jz        short loc_45F8A0
push    0
push    1
push    39h
call      EQ_Character__TotalSpellAffects
which I'd translate into :

Code: Select all

if (this->EQ_Character == 0) {
   goto exit;
}

int result = this->EQ_Character->TotalSpellEffects(0x39, 1, 0);
and then finally the asm code :

Code: Select all

test    eax, eax
jz       short loc_45F8A0
xor     eax, eax
inc      eax
retn
translates to :

Code: Select all

if (result == 0) {
   goto exit;
}

return 1;

exit :

return 0;

translation may not be perfect but I think it is pretty close, here are a few notes :

xor eax, eax

this is the same as saying eax = 0 since a number exclusively or'd with itself is always 0

also arguments to functions are pushed onto the stack in the reverse order you'd see them in C++ function call, thus the code I wrote above.

and I leave you with my complete translation (or not so complete :) )

Code: Select all

bool 
EQPlayer::Levitating(void)
{
   if (this->someDataMember != 0) {
      goto exit;
   }

   if (this->EQ_Character == 0) {
      goto exit;
   }

   int result = this->EQ_Character->TotalSpellEffects(0x39, 1, 0);

   if (result == 0) {
      goto exit;
   }

   return 1;

exit :

   return 0;
}

Amadeus
The Maestro
The Maestro
Posts: 2036
Joined: Sat Jun 29, 2002 3:51 pm

Post by Amadeus » Sun Oct 05, 2003 2:28 am

OMG!!! That's perfect!

Now my questions :)


----------------------------------
1. You said
ok first of all this is a member function of the class EQPlayer, called Levitating which takes no arguments and returns an int (or maybe bool)
This is because there are no args given and because at the end it just says 'retn' with nothing afterwards, correct? So, in assembly, if a function has arguments it looks like:

Code: Select all

.text:0045F545 arg_0           = dword ptr  4
.text:0045F545 arg_4           = dword ptr  8
Right?

----------------------------------

2. if "cmp byte ptr [ecx+16Ch], 0" = "if ( this->Something != 0 )" ...then, what would the assembly syntax for the following?
A. "if (this.something != 0 )"

....again, mostly asking this question just to try to come to terms with things, your explanation is great!
-----------------------------------

3. You said that this:

Code: Select all

mov     ecx, [ecx+120h] 
test      ecx, ecx 
jz        short loc_45F8A0 
means:

Code: Select all

if (this->EQ_Character == 0) { 
   goto exit; 
} 
I don't follow this exactly. And, I think it's the 'mov' statement that I don't understand. How do you know that "mov ecx, [ecx+120h]" somehow means that ecx is now "this->EQ_Character"?

Also, any time we 'test' something against itself, are we always doing a "if whatever == 0"?

------------------------------------

4. You said:

Code: Select all

push    0 
push    1 
push    39h 
call      EQ_Character__TotalSpellAffects 
Means:

Code: Select all

int result = this->EQ_Character->TotalSpellEffects(0x39, 1, 0); 
Is this always the case? That the pushes before a 'call' are the arguments sent to the function that is called?

Also, when I go to EQ_Character__TotalSpellEffects() I see a function with tons of variables at the top of it (21 in fact) .....*sigh* ...my mind explodes....if you get bored, I'd love to see you translate TotalSpellEffects() into C++ too ...seeing one with lots of variables like that would be helpful.
------------------------------------------

5. You said that:

Code: Select all

xor     eax, eax 
inc      eax 
Somehow means "Return 1;" ...but, at the end you said that 'xor eax, eax' would equal zero. So, where does the "Return 1;" come from? I guess I don't know what 'inc' means.

---------------------------------------

6. Thanks for explaining what eax and ecx are! What is "esp" usually?

...oh, and a few more while I'm asking ;) "ebx", "esi", "edi", "ebp"





Thanks for my all my newbie questions!!! People may laugh, but this is how I learned to find offsets from DKAA ;) ...tons of questions and windbg later, I can search pretty well nowadays.

MacroFiend
a grimling bloodguard
a grimling bloodguard
Posts: 662
Joined: Mon Jul 28, 2003 2:47 am

Post by MacroFiend » Sun Oct 05, 2003 3:23 am

I won't claim to have my ASM up to snuff ... but I can answer some of your questions ...

#4: The short answer is yes. You always have to push your variables on to the stack before executing the call. Since ASM is a linear language that doesn't support multiple parameters in a call (It doesn't support any parameters in the actual call), you have to feed them to the stack before executing the call (or jump).

#5: xor eax, eax always equals 0
inc eax means "increment eax" or ++eax
Similarly, dec means decrement eax or --eax

kaz
a ghoul
a ghoul
Posts: 103
Joined: Tue Jan 14, 2003 4:09 am

Post by kaz » Sun Oct 05, 2003 5:56 am

Amadeus,

Q#1

yes whenever a function has parameters they show up in IDA of the form at the top of the function

Code: Select all

arg_0           = dword ptr  4 
arg_4           = dword ptr  8 
Q#2

Im not an expert with this one but I believe for it to be dot notation the object would have to be first located in a local var or a parameter that was a struct.

Q#3

I knew that ecx+120h was really this->EQ_Character because there is a function call to EQ_Character_TotalSpellEffects just after that, and when ever you call a class member function in asm, you first move the class pointer (this) into ecx register. This is not nesicarilly an asm standard but a C++ compiler standard (when the C++ compiler converts the C++ code to asm).

2nd part of your question, no its not always if a == 0, I wrote the if statements according to the type of tests used in the original code, for example where it said jz, which means jump if zero, I wrote, if a == 0, and where it said jnz, that means jump if not zero.

other variations are jge (jump greater than or equal), jle (jump less than or equal), je (jump equal), jg (jump greater than) etc, etc

Q#4

yes if a function has parameters they are always pushed before the call, like wise if it is a class member function the class pointer is always mov to ecx (or already in ecx sometimes) before the call.

Q#5

xor eax, eax
inc eax
retn

essentailly means set eax to 1 and then return control to the caller, therefore I wrote it as simply as possible in C++ as :

return 1

If a function returns a value it is placed into eax before control is returned to the caller, as eax is the register used for return values (again this is a C++ complier standard but not nes a generic asm standard.)

Q#6
esp is I believe the register used for indexing the stack, and most the others are just general purpose registers and are used for all sorts of things.


and about your question about all the variable in EQ_Character_TotalSpellEffects, a variable and an argument are not the same thing

so if you look at that code

Code: Select all

.text:00426C71 var_4C          = dword ptr -4Ch
.text:00426C71 var_48          = dword ptr -48h
.text:00426C71 var_44          = dword ptr -44h
.text:00426C71 var_40          = dword ptr -40h
.text:00426C71 var_3C          = dword ptr -3Ch
.text:00426C71 var_38          = dword ptr -38h
.text:00426C71 var_34          = dword ptr -34h
.text:00426C71 var_30          = dword ptr -30h
.text:00426C71 var_2C          = dword ptr -2Ch
.text:00426C71 var_28          = dword ptr -28h
.text:00426C71 var_24          = dword ptr -24h
.text:00426C71 var_20          = dword ptr -20h
.text:00426C71 var_1C          = dword ptr -1Ch
.text:00426C71 var_18          = dword ptr -18h
.text:00426C71 var_14          = dword ptr -14h
.text:00426C71 var_10          = dword ptr -10h
.text:00426C71 var_C           = dword ptr -0Ch
.text:00426C71 var_8           = dword ptr -8
.text:00426C71 var_4           = dword ptr -4
.text:00426C71 arg_0           = dword ptr  8
.text:00426C71 arg_4           = byte ptr  0Ch
there are only appear to be 2 parameters (although it looks like 3 in the other function), the rest are local vars.

Lax
We're not worthy!
We're not worthy!
Posts: 3524
Joined: Thu Oct 17, 2002 1:01 pm
Location: ISBoxer
Contact:

Post by Lax » Sun Oct 05, 2003 9:22 am

They dont always show up at the top, but most of the time yes :)

Also, many functions that return a bool will use only al instead of eax depending on the compiler and conventions used

mov ecx, class
is indeed the way my program detects which class a function is in and used in calculations :) [class+offset] is obviously also a way of using class data members (reiterating stuff already said), and if it's a static instance of the class you can actually go to that point in the program to find the hardcoded function offset (in its table of function offsets) or the actual memory location for the data.

Something that might be of interest is this function: DrawNetStatus .. showing more or less clearly how to display things like a HUD.

Also, bear in mind that we HAVE the original function declarations of all of these functions from the original leaked map.

int __thiscall EQPlayer::Levitating(void)
int __thiscall EQ_Character::TotalSpellAffects(unsigned char,bool,int *)

I'll make these show up as comments pretty soon
Lax Lacks
Master of MQ2 Disaster
Purveyor of premium, EULA-safe MMORPG Multiboxing Software
* Multiboxing with ISBoxer: Quick Start Video
* EQPlayNice, WinEQ 2.0