with "out-of-process" I've understood something like "Initial call comes from out-of-process". Seems as it is really only memory-read + keystroke sending and that the terminology is not clearly used here on MMOwned (I've read Cypher's post regarding this. He explains quite good what "out-of-process" is).
I've chosen the DLL injection way via LoadLibrary and have written the following DLL. Let me explain my sample code which sadly is bugged. (I know that it looks horrible, I just want to get it work first before I increase code quality on something that is not working)
Code:
#include <windows.h>
#include "lua/lua.h"
I've managed to get the lua State offset using ollydbg through the following process:
- open lua_pushstring and setting a breakpoint there (offset from berserk85 in the info dump thread)
- checking the argument and going back in little steps to see from where it came from
- finding that it is written to 0x0133b99c
- putting a memory write breakpoint on this address
- finding out that it is only written by two functions, from which one is nulling it and the other is writing the location.
With this offset and some from berserk85 (lua_pushcclosure, lua_setfield, lua_gettop and lua_pushnumber) I could write and inject a very simple lua function:
Code:
int lua_Test (lua_State *L) {
// 0x00803340 == lua_gettop; Credits: berserk85
// 0x00803a10 == lua_pushnumber; Credits: berserk85
typedef int (* p_lua_gettop) (lua_State *L);
p_lua_gettop gettop = (p_lua_gettop)0x00803340;
typedef void (* p_lua_pushnumber) (lua_State *L, lua_Number n);
p_lua_pushnumber pushnumber = (p_lua_pushnumber)0x00803a10;
int numberOfArgs = gettop(L);
lua_Number n = 42;
pushnumber(L, n);
return 1;
}
This function gets the number of arguments from the lua stack and returns 42 regardless of the arguments.
After defining lua_Test, I've written a register function which should expose it to the WoW LUA engine. It first gets the current lua_State * (is my offset correct? was the first time I've got one from myself) from the previously mentioned memory location and then registers my sample.
Code:
void registerLua () {
// 0x00803b70 == lua_pushcclosure; Credits: berserk85
// 0x00804070 == lua_setfield; Credits: berserk85
// 0x0133b99c == lua_State
//#define lua_register(L,n,f) (lua_pushcfunction(L, (f)), lua_setglobal(L, (n)))
//#define lua_pushcfunction(L,f) lua_pushcclosure(L, (f), 0)
//#define lua_setglobal(L,s) lua_setfield(L, LUA_GLOBALSINDEX, (s))
//#define LUA_GLOBALSINDEX (-10002)
typedef void (* p_lua_pushcclosure) (lua_State *L, lua_CFunction fn, int n);
p_lua_pushcclosure pushcclosure = (p_lua_pushcclosure)0x00803b70;
typedef void (* p_lua_setfield) (lua_State *L, int idx, const char *k);
p_lua_setfield setfield = (p_lua_setfield)0x00804070;
lua_State *state = (lua_State*)(*(void **)0x0133b99c);
pushcclosure(state, lua_Test, 0);
setfield(state, -10002, "Test");
}
Let's hope that it is correct :-)
Finally, the DllMain function completes my DLL's source. It patches the TLS to be able to access objects from WoW's main thread and calls registerLua()
Code:
BOOL WINAPI DllMain (HINSTANCE hDLL, DWORD reason, LPVOID reserved) {
if (reason == DLL_PROCESS_ATTACH) {
// patch TLS to be able to access data from WoW's main thread
// ds:[0x012705b0] == g_clientConnection; Credits: FearAndLawyering
// 0x00002d94 == s_curMgrOffset; Credits: FearAndLawyering
_asm {
mov eax, dword ptr fs:[0x2c] // fs:0x2c == Linear address of the thread-local storage array
mov eax, dword ptr ds:[eax]
add eax, 8 // current TLS
mov ebx, dword ptr ds:[0x012705b0]
mov ebx, dword ptr ds:[eax + 0x00002d94] // WoW's main thread TLS
mov [eax], ebx // Perform patch
}
registerLua();
}
return TRUE;
}
Injection works fine and the function gets registered in the game.
However, when I try to call it via it just crashes WoW with a "Invalid function pointer" critical error which points to lua_Test (checked by writing a log file and with ollydbg).
What did I forget?