C++ hooking winsock

15,710

Solution 1

Ok. Its working now, even with DataExecutionPrevention enabled. In case someone has a similar problem in future, here is the working code:

dllmain.cpp:

#include "dll.h"
#include <windows.h>
#include <winsock2.h>
#include <iostream>
#include <fstream>

#pragma comment(lib, "ws2_32.lib")

using namespace std;

DllClass::DllClass()
{

}


DllClass::~DllClass ()
{

}

BYTE hook[6];
BYTE hook2[6];
BYTE jmp[6] = { 0xe9,0x00, 0x00, 0x00, 0x00 ,0xc3 };  
ofstream myfile;
ofstream myfile2;
DWORD pPrevious;

DWORD HookFunction(LPCSTR lpModule, LPCSTR lpFuncName, LPVOID lpFunction, unsigned char *lpBackup)
{  
      DWORD dwAddr = (DWORD)GetProcAddress(GetModuleHandle(lpModule), lpFuncName);
      ReadProcessMemory(GetCurrentProcess(), (LPVOID)dwAddr, lpBackup, 6, 0);
      DWORD dwCalc = ((DWORD)lpFunction - dwAddr - 5);
      VirtualProtect((void*) dwAddr, 6, PAGE_EXECUTE_READWRITE, &pPrevious);
      memcpy(&jmp[1], &dwCalc, 4);
      WriteProcessMemory(GetCurrentProcess(), (LPVOID)dwAddr, jmp, 6, 0);
      VirtualProtect((void*) dwAddr, 6, pPrevious, &pPrevious);
      FlushInstructionCache(GetCurrentProcess(),0,0);
      return dwAddr;
}    

BOOL UnHookFunction(LPCSTR lpModule, LPCSTR lpFuncName, unsigned char *lpBackup)
{
DWORD dwAddr = (DWORD)GetProcAddress(GetModuleHandle(lpModule), lpFuncName);

if (WriteProcessMemory(GetCurrentProcess(), (LPVOID)dwAddr, lpBackup, 6, 0))
        return TRUE;
        FlushInstructionCache(GetCurrentProcess(),0,0);

return FALSE;  
}

int __stdcall nSend(SOCKET s, const char *buf, int len,int flags){
UnHookFunction("ws2_32.dll", "send", hook);


int result = send(s,buf,len,flags);


  myfile.open ("C:\\tmp\\log.txt",ios::app | ios::binary);
  myfile << buf;
  myfile.close();




HookFunction("ws2_32.dll", "send", (LPVOID*) nSend, hook);
return result;
} 

int __stdcall nRecv(SOCKET s, char* buf, int len, int flags)
{
    UnHookFunction("ws2_32.dll", "recv", hook2);
    DWORD tmp;

    len = recv(s, buf, len, flags);

    if (len > 0)
    {

        myfile2.open ("C:\\tmp\\log.txt",ios::app | ios::binary);
        myfile2 << buf;
        myfile2.close();
    }
   HookFunction("ws2_32.dll", "recv", (LPVOID*) nRecv, hook2);
    return len;
}
void fun(){
HookFunction("ws2_32.dll", "send", (LPVOID*) nSend, hook);
HookFunction("ws2_32.dll", "recv", (LPVOID*) nRecv, hook2);
}

BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
HookFunction("ws2_32.dll", "send", (LPVOID*) nSend, hook);
HookFunction("ws2_32.dll", "recv", (LPVOID*) nRecv, hook2);
case DLL_THREAD_ATTACH:
case DLL_THREAD_DETACH:
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}

dll.h

#ifndef _DLL_H_
#define _DLL_H_

#if BUILDING_DLL
# define DLLIMPORT __declspec (dllexport)
#else /* Not BUILDING_DLL */
# define DLLIMPORT __declspec (dllimport)
#endif /* Not BUILDING_DLL */


class DLLIMPORT DllClass
{
  public:
    DllClass();
    virtual ~DllClass(void);

  private:

};
extern "C" __declspec(dllexport) void fun();

#endif /* _DLL_H_ */

Tested and working with nearly all programs on Win XP 32bit and some programs on Win 7 x64

Solution 2

Be sure to use the correct calling convention on your hooked functions. The default calling convention is usually __cdecl. However 'send', and 'recv' use __stdcall (#define WINAPI __stdcall)

The main difference between the two are:

When a function uses __cdecl the caller is responsible for stack cleanup. However when a function uses __stdcall the called function is responsible for stack cleanup.

int WINAPI nSend(SOCKET s, const char *buf, int len,int flags);
int WINAPI nRecv(SOCKET s, char* buf, int len, int flags)

See here for more information.

Share:
15,710
incognym
Author by

incognym

Sorry for my English. Learning by doing...

Updated on June 04, 2022

Comments

  • incognym
    incognym almost 2 years

    I am trying to hook winsock send and recv in order to read all traffic of a process. I am injectin the following code as a dll inside the target process

    #include "dll.h"
    #include <windows.h>
    #include <winsock2.h>
    #include <iostream>
    #include <fstream>
    
    #pragma comment(lib, "ws2_32.lib")
    
    using namespace std;
    
    DllClass::DllClass()
    {
    
    }
    
    
    DllClass::~DllClass ()
    {
    
    }
    
    BYTE hook[6];
    BYTE hook2[6];
    BYTE jmp[6] = { 0xe9,0x00, 0x00, 0x00, 0x00 ,0xc3 };  
    ofstream myfile;
    ofstream myfile2;
    
    DWORD HookFunction(LPCSTR lpModule, LPCSTR lpFuncName, LPVOID lpFunction, unsigned char *lpBackup)
    {  
          DWORD dwAddr = (DWORD)GetProcAddress(GetModuleHandle(lpModule), lpFuncName);
          ReadProcessMemory(GetCurrentProcess(), (LPVOID)dwAddr, lpBackup, 6, 0);
          DWORD dwCalc = ((DWORD)lpFunction - dwAddr - 5);
          memcpy(&jmp[1], &dwCalc, 4);
          WriteProcessMemory(GetCurrentProcess(), (LPVOID)dwAddr, jmp, 6, 0);
          return dwAddr;
    }    
    
    BOOL UnHookFunction(LPCSTR lpModule, LPCSTR lpFuncName, unsigned char *lpBackup)
    {
    DWORD dwAddr = (DWORD)GetProcAddress(GetModuleHandle(lpModule), lpFuncName);
    if (WriteProcessMemory(GetCurrentProcess(), (LPVOID)dwAddr, lpBackup, 6, 0))
            return TRUE;
    return FALSE;  
    }
    
    int nSend(SOCKET s, const char *buf, int len,int flags){
    UnHookFunction("ws2_32.dll", "send", hook);
    
    
    int result = send(s,buf,len,flags);
    
    
      myfile.open ("C:\\tmp\\log.txt",ios::app | ios::binary);
      myfile << buf;
      myfile.close();
    
    
    
    
    HookFunction("ws2_32.dll", "send", (LPVOID*) nSend, hook);
    return result;
    } 
    
    int nRecv(SOCKET s, char* buf, int len, int flags)
    {
        UnHookFunction("ws2_32.dll", "recv", hook2);
        DWORD tmp;
    
        len = recv(s, buf, len, flags);
    
        if (len > 0)
        {
    
            myfile2.open ("C:\\tmp\\log.txt",ios::app | ios::binary);
            myfile2 << buf;
            myfile2.close();
        }
       HookFunction("ws2_32.dll", "recv", (LPVOID*) nRecv, hook2);
        return len;
    }
    void fun(){ // <-- this is called after the DLL has been injected
    HookFunction("ws2_32.dll", "send", (LPVOID*) nSend, hook);
    HookFunction("ws2_32.dll", "recv", (LPVOID*) nRecv, hook2);
    }
    
    BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
    {
    switch (ul_reason_for_call)
    {
    case DLL_PROCESS_ATTACH:
    
    case DLL_THREAD_ATTACH:
    case DLL_THREAD_DETACH:
    case DLL_PROCESS_DETACH:
    break;
    }
    return TRUE;
    }
    

    This works in some cases and in some it doesnt. If i inject it into filezilla ftp it works like a charm and writes everything that is send or recieved to a file.

    But on nearly all other programms (internet explorer, firefox usw.) it just writes some bytes to the file and then the process crashes...

    Has anyone an idea what is going wrong?

  • incognym
    incognym about 11 years
    ok. i used: int __stdcall nRecv(SOCKET s, char* buf, int len, int flags); Now it works in Firefox, but if i inject it into internet explorer or any windows software (explorer usw.) it still crashes...
  • user1052842
    user1052842 about 11 years
    Try using FlushInstructionCache - "Applications should call FlushInstructionCache if they generate or modify code in memory. The CPU cannot detect the change, and may execute the old code it cached."
  • incognym
    incognym about 11 years
    It's getting better... Now I'm calling FlushInstructionCache at the end of HookFunction & UnHookFunction (before the return) Now it works with InternetExplorer on Win XP x86 But it still crashes in InternetExplorer (32bit) on Win7 x64 And if i try to inject it in explorer.exe (on Xp x86) the DataExecutionPrevention kills the process -.-' Any ideas? (BTW. thanks so far, you already helped alot)
  • user1052842
    user1052842 about 11 years
    x64 hooking is different than x86. 0xE9 can only JMP 32 signed bits. So if your JMP is bigger than that, that could be your problem. Try a 0xFF 0x25 JMP. Also on x64 the first 5 bytes can be different. (Not your usual x86 (mov edi, edi), (push ebp), etc)
  • incognym
    incognym about 11 years
    Using VirtualProtect() fixed the left issues. Thanks for your help :)