2012-04-08 155 views
3

我有一个应用程序,它使用Winsock 2.0 recv函数,我可以通过Redox Packet Editor捕获输出,例如,它确认版本是2.0。Winsock recv hooking Detours

我有这样的代码挂钩函数:

#define _CRT_SECURE_NO_DEPRECATE 
#ifndef WIN32_LEAN_AND_MEAN 
#define WIN32_LEAN_AND_MEAN 
#endif 

#include <windows.h> 
#include <WinSock2.h> 
#include <detours.h> 
#include <stdio.h> 
#pragma comment(lib, "ws2_32.lib") 


FILE *pSendLogFile; 
FILE *pRecvLogFile; 

int (WINAPI *pSend)(SOCKET s, const char* buf, int len, int flags) = send; 
int WINAPI MySend(SOCKET s, const char* buf, int len, int flags); 
int (WINAPI *pRecv)(SOCKET s, char *buf, int len, int flags) = recv; 
int WINAPI MyRecv(SOCKET s, char* buf, int len, int flags); 


INT APIENTRY DllMain(HMODULE hDLL, DWORD Reason, LPVOID Reserved) 
{ 
    switch(Reason) 
    { 
     case DLL_PROCESS_ATTACH: 
      DisableThreadLibraryCalls(hDLL); 

      DetourTransactionBegin(); 
      DetourUpdateThread(GetCurrentThread()); 
      DetourAttach(&(PVOID&)pSend, MySend); 
      if(DetourTransactionCommit() == NO_ERROR) 
       MessageBox(0,"send() detoured successfully","asd",MB_OK); 

      DetourTransactionBegin(); 
      DetourUpdateThread(GetCurrentThread()); 
      DetourAttach(&(PVOID&)pRecv, MyRecv); 
      if(DetourTransactionCommit() == NO_ERROR) 
       MessageBox(0,"recv() detoured successfully","asd",MB_OK); 
      break; 

    case DLL_PROCESS_DETACH: 
    case DLL_THREAD_ATTACH: 
    case DLL_THREAD_DETACH: 
     break; 
    } 
    return TRUE; 
} 


int WINAPI MySend(SOCKET s, const char* buf, int len, int flags) 
{ 
    MessageBox(0,"sent","sent",MB_OK); 
    return pSend(s, buf, len, flags); 
} 

int WINAPI MyRecv(SOCKET s, char* buf, int len, int flags) 
{ 
    MessageBox(0,"recvd","recvd",MB_OK); 
    return pRecv(s, buf, len, flags); 
} 

对于send,一切完美,但我没有得到任何输出recv。我尝试使用1.1版Winsock的另一个应用程序,它工作正常。试图挂钩WSARecv,WSARecvEx没有任何运气。

使用WinAPIOverride32检查了应用程序,它清楚地表明它使用了recv函数,并成功记录了使用情况。 Winsock Packet Editor也正在读取数据。

任何想法?

int WINAPI MyRecv(SOCKET s, char* buf, int len, int flags) 
{ 
    fopen_s(&pRecvLogFile, "C:\\RecvLog.txt", "a+"); 
    fprintf(pRecvLogFile, "%s\n", buf); 
    fclose(pRecvLogFile); 
    return pRecv(s, buf, len, flags); //you need to call recv first 
} 

,而不是做这样的事情:

+1

我的建议是:写一个LSP(Layered Service Provider)。修改其中一个LSP样本将使您获得更多,并且可能比挂钩方式更具包容性。将其设想为TDI驱动程序和朋友的替代用户模式。 – 0xC0000022L 2012-04-09 00:17:06

+0

该LSP的任何文章或示例代码?我希望它不那么复杂。 – methyl 2012-04-09 08:34:12

+0

当然,这个大部分仍然有效:https://www.microsoft.com/msj/0599/layeredservice/layeredservice.aspx,当然还有:http://msdn.microsoft.com/en-us/ library/windows/desktop/bb513664(v = vs.85).aspx – 0xC0000022L 2012-04-09 11:50:07

回答

3

你确定你在钩正确的dll吗?我会仔细检查程序实际使用的是哪个dll:WSOCK32.dll或ws2_32.dll。

编辑:

也许尝试这样的事:

typedef int (WINAPI *SendPtr)(SOCKET s, const char* buf, int len, int flags); 
HMODULE hLib = LoadLibrary("wsock32.dll"); 
SendPtr pSend = (SendPtr)GetProcAddress(hLib, "send"); 

然后使用pSend与值(recv的同样的事情)。不要忘记最后调用FreeLibrary。 如果您确定该dll已经被加载,那么最好使用GetModuleHandle("wsock32.dll"),因为在这种情况下您不必调用FreeLibrary。

+0

是的,我检查了它,并试图将注入dll中的头文件和lib更改为winsock32没有任何结果。 – methyl 2012-04-12 08:40:05

+0

我认为这是很好的跟踪,因为在EasyHook中我必须将'[Dllimport]'设置为'wsock32.dll'而不是'ws2_32.dll'。如何在少走弯路? – methyl 2012-04-16 12:10:19

+0

你说得对,但Ivarpoiss第一次有确切的解决方案,所以赏金是他的。感谢帮助! – methyl 2012-04-17 17:02:03

1

您的问题从尝试写了一个空的(或甚至未初始化的缓冲区)茎

int WINAPI MyRecv(SOCKET s, char* buf, int len, int flags) 
{ 
    int read = pRecv(s, buf, len, flags); 
    if(read <= 0) 
    { 
     //read error/connection closed 
     return read; 
    } 

    fopen_s(&pRecvLogFile, "C:\\RecvLog.txt", "a+"); 
    fwrite(buf,sizeof(char),read,pRecvLogFile); 
    fclose(pRecvLogFile); 
    return read; 
} 

作为一个次要问题,你似乎是假设发送或接收的数据纯粹是基于字符串的,但通常数据包可能包含零字节,这会过早地结束fprintf输出,您应该使用fwrite,而不是传递发送/接收大小(这也是我mplies以二进制模式打开文件)。

+0

不要认为这是一个问题,发送工作正常,看起来相同,尝试通过MessageBox调试它作为MyRecv中的第一个调用,没有显示一个应用程序,另一方面一切正常 - 消息显示和数据被倾倒。 – methyl 2012-04-09 06:41:16

+0

@methyl:但'send' * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * send * '。通过调试器tbh来运行这将是一个好主意。 – Necrolis 2012-04-09 08:59:31

+0

但是,问题是功能不能绕道。该日志甚至没有创建。 – methyl 2012-04-09 09:06:37

1

我想你应该一定使用GetProcAddress来获取钩子的地址。

喜欢的东西:

int (WINAPI *pRecv)(SOCKET s, char *buf, int len, int flags) = GetProcAddress(GetModuleHandle("ws2_32.dll"), "recv");

编译器可以拿出从“recv的”加载了该DLL的一个各类野生路线。所以这两个地址可能有所不同。要测试是否是这种情况,只需使用recv从你的DLL。

您可能还想关注ReadFile/WriteFile。

并且也期望挂钩是不可靠的。例如,目标可以随意移除钩子并做更多事情。

+0

Downvote复制我的解决方案。 – newgre 2012-04-18 12:19:22