问题描述
需要在客户端收到之前修改服务器发送的未加密数据。
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,0x3A,0x5B,0x5C,0x75,0x30,0x33,0x63,0x58,0x70,0x6C,0x31,0x54,0x52,0x20,0x5D,0x2C,0x7D,0x01,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,0x3A,0x5B,0x5C,0x75,0x30,0x33,0x63,0x58,0x70,0x6C,0x31,0x54,0x52,0x20,0x5D,0x2C,0x7D,0x01,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];
替换缓冲区地址将起作用。因此,替换缓冲区的内容是一个更好的解决方案。