c++detours

How to Get ConnectEx() pointer


I'm using MS Detours and I want get the ConnectEx() pointer but is load at run time, how to get pointer and use with MS Detours?


Solution

  • ConnectEx() is not an exported DLL function. Per the ConnectEx() documentation:

    Note The function pointer for the ConnectEx function must be obtained at run time by making a call to the WSAIoctl function with the SIO_GET_EXTENSION_FUNCTION_POINTER opcode specified. The input buffer passed to the WSAIoctl function must contain WSAID_CONNECTEX, a globally unique identifier (GUID) whose value identifies the ConnectEx extension function. On success, the output returned by the WSAIoctl function contains a pointer to the ConnectEx function. The WSAID_CONNECTEX GUID is defined in the Mswsock.h header file.

    For example:

    #include <winsock2.h> // Must be included before Mswsock.h
    #include <mswsock.h>
    
    #pragma comment(lib, "ws2_32.lib")
    
    ...
    
    LPFN_CONNECTEX GetConnectExPtr(SOCKET s)
    {
        LPFN_CONNECTEX lpConnectEx = NULL;
        GUID guid = WSAID_CONNECTEX;
        DWORD dwNumBytes = 0;
        WSAIoctl(s, SIO_GET_EXTENSION_FUNCTION_POINTER, &guid, sizeof(guid), &lpConnectEx, sizeof(lpConnectEx), &dwNumBytes, NULL, NULL);
        return lpConnectEx;
    }
    

    Once you have a pointer to ConnectEx(), you can detour it. Depending on the version of MSDetours you are using, you can either:

    Use DetourFunction():

    #include <winsock2.h> // Must be included before Mswsock.h
    #include <mswsock.h>
    #include <detours.h>
    
    #pragma comment(lib, "ws2_32.lib")
    #pragma comment(lib, "detours.lib")
    
    ...
    
    LPFN_CONNECTEX Real_ConnectEx = NULL;
    LPFN_CONNECTEX Trampoline_ConnectEx = NULL;
    
    BOOL WINAPI MyConnectEx(SOCKET s, const struct sockaddr *name, int namelen, PVOID lpSendBuffer, DWORD dwSendDataLength, LPDWORD lpdwBytesSent, LPOVERLAPPED lpOverlapped)
    {
        // do something...
        return Trampoline_ConnectEx(s, name, namelen, lpSendBuffer, dwSendDataLength, lpdwBytesSent, lpOverlapped);
    }
    
    ...
    
    SOCKET s = ...;
    Real_ConnectEx = GetConnectExPtr(s);
    if (Real_ConnectEx)
    {
        Trampoline_ConnectEx = (LPFN_CONNECTEX) DetourFunction((PBYTE)Real_ConnectEx, (PBYTE)MyConnectEx);
    }
    
    ...
    
    if (Trampoline_ConnectEx)
        DetourRemoveTrampoline(Trampoline_ConnectEx);
    

    Use DetourAttach/Ex():

    #include <winsock2.h> // Must be included before Mswsock.h
    #include <mswsock.h>
    #include <detours.h>
    
    #pragma comment(lib, "ws2_32.lib")
    #pragma comment(lib, "detours.lib")
    #pragma comment(lib, "detoured.lib")
    
    ...
    
    LPFN_CONNECTEX Real_ConnectEx = NULL;
    LPFN_CONNECTEX Trampoline_ConnectEx = NULL;
    
    BOOL WINAPI MyConnectEx(SOCKET s, const struct sockaddr *name, int namelen, PVOID lpSendBuffer, DWORD dwSendDataLength, LPDWORD lpdwBytesSent, LPOVERLAPPED lpOverlapped)
    {
        // do something...
        return Trampoline_ConnectEx(s, name, namelen, lpSendBuffer, dwSendDataLength, lpdwBytesSent, lpOverlapped);
    }
    
    ...
    
    SOCKET s = ...;
    Real_ConnectEx = GetConnectExPtr(s);
    if (Real_ConnectEx)
    {
        DetourTransactionBegin();
        DetourUpdateThread(GetCurrentThread());
    
        // using DetourAttach()...
        Trampoline_ConnectEx = Real_ConnectEx;
        DetourAttach((PVOID*)&Trampoline_ConnectEx, MyConnectEx);
    
        // using DetourAttachEx()...
        // DetourAttachEx(&Real_ConnectEx, MyConnectEx, (PDETOUR_TRAMPOLINE*)&Trampoline_ConnectEx, NULL, NULL);
    
        DetourTransactionCommit();
    }
    
    ...
    
    if ((Real_ConnectEx) && (Trampoline_ConnectEx))
    {    
        DetourTransactionBegin();
        DetourUpdateThread(GetCurrentThread());
    
        // if using DetourAttach()...
        DetourDetach((PVOID*)&Trampoline_ConnectEx, MyConnectEx);
    
        // if using DetourAttachEx()...
        // DetourDetach((PVOID*)&Real_ConnectEx, MyConnectEx);
    
        DetourTransactionCommit();
    }