System.Net.Sockets.Socket.Disconnect 如何从套接字断开连接?

问题描述

我的 DLL 被注入到程序中,然后使用 Detours 挂钩到 connectsendrecvclosesocket 函数。关键是阻止程序连接到某个服务器,而是直接与我的 DLL 通信。

我的 recv 函数使用无限循环,只是等待任何数据发送到程序。当调用 closesocket 时,循环被破坏,一切正常。

但是有一个用 C# 编写的程序在我关闭它时会挂起。它的错误日志说:

SocketException:由于套接字未连接并且(使用 sendto 调用在数据报套接字上发送时)未提供地址,因此不允许发送或接收数据的请求。

在 System.Net.sockets.socket.disconnect(布尔重用套接字)[0x00000] 中:0

异常是意料之中的,因为套接字从未连接到任何东西。但是有什么解决方法吗? System.Net.sockets.socket.disconnect 在幕后叫什么?我还需要挂钩什么其他功能来检测它?

我试过挂钩 shutdownsetsockoptWSACancelBlockingCallWSACleanupWSASendWSASenddisconnectWSASendMsgWSASendToWSARecvWSARecvdisconnectWSARecvFrom。他们都没有接到电话。

解决方法

System.Net.Sockets.Socket.Disconnect 调用 DisconnectEx。正如评论所说:

注意DisconnectEx 函数的函数指针必须在运行时通过使用 SIO_GET_EXTENSION_FUNCTION_POINTERWSAIoctl 函数获得/strong> 指定的操作码。传递给 WSAIoctl 函数的输入缓冲区必须包含 WSAID_DISCONNECTEX,这是一个全局唯一标识符 (GUID),其值标识 DisconnectEx 扩展函数。成功时,WSAIoctl 函数返回的输出包含一个指向 DisconnectEx 函数的指针。 WSAID_DISCONNECTEX GUID 在 Mswsock.h 头文件中定义。

所以如果你想做我所做的,你必须:

  1. 连接到 WSAIoctl
  2. 检查 dwIoControlCode 是否为 SIO_GET_EXTENSION_FUNCTION_POINTER
  3. 检查 lpvInBuffer 是否为 WSAID_DISCONNECTEX
IsEqualGUID(*((GUID*)lpvInBuffer),WSAID_DISCONNECTEX)
  1. 将地址存储到真实的 DisconnectEx 某处
LPFN_DISCONNECTEX Real_DisconnectEx = NULL;
(...)
Real_DisconnectEx = *((LPFN_DISCONNECTEX*)lpvOutBuffer);
  1. 返回函数的地址
*((LPFN_DISCONNECTEX*)lpvOutBuffer) = &Mine_DisconnectEx;