C++钩取Winsock

5

我正在尝试钩取Winsock的发送和接收,以便读取进程的所有流量。我将以下代码作为DLL注入到目标进程中:

#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;
}

这在某些情况下可以正常工作,但在某些情况下则不行。

如果我将其注入到FileZilla FTP中,它就能完美运行,并将发送或接收的所有内容写入文件。

但在几乎所有其他程序(如Internet Explorer、Firefox等)中,它只会向文件写入一些字节,然后进程崩溃...

有没有人知道是哪里出了问题?

2个回答

5

好的,现在它可以工作了,即使启用了数据执行保护。以防将来有人遇到类似问题,这里是可行的代码:

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_ */

已测试并可与Win XP 32位上的几乎所有程序以及Win 7 x64上的一些程序兼容。


3

请确保在钩子函数中使用正确的调用约定。默认的调用约定通常是__cdecl。但是,'send'和'recv'使用__stdcall(#define WINAPI __stdcall)。

两种调用约定之间的主要区别是:

当一个函数使用__cdecl时,调用者负责栈清理。然而,当一个函数使用__stdcall时,被调用的函数负责栈清理。

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

欲了解更多信息,请点击此处


好的。我使用了以下代码: int __stdcall nRecv(SOCKET s, char* buf, int len, int flags);现在它可以在Firefox中运行,但是如果我将它注入到Internet Explorer或任何Windows软件(如资源管理器等)中,它仍然会崩溃... - incognym
1
尝试使用FlushInstructionCache - “如果应用程序在内存中生成或修改代码,则应调用FlushInstructionCache。CPU无法检测更改,可能会执行其缓存的旧代码。” - user1052842
越来越好了... 现在我在HookFunction和UnHookFunction的末尾调用FlushInstructionCache(在返回之前)现在它可以在Win XP x86上与InternetExplorer一起工作 但是在Win7 x64上的InternetExplorer(32位)仍然会崩溃而且,如果我尝试将其注入到explorer.exe中(在Xp x86上),数据执行预防会终止该进程 -.-'有什么想法吗? (顺便说一句,非常感谢你迄今为止的帮助) - incognym
1
x64的hooking与x86不同。0xE9只能JMP 32位有符号数。因此,如果你的JMP比这个大,那可能就是问题所在。尝试使用0xFF 0x25 JMP。此外,在x64上,前5个字节可能会有所不同。(不是你通常在x86上看到的mov edi, edi、push ebp等) - user1052842
使用VirtualProtect()解决了遗留问题。感谢你的帮助 :) - incognym

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接