0

How I can get the Winsock2 WSASend() Buffer into a string?

This is the code I currently have, and it write only a lot of Icharacters.

int WINAPI Hook_WSASend(SOCKET a0, LPWSABUF a1, DWORD a2, LPDWORD a3, DWORD a4, LPWSAOVERLAPPED a5, LPWSAOVERLAPPED_COMPLETION_ROUTINE a6)
{
    int rv = 0;
    char * buf = "";
    WSABUF * wb = a1;

    for(int i = 0; i == a2; i++){
        strcpy_s(buf, wb[i].len, wb[i].buf);
    }

    fopen_s(&pWSASendLogFile, "C:\\WSASendLog.txt", "a+");
    fprintf(pWSASendLogFile, "%s\n", buf);
    fclose(pWSASendLogFile);
    rv = Real_WSASend(a0,a1,a2,a3,a4,a5,a6);
    return rv;
}

As Remy Lebeau asked, I'm adding more info on what i need to achieve.

I need to have the buffer inside a string because:

  • I have to search for a specific string inside the buffer, specifically before doing anything the string must start with <TalkMsg.

  • Then, i have to send the buffer trough a NamedPipe, i already have my functions handling that.

Just to Explain better what i'm doing, this is the code i currently have for the Winsock send(). I have to do the same thing with WSASend().

int WINAPI Hook_Send(SOCKET s, const char* buf, int len, int flags)
{
    /*
    fopen_s(&pSendLogFile, "C:\\SendLog.txt", "a+");
    fprintf(pSendLogFile, "%s\n", buf);
    fclose(pSendLogFile);
    */
    curSocket = s;
    if(Filtering){
        PipeHeader ph;
        string p(buf);
        if(p.find("<TalkMsg") == 0){
            ph.command = 5;
            ph.sockid = s;
            ph.datasize = len;
            if(SendPipeHeader((char*)&ph, sizeof(ph))){
                if(SendPipeData(buf, len)){
                    return len;
                }
            }
        }
    }

    return Real_Send(s, buf, len, flags);
}
Fr0z3n
  • 1,569
  • 1
  • 18
  • 39
  • `buf` points to an area of memory that contains an empty string and a null terminator. That is, it 'owns' 1 byte of memory. Your for-loop is therefore bound to end in tears at some point. – enhzflep May 14 '15 at 16:24

1 Answers1

0

As @enhzflep said in comments, you are not managing your buf variable correctly. Nor do you even need it at all. Just write the source buffers as-is directly to the file:

int WINAPI Hook_WSASend(SOCKET a0, LPWSABUF a1, DWORD a2, LPDWORD a3, DWORD a4, LPWSAOVERLAPPED a5, LPWSAOVERLAPPED_COMPLETION_ROUTINE a6)
{
    fopen_s(&pWSASendLogFile, "C:\\WSASendLog.txt", "a+");
    for(DWORD i = 0; i < a2; i++)
        fwrite(a1[i].buf, 1, a1[i].len, pWSASendLogFile);
    fprintf(pWSASendLogFile, "\n");
    fclose(pWSASendLogFile);

    int rv = Real_WSASend(a0,a1,a2,a3,a4,a5,a6);
    return rv;
}

Update: your send() hook is assuming that buf is always null-terminated, but that is not the case. You have to use the provided len when copying the buf data to a `string:

int WINAPI Hook_Send(SOCKET s, const char* buf, int len, int flags)
{
    /*
    fopen_s(&pSendLogFile, "C:\\SendLog.txt", "a+");
    fwrite(buf, 1, len, pSendLogFile);
    fprintf(pSendLogFile, "\n");
    fclose(pSendLogFile);
    */
    curSocket = s;
    if(Filtering){
        PipeHeader ph;
        string p(buf, len); // <-- here
        if(p.find("<TalkMsg") == 0){
            ph.command = 5;
            ph.sockid = s;
            ph.datasize = len;
            if(SendPipeHeader((char*)&ph, sizeof(ph))){
                if(SendPipeData(buf, len)){
                    return len;
                }
            }
        }
    }

    return Real_Send(s, buf, len, flags);
}

You would have to do something similar in your WSASend() hook, taking the total length of all WSABUF buffers into account:

int WINAPI Hook_WSASend(SOCKET s, LPWSABUF lpBuffers, DWORD dwBufferCount, LPDWORD lpNumberOfBytesSent, DWORD dwFlags, LPWSAOVERLAPPED                    lpOverlapped, LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine)
{
    /*
    fopen_s(&pWSASendLogFile, "C:\\WSASendLog.txt", "a+");
    for(DWORD i = 0; i < dwBufferCount; i++)
        fwrite(lpBuffers[i].buf, 1, lpBuffers[i].len, pWSASendLogFile);
    fprintf(pWSASendLogFile, "\n");
    fclose(pWSASendLogFile);
    */
    curSocket = s;
    if(Filtering){
        PipeHeader ph;
        string p;
        size_t len = 0;
        for(DWORD i = 0; i < dwBufferCount; i++) {
            len += lpBuffers[i].len;
        }
        p.reserve(len);
        for(DWORD i = 0; i < dwBufferCount; i++) {
            p.append(lpBuffers[i].buf, lpBuffers[i].len);
        }
        if(p.find("<TalkMsg") == 0){
            ph.command = 5;
            ph.sockid = s;
            ph.datasize = len;
            if(SendPipeHeader((char*)&ph, sizeof(ph))){
                if(SendPipeData(p.c_str(), len)){
                    if (lpNumberOfBytesSent){
                        *lpNumberOfBytesSent = len;
                    }
                    if (lpCompletionRoutine) {
                        lpCompletionRoutine(0, len, lpOverlapped, 0);
                    }
                    return 0;
                }
            }
        }
    }

    return Real_WSASend(s, lpBuffers, dwBufferCount, lpNumberOfBytesSent, dwFlags, lpOverlapped, lpCompletionRoutine);
}

That being said, this kind of filtering code is not very reliable due to the streaming nature of TCP. There is no guarantee that the input data will represent a complete message in a single send when "<TalkMsg" is present, or even that "<TalkMsg" itself will be complete in a single send. What you really need to do instead is save the outbound data as-is to a per-socket buffer, and then parse the buffer looking for complete messages, passing only complete messages to your pipe and removing them from the buffer, leaving partial data in the buffer to be completed by subsequent sends.

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
  • Well, i need it, because the file write is just a placeholder, i need to have the buffer inside a string because i have to do other things with it. – Fr0z3n May 15 '15 at 07:43
  • Then you need to allocate adequate memory for the string (sum the buffer lengths together to know how much) and copy the data into the string (NOT using a strcpy function, though). And then requestion why you are copying the buffers into a string to begin with, because there is bound to be a better choice. – Remy Lebeau May 15 '15 at 08:04
  • I have edited my question, added more info on what i need to achieve, thanks. – Fr0z3n May 15 '15 at 08:28