Jump to content
Moopler
Sign in to follow this  
pkedpker

Help Hooking WS2_32.DLL connect for redirector for maplestory

Recommended Posts

I'm attempting to make a maplestory redirector so I could setup a proxy server.

 

I cannot hook WS2_32.dll as its detected but I attempt to use the public dinput8.dll hook and redirect WS2_32.dll connect function from inside it.

My code works for before Nexon GameGuard loads then just before maplestory loads up it crashes.

	
typedef HRESULT(WINAPI* tconnect)(_In_  SOCKET s, _In_  const struct sockaddr *name, _In_  int namelen);
tconnect oconnect = reinterpret_cast<tconnect>(GetProcAddress(GetModuleHandle(L"WS2_32.dll"), "connect"));

HRESULT WINAPI hkconnect(_In_  SOCKET s, _In_ const struct sockaddr *name, _In_ int namelen)
{
    struct sockaddr_in *in = (struct sockaddr_in *)name;
	    printf("Attempting connect %d  %d.%d.%d.%d : %d\n", s, in->sin_addr.S_un.S_un_b.s_b1, in->sin_addr.S_un.S_un_b.s_b2, in->sin_addr.S_un.S_un_b.s_b3, in->sin_addr.S_un.S_un_b.s_b4, in->sin_port);
    return oconnect(s, name, namelen);
}
	

 

The DLLMain Injected thread has this code

while (!(unsigned long)GetModuleHandle(L"ws2_32.dll"))
    Sleep(100);// Wait until loaded
        
printf("dinput8.dll = %X\n", GetModuleHandle(L"dinput8.dll"));

if (oconnect != 0) {
    CMemory Client;
    printf("Before \n");
    Client.DetourFunction(TRUE, reinterpret_cast<void**>(&oconnect), hkconnect);
    printf("After \n");
}
	

 

the DetourFunction is this

BOOL CMemory::DetourFunction(__in BOOL bState, __inout PVOID* ppPointer, __in PVOID pDetour)
{
    if (DetourTransactionBegin() == NO_ERROR)
        if (DetourUpdateThread(GetCurrentThread()) == NO_ERROR)
            if ((bState ? DetourAttach : DetourDetach)(ppPointer, pDetour) == NO_ERROR)
                if (DetourTransactionCommit() == NO_ERROR)
                    return TRUE;
    return FALSE;
}
	

 

Here is a screenshot

kHhShyS.png

 

As you can see the first original hook crashes the second one doesn't crash even though it didn't do any hooking. the second one gets started by the anticheat i think.

 

How do I fix this?

Edited by pkedpker

Share this post


Link to post

It has nothing to do with NGS. You're being detected by virtualized "SafeDll" functions thatchecks for corruption in networking files.

If you want to resirect, you hve to use the method I derived where we hook deeper into the connect chain (I believe Rajan released it on ragezone)

Share this post


Link to post
1 hour ago, NewSprux2.0? said:

It has nothing to do with NGS. You're being detected by virtualized "SafeDll" functions thatchecks for corruption in networking files.

If you want to resirect, you hve to use the method I derived where we hook deeper into the connect chain (I believe Rajan released it on ragezone)

Or hook with page exceptions/debug registers.

Share this post


Link to post
18 minutes ago, Erotica said:

Or hook with page exceptions/debug registers.

That works too, but you'll still face problems with the gethostname checks :(

Share this post


Link to post

@NewSprux2.0?

 

you mean this ? https://github.com/RajanGrewal/AuthHook/blob/master/AuthHook/WinsockHax.cpp

 

it has some weird VM_START   / VM_END functions is it this? nevermind he explained thats for protecting his DLL from people when he sold it out.

 

I tried it out just now and it doesn't crash I was happy but then at the end when I joined a Channel It didn't show up the proper channel/lobby ports 8484 etc.. seems this MSWOCK is only used for the browser and other useless SSL ports.

 

It gets the connect() and GetPeerName() for the useless ports but the one I want 8484 and other ones it doesn't get.

 

screenshot.1.png.png

 

 

 

 

I tried with Page Exceptions / Debug Registers for a Thread. Could only get 1 Connection and it never got back on track again

Added this class

AwBreakPoint.cpp

#include "AwBreakPoint.h"
#include <windows.h>
#include <cstdio>
	EXCEPTION_HANDLER AwBreakPoint::Handler;
 
LONG __stdcall Ex_handler(EXCEPTION_POINTERS* ep)
{
    if(ep->ExceptionRecord->ExceptionCode == EXCEPTION_SINGLE_STEP)
    {
        EXCEPTION_HANDLER handler = AwBreakPoint::GetHandler();
 
        handler(ep);
 
        return EXCEPTION_CONTINUE_EXECUTION;
    }
    return EXCEPTION_CONTINUE_SEARCH;
}
 
void AwBreakPoint::GetMainThreadFromProcessId()
{
    unsigned long uProcessId = GetCurrentProcessId();
    HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD,uProcessId);
    
    if(!hSnapshot)
        return;
 
    THREADENTRY32 lpThread;
    
    lpThread.dwSize = sizeof(THREADENTRY32);
 
    if(Thread32First(hSnapshot,&lpThread))
    {
        do {
            if(lpThread.th32OwnerProcessID == uProcessId && lpThread.th32ThreadID != GetCurrentThreadId()) //Ignore threads from other processes AND the own thread of course
            {
                break;
            }
        }while(Thread32Next(hSnapshot,&lpThread));
 
        CloseHandle(hSnapshot);
        AwBreakPoint::m_hThread = OpenThread(THREAD_GET_CONTEXT | THREAD_SET_CONTEXT | THREAD_SUSPEND_RESUME,1,lpThread.th32ThreadID);
    }
    return;
}
 
bool AwBreakPoint::SetExceptionHandler(EXCEPTION_HANDLER eHandler)
{
    AwBreakPoint::Handler = eHandler;
    AddVectoredExceptionHandler(0, Ex_handler);
    return true;
}
 
EXCEPTION_HANDLER AwBreakPoint::GetHandler()
{
    return AwBreakPoint::Handler;
}
 
bool AwBreakPoint::SetHWBreakPoint(unsigned long uAddress, int iIndex)
{
    GetMainThreadFromProcessId();
    CONTEXT c = {CONTEXT_DEBUG_REGISTERS | CONTEXT_FULL };
    SuspendThread(AwBreakPoint::m_hThread);
    GetThreadContext(AwBreakPoint::m_hThread,&c);
    
    switch(iIndex)
    {
        case 0:
 
            c.Dr0 = uAddress;
            c.Dr7 |= 0x00000001;  // set 0th bit
            break;
 
        case 1:
 
            c.Dr1 = uAddress;
            c.Dr7 |= 0x00000004; // set 2nd bit
            break;
 
        case 2:
 
            c.Dr2 = uAddress;
            c.Dr7 |= 0x00000010; // set 4th bit
            break;
 
        case 3:
 
            c.Dr3 = uAddress;
            c.Dr7 |= 0x00000040; // set 6th bit
            break;
 
        default:
            return false;
    }
 
    //c.Dr6 = 0;
    SetThreadContext(AwBreakPoint::m_hThread,&c);
    ResumeThread(AwBreakPoint::m_hThread);
 
    return true;
}

bool AwBreakPoint::RemoveHWBreakPoint(int iIndex)
{
    //GetMainThreadFromProcessId();
    CONTEXT c = {CONTEXT_FULL | CONTEXT_DEBUG_REGISTERS};
    SuspendThread(AwBreakPoint::m_hThread);
    GetThreadContext(AwBreakPoint::m_hThread,&c);
    
    switch(iIndex)
    {
        case 0:
 
            c.Dr0 = 0;
            c.Dr7 &= 0xFFF0FFFE;  //  Clear the 16-19th and 1st bits  
            break;
 
        case 1:
 
            c.Dr1 = 0;
            c.Dr7 &= 0xFF0FFFFB;   //  Clear the 20-23rd and 2nd bits   
            break;
 
        case 2:
 
            c.Dr2 = 0;
            c.Dr7 &=0xF0FFFFEF; //  Clear the 24-27th and 3rd bits
            break;
 
        case 3:
 
            c.Dr3 = 0;
            c.Dr7 &=0xFFFFFBF; //  Clear the 28-31st and 4th bits      
            break;
 
        default:
            return false;
    }
 
    //c.Dr6 = 0;
    SetThreadContext(AwBreakPoint::m_hThread,&c);
    ResumeThread(AwBreakPoint::m_hThread);
    //RemoveVectoredExceptionHandler(Ex_handler);
    return true;
}
	

 

AwBreakPoint.h

#include <windows.h>
#include <tlhelp32.h>
 
typedef void(__cdecl* EXCEPTION_HANDLER)(EXCEPTION_POINTERS*);
 
class AwBreakPoint
{
    public:
        
        bool SetExceptionHandler(EXCEPTION_HANDLER);
        bool SetHWBreakPoint(unsigned long,int);
        bool RemoveHWBreakPoint(int);
        static EXCEPTION_HANDLER GetHandler();
    
    private:
        
        void GetMainThreadFromProcessId();
 
        HANDLE m_hThread;
        static EXCEPTION_HANDLER Handler;
 
};
	

 

DllMain Inject function for dInput8

AwBreakPoint BP;
DWORD connectFunctionAddress;
typedef int(WINAPI* tconnect)(SOCKET s, const struct sockaddr *name, int namelen);
tconnect oconnect;

int WINAPI hkconnect(SOCKET s, const struct sockaddr *name, int namelen)
{
	struct sockaddr_in *in = (struct sockaddr_in *)name;
	printf("Attempting connect %d  %d.%d.%d.%d : %d\n", s, in->sin_addr.S_un.S_un_b.s_b1, in->sin_addr.S_un.S_un_b.s_b2, in->sin_addr.S_un.S_un_b.s_b3, in->sin_addr.S_un.S_un_b.s_b4, htons(in->sin_port));
	BP.RemoveHWBreakPoint(0); //Remove breakpoint, process the ws2_32.connect below
	printf("Debug no go\n");
	int result = oconnect(s, name, namelen);
	printf("Oconnect called\n");
	BP.SetHWBreakPoint((unsigned long)connectFunctionAddress, 0); //Add breakpoint again for ws2_32.connect
	printf("reset\n");
	//return result;
	return 0;
}
	 
void HandleFunction(EXCEPTION_POINTERS* ep)
{
    if (ep->ContextRecord->Eip == (unsigned long)connectFunctionAddress) {
        ep->ContextRecord->Eip = (unsigned long)&hkconnect; //redirect it to my function.
        printf("EIP = %x connectFunctionAddress = %x \n", ep->ContextRecord->Eip, connectFunctionAddress);
    }
}
	
static int Injected()
{
	while (!(unsigned long)GetModuleHandle(L"ws2_32.dll"))
        Sleep(100);// Wait until loaded
	 
	BP.SetExceptionHandler(HandleFunction);
    oconnect = reinterpret_cast<tconnect>(GetProcAddress(GetModuleHandle(L"WS2_32.dll"), "connect"));
    connectFunctionAddress = (DWORD)GetProcAddress(GetModuleHandle(L"WS2_32.dll"), "connect");
	printf("ws2_32.dll connect function address = %x", connectFunctionAddress);
    BP.SetHWBreakPoint((unsigned long)connectFunctionAddress, 0);
}
	

607151123_screenshot.1.png(1).png.247844407e2405db24566299df0f9b20.png

 

Seems oconnect() creates a infinite loop on the first address and if I call GetMainThreadFromProcessId(); in the RemoveHWBreakPoint the above screenshot happens otherwise with it commented only 1 appears.. it looks like you cannot make another 1 from the same thread or something i cant figure it out.

 

Seems I cannot SuspendThread of the GetCurrentThread() as I won't be able to do ResumeThread() after idk how to fix it.

Edited by pkedpker
  • Like 1

Share this post


Link to post

 

22 hours ago, NewSprux2.0? said:

That works too, but you'll still face problems with the gethostname checks :(

Huh, when I made a redirector for some side/fun project all I did was hook connect() and the guy developing the server for fun (in swift, lol) got in-game with it.

 

About 8-12 months ago.

Share this post


Link to post
28 minutes ago, Erotica said:

 

Huh, when I made a redirector for some side/fun project all I did was hook connect() and the guy developing the server for fun (in swift, lol) got in-game with it.

 

About 8-12 months ago.

Somewhere in EnterField (iirc) it calls some identification API on the socket object to check the IP address of the remote host. If it is not within the "allowed" range of MapleStory IPs, the game is crashed.

Share this post


Link to post

I still cannot figure this out, I tried this code, which almost works, but it exits the game unexpectedly. I ran maplestory in OllyDbg and i get the error code 0xC00000005 Process terminated

screenshot.1.png.png.90a00a3863b351b5f094661cfecda526.png

DWORD connectFunctionAddress;
DWORD connectFunctionAddressReturn = connectFunctionAddress + 2;

int __cdecl ws2_32_connect_hook_output(SOCKET s, const struct sockaddr *name, int namelen) {
    struct sockaddr_in *in = (struct sockaddr_in *)name;
    printf("Attempting connect %d %d.%d.%d.%d : %d\n", s, in->sin_addr.S_un.S_un_b.s_b1, in->sin_addr.S_un.S_un_b.s_b2, in->sin_addr.S_un.S_un_b.s_b3, in->sin_addr.S_un.S_un_b.s_b4, htons(in->sin_port));
    return 1;
}
	
void __declspec(naked) ws2_32_connect_hook(void) { //ws2_32.connect = 775368F5
  __asm {
        PUSHAD //To be in safe environment
        PUSHFD //To be safe environment
        PUSH 0x10    //namelen
        PUSH ECX    //name
        PUSH EAX    //socket
        CALL DWORD PTR [ws2_32_connect_hook_output]
        ADD ESP, 0xC
        POPFD //Finish being in safe environment
        POPAD //Finish being in safe environment
        JMP connectFunctionAddressReturn
    }
}
void HandleFunction(EXCEPTION_POINTERS* ep)
{
    if (ep->ContextRecord->Eip == (DWORD)connectFunctionAddress) { //0x0043B260   MOV DWORD PTR DS:[ESI+3C],EDX
        connectFunctionAddressReturn = ep->ContextRecord->Eip + 2;
        ep->ContextRecord->Eip = (DWORD)&ws2_32_connect_hook; //redirect it to my function.
        printf("EIP = %x connectFunctionAddress = %x \n", ep->ContextRecord->Eip, connectFunctionAddress);
	    
        ep->ContextRecord->EFlags |= 0x100; //Set single step flag, causing only one line of code to be executed and then throwing the STATUS_SINGLE_STEP exception.
        printf("Set\n");
    }
}
	

 

Inject code

BP.SetExceptionHandler(HandleFunction);
connectFunctionAddress = (DWORD)GetProcAddress(GetModuleHandle(L"WS2_32.dll"), "connect");
printf("ws2_32.dll connect function address = %x", connectFunctionAddress);
BP.SetHWBreakPoint((unsigned long)connectFunctionAddress, 0);
	 
Edited by pkedpker

Share this post


Link to post
15 hours ago, Erotica said:

You do have the internal maplestory debug register scan bypassed right?

no figure i dont need any bypassses for something as simple as this.

 

Share this post


Link to post
1 hour ago, pkedpker said:

no figure i dont need any bypassses for something as simple as this.

 

Well maple reads the value of the debug registers periodically, and if it is non-zero(as it is, since you set a hwbp) it will crash the game.

Share this post


Link to post

the reason my localhost enabler didnt work for u was because u injected it too late.  wspstartup had already been called for maplestory context very early in client launch.  you need to create maplestory suspended , inject, then resume thread so youre the first mofucker in this bitch.  then itll work np for u.  heres code i use to inject my thingy https://github.com/RajanGrewal/Rebirth/blob/master/RebirthClient/RebirthLauncher/Main.cpp

  • Like 1

Share this post


Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
Sign in to follow this  

×