0

I am working on dll which hooks winsock2 functions, using C++ and detours. My goal is to modify TCP traffic that goes from and to the original executable. At some point, I need to stop certain packet delivery (so that original executable has no idea about that packet at all, but still keeps the connection).

With WSASend hook, it's clear (you just don't call original WSASend and return 0). But I have no idea how to make it in WSARecv hook using WSAOVERLAPPED structure.

I hope this code below demonstrates what do I want:

__declspec(dllexport) int WINAPI WSARecv_hook(SOCKET s, LPWSABUF lpBuffers, DWORD dwBufferCount, LPDWORD lpNumberOfBytesRecvd, LPDWORD lpFlags, LPWSAOVERLAPPED lpOverlapped, LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine)
{
    // Recieve real data
    int ret = WSARecv_real(s, lpBuffers, dwBufferCount, lpNumberOfBytesRecvd, lpFlags, lpOverlapped, lpCompletionRoutine);

    // Loop over lpBuffers and analyze it
    for(int i=0; i < dwBufferCount; i++)
    {
        // analyze it
        if(packet_should_be_blocked(lpBuffers[i].buf, lpBuffers[i].len))
        {
            // Do or return what?
        } else {
            // Otherwise, just process as usual
        }
    }
    return ret;
}

How do I pretend that nothing happened and no packet was recieved (like fake WSA_IO_PENDING)? Any ideas/thoughts?

P.S. From what I know, executable is not using completion routine (lpCompletionRoutine is always NULL), only overlapped structure.

splattru
  • 608
  • 1
  • 9
  • 19
  • 1
    Hmm. I thought I wrote a comment asking what you want the application to actually do when you "discard" the packet? Believe it was a timeout, or that the network went down? – Mats Petersson Aug 06 '14 at 23:04
  • No, I just want it to keep waiting for other packets like nothing happened. – splattru Aug 06 '14 at 23:26
  • 2
    Note that `packet_should_be_blocked` cannot work, since TCP is not message-oriented. You'll have to buffer data until you have enough to analyze, and then potentially remove only part of the data you received in a single call. This applies to blocking receive calls as well. – Ben Voigt Aug 07 '14 at 00:23
  • @BenVoigt I am familiar with the protocol I am modifying (first two bytes of each packet/message define packet/message type, each packet type has fixed length), so it's not a problem at all. Thank you anyway. – splattru Aug 07 '14 at 01:11
  • @splattru: It is a problem, because you assume that the header and payload arrive together in a single buffer. That assumption is erroneous with TCP. – Ben Voigt Aug 07 '14 at 01:14
  • @BenVoigt Oh, ok, I see now why it's a problem. Thank you again for your help. – splattru Aug 07 '14 at 01:26

2 Answers2

3

The main hurdle is that overlapped operations are meant to be performed in the background after the calling function has exited with a pending status. If the caller asks WSARecv() to perform an overlapped read, it is expecting the data to arrive in the background, and you won't be able to validate the data inside of your hook directly because it has not been received yet. You will have to use your own private WSAOVERLAPPED to perform your own overlapped read, using a thread or completion callback to detect when that read finishes so that you can then analyze the data. If the data is acceptable, copy it into the caller's buffer and signal the caller's WSAOVERLAPPED. Otherwise, post another read and wait for that data to arrive, repeating as needed until you finally receive some data that you want to give to the caller.

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
  • It's not such a problem. If you receive a message you don't want to pass along to the original program, you leave the original request pending while you call `WSARecv()` again, giving the *next* incoming packet a chance to complete the request. – Ben Voigt Aug 07 '14 at 00:21
-1

A much easier way to modify TCP traffic is to hook only the connect family of functions, and make the application connect to a transparent proxy under your control that performs the actual stream modification.

Although it is possible for the application to write its own port number in the stream for the remote end to compare to the packet source address, this isn't a problem in practice because

  1. This would also break NAT-PAT gateways which are very common on residential internet connections
  2. You can rewrite the content and send the proxy's address, so the check passes

In fact, FTP proxies have to do this command rewriting because they spawn slave connections for file transfers. But most modern applications are written to be PAT compatible.

Ben Voigt
  • 277,958
  • 43
  • 419
  • 720
  • Re-writing packet content to replace the client's IP with the proxy's IP can be dangerous if you are not careful. Only do it for protocols you are familiar with, like FTP. If the proxy blindly alters arbitrary data that happens to look like the client's IP, the proxy might corrupt data that has nothing to do with IPs. Some proxies are known to exhibit this very problem. – Remy Lebeau Aug 07 '14 at 00:32
  • @Remy: I'm quite sure the protocol is known in this question; the stream modification wouldn't work otherwise. – Ben Voigt Aug 07 '14 at 00:34
  • @Remy: Thanks for spotting the typo, I did in fact intend "FTP" in the last paragraph. – Ben Voigt Aug 07 '14 at 00:35