记录 WSASend 缓冲区并发送它们

Recording WSASend Buffers and sending them

我正在尝试为一款冷门游戏作弊。每次游戏调用 WSASend 函数时,lpBuffers 变量中都会有 1 个一定长度的缓冲区。我需要这样做,以便在按住鼠标侧面按钮的同时,将缓冲区写入某种数组。然后,当按钮被释放时,检查我的数组中是否有东西,如果有,一个一个地发送每个缓冲区。作弊的本质是在快速发送记录的数据时,我的角色会突然从一个点移动到另一个点或者非常快速地执行一些其他动作。我写了下面的代码,但它不能正常工作。

std::vector<std::string> records;
WSABUF buffer;

/*
    The WSASend function leads to __WSASend. The original WSASend function is in _WSASend.
*/

int WSAAPI __WSASend(SOCKET s, LPWSABUF lpBuffers, DWORD dwBufferCount, LPDWORD lpNumberOfBytesSent, DWORD dwFlags, LPWSAOVERLAPPED lpOverlapped, LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine)
{
    if (GetAsyncKeyState(VK_XBUTTON1) < 0) // If the side mouse button is pressed when calling WSASend, write the buffer data to my array of strings
    {
        records.emplace_back(lpBuffers->buf);

/*
While the mouse button is held down, the game will think that the data was sent because * lpNumberOfBytesSent = lpBuffers-> len; This is necessary in order for the game to send new data.
*/

        *lpNumberOfBytesSent = lpBuffers->len; 
        return 0;
    }


/* I need to send data with a delay, but I cannot use the Sleep () function since WSASend and WSARecv are on the same thread. Since the game tries to send the same data if it just returns 0 (without setting * lpNumberOfBytesSent = lpBuffers-> len) I decided to take advantage of this. */
    if (records.size() > 0)
    {
        buffer.buf = &records[0][0];
        buffer.len = records[0].length();
        _WSASend(s, &buffer, 1, 0, 0, 0, 0);
        records.erase(records.begin());

/* No delay because I decided to check if it works at all. And as it turned out, it works, but very rarely. When the saved data was small - 50 to 50 that will go and everything will be ok, but when there is a lot, it always kicks from the server with a data read error. */

        return 0; // I am returning 0 without setting * lpNumberOfBytesSent = lpBuffers-> len; so that the game calls the same function again with the same data to send next recorded buffer data
    }

    return _WSASend(s, lpBuffers, dwBufferCount, lpNumberOfBytesSent, dwFlags, lpOverlapped, lpCompletionRoutine); // When there is no data recorded
}

以正确的顺序(先记录到最后)写入和发送数据非常重要,因为游戏在双方都使用加密+计数器。理论上,如果您正确地记下并以正确的顺序发送,然后允许游戏继续发送未记录的数据,那么一切都会顺利进行。但正如我所说,有时它适用于小数据,但不适用于大数据。我因读取错误而被服务器抛出。

我发现您的代码存在多个问题。

  • 当鼠标按钮按下时,您在将呼叫者的新数据添加到您的列表时完全忽略了 WSASend()dwBufferCount 参数。如果调用方尝试一次发送 多个 WSABUF,您将丢失数据。

  • 您根本没有将 lpBuffers->len 保存到您的列表中,您假设 lpBuffers->buf 是一个以 null 结尾的字符串,这很可能不是 99.99999% 的情况时间。因此,发送列表的代码无法知道要给 _WSASend().

    的正确长度
  • 发送列表中的数据时,您完全忽略了 _WSASend() 的输出。

  • 当鼠标按钮未按下时,如果您的列表不为空,则您只发送列表中的第一条记录,并完全忽略调用者的新数据,永远丢失它。您需要:

    • 如果在调用 _WSASend().

      后列表不为空,则将调用者的新数据附加到列表的末尾
    • 发送列表中的所有内容,然后将调用者的新数据提供给 _WSASend()

话虽如此,请尝试更多类似的操作:

int WSAAPI __WSASend(SOCKET s, LPWSABUF lpBuffers, DWORD dwBufferCount, LPDWORD lpNumberOfBytesSent, DWORD dwFlags, LPWSAOVERLAPPED lpOverlapped, LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine)
{
    *lpNumberOfBytesSent = 0; 

    if (GetAsyncKeyState(VK_XBUTTON1) < 0)
    {
        for(DWORD i = 0; i < dwBufferCount; ++i)
        {
            auto &buffer = lpBuffers[i];
            records.emplace_back(buffer.buf, buffer.len);
            *lpNumberOfBytesSent += buffer.len;
        }

        return 0;
    }

    if (!records.empty())
    {
        WSABUF buffer;
        DWORD numSent;
        auto &rec = records[0];
        do
        {
            buffer.buf = rec.data();
            buffer.len = rec.size();
            if (_WSASend(s, &buffer, 1, &numSent, 0, nullptr, nullptr) == SOCKET_ERROR)
                return SOCKET_ERROR;
            rec.erase(0, numSent);
        }
        while (!rec.empty());
        records.erase(records.begin());
        return 0;
    }

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

或者这样:

int WSAAPI __WSASend(SOCKET s, LPWSABUF lpBuffers, DWORD dwBufferCount, LPDWORD lpNumberOfBytesSent, DWORD dwFlags, LPWSAOVERLAPPED lpOverlapped, LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine)
{
    *lpNumberOfBytesSent = 0; 

    if (GetAsyncKeyState(VK_XBUTTON1) < 0)
    {
        for(DWORD i = 0; i < dwBufferCount; ++i)
        {
            auto &buffer = lpBuffers[i];
            records.emplace_back(buffer.buf, buffer.len);
            *lpNumberOfBytesSent += buffer.len;
        }

        return 0;
    }

    while (!records.empty())
    {
        WSABUF buffer;
        DWORD numSent;
        auto &rec = records[0];
        do
        {
            buffer.buf = rec.data();
            buffer.len = rec.size();
            if (_WSASend(s, &buffer, 1, &numSent, 0, nullptr, nullptr) == SOCKET_ERROR)
                return SOCKET_ERROR;
            rec.erase(0, numSent);
        }
        while (!rec.empty());
        records.erase(records.begin());
    }

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