【问题标题】:WSASend Buffer to StringWSAS将缓冲区发送到字符串
【发布时间】:2015-05-16 00:51:31
【问题描述】:

如何将 Winsock2 WSASend() 缓冲区转换为字符串?

这是我目前拥有的代码,它只写了很多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;
}

正如 Remy Lebeau 所问,我正在添加更多关于我需要实现的目标的信息。

我需要将缓冲区放在字符串中,因为:

  • 我必须在缓冲区中搜索特定字符串,特别是在执行任何操作之前,该字符串必须以 <TalkMsg 开头。

  • 然后,我必须通过 NamedPipe 发送缓冲区,我已经有我的函数来处理它。

为了更好地解释我在做什么,这是我目前拥有的 Winsock send() 的代码。我必须对 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);
}

【问题讨论】:

  • buf 指向包含空字符串和空终止符的内存区域。也就是说,它“拥有”1 个字节的内存。因此,您的 for 循环一定会在某个时候流泪。

标签: c++ winsock2 packet-capture


【解决方案1】:

正如@enhzflep 在 cmets 中所说,您没有正确管理您的 buf 变量。你甚至根本不需要它。只需将源缓冲区按原样直接写入文件即可:

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;
}

更新:您的 send() 钩子假设 buf 始终以空值结尾,但事实并非如此。将buf 数据复制到`字符串时,您必须使用提供的len

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);
}

您必须在 WSASend() 挂钩中执行类似的操作,将所有 WSABUF 缓冲区的总长度考虑在内:

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);
}

话虽如此,由于 TCP 的流式特性,这种过滤代码不是很可靠。当"&lt;TalkMsg" 存在时,无法保证输入数据将在一次发送中表示完整的消息,甚至不能保证"&lt;TalkMsg" 本身将在一次发送中完成。您真正需要做的是将出站数据按原样保存到每个套接字缓冲区,然后解析缓冲区以查找完整消息,仅将完整消息传递到您的管道并将它们从缓冲区中删除,将部分数据留在后续发送要完成的缓冲区。

【讨论】:

  • 嗯,我需要它,因为文件写入只是一个占位符,我需要将缓冲区放在字符串中,因为我必须用它做其他事情。
  • 然后您需要为字符串分配足够的内存(将缓冲区长度相加以了解多少)并将数据复制到字符串中(但不使用 strcpy 函数)。然后询问为什么要将缓冲区复制到一个字符串中,因为肯定会有更好的选择。
  • 我已经编辑了我的问题,添加了更多关于我需要实现的信息,谢谢。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-07-17
  • 1970-01-01
相关资源
最近更新 更多