我有一个使用Winsock 2.0 recv
函数的应用程序,我可以通过Redox Packet Editor捕获输出,例如,它确认版本是2.0。
我有这个代码来挂钩函数:
#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也在很好地阅读数据。
有什么想法吗?
答案 0 :(得分: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。
答案 1 :(得分:1)
你的问题源于尝试写出一个空的(甚至是未初始化的缓冲区):
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
}
而是做这样的事情:
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
输出,您应该使用{ {1}}而是传递发送/接收大小(这也意味着以二进制模式打开文件)。
答案 2 :(得分:0)
我认为你当然应该使用GetProcAddress来获取要挂钩的地址。
类似的东西:
int (WINAPI *pRecv)(SOCKET s, char *buf, int len, int flags) = GetProcAddress(GetModuleHandle("ws2_32.dll"), "recv");
编译器可以提供从你的'recv'到装载dll的各种狂野路线。所以这两个地址可能有所不同。要测试是否是这种情况,只需使用你的dll中的recv。
您可能还想关注ReadFile / WriteFile。
并且还期望挂钩不可靠。例如,目标可以随意删除钩子并执行更多操作。