Shynd’s WoW Modification Journal

June 27, 2008

SelectUnit

Filed under: World of Warcraft — Tags: , , , , , , , — Shynd @ 8:14 am

If you haven’t yet downloaded bobbysing’s WoWX framework, do so immediately.  Look through it, learn what you can from it, always keep it as a resource.  Kynox and bobby (and others, I’m sure) have done a ton of reverse-engineering and whatnot and it would be folly to do the same reversing, wasting your time, when you could be building upon the work of others and furthering the WoW hacking community in other directions.

That said, the SelectUnit function that I’m using is ripped directly from bobbysing’s WoWX framework, right down to the pattern that I use to find it.  Instead of screwing with patterns–if you want to screw with patterns, you can find the pattern in bobby’s Patterns.xml, labeled SelectUnit–I’ll just provide you with the address of the function we’re talking about: 0×006D8760.  This function has one parameter: the 64-bit integer representing the unit’s GUID (read from UnitBase+0×30).

I don’t know about you, but my bot doesn’t select units all that often; it’s not something done multiple times a second, anyway.  SelectUnit, kill unit (takes some time, depending on level and class), loot unit, find next unit, SelectUnit.  For that reason, I’m okay with the added overhead for creating a new thread each time I want to select a unit, solely because it keeps me from having to inject a DLL into the client (which I’d like to avoid doing, for now).  Basically, the way I’m doing it goes a little like this:

  • Allocate a chunk of memory for my codecave
  • MemoryWrite ASM opcodes that push the 64-bit integer GUI onto the stack (you need two push commands, seeing as you can only push 4 bytes per command and a 64-bit integer is 8 bytes long)
  • MemoryWrite ASM opcodes that will call SelectUnit, clean up the stack, and return
  • MemoryWrite the 64-bit integer GUID at an address I know (that pointed to by my two pushes)
  • Use CreateRemoteThread API to create a thread that executes my injected code
  • Use WaitForSingleObject to wait until the thread returns

In pseudo-c, it might look a little like this (remember, ASM CALLs are relative, so you have to transform the static SelectUnit address into a relative call).

DWORD dwSelectUnit = 0x006D8760;
__int64 GUID = 0; //clears target

//Allocate with address NULL and it will give us the first available chunk
LPVOID lpCodeCave= VirtualAllocEx(hProcess, NULL, 0x100, MEM_COMMIT, PAGE_READWRITE);
//ASM with two pushes and a call (relative pushes and calls are represented by 0s temporarily)
byte[21] bInject = { 0xFF, 0x35, 0, 0, 0, 0, 0xFF, 0x35, 0, 0, 0, 0, 0xE8, 0, 0, 0, 0, 0x83, 0xC4, 0x08, 0xC3 };
//inject code
WriteProcessMemory(hProcess, lpCodeCave, bInject, sizeof(bInject), NULL);

//transform relative call address and patch
dwSelectUnit = dwSelectUnit - ((DWORD)lpCodeCave + 17);
WriteProcessMemory(hProcess, (void *)((DWORD)lpCodeCave + 13), dwSelectUnit, 4, NULL);

//patch PUSH opcodes to point to correct places
WriteProcessMemory(hProcess, ((DWORD)lpCodeCave + 2), ((DWORD)lpCodeCave + 0x504), 4, NULL);
WriteProcessMemory(hProcess, ((DWORD)lpCodeCave + 8), ((DWORD)lpCodeCave + 0x500), 4, NULL);

//write the GUID to be selected to memory
WriteProcessMemory(hProcess, ((DWORD)lpCodeCave + 0x500), GUID, sizeof(GUID), NULL);

//create the thread that executes our injected code
HANDLE hThread = CreateRemoteThread(hProcess, NULL, 0, (LPTHREAD_START_ROUTINE)lpCodeCave, 0, 0, NULL);
WaitForSingleObject(hThread, INFINITE);
CloseHandle(hThread);

Easy enough?  I hope so.

As always, here’s a link to the next article in this journal.

1 Comment »

  1. well I found some time to work through another one of your posts. Or 2 since I used your next one quite a bit. Thanks for replying on the Movement post, I used spy++ instead of wininspector though. managed to piece it all together with your code sample and the spy++ messages.

    Now I ran into a little snag with this one. This works very nicely up to a certain point. So first off thanks for the thorough explanation of code injection. Secondly, when I use this to select stuff every once in a while it will crash my WoW client. During the testing I kept selecting the same object over and over.

    My select function is as followed:
    http://www.nomorepasting.com/getpaste.php?pasteid=17688

    I would be gratefull if you could look through it and give some feedback.

    Comment by katsumura — July 6, 2008 @ 8:07 am


RSS feed for comments on this post.

Leave a comment

You must be logged in to post a comment.

Blog at WordPress.com.