1+ #include " pch.h"
2+ #include < winsock.h>
3+ #include < Windows.h>
4+ #include < string>
5+ #include < vector>
6+ #include < detours.h>
7+ #include " GameExeImports.hpp"
8+
9+ std::string sockaddrToString (const sockaddr_in* addr)
10+ {
11+ return " family: " + std::to_string (addr->sin_family ) + " " + std::string (inet_ntoa (addr->sin_addr )) + " :" + std::to_string (ntohs (addr->sin_port ));
12+ }
13+
14+ std::string sockaddrToString (const sockaddr* addr)
15+ {
16+ if (addr->sa_family != AF_INET)
17+ return " ERR: NOT IPV4" ;
18+ return sockaddrToString ((const sockaddr_in*)addr);
19+ }
20+
21+ std::string socketToString (SOCKET s)
22+ {
23+ if (s == INVALID_SOCKET)
24+ return " INVALID_SOCKET" ;
25+
26+ sockaddr sa = {};
27+ int len = sizeof (sockaddr);
28+
29+ if (getsockname (s, &sa, &len))
30+ return std::string (" getsockname error " ) + std::to_string (WSAGetLastError ());
31+
32+ int type = 0 ;
33+ int length = sizeof (int );
34+ getsockopt (s, SOL_SOCKET, SO_TYPE, (char *)&type, &length);
35+
36+ return sockaddrToString (&sa) + " type: " + std::to_string (type);
37+ }
38+
39+ std::vector<std::pair<in_addr, sockaddr_in>> connectionsMapping;
40+ sockaddr_in serverAddress = {};
41+
42+
43+ enum class ConnectionType
44+ {
45+ Server,
46+ Client,
47+ };
48+ ConnectionType connectionType = ConnectionType::Server;
49+
50+ #define netprintf (...) printf(__VA_ARGS__)
51+ // #define netprintf(...) do {} while (false)
52+
53+
54+ int (PASCAL FAR* sendtoReal)(
55+ _In_ SOCKET s,
56+ _In_reads_bytes_ (len) const char FAR* buf,
57+ _In_ int len,
58+ _In_ int flags,
59+ _In_reads_bytes_opt_(tolen) const struct sockaddr FAR* to,
60+ _In_ int tolen) = nullptr;
61+
62+
63+ int PASCAL FAR sendtoWrap (
64+ _In_ SOCKET s,
65+ _In_reads_bytes_ (len) const char FAR* buf,
66+ _In_ int len,
67+ _In_ int flags,
68+ _In_reads_bytes_opt_(tolen) const struct sockaddr FAR* to,
69+ _In_ int tolen)
70+ {
71+ netprintf (" send packet to %s\n " , sockaddrToString (to).c_str ());
72+ netprintf (" SOCKET %s\n " , socketToString (s).c_str ());
73+
74+
75+ if (connectionType == ConnectionType::Server && to)
76+ {
77+ const sockaddr_in* addr = (const sockaddr_in*)to;
78+ auto it = std::find_if (connectionsMapping.begin (), connectionsMapping.end (), [&](const std::pair<in_addr, sockaddr_in>& pair) { return pair.first .S_un .S_addr == addr->sin_addr .S_un .S_addr ; });
79+ if (it != connectionsMapping.end ())
80+ {
81+ sockaddr_in* realAddr = &it->second ;
82+
83+ netprintf (" REDIR to %s\n " , sockaddrToString (realAddr).c_str ());
84+
85+ int ret = sendtoReal (s, buf, len, flags, (struct sockaddr *)realAddr, sizeof (sockaddr_in));
86+ if (ret == SOCKET_ERROR)
87+ netprintf (" socket error: %d\n " , WSAGetLastError ());
88+
89+ return ret;
90+ }
91+ }
92+
93+ if (connectionType == ConnectionType::Client)
94+ {
95+ netprintf (" CLIENT REDIR to %s\n " , sockaddrToString (&serverAddress).c_str ());
96+
97+ int ret = sendtoReal (s, buf, len, flags, (struct sockaddr *)&serverAddress, sizeof (sockaddr_in));
98+ if (ret == SOCKET_ERROR)
99+ netprintf (" socket error: %d\n " , WSAGetLastError ());
100+
101+ return ret;
102+ }
103+
104+
105+ return sendtoReal (s, buf, len, flags, to, tolen);
106+ }
107+
108+
109+ int (PASCAL FAR* recvfromReal)(
110+ _In_ SOCKET s,
111+ _Out_writes_bytes_to_ (len, return ) __out_data_source(NETWORK) char FAR* buf,
112+ _In_ int len,
113+ _In_ int flags,
114+ _Out_writes_bytes_to_opt_(*fromlen, *fromlen) struct sockaddr FAR* from,
115+ _Inout_opt_ int FAR* fromlen) = nullptr;
116+
117+ int PASCAL FAR recvfromWrap (
118+ _In_ SOCKET s,
119+ _Out_writes_bytes_to_ (len, return ) __out_data_source(NETWORK) char FAR* buf,
120+ _In_ int len,
121+ _In_ int flags,
122+ _Out_writes_bytes_to_opt_(*fromlen, *fromlen) struct sockaddr FAR* from,
123+ _Inout_opt_ int FAR* fromlen)
124+ {
125+ int bytesReceived = recvfromReal (s, buf, len, flags, from, fromlen);
126+ netprintf (" recv from real: %s\n " , sockaddrToString (from).c_str ());
127+ netprintf (" SOCKET %s\n " , socketToString (s).c_str ());
128+
129+ if (connectionType == ConnectionType::Server)
130+ {
131+ sockaddr_in* from_in = (sockaddr_in*)from;
132+
133+ auto it = std::find_if (connectionsMapping.begin (), connectionsMapping.end (), [&](const std::pair<in_addr, sockaddr_in>& pair)
134+ {
135+ return pair.second .sin_family == from_in->sin_family &&
136+ pair.second .sin_addr .S_un .S_addr == from_in->sin_addr .S_un .S_addr &&
137+ pair.second .sin_port == from_in->sin_port ;
138+ });
139+
140+ if (it != connectionsMapping.end ())
141+ {
142+ sockaddr_in* realAddr = &it->second ;
143+ netprintf (" REDIR to fake: %s\n " , sockaddrToString (realAddr).c_str ());
144+ *from_in = *realAddr;
145+ }
146+ else if (bytesReceived != SOCKET_ERROR && bytesReceived == 128 )
147+ {
148+ in_addr* ip = (in_addr*)(buf + 0x2C );
149+
150+ char ipString[32 ] = {};
151+ strcpy (ipString, inet_ntoa (*ip));
152+
153+ netprintf (" MAGIC PACKET!!! ip: %s, real ip: %s\n " , ipString, sockaddrToString (from_in).c_str ());
154+
155+ connectionsMapping.emplace_back (*ip, *from_in);
156+ from_in->sin_addr = *ip;
157+ from_in->sin_port = htons (4927 );
158+ }
159+ }
160+
161+ return bytesReceived;
162+ }
163+
164+ int (PASCAL FAR * bindReal)(
165+ _In_ SOCKET s,
166+ _In_reads_bytes_ (namelen) const struct sockaddr FAR * addr,
167+ _In_ int namelen) = nullptr;
168+
169+ int PASCAL FAR bindWrap (
170+ _In_ SOCKET s,
171+ _In_reads_bytes_ (namelen) const struct sockaddr FAR * addr,
172+ _In_ int namelen)
173+ {
174+
175+ netprintf (" -------------------------------------------BIND %s\n " , sockaddrToString (addr).c_str ());
176+ int ret = bindReal (s, addr, namelen);
177+ return ret;
178+ }
179+
180+
181+ int (PASCAL FAR * setsockoptReal)(
182+ _In_ SOCKET s,
183+ _In_ int level,
184+ _In_ int optname,
185+ _In_reads_bytes_opt_ (optlen) const char FAR * optval,
186+ _In_ int optlen) = nullptr;
187+
188+ int PASCAL FAR setsockoptWrap (
189+ _In_ SOCKET s,
190+ _In_ int level,
191+ _In_ int optname,
192+ _In_reads_bytes_opt_ (optlen) const char FAR * optval,
193+ _In_ int optlen)
194+ {
195+ netprintf (" setsockopt %d %d\n " , level, optname);
196+ return setsockoptReal (s, level, optname, optval, optlen);
197+ }
198+
199+ // original is __thiscall, but we can't declare a thiscall func outside a class, so we fake it with fastcall and an unused edx param
200+ int __fastcall SomeNetworkManager_SendLobbyMessageWrap (SomeNetworkManager * This, DWORD edx, __int16 a2, int a3, wchar_t * message_, char a5)
201+ {
202+ printf (" GOT CHAT MESSAGE %S\n " , message_);
203+
204+ std::wstring commandReply;
205+
206+ std::wstring_view message (message_);
207+ if (message == L" /connect" )
208+ {
209+ connectionType = ConnectionType::Client;
210+ connectionsMapping.clear ();
211+ commandReply = L" connecting!" ;
212+
213+ serverAddress.sin_family = AF_INET;
214+ serverAddress.sin_addr .S_un .S_addr = inet_addr (" 86.246.78.252" );
215+ serverAddress.sin_port = htons (4927 );
216+ }
217+ else if (message == L" /disconnect" )
218+ {
219+ connectionType = ConnectionType::Server;
220+ connectionsMapping.clear ();
221+ commandReply = L" disconnected!" ;
222+ }
223+
224+ if (!commandReply.empty ())
225+ return SomeNetworkManager_SendLobbyMessageOrig (This, a2, a3, (std::wstring (message_) + L" : " + commandReply).data (), a5);
226+
227+ return SomeNetworkManager_SendLobbyMessageOrig (This, a2, a3, message_, a5);
228+ }
229+
230+ void patchLan ()
231+ {
232+ HMODULE wsock = LoadLibraryA (" wsock32.dll" );
233+
234+ sendtoReal = (int (PASCAL FAR*)(
235+ _In_ SOCKET s,
236+ _In_reads_bytes_ (len) const char FAR * buf,
237+ _In_ int len,
238+ _In_ int flags,
239+ _In_reads_bytes_opt_ (tolen) const struct sockaddr FAR * to,
240+ _In_ int tolen)) GetProcAddress (wsock, " sendto" );
241+
242+ recvfromReal = (int (PASCAL FAR*)(_In_ SOCKET s,
243+ _Out_writes_bytes_to_ (len, return ) __out_data_source (NETWORK) char FAR* buf,
244+ _In_ int len,
245+ _In_ int flags,
246+ _Out_writes_bytes_to_opt_ (*fromlen, *fromlen) struct sockaddr FAR* from,
247+ _Inout_opt_ int FAR* fromlen)) GetProcAddress (wsock, " recvfrom" );
248+
249+ bindReal = (int (PASCAL FAR*)(
250+ _In_ SOCKET s,
251+ _In_reads_bytes_ (namelen) const struct sockaddr FAR * addr,
252+ _In_ int namelen)) GetProcAddress (wsock, " bind" );
253+
254+ setsockoptReal = (int (PASCAL FAR*)(
255+ _In_ SOCKET s,
256+ _In_ int level,
257+ _In_ int optname,
258+ _In_reads_bytes_opt_ (optlen) const char FAR * optval,
259+ _In_ int optlen)) GetProcAddress (wsock, " setsockopt" );
260+
261+
262+ DetourAttach (&(PVOID&)sendtoReal, sendtoWrap);
263+ DetourAttach (&(PVOID&)recvfromReal, recvfromWrap);
264+ DetourAttach (&(PVOID&)bindReal, bindWrap);
265+ DetourAttach (&(PVOID&)setsockoptReal, setsockoptWrap);
266+ DetourAttach (&(PVOID&)SomeNetworkManager_SendLobbyMessageOrig, SomeNetworkManager_SendLobbyMessageWrap);
267+ }
0 commit comments