Lua_Register menu

User Tag List

Thread: Lua_Register

Page 1 of 2 12 LastLast
Results 1 to 15 of 20
  1. #1
    Ellesar1's Avatar Member
    Reputation
    20
    Join Date
    Feb 2009
    Posts
    78
    Thanks G/R
    0/0
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)

    [Source] Lua_Register

    I'm interested in registering an additional function to WoW.
    I think that the easiest method to do this is putting the function into a DLL, injecting the DLL and calling lua_register from there to make it available in game.

    However, I'm wondering if there is a neat out-of-process solution to accomplish this goal.

    Edit: Thanks for your help. Here is the complete get-it-work-quality code (I know it is not beautiful, but it is nice to see some results fast) which I could put together thanks to some of you.

    Note that you have to replace 0xDEADBEEF by a valid offset.
    Code:
    #include <windows.h>
    #include "lua/lua.h"
    
    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;
    }
    
    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);
    
    	unsigned char * pCodeCave = (unsigned char *)0xDEADBEEF; // replace before use
    
    	DWORD old;
    	VirtualProtect((LPVOID)pCodeCave, 5, PAGE_EXECUTE_READWRITE, &old);
    	*(byte *)pCodeCave = 0xe9;
    	*(int *)(pCodeCave + 1) = (int)lua_Test - (int)pCodeCave - 5;
    	VirtualProtect((LPVOID)pCodeCave, 5, old, NULL);
    
    	// /script SendChatMessage(Test(), "WHISPER", nil, UnitName("player"));
    
    	pushcclosure(state, (lua_CFunction)(pCodeCave), 0);
    	setfield(state, -10002, "Test");
    }
    
    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
    		// fs:[0x2c] == Linear address of the thread-local storage array
    		// ds:[0x012705b0] == g_clientConnection; Credits: FearAndLawyering
    		// 0x00002d94 == s_curMgrOffset; Credits: FearAndLawyering
    		_asm {
    			mov eax, dword ptr fs:[0x2c] 
    			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;
    }
    Last edited by Ellesar1; 10-17-2009 at 04:46 PM.

    Lua_Register
  2. #2
    flo8464's Avatar Active Member
    Reputation
    30
    Join Date
    Apr 2009
    Posts
    434
    Thanks G/R
    0/0
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    When was the last time you called a function you don't have?
    At least my linker tells me its impossible...

    How is WoW supposed to execute a function which isn't in its memory ?
    If you want to do something like that you HAVE to be in-process.

  3. #3
    flukes1's Avatar Member
    Reputation
    6
    Join Date
    Aug 2009
    Posts
    27
    Thanks G/R
    0/0
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Short answer: no. You'll need to do what you described above. If you wanted to do it "out of process" you'd need to manually map your function into WoW's address space (and make a metric ton of adjustments to it on-the-fly), which is basically equivalent to injecting. Expect to spend a good few weeks writing a functional mapper.

    If your justification for this is Warden, you'd be wasting your time. Blizzard will just count the number of internally registered Lua funcs, realize there's more than there should be, and ban you. Just inject and keep your app private.

  4. #4
    Ellesar1's Avatar Member
    Reputation
    20
    Join Date
    Feb 2009
    Posts
    78
    Thanks G/R
    0/0
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    well that's what I've also thought @flo. I've thought about writing the assembler of the function into wow's address space and then calling lua_register with a pointer to it as flukes1 mentioned.

    what do you mean with "metric ton of adjustments"?

    and do they currently check the registered function count?

    (app will be private, so they'll never get the source)

  5. #5
    tanis2000's Avatar Active Member
    Reputation
    39
    Join Date
    Feb 2009
    Posts
    123
    Thanks G/R
    0/0
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Originally Posted by Ellesar1 View Post
    well that's what I've also thought @flo. I've thought about writing the assembler of the function into wow's address space and then calling lua_register with a pointer to it as flukes1 mentioned.

    and do they currently check the registered function count?
    That's pretty much what I do. Write a jump to your function inside the client's memory space. But I keep my code inside a DLL that is being injected into the client too. (aka, mine is a relative jump to my function) and I'm not sure this would work with external code. Someone here can certainly tell you if it does or not.

    And as far as I know there's no check on the number of functions that have been registered. But there's a crc check on the client's address space during login so you have to remember to remove your jump from the code when at the login screen.

  6. #6
    xzidez's Avatar Member
    Reputation
    12
    Join Date
    Dec 2007
    Posts
    136
    Thanks G/R
    1/0
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Originally Posted by tanis2000 View Post
    That's pretty much what I do. Write a jump to your function inside the client's memory space. But I keep my code inside a DLL that is being injected into the client too. (aka, mine is a relative jump to my function) and I'm not sure this would work with external code. Someone here can certainly tell you if it does or not.

    And as far as I know there's no check on the number of functions that have been registered. But there's a crc check on the client's address space during login so you have to remember to remove your jump from the code when at the login screen.
    now you got me worried here? crc check at the login? I havent removed my jump .. so faar. Perhaps I should start doing it :P


    But as mentioned. Inject a DLL with your function. Get the function pointer. Write a jump anywhere in wows data section to that pointer. Register that jump as your function. And you should be fine.

  7. #7
    flo8464's Avatar Active Member
    Reputation
    30
    Join Date
    Apr 2009
    Posts
    434
    Thanks G/R
    0/0
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Writing code into WoWs address space doesn't make you be out-of-process.

  8. #8
    Ellesar1's Avatar Member
    Reputation
    20
    Join Date
    Feb 2009
    Posts
    78
    Thanks G/R
    0/0
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    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:
    1. open lua_pushstring and setting a breakpoint there (offset from berserk85 in the info dump thread)
    2. checking the argument and going back in little steps to see from where it came from
    3. finding that it is written to 0x0133b99c
    4. putting a memory write breakpoint on this address
    5. 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
    Code:
    /script Test()
    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?
    Last edited by Ellesar1; 10-17-2009 at 09:43 AM.

  9. #9
    berserk85's Avatar Member
    Reputation
    8
    Join Date
    Apr 2008
    Posts
    35
    Thanks G/R
    0/0
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Check with a disasm the function at 0x820CF0 (3.2.2a)
    Last edited by berserk85; 10-17-2009 at 09:53 AM.

  10. #10
    Ellesar1's Avatar Member
    Reputation
    20
    Join Date
    Feb 2009
    Posts
    78
    Thanks G/R
    0/0
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Thanks ("You must spread some Reputation around before giving it to berserk85 again.")

    it seems that you have found the source for my problem:
    Code:
    CPU Disasm
    Address   Hex dump          Command                                  Comments
    00820CF0  /$  55            PUSH EBP
    00820CF1  |.  8BEC          MOV EBP,ESP
    00820CF3  |.  A1 C8D73301   MOV EAX,DWORD PTR DS:[133D7C8]
    00820CF8  |.  8B0D CCD73301 MOV ECX,DWORD PTR DS:[133D7CC]
    00820CFE  |.  83EC 40       SUB ESP,40
    00820D01  |.  85C0          TEST EAX,EAX
    00820D03  |.  74 04         JE SHORT 00820D09
    00820D05  |.  85C9          TEST ECX,ECX
    00820D07  |.  75 10         JNE SHORT 00820D19
    00820D09  |>  E8 52FFFFFF   CALL 00820C60
    00820D0E  |.  A1 C8D73301   MOV EAX,DWORD PTR DS:[133D7C8]           ; EAX = 0x00401000 WoW.<ModuleEntryPoint>
    00820D13  |.  8B0D CCD73301 MOV ECX,DWORD PTR DS:[133D7CC]           ; ECX = 0x0099EAD3
    00820D19  |>  8B55 08       MOV EDX,DWORD PTR SS:[ARG.1]             ; EDX = 0x6b6c1190 my function pointer
    00820D1C  |.  3BD0          CMP EDX,EAX
    00820D1E  |.  72 04         JB SHORT 00820D24                        ; fail if function pointer < eax => OK
    00820D20  |.  3BD1          CMP EDX,ECX
    00820D22  |.  72 1D         JB SHORT 00820D41                        ; fail if function pointer >= ecx => FAIL
    00820D24  |>  52            PUSH EDX
    00820D25  |.  68 E83DA000   PUSH OFFSET WoW.00A03DE8                 ; ASCII "Invalid function pointer: %p"
    00820D2A  |.  8D45 C0       LEA EAX,[LOCAL.16]
    00820D2D  |.  6A 40         PUSH 40
    00820D2F  |.  50            PUSH EAX
    00820D30  |.  E8 7B44ECFF   CALL 006E51B0
    00820D35  |.  8D4D C0       LEA ECX,[LOCAL.16]
    00820D38  |.  51            PUSH ECX
    00820D39  |.  E8 426CECFF   CALL 006E7980
    00820D3E  |.  83C4 14       ADD ESP,14
    00820D41  |>  8BE5          MOV ESP,EBP
    00820D43  |.  5D            POP EBP
    00820D44  \.  C3            RETN
    Will now check when DS:[133D7CC] is written and think about rewriting it so that the allowed range includes my function.

  11. #11
    Ellesar1's Avatar Member
    Reputation
    20
    Join Date
    Feb 2009
    Posts
    78
    Thanks G/R
    0/0
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    manuelly editing DS:[133d7cc] to 0xffffffff works.

    Does anybody know, if this value is checked by Warden / if it is currently being detected if you modify it?
    edit: yes, is checked! ban after 5 mins

    Last edited by Ellesar1; 10-17-2009 at 11:04 AM.

  12. #12
    berserk85's Avatar Member
    Reputation
    8
    Join Date
    Apr 2008
    Posts
    35
    Thanks G/R
    0/0
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Yep is checked ^^
    You can use the apoc method http://www.mmowned.com/forums/bots-p...-commands.html (callback etc etc) or use HWBP.
    Last edited by berserk85; 10-17-2009 at 10:51 AM.

  13. #13
    Ellesar1's Avatar Member
    Reputation
    20
    Join Date
    Feb 2009
    Posts
    78
    Thanks G/R
    0/0
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    what about writing into the allowed range some codeCave which just jumps to the real function? or is there absolutely zero space to do that?

  14. #14
    berserk85's Avatar Member
    Reputation
    8
    Join Date
    Apr 2008
    Posts
    35
    Thanks G/R
    0/0
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Yep this is a way ... with callback it will work fine ^^
    Last edited by berserk85; 10-17-2009 at 12:18 PM.

  15. #15
    flo8464's Avatar Active Member
    Reputation
    30
    Join Date
    Apr 2009
    Posts
    434
    Thanks G/R
    0/0
    Trade Feedback
    0 (0%)
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    There is no need to have access to the TLS to register a function.
    Last edited by flo8464; 10-17-2009 at 12:23 PM.

Page 1 of 2 12 LastLast

Similar Threads

  1. Auto-login, Finding Lua_Register Offset (Help)
    By schifers in forum WoW Memory Editing
    Replies: 14
    Last Post: 07-09-2010, 04:39 PM
All times are GMT -5. The time now is 12:36 AM. Powered by vBulletin® Version 4.2.3
Copyright © 2025 vBulletin Solutions, Inc. All rights reserved. User Alert System provided by Advanced User Tagging (Pro) - vBulletin Mods & Addons Copyright © 2025 DragonByte Technologies Ltd.
Google Authenticator verification provided by Two-Factor Authentication (Free) - vBulletin Mods & Addons Copyright © 2025 DragonByte Technologies Ltd.
Digital Point modules: Sphinx-based search