4

我有一个应用程序,它使用 Winsock 2.0recv功能,例如,我可以通过 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 也能很好地读取数据。

有任何想法吗?

4

3 回答 3

4

你确定你挂的是正确的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。

于 2012-04-11T22:46:30.363 回答
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输出,您应该fwrite改为使用,传递发送/接收大小(这也意味着以二进制模式打开文件)。

于 2012-04-09T06:08:42.417 回答
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。

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

于 2012-04-16T21:35:07.573 回答