Lets take CL_CreateMove as an example
Code:
01955750 83EC 10 SUB ESP,10
01955753 8D4424 1C LEA EAX,DWORD PTR SS:[ESP+1C]
01955757 8D4C24 18 LEA ECX,DWORD PTR SS:[ESP+18]
0195575B 8D5424 14 LEA EDX,DWORD PTR SS:[ESP+14]
0195575F 53 PUSH EBX
01955760 50 PUSH EAX
01955761 A1 F079A101 MOV EAX,DWORD PTR DS:[1A179F0]
01955766 51 PUSH ECX
01955767 52 PUSH EDX
01955768 FF50 38 CALL NEAR DWORD PTR DS:[EAX+38]
the sub esp 10, sets up some space on the stack to pass 3 arguments. the lea loads the address of these arguments and the push passes them to the nullstub which normally would return. Now when you use ltfx hooking you modify the export table to point to your table.
let me explain this part now
You cast the slots pointer as a byte pointer, (unsigned char *) to check if the opcode at that particular point in the data segment is 0xC3 If it doesn't equal 0xC3, then we do nothing. Of course this is redundant since look a bit above
Code:
c = (unsigned char*)slots[s];
if( c[0] != 0xc3 )
{
patched=false;
MessageBox(NULL, "Things look wrong... very wrong", NULL, MB_OK);
}
With that out of the way lets continue.
Code:
01955761 A1 F079A101 MOV EAX,DWORD PTR DS:[1A179F0]
This is the "retart", slotsfx, slointer, whatever you want to call it. it holds the address of the export table. LTFXGuy found it first but this isn't story time.
Code:
01955768 FF50 38 CALL NEAR DWORD PTR DS:[EAX+38]
now eax contains the start of the export table, we want createmove so we add 0x38 and call it, which happens to be...
0xC3, which will just return.
Now onto the real stuff, with all this out of the way.
We modify the export table to point to our jumpgates and then the real fun starts. When the nullstub is called rather than just returning it goes to our jumpgate.
Code:
10014F55 56 PUSH ESI ; hl.02EB8F84
10014F56 36:8B7424 28 MOV ESI,DWORD PTR SS:[ESP+28]
10014F5B 8935 380D0510 MOV DWORD PTR DS:[10050D38],ESI
10014F61 FF35 E0180010 PUSH DWORD PTR DS:[100018E0] ; OGC Tweak.10014F4A
10014F67 5E POP ESI
10014F68 36:897424 28 MOV DWORD PTR SS:[ESP+28],ESI
10014F6D 5E POP ESI
10014F6E C3 RETN
esi in this case currently holds the usercmd struct. so we store in on the stack. now this is where the retaddress comes into play.
Code:
MOV ESI,DWORD PTR SS:[ESP+28]
esi will hold the retaddress, but how did we get esp + 0x28.
here's how.
remember cl_createmove's start?
Code:
01955750 83EC 10 SUB ESP,10
01955753 8D4424 1C LEA EAX,DWORD PTR SS:[ESP+1C]
01955757 8D4C24 18 LEA ECX,DWORD PTR SS:[ESP+18]
0195575B 8D5424 14 LEA EDX,DWORD PTR SS:[ESP+14]
0195575F 53 PUSH EBX
01955760 50 PUSH EAX
01955761 A1 F079A101 MOV EAX,DWORD PTR DS:[1A179F0]
01955766 51 PUSH ECX
01955767 52 PUSH EDX
01955768 FF50 38 CALL NEAR DWORD PTR DS:[EAX+38]
breakpoint on the 1955750 and notice the stack.
Code:
0012F304 01D1C08D RETURN to hl.01D1C08D from hl.01D0E4F0
now breakpoint on the 1955768.
12F304 - 12F2DC = 0x28
Simple enough.
now,
Code:
10014F56 36:8B7424 28 MOV ESI,DWORD PTR SS:[ESP+28] ; hl.01D1C08D
hmm, clientmove is what called cl_createmove. Must be the return address.
Code:
10014F61 FF35 E0180010 PUSH DWORD PTR DS:[100018E0] ; OGC Tweak.10014F4A
This simply stores the address of the jumpgate on the stack. It will be used to "call" our gateway after the clientfunction is finished.
Code:
10014F67 5E POP ESI
10014F68 36:897424 28 MOV DWORD PTR SS:[ESP+28],ESI ; OGC Tweak.10014F4A
10014F6D 5E POP ESI
10014F6E C3 RETN
we pop esi twice to get the usercmd struct back. but first
Code:
MOV DWORD PTR SS:[ESP+28],ESI
All this does is move the gateway into esp + 0x28. It will be used later to call our gateway
Finally we retn to the client function, with everything setup, then after the client function returns it calls the gateway.
This may not appear elsewhere without permission, but may be linked to.