Page 1 of 1

new memory checker routine

Posted: Wed Apr 09, 2003 11:30 pm
by dont_know_at_all
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
}

Posted: Thu Apr 10, 2003 12:22 am
by dont_know_at_all
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.

Posted: Thu Apr 10, 2003 12:33 am
by vzmule
nice work sir

Posted: Thu Apr 10, 2003 7:03 am
by Clawed
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.

Posted: Thu Apr 10, 2003 8:01 am
by Clawed
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*)

Posted: Fri Apr 11, 2003 5:06 am
by Clawed
Finally got some time to really test it... and I'm still getting booted. Memchecker isn't working. Gonna gimp it tonight. :)

Posted: Fri Apr 11, 2003 5:38 am
by dont_know_at_all
CVS version is now working.

LD GM RP ANON flags are not working for who.

Posted: Fri Apr 11, 2003 6:58 am
by Clawed
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).

Posted: Fri Apr 11, 2003 8:51 am
by Mckorr
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.

Posted: Fri Apr 11, 2003 9:00 am
by Clawed
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...

Posted: Fri Apr 11, 2003 9:09 am
by Mckorr
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;

Posted: Fri Apr 11, 2003 9:30 am
by Clawed
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.

Re: new memory checker routine

Posted: Sun Jan 18, 2026 3:15 pm
by xyilla