My DLL gets injected into a program and then hooks to connect
, send
, recv
and closesocket
functions using Detours. The point is to stop the program from connecting to some server and instead communicate with my DLL directly.
My recv
function uses an infinite loop, just waiting for any data to send to the program. When closesocket
is called that loop is broken and everything works fine.
But there's one program written in C# that just hangs when I close it. Its error log says:
SocketException: A request to send or receive data was disallowed because the socket is not connected and (when sending on a datagram socket using a sendto call) no address was supplied.
at System.Net.Sockets.Socket.Disconnect (Boolean reuseSocket) [0x00000] in :0
The exception is expected since the socket never connects to anything. But is there any workaround for this? What does System.Net.Sockets.Socket.Disconnect
call under the hood? What other function do I need to hook to detect that?
I've tried hooking to shutdown
, setsockopt
, WSACancelBlockingCall
, WSACleanup
, WSASend
, WSASendDisconnect
, WSASendMsg
, WSASendTo
, WSARecv
, WSARecvDisconnect
and WSARecvFrom
. None of them get called.
System.Net.Sockets.Socket.Disconnect
calls DisconnectEx
. And as the remarks say:
Note The function pointer for the DisconnectEx function must be obtained at run time by making a call to the WSAIoctl function with the SIO_GET_EXTENSION_FUNCTION_POINTER opcode specified. The input buffer passed to the WSAIoctl function must contain WSAID_DISCONNECTEX, a globally unique identifier (GUID) whose value identifies the DisconnectEx extension function. On success, the output returned by the WSAIoctl function contains a pointer to the DisconnectEx function. The WSAID_DISCONNECTEX GUID is defined in the Mswsock.h header file.
So if you want to do what I did you have to:
WSAIoctl
dwIoControlCode
is SIO_GET_EXTENSION_FUNCTION_POINTER
lpvInBuffer
is WSAID_DISCONNECTEX
:IsEqualGUID(*((GUID*)lpvInBuffer), WSAID_DISCONNECTEX)
DisconnectEx
somewhereLPFN_DISCONNECTEX Real_DisconnectEx = NULL;
(...)
Real_DisconnectEx = *((LPFN_DISCONNECTEX*)lpvOutBuffer);
*((LPFN_DISCONNECTEX*)lpvOutBuffer) = &Mine_DisconnectEx;