使用不同版本的 Winsock

Winsock working with different versions

我写了一个数据包拦截器来从 winsock 的 send/recv 函数中转储信息,据我所知,这两个函数都位于 ws2_32.dll;挂钩是通过将 jmp 写入记录我需要的信息然后调用原始函数的函数来完成的,挂钩本身工作正常。

真正奇怪的是,我开始注意到我无法记录任何 RECV 调用,而 SEND 调用却被截获了。

写hook的函数如下:

procedure Setup;
var
  lModuleHandle : dword;
  lPlaceHolder  : dword;
begin
  lModuleHandle := LoadLibrary(MODULE_NAME);

  OriginalSend := Dword(GetProcAddress(lModuleHandle, FUNCTION_SEND));
  OriginalRecv := Dword(GetProcAddress(lModuleHandle, FUNCTION_RECV));

  VirtualProtect(Ptr(OriginalSend), 5, PAGE_EXECUTE_READWRITE, lPlaceHolder);
  VirtualProtect(Ptr(OriginalRecv), 5, PAGE_EXECUTE_READWRITE, lPlaceHolder);

  PByte(OriginalRecv)^ := $E9;
  PDword(OriginalRecv + 1)^ := Dword(@Hook_Recv) - OriginalRecv - 5;

  PByte(OriginalSend)^ := $E9;
  PDword(OriginalSend + 1)^ := Dword(@Hook_Send) - OriginalSend - 5;

  Inc(OriginalSend, 5);
  Inc(OriginalRecv, 5);
end;

我正在使用的程序(被拦截的程序)使用 winsock 2,经过一些调试后我注意到我已经加载了 wsock32.dll 并决定在它的 RECV 上放置一个断点,而我有另一个断点在 ws2_32.dll 的 SEND 中;两个断点都命中了。

这意味着程序使用 ws2_32.dll 发送和 wsock32.dll 接收,这有意义吗?这种行为在任何方面都是正常的吗?

在不同的模块中编写钩子相当容易,但由于它们应该是不同的,这让我相信出了点问题,而且,我计算机中的其他一些应用程序(如 firefox 本身)也有同样的行为.

我添加这张图片是为了更好地解释这种情况,看起来程序链接到 wsock32 并以一些 ws2_32 的功能结束。

wsock32.dll 适用于 Winsock 1.x,ws2_32.dll 适用于 Winsock 2.x。大多数应用 link 到 ws2_32.dll,但旧版应用(和配置错误的应用)可能仍然 link 到 wsock32.dll。在现代系统中,wsock32.dll 在内部将其 大多数 函数重定向到 ws2_32.dllmswsock.dll.

您的目标应用 link 正在 wsock32.dll。您正在 ws2_32.dll 中挂钩函数。

在内部,wsock32.send() 直接映射到 ws2_32.send(),这就是您的 send() 挂钩起作用的原因。但是,wsock32.recv() 不会 映射到 ws2_32.recv(),这就是为什么您的 recv() 挂钩不起作用的原因。 wsock32.recv() 实际上调用了 ws2_32.WSARecv()

在 WinSock 2.x 中,标准 BSD 套接字函数仍然可用(send()recv() 等),但也有 Winsock-specific 扩展函数可用,如好吧(WSASend()WSARecv() 等),Winsock 2.x 套接字也可以支持重叠 I/O 和 I/O 完成端口。因此,如果您真的想在任何给定应用程序中挂接所有可能的数据交换途径,您可能必须挂接 BSD 函数、Winsock 扩展函数和 I/O 函数。但是,如果您只针对一个特定的应用程序,则只需挂钩它实际调用的函数(在本例中为 send()WSARecv())。