-
Member
[1.12.1] Trouble calling DefaultServerLogin
Hi all, I've been playing on a private WoW 1.12.1 server lately and have started reversing the client. I've never reversed something quite as complicated as WoW before so the going has been slow.
I've been trying to do the most basic thing I could think of - logging in via the client:
I've tried two methods of logging in, I've tried to call the DefaultServerLogin method at 0046D160 and also tried to call a method called by DefaultServerLogin that takes login/pass as arguments at 0046AFB0
When I call the nested method the function call works but all I see is the "Connecting" login box -- and when I try to call the top level DefaultServerLogin it doesnt recognize the GUI textboxes as valid....
0046D160
Code:
.text:0046D160 fn_DefaultServerLogin proc near ; DATA XREF: .data:00837484o
.text:0046D160 push esi
.text:0046D161 mov edx, 1
.text:0046D166 mov esi, ecx
.text:0046D168 call sub_6F3510 // returns 1 during normal execution, but during injection returns 0
.text:0046D16D test eax, eax
.text:0046D16F jz short loc_46D1AA // during injection makes this jump and ends function prematurely
.text:0046D171 mov edx, 2
.text:0046D176 mov ecx, esi
.text:0046D178 call sub_6F3510 // returns 1 during normal execution, but during injection returns 0
.text:0046D17D test eax, eax
.text:0046D17F jz short loc_46D1AA // during injection never makes it to this jump
.text:0046D181 push edi
.text:0046D182 mov edx, 2 ; ID of GUI textbox
.text:0046D187 mov ecx, esi ; base address
.text:0046D189 call fn_WoW_GetGUIData
.text:0046D18E mov edx, 1 ; ID of GUI textbox
.text:0046D193 mov ecx, esi ; base address
.text:0046D195 mov edi, eax ; password
.text:0046D197 call fn_WoW_GetGUIData
.text:0046D19C mov edx, edi ; password
.text:0046D19E mov ecx, eax ; username
.text:0046D1A0 call fn_DefaultServerLogin_Validate
.text:0046D1A5 pop edi
.text:0046D1A6 xor eax, eax
.text:0046D1A8 pop esi
.text:0046D1A9 retn
.text:0046D1AA ; ---------------------------------------------------------------------------
.text:0046D1AA
.text:0046D1AA loc_46D1AA: ; CODE XREF: fn_DefaultServerLogin+Fj
.text:0046D1AA ; fn_DefaultServerLogin+1Fj
.text:0046D1AA push offset aUsageDefaultse ; "Usage: DefaultServerLogin(\"accountName"...
.text:0046D1AF push esi
.text:0046D1B0 call sub_6F4940
.text:0046D1B0 fn_DefaultServerLogin endp
Here's my code:
Code:
// VanillaDll.cpp : Defines the exported functions for the DLL application.
//
#include "stdafx.h"
#include "Console.h"
#include <ctime>
#include <iostream>
#include <stdio.h>
#include <sstream>
#include <iomanip>
#include "Utils.h"
namespace Vanilla {
typedef int(__thiscall *ppLogin)(char *login, char *pass); ppLogin pLogin = NULL;
typedef int(__thiscall *ppDefaultLoginValidate)(char *login, char *pass); ppDefaultLoginValidate pValidate = NULL;
typedef int(__thiscall *ppDefaultLogin)(DWORD ecx); ppDefaultLogin pDefaultLogin = NULL;
typedef int(__stdcall *ppGetFuncPtrBase)(); ppGetFuncPtrBase pGetFuncPtrBase = NULL;
unsigned int __stdcall GETPTRBASE() {
return pGetFuncPtrBase();
}
void __fastcall DefaultServerLogin() {
DWORD ecx = pGetFuncPtrBase();
pDefaultLogin(ecx);
}
void DefaultLogin(char* login, char* pass) {
unsigned int address;
//__asm mov edx, pass;
__asm call GETPTRBASE;
__asm mov address, eax;
std::stringstream ss;
ss << std::hex << address;
std::string addressStr = ss.str();
Utils::Log("Address is 0x%s", addressStr.c_str());
__asm call pGetFuncPtrBase;
__asm mov esi, eax;
__asm mov edx, pass;
pValidate(login, pass);
}
bool Attach(HINSTANCE DLL, VOID* Reserved) {
Console::RedirectIOToConsole();
Utils::Log("Hello were logging now....");
//int(*hLogin)(char*,char*);
pLogin = (ppLogin)0x005AB4B0;
pDefaultLogin = (ppDefaultLogin)0x0046D160;
pValidate = (ppDefaultLoginValidate)0x0046AFB0;
pGetFuncPtrBase = (ppGetFuncPtrBase)0x007040D0;
Utils::Log("Typedef set hook ready");
Utils::Log("Calling login at address 0x0046AFB0");
DefaultServerLogin();
//pLogin("user", "pass");
//DefaultLogin("user","pass");
Utils::Log("Hook called");
return true;
}
bool Detach() {
return true;
}
}
Calling 0046D160 should attempt to login with the current text contained in memory (expecting to get a "Enter a username" popup), but it simply gives me the invalid default info jump. One thing I notice is that naturally the method gets called from this method 006F6050
This looks to me like a function ptr handler and checks if the ptr is pointing to a valid function within the binaries .text segment but it's at this point I start to really hit trouble.
Last edited by flawblure; 03-28-2017 at 01:05 PM.
-
Contributor
That's like your function looks in IDA with some naming added:
Code:
int __thiscall Script_DefaultServerLogin(void *state)
{
int lua_state; // esi@1
char *pass; // edi@3
char *user; // eax@3
lua_state = state;
if ( !FrameScript::IsString(state, 1) || !FrameScript::IsString(lua_state, 2) )
{
FrameScript::DisplayError(lua_state, "Usage: DefaultServerLogin(\"accountName\", \"password\")");
}
pass = FrameScript::LuaToLString(lua_state, 2);
user = FrameScript::LuaToLString(lua_state, 1);
CGlueMgr::DefaultServerLogin(user, pass); // 0x0046D1A0
return 0;
}
And you should be able to call the CGlueMgr::DefaultServerLogin() from your injected code like this (I just tested it and it works):
Code:
char user[]{ "username" };
char pass[]{ "password" };
((int(__fastcall*)(char*, char*))0x0046AFB0)(user, pass);
P.S - The error that I made too in the beginning (and had crashes) was to not reserve space for the char* literals (maybe the compiler made them const automatically and CGlueMgr::DefaultServerLogin() tried to put zeroes to pass at 0046B07A).
Last edited by tutrakan; 03-28-2017 at 09:21 PM.
-
Post Thanks / Like - 1 Thanks
flawblure (1 members gave Thanks to tutrakan for this useful post)
-
Originally Posted by
tutrakan
Code:
char user[]{ "username" };
char pass[]{ "password" };
wot.
why.
-
Member
Great! Thanks! So I'm trying to use this code
Code:
char user[]{ "" };
char pass[]{ "" };
((int(__fastcall*)(char*, char*))0x0046AFB0)(user, pass);
To display the error that asks you to enter a username, but this also hangs on connecting? Am I not injecting into the main thread? That's the entire program that I pasted so I'm not doing much....
Also, after I try to inject and call CGlueMgr:efaultServerLogin(user, pass); getting hte connecting screen, I'm then unable to login normally. As though the call corrupted the program -- more evidence of the wrong thread?
EDIT: I've been looking at GitHub - acidburn974/CorthezzWoWBot: Bot for WoW Vanilla from OwnedCore: http://www.ownedcore.com/forums/world-of-warcraft/world-of-warcraft-bots-programs/wow-memory-editing/515591-bot-1-12-1-wow-bot-source-code.html and I see how it's hooking EndScene to execute in the main thread... so I have to call my login from there
Last edited by flawblure; 03-29-2017 at 04:22 AM.
-
Contributor
Originally Posted by
Jadd
wot.
why.
Originally Posted by
tutrakan
P.S - The error that I made too in the beginning (and had crashes) was to not reserve space for the char* literals (maybe the compiler made them const automatically and CGlueMgr:efaultServerLogin() tried to put zeroes to pass at 0046B07A).
Because the function at 0x0046AFB0 writes zeroes to the password char* pointer. So, it expects a pointer to non constant C-string.
Code:
memset(passw, 0, strlen(passw));
Last edited by tutrakan; 03-29-2017 at 06:00 PM.
-
Contributor
Originally Posted by
flawblure
To display the error that asks you to enter a username, but this also hangs on connecting? Am I not injecting into the main thread? That's the entire program that I pasted so I'm not doing much....
Also, after I try to inject and call CGlueMgr:
efaultServerLogin(user, pass); getting hte connecting screen, I'm then unable to login normally. As though the call corrupted the program -- more evidence of the wrong thread?
I called it from my DllMain like this:
Code:
DWORD MainThreadControl(LPVOID /* param */);
// entry point of the DLL
BOOL APIENTRY DllMain(HINSTANCE instDLL, DWORD reason, LPVOID /* reserved */)
{
if (reason == DLL_PROCESS_ATTACH)
{
// disables thread notifications (DLL_THREAD_ATTACH, DLL_THREAD_DETACH)
DisableThreadLibraryCalls(instDLL);
CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)&MainThreadControl, NULL, 0, NULL);
}
else if (reason == DLL_PROCESS_DETACH)
{
}
return TRUE;
}
DWORD MainThreadControl(LPVOID lpParm)
{
char user[]{ "user" };
char pass[]{ "pass" };
((int(__fastcall*)(char*, char*))0x0046AFB0)(user, pass);
while (1) {};
}
Last edited by tutrakan; 03-29-2017 at 04:36 AM.
-
Post Thanks / Like - 1 Thanks
flawblure (1 members gave Thanks to tutrakan for this useful post)
-
Member
Aha! Alright.. so the thread was my issue all along. The copy pasta you gave me works perfectly of course
I was looking at the source for GitHub - acidburn974/CorthezzWoWBot: Bot for WoW Vanilla from OwnedCore: http://www.ownedcore.com/forums/world-of-warcraft/world-of-warcraft-bots-programs/wow-memory-editing/515591-bot-1-12-1-wow-bot-source-code.html -- in another thread I believe I read that it hooks EndScene in order to execute DoString in the main thread.
Looking through the source I see it allocating a code cave and injecting DoString in there -- is that a seperate issue to executing on the main thread? Your example is just creating a new thread? Or does that call to CreateThread actually access the main thread? Much to learn! Thanks!
-
Contributor
You have first to inject your dll.
-
Member
What I mean is that after you've injected the DLL if you CreateThread your just creating a new thread alongside the main thread arnt you? In the example you posted, could you safely call DoString from that MainThreadControl func?
-
Contributor
I don't think so. As I know, dostring must be called from the end scene. Not sure for Vanilla, because I never tested. If you call it outside - you need loadbuffer, pcall etc.
Last edited by tutrakan; 03-29-2017 at 05:16 AM.
-
Post Thanks / Like - 1 Thanks
flawblure (1 members gave Thanks to tutrakan for this useful post)