修改 WSARecv 数据

Modifying WSARecv data

服务端发送的未加密数据在客户端收到之前需要修改。

int WSAAPI __WSARecv(SOCKET s, LPWSABUF lpBuffers, DWORD dwBufferCount, LPDWORD lpNumberOfBytesRecvd, LPDWORD lpFlags, LPWSAOVERLAPPED lpOverlapped, LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine)
    {
        int result = _WSARecv(s, lpBuffers, dwBufferCount, lpNumberOfBytesRecvd, lpFlags, lpOverlapped, lpCompletionRoutine);
        // The original WSARecv must be called to fill the lpBuffers buffer
        
        if (lpBuffers->buf[0] == 0x09 and lpBuffers->buf[1] == 0x00 and lpBuffers->buf[2] == 0x12)
        {
            // 09 00 12 32 00 00 FFFFFFFD FFFFFF8D 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
     
            char replace[] = { 0x33, 0x00, 0x02, 0x2F, 0x7B, 0x22, 0x65, 0x78, 0x74, 0x72, 0x61, 0x22, 0x3A, 0x5B, 0x22, 0x5C, 0x75, 0x30, 0x30, 0x33, 0x63, 0x65, 0x58, 0x70, 0x6C, 0x30, 0x31, 0x54, 0x65, 0x52, 0x5C, 0x75, 0x30, 0x30, 0x33, 0x65, 0x20, 0x31, 0x22, 0x5D, 0x2C, 0x22, 0x74, 0x65, 0x78, 0x74, 0x22, 0x3A, 0x22, 0x22, 0x7D, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
     
            lpBuffers->buf = replace;
            lpBuffers->len = 64;
     
        cout << "replaced" << endl; // Writes to the console, which means it works, but the game still sees the same data
    }
 
    return result;
}

lpOverlapped 和 lpCompletionRoutine 为零。 TCP协议。

理想情况下,我希望能够阻止不需要的数据到达客户端,但据我了解,如果不编写代理服务器或外部拦截器(例如 Wireshark),这是不可能的。

WSARecv逻辑复杂,最简单的使用场景是当它立即接收数据(重叠未使用)并且调用者只读到一个缓冲区(dwBufferCount == 1)。 此函数处理这种情况,重写接收缓冲区并相应地更新接收到的字节数:

int WSAAPI __WSARecv(SOCKET s, LPWSABUF lpBuffers, DWORD dwBufferCount, LPDWORD lpNumberOfBytesRecvd, LPDWORD lpFlags, LPWSAOVERLAPPED lpOverlapped, LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine)
{
    int result = _WSARecv(s, lpBuffers, dwBufferCount, lpNumberOfBytesRecvd, lpFlags, lpOverlapped, lpCompletionRoutine);
    // The original WSARecv must be called to fill the lpBuffers buffer

    // Check WSARecv received the data, read was to one buffer, received data satisfies our pattern.
    if (!result && dwBufferCount == 1 && lpBuffers->buf[0] == 0x09 && lpBuffers->buf[1] == 0x00 && lpBuffers->buf[2] == 0x12)
    {
        // 09 00 12 32 00 00 FFFFFFFD FFFFFF8D 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
        char replace[] = { 0x33, 0x00, 0x02, 0x2F, 0x7B, 0x22, 0x65, 0x78, 0x74, 0x72, 0x61, 0x22, 0x3A, 0x5B, 0x22, 0x5C, 0x75, 0x30, 0x30, 0x33, 0x63, 0x65, 0x58, 0x70, 0x6C, 0x30, 0x31, 0x54, 0x65, 0x52, 0x5C, 0x75, 0x30, 0x30, 0x33, 0x65, 0x20, 0x31, 0x22, 0x5D, 0x2C, 0x22, 0x74, 0x65, 0x78, 0x74, 0x22, 0x3A, 0x22, 0x22, 0x7D, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
        if( lpBuffers->len >= sizeof( replace ) )
        {
            memcpy( lpBuffers->buf, replace, sizeof( replace ) );
            cout << "replaced" << endl; // Writes to the console, which means it works, but the game still sees the same data

            // Update lpNumberOfBytesRecvd
            if (lpNumberOfBytesRecvd)
                *lpNumberOfBytesRecvd = sizeof( replace );
        }
        else
          cout << "Cannot replace - buffer too small (" << lpBuffers->len << " bytes)" << endl;
    }

    return result;
}

调用者通常这样调用和读取数据:

char buffer[DATA_BUFSIZE];
WSABUF DataBuf;
DataBuf.len = DATA_BUFSIZE;
DataBuf.buf = buffer;

rc = WSARecv(..., &DataBuf, ....);

data = buffer[0];

因此更改 lpBuffers->buf 的值将无济于事,因为调用者不使用它。当调用者这样使用时

data = DataBuf.buf[0];

替换缓冲区地址即可。因此,替换缓冲区的内容是一个更好的解决方案。