This is a continuation of two discussions. The older one, pertaining to SetFacing:
Originally Posted by
Sillyboy72
It's calling the function fine, but seems to be bailing out early. Is there magic "patching" that has to happen to convince this function to actually... do stuff?
And a more recent one that is in an unrelated thread:
Originally Posted by
SKU
SetFacing works fine for me, just tested it.
typedef void (__thiscall * tSetFacing)(void* lp, float angle);
tSetFacing oSetFacing = (tSetFacing)0x005AFA10;
then call it somewhere:
oSetFacing(reinterpret_cast<void*>(GetLocalPlayer()), 1.337f);
This is if you don't have a reconstructed player class.
I figured I would merge the two and create a new one, rather than continuing to pollute the 3.1.2 info thread with off-topic discussion.
To summarize: for people in the past, as well as me presently, calling SetFacing does nothing.
I fired up OllyDbg to try and figure out why. This is the code for the function we call SetFacing:
Code:
005AFA10 55 PUSH EBP
005AFA11 8BEC MOV EBP,ESP
005AFA13 8B81 D0000000 MOV EAX,DWORD PTR DS:[ECX+D0]
005AFA19 33D2 XOR EDX,EDX
005AFA1B 83EC 14 SUB ESP,14
005AFA1E 3950 44 CMP DWORD PTR DS:[EAX+44],EDX
005AFA21 7E 4B JLE SHORT WoW.005AFA6E
005AFA23 8B41 08 MOV EAX,DWORD PTR DS:[ECX+8]
005AFA26 56 PUSH ESI
005AFA27 8B30 MOV ESI,DWORD PTR DS:[EAX]
005AFA29 3B35 00811101 CMP ESI,DWORD PTR DS:[1118100]
005AFA2F 5E POP ESI
005AFA30 75 3C JNZ SHORT WoW.005AFA6E
005AFA32 8B40 04 MOV EAX,DWORD PTR DS:[EAX+4]
005AFA35 3B05 04811101 CMP EAX,DWORD PTR DS:[1118104]
005AFA3B 75 31 JNZ SHORT WoW.005AFA6E
005AFA3D A1 C0401D01 MOV EAX,DWORD PTR DS:[11D40C0]
005AFA42 3950 30 CMP DWORD PTR DS:[EAX+30],EDX
005AFA45 74 27 JE SHORT WoW.005AFA6E
005AFA47 D9EE FLDZ
005AFA49 51 PUSH ECX
005AFA4A D955 EC FST DWORD PTR SS:[EBP-14]
005AFA4D 8955 F8 MOV DWORD PTR SS:[EBP-8],EDX
005AFA50 D955 F0 FST DWORD PTR SS:[EBP-10]
005AFA53 8955 FC MOV DWORD PTR SS:[EBP-4],EDX
005AFA56 D95D F4 FSTP DWORD PTR SS:[EBP-C]
005AFA59 8D55 EC LEA EDX,DWORD PTR SS:[EBP-14]
005AFA5C D945 08 FLD DWORD PTR SS:[EBP+8]
005AFA5F 8D45 F8 LEA EAX,DWORD PTR SS:[EBP-8]
005AFA62 D91C24 FSTP DWORD PTR SS:[ESP]
005AFA65 52 PUSH EDX
005AFA66 50 PUSH EAX
005AFA67 6A 02 PUSH 2
005AFA69 E8 92C4FFFF CALL WoW.005ABF00
005AFA6E 8BE5 MOV ESP,EBP
005AFA70 5D POP EBP
005AFA71 C2 0400 RETN 4
Now, there are some basic sanity checks going on here at the start. From what I understand, we are first making sure the target's health is > 0. Secondly, we are making sure that this is being called only on ourselves. The third check seems to be some sort of redundant assertion of the second check? The fourth check is where when my injected code which calls the function is getting nailed:
Code:
005AFA3D A1 C0401D01 MOV EAX,DWORD PTR DS:[11D40C0]
005AFA42 3950 30 CMP DWORD PTR DS:[EAX+30],EDX
005AFA45 74 27 JE SHORT WoW.005AFA6E
At this point EDX is 0, so it's just checking if [[0x11D40C0] + 0x30] is 0 (which for me it is, so the function bails).
Does anyone have any insight as to what this check is doing?
Incidentally, I have (once again!) attempted to re-write this function in psuedo-code so that I could better understand what was happening:
Code:
push ebp
ebp = esp
eax = [ecx + 0xD0]
edx = 0
esp = esp - 0x14
if ([eax + 0x44] <= 0) /* if target is dead */
{
esp = ebp
pop ebp
return 0x4
}
eax = [ecx + 0x8] /* object @ ecx's guid */
push esi
esi = [eax]
if (esi != [0x1118100]) /* check first half of guid */
{
pop esi
esp = ebp
pop ebp
return 0x4
}
eax = [eax + 0x4]
if (eax != [0x1118104]) /* check second half of guid */
{
esp = ebp
pop ebp
return 0x4
}
eax = [0x11d40c0]
if ([eax + 0x30] == 0) /* ??? */
{
esp = ebp
pop ebp
return 0x4
}
push ecx
[ebp - 0x14] = (float)param1
[ebp - 0x8] = edx
[ebp - 0x10] = (float)param1
[ebp - 0x4] = edx
[ebp - 0xc] = (float)param1 (also popped)
eax = ebp - 8
esp = (float)param2
push edx
push eax
push 2
call 005ABF00
esp = ebp
pop ebp
return 0x4
Edit: Victory!
For yucks, I tried patching that magical memory location (brute force and ignorance will always win over time!), and now SetFacing works as it was supposed to.
Code:
unsigned long sf = 0x005AFA10;
float rad = 1.76f;
CGObject_C *p = gpWoWX->GetCurMgr()->GetLocalPlayer();
DWORD a;
a = * (DWORD *)(0x011D40C0) + 0x30;
DBGLOG("Patching [[0x011D40C0] + 0x30] (0x" << std::hex << a << ")..");
gpWoWX->GetPatcher()->AddPatch(a, reinterpret_cast<PBYTE>( "\x01\x00\x00\x00" ), 4, "SetFacing_Patch" );
DBGLOG("Calling SetFacing at 0x" << std::hex << sf << " playerBase: 0x" << p);
_asm
{
mov ecx, p
push rad
call sf
}
DBGLOG("Done.");