new memory checker routine

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

Moderator: MacroQuest Developers

User avatar
dont_know_at_all
Developer
Developer
Posts: 5450
Joined: Sun Dec 01, 2002 4:15 am
Location: Florida, USA
Contact:

new memory checker routine

Post by dont_know_at_all » Wed Apr 09, 2003 11:30 pm

I have tested this against the raw assembly and it seems to work. I'm too tired tonight to patch the eqlib.cpp. All the addresses listed below (four of them) need to be added to the ini file. Oh, and the detour stuff needs to be added to the loop below.

Code: Select all

//
// detour 4F77B2 to mymemcheck2
//

int *extern_array = 0x5C26D0;
int __cdecl mymemcheck2(unsigned char *buffer, int count, struct mckey key);

#define first 0x4F7820
#define second 0x4F7858

//        TITLE orig.asm
//        .386P
//
//EXTRN _extern_array:DWORD
//
//_TEXT SEGMENT
//
//getret  PROC NEAR
//        mov         eax,dword ptr [esp]
//        ret
//getret  ENDP
//
//PUBLIC _memcheck2
int __cdecl mymemcheck2(unsigned char *buffer, int count, struct mckey key)
{
    unsigned int x, i, j;
    unsigned int ecx, ebx, edx, eax;

    if (!extern_array) {
    }
//_memcheck2 PROC NEAR
//        push        ebp
//        mov         ebp,esp
//        mov         al,byte ptr [ebp+10h]
//        push        ebx
//        not         al
//        movzx       eax,al
    eax = ~key.a[0] & 0xff;

//        movzx       edx,byte ptr [ebp+11h]
    edx = key.a[1] & 0xff;

//        mov         eax,dword ptr [eax*4+_extern_array]
    eax = extern_array[eax];

//        push        esi
//        mov         esi,0FFFFFFh
//        push        edi
//        xor         eax,esi
    eax ^= 0xffffff;

//        mov         edi,0FFh
//        mov         ecx,eax
//        and         ecx,edi
    ecx = eax & 0xff;

//        xor         ecx,edx
    ecx ^= edx;

//        movzx       edx,byte ptr [ebp+12h]
    edx = key.a[2] & 0xff;
    
//        mov         ecx,dword ptr [ecx*4+_extern_array]
    ecx = extern_array[ecx];

//        sar         eax,8
//        and         eax,esi
    eax = ((int)eax>>8) & 0xffffff;

//        xor         ecx,eax
    ecx ^= eax;

//        mov         eax,ecx
//        and         eax,edi
//        xor         eax,edx
    eax = (ecx & 0xff) ^ edx;

//        movzx       edx,byte ptr [ebp+13h]
    edx = key.a[3] & 0xff;

//        mov         eax,dword ptr [eax*4+_extern_array]
    eax = extern_array[eax];

//        sar         ecx,8
//        and         ecx,esi
    ecx = ((int)ecx>>8) & 0xffffff;

//        xor         eax,ecx
    eax ^= ecx;

//        mov         ecx,eax
//        and         ecx,edi
//        xor         ecx,edx
    ecx = (eax & 0xff) ^ edx;

//        sar         eax,8
    eax = ((int)eax>>8) & 0xffffff;
//        mov         ebx,dword ptr [ecx*4+_extern_array]
//        and         eax,esi
    ebx = extern_array[ecx];

//        xor         ebx,eax
    ebx ^= eax;
    ebx ^= first;
//        call        getret
//        mov         ecx,dword ptr [ebp+0Ch]
//        xor         ebx,eax
//        mov         eax,dword ptr [ebp+8]
//        add         ecx,eax
//        mov         dword ptr [ebp+10h],eax
//        cmp         eax,ecx
    if (count == 0) goto done;
//        jae         done
//myloop:
//        mov         edx,dword ptr [ebp+10h]
//        mov         eax,ebx
//        and         eax,edi
//        movzx       edx,byte ptr [edx]
//        xor         eax,edx
//        sar         ebx,8
//        mov         eax,dword ptr [eax*4+_extern_array]
//        
//        and         ebx,esi
//        xor         ebx,eax
//        inc         dword ptr [ebp+10h]
//        cmp         dword ptr [ebp+10h],ecx
//        jb          myloop
for (i=0;i<(unsigned int)count;i++) {
    unsigned char tmp = buffer[i];
    eax = (int) tmp ^ (ebx & 0xff);
    ebx = ((int)ebx >> 8) & 0xffffff; 
    eax = extern_array[eax];
    ebx ^= eax;
}
//done:
done:
//        call        getret
    eax = second;
    eax ^= ~ebx;
    return eax;
//        not         ebx
//        pop         edi
//        xor         eax,ebx
//        pop         esi
//        pop         ebx
//        pop         ebp
//        ret
//_memcheck2  ENDP 
//_TEXT   ENDS
//END
}

User avatar
dont_know_at_all
Developer
Developer
Posts: 5450
Joined: Sun Dec 01, 2002 4:15 am
Location: Florida, USA
Contact:

Post by dont_know_at_all » Thu Apr 10, 2003 12:22 am

More fun stuff: here are the addresses that they are checking (from the client side, there may be more addresses from the server):

4C7E04->4E6118
4643ED->46E78E
4F77B2->46ED5B
46ED67->47676A
477B76->47AD30
4A77B0->4A77B0
4F60B3->4F95E7
492F04->4C606B

These are checked every time the client invokes its memory checker. Crap, I may detour this just to speed up my client.

When you are a bard, lag == death.

User avatar
vzmule
Contributing Member
Contributing Member
Posts: 378
Joined: Thu Mar 13, 2003 11:56 pm

Post by vzmule » Thu Apr 10, 2003 12:33 am

nice work sir

Clawed
a ghoul
a ghoul
Posts: 105
Joined: Mon Jan 20, 2003 6:17 am

Post by Clawed » Thu Apr 10, 2003 7:03 am

DKAA's memcheck disassembly, when converted to use the detoured data, appears initially to work for me. I am able to log in and stay in. However, there still appear to be multiple struct errors, both in _SPAWNINFO and _CHARINFO (and probably others)... even with using Rainbean's new version of _SPAWNINFO. Obviously this means that eqgame crashes when running /who or /charinfo.

Just wanted to provide some feedback for DKAA.
Clawed

Clawed
a ghoul
a ghoul
Posts: 105
Joined: Mon Jan 20, 2003 6:17 am

Post by Clawed » Thu Apr 10, 2003 8:01 am

It seems that for some reason I was using a bad offset for SpawnHeader. With that fixed (00759B74), I was able to get /who working marginally well -- at least so it didn't crash. The struct is still not 100% correct, however. I am having a strange inability to see surnames. All pets get flagged as *GM*. There are probably other bugs.

I haven't made any changes yet to the CharInfo code, so it still crashes for me. I am able to correctly view my Exp, AAExp, and Mana from the _CHARINFO struct that was released in the last official release. Haven't tried much else yet.

The Guilds offset (006EDEB4) works just fine for me, after applying NealThorpayt's revision which changes the guildname length to 64.

All the other offsets previously verified by others seem to work just fine. I will let DKAA finalize his memchecker2 function and add the necessary INI checks for release. (I'd post my function, but it won't be used in release anyway.) Looks like things are close to being fixed after this rather infamous patch... (*cough* charm nerf *cough*)
Clawed

Clawed
a ghoul
a ghoul
Posts: 105
Joined: Mon Jan 20, 2003 6:17 am

Post by Clawed » Fri Apr 11, 2003 5:06 am

Finally got some time to really test it... and I'm still getting booted. Memchecker isn't working. Gonna gimp it tonight. :)
Clawed

User avatar
dont_know_at_all
Developer
Developer
Posts: 5450
Joined: Sun Dec 01, 2002 4:15 am
Location: Florida, USA
Contact:

Post by dont_know_at_all » Fri Apr 11, 2003 5:38 am

CVS version is now working.

LD GM RP ANON flags are not working for who.

Clawed
a ghoul
a ghoul
Posts: 105
Joined: Mon Jan 20, 2003 6:17 am

Post by Clawed » Fri Apr 11, 2003 6:58 am

CVS currently won't compile because in the _SPAWNINFO struct you renamed Zone to NotZone and commented out AARank... obviously because these aren't at the right offset, but this renders the code uncompileable as-is. Renamed NotZone back and moved AARank to the end of the struct (on my local copy of the code).
Clawed

Mckorr
Developer
Developer
Posts: 2326
Joined: Fri Oct 18, 2002 1:16 pm
Location: Texas

Post by Mckorr » Fri Apr 11, 2003 8:51 am

The only problem I've had with Rainbean's _SPAWNINFO is that last names don't show up. Might be related to the Deity part of the code, which he says doesn't work right. My personal build removes all the Deity functions from eqlib.cpp, since I don't need them for anything.

Clawed
a ghoul
a ghoul
Posts: 105
Joined: Mon Jan 20, 2003 6:17 am

Post by Clawed » Fri Apr 11, 2003 9:00 am

CVS from DKAA has a new _SPAWNINFO struct that fixes the surname problem. (He moved the surname offset up a bit.) Although you have to make the 2 changes I mentioned earlier if you want to compile it.

And dammit... no sooner do we get MQ fixed then they smurfing patch again. :x Oh well, maybe they won't patch eqgame.exe... One can hope...
Clawed

Mckorr
Developer
Developer
Posts: 2326
Joined: Fri Oct 18, 2002 1:16 pm
Location: Texas

Post by Mckorr » Fri Apr 11, 2003 9:09 am

Thanks Clawed, haven't had time to compare the CVS _SPAWNINFO and _CHARINFO with what I have.

DKAA keeps yelling at me for not using the CVS versions of files, but since for some reason big chunks of the official version crash me I have to do the modifications by hand, sometimes line by line. Frequently that means backing up my source files, adding new code, testing it, crashing, then putting back in old code that only partially works so I can at least stay connected.

Will compare DKAA's official _SPAWINFO against Rainbean's version, see if one can be used to fix the other, test it out this weekend if I get time.

Clawed, please verify:

In _SPAWINFO, you changed

Code: Select all

   //DWORD AARank;             // 108 ~ 10C
   //BYTE Unknown014[36];      // 10C ~ 130
   CHAR Lastname[22];        // 108 ~ 130
} SPAWNINFO, *PSPAWNINFO;
to

Code: Select all

   BYTE Unknown014[36];      // 108 ~ 10c
   CHAR Lastname[22];        // 10C ~ 130
   DWORD AARank;             // 130 ~ 146
} SPAWNINFO, *PSPAWNINFO;

Clawed
a ghoul
a ghoul
Posts: 105
Joined: Mon Jan 20, 2003 6:17 am

Post by Clawed » Fri Apr 11, 2003 9:30 am

Don't uncomment out the Unknown014[36], or you screw up the offset for Lastname. Do it like this:

Code: Select all

   //BYTE Unknown014[36];      // 10C ~ 130 
   CHAR Lastname[22];        // 108 ~ 130 
   DWORD AARank;
} SPAWNINFO, *PSPAWNINFO;
All this does is put the AARank variable into the structure so the rest of it compiles... but don't expect to be able to USE AARank, since that's not the right spot for it. This just renders the code compileable without changing the structure offsets.

BTW I can also confirm that the AAExp member of _CHARINFO isn't correct. Whether it used to be or not, I don't know, as I'm only now writing the code that makes use of it. Any help finding the correct location of that would be appreciated. :)

Also DKAA... in my testing it appears that RP and ANON flags are working as intended in _SPAWNINFO... but I could be wrong.
Clawed