Use original logic if there's no fallback and / or webservice failed.

This commit is contained in:
Ray Koopa 2020-07-12 20:20:32 +02:00
parent f242a6b745
commit 48e6988083
6 changed files with 101 additions and 86 deletions

View File

@ -65,7 +65,7 @@
<SubSystem>Windows</SubSystem> <SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation> <GenerateDebugInformation>true</GenerateDebugInformation>
<EnableUAC>false</EnableUAC> <EnableUAC>false</EnableUAC>
<AdditionalDependencies>wininet.lib;%(AdditionalDependencies)</AdditionalDependencies> <AdditionalDependencies>wininet.lib;ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link> </Link>
</ItemDefinitionGroup> </ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
@ -83,20 +83,18 @@
<OptimizeReferences>true</OptimizeReferences> <OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation> <GenerateDebugInformation>true</GenerateDebugInformation>
<EnableUAC>false</EnableUAC> <EnableUAC>false</EnableUAC>
<AdditionalDependencies>wininet.lib;%(AdditionalDependencies)</AdditionalDependencies> <AdditionalDependencies>wininet.lib;ws2_32.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link> </Link>
</ItemDefinitionGroup> </ItemDefinitionGroup>
<ItemGroup> <ItemGroup>
<ClCompile Include="fkConfig.cpp" /> <ClCompile Include="fkConfig.cpp" />
<ClCompile Include="fkPatch.cpp" /> <ClCompile Include="fkPatch.cpp" />
<ClCompile Include="fkUtils.cpp" /> <ClCompile Include="fkUtils.cpp" />
<ClCompile Include="fkWinHandle.cpp" />
<ClCompile Include="main.cpp" /> <ClCompile Include="main.cpp" />
<ClCompile Include="PEInfo.cpp" /> <ClCompile Include="PEInfo.cpp" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClInclude Include="fkConfig.h" /> <ClInclude Include="fkConfig.h" />
<ClInclude Include="fkWinHandle.h" />
<ClInclude Include="fkPatch.h" /> <ClInclude Include="fkPatch.h" />
<ClInclude Include="fkUtils.h" /> <ClInclude Include="fkUtils.h" />
<ClInclude Include="PEInfo.h" /> <ClInclude Include="PEInfo.h" />

View File

@ -1,4 +1,5 @@
#include "fkUtils.h" #include "fkUtils.h"
#include <string>
#include "fkPatch.h" #include "fkPatch.h"
namespace fk namespace fk
@ -17,11 +18,10 @@ namespace fk
return GAME_VERSION_NONE; return GAME_VERSION_NONE;
} }
void throwLastError() std::string getErrorMessage(int error)
{ {
DWORD error = GetLastError();
if (error == ERROR_SUCCESS) if (error == ERROR_SUCCESS)
return; return std::string();
LPTSTR buffer = NULL; LPTSTR buffer = NULL;
const DWORD cchMsg = FormatMessageA( const DWORD cchMsg = FormatMessageA(
@ -31,13 +31,13 @@ namespace fk
{ {
std::string message(buffer); std::string message(buffer);
LocalFree(buffer); LocalFree(buffer);
throw std::exception(message.c_str()); return message;
} }
else else
{ {
CHAR buffer[32]; CHAR buffer[32];
sprintf_s(buffer, "Error code 0x%08X.", error); sprintf_s(buffer, "Error code 0x%08X.", error);
throw std::exception(buffer); return buffer;
} }
} }

View File

@ -25,7 +25,7 @@ namespace fk
}; };
int getGameVersion(DWORD timeDateStamp); int getGameVersion(DWORD timeDateStamp);
void throwLastError(); std::string getErrorMessage(int error);
void patchNops(ULONG dwAddr, SIZE_T dwPatchSize); void patchNops(ULONG dwAddr, SIZE_T dwPatchSize);
void patchJump(PVOID pDest, SIZE_T dwPatchSize, PVOID pCallee, DWORD dwJumpType = IJ_JUMP); void patchJump(PVOID pDest, SIZE_T dwPatchSize, PVOID pCallee, DWORD dwJumpType = IJ_JUMP);

View File

@ -1,20 +0,0 @@
#include "fkWinHandle.h"
#include "fkUtils.h"
#include <stdexcept>
namespace fk
{
WinHandle::WinHandle(HANDLE handle, BOOL(__stdcall* closeProc)(HANDLE))
: _handle(handle)
, _closeProc(closeProc)
{
if (!_handle || _handle == INVALID_HANDLE_VALUE)
fk::throwLastError();
}
WinHandle::~WinHandle()
{
if (_handle)
_closeProc(_handle);
}
}

View File

@ -1,19 +0,0 @@
#pragma once
#include <Windows.h>
namespace fk
{
struct WinHandle
{
public:
WinHandle(HANDLE handle, BOOL(__stdcall* closeProc)(HANDLE));
~WinHandle();
operator bool() { return _handle; }
operator HANDLE() { return _handle; }
private:
HANDLE _handle;
BOOL(__stdcall* _closeProc)(HANDLE);
};
}

View File

@ -1,16 +1,16 @@
#define WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN
#include <Windows.h> #include <Windows.h>
#include <WinInet.h> #include <WinInet.h>
#include <winsock.h>
#include "fkConfig.h" #include "fkConfig.h"
#include "fkUtils.h" #include "fkUtils.h"
#include "fkWinHandle.h"
#include "PEInfo.h" #include "PEInfo.h"
// ---- Configuration ----
CHAR cfgFallbackIP[16]; CHAR cfgFallbackIP[16];
CHAR cfgServiceUrl[MAX_PATH]; CHAR cfgServiceUrl[MAX_PATH];
BOOL cfgShowErrors; BOOL cfgShowErrors;
PEInfo pe;
CHAR resolvedIP[16] = {};
void configure() void configure()
{ {
@ -35,52 +35,105 @@ void configure()
} }
} }
void resolveIP(LPTSTR buffer) // ---- Patch: IP Resolval ----
CHAR cachedIP[16] = {};
bool resolveIPCached(LPSTR buffer)
{ {
if (!*resolvedIP) if (!*cachedIP)
return false;
lstrcpy(buffer, cachedIP);
return true;
}
bool resolveIPExternal(LPSTR buffer)
{
if (!*cfgServiceUrl)
return false;
// Query a web service which replies with the IP in plain text.
HINTERNET hInternet = 0, hFile = 0;
if (hInternet = InternetOpen(NULL, INTERNET_OPEN_TYPE_DIRECT, NULL, NULL, 0))
{ {
// Initially resolve the external IP through a web service. if (hFile = InternetOpenUrl(hInternet, cfgServiceUrl, NULL, 0,
fk::WinHandle hInternet(InternetOpen(NULL, INTERNET_OPEN_TYPE_DIRECT, NULL, NULL, 0), InternetCloseHandle); INTERNET_FLAG_NO_COOKIES | INTERNET_FLAG_NO_CACHE_WRITE | INTERNET_FLAG_RELOAD, NULL))
fk::WinHandle hFile(InternetOpenUrl(hInternet, cfgServiceUrl, NULL, 0, {
INTERNET_FLAG_NO_COOKIES | INTERNET_FLAG_NO_CACHE_WRITE | INTERNET_FLAG_RELOAD, NULL), InternetCloseHandle); DWORD responseLength = 0;
CHAR response[16];
DWORD responseLength = 0; if (InternetReadFile(hFile, response, 16, &responseLength))
CHAR response[16]; {
if (!InternetReadFile(hFile, response, 16, &responseLength)) if (responseLength >= 8)
fk::throwLastError(); {
if (responseLength < 8) response[responseLength] = '\0';
throw std::exception("Response was too short."); BYTE temp;
if (sscanf_s(response, "%hhu.%hhu.%hhu.%hhu", &temp, &temp, &temp, &temp) == 4)
response[responseLength] = '\0'; lstrcpy(buffer, response);
BYTE temp; else
if (sscanf_s(response, "%hhu.%hhu.%hhu.%hhu", &temp, &temp, &temp, &temp) != 4) SetLastError(0x20000002);
throw std::exception("Response could not be parsed."); }
else
lstrcpy(resolvedIP, response); {
SetLastError(0x20000001);
}
}
}
} }
lstrcpy(buffer, resolvedIP);
DWORD error = GetLastError();
if (hFile) InternetCloseHandle(hFile);
if (hInternet) InternetCloseHandle(hInternet);
if (error && cfgShowErrors)
{
CHAR msg[512];
sprintf_s(msg, "Could not resolve your IP through the web service. %s", fk::getErrorMessage(error).c_str());
MessageBox(NULL, msg, "fkNetcode", MB_ICONWARNING);
}
return !error;
}
bool resolveIPFallback(LPSTR buffer)
{
if (!*cfgFallbackIP)
return false;
lstrcpy(buffer, cfgFallbackIP);
return true;
}
bool resolveIPOriginal(LPSTR buffer)
{
// Use the original logic to "resolve" the (NAT) IP.
CHAR hostName[200];
hostent* host;
if (gethostname(hostName, 200) || !(host = gethostbyname(hostName)))
return false;
sprintf_s(hostName, "%hhu.%hhu.%hhu.%hhu",
host->h_addr_list[0][0],
host->h_addr_list[0][1],
host->h_addr_list[0][2],
host->h_addr_list[0][3]);
lstrcpy(buffer, hostName);
return true;
} }
bool __stdcall patchResolveIP(LPSTR buffer, int bufferLength) bool __stdcall patchResolveIP(LPSTR buffer, int bufferLength)
{ {
try // Return value not used by W2, but meant to be 0 if no error.
if (resolveIPCached(buffer) || resolveIPExternal(buffer) || resolveIPFallback(buffer) || resolveIPOriginal(buffer))
{ {
resolveIP(buffer); lstrcpy(cachedIP, buffer);
return false;
} }
catch (std::exception& ex) else
{ {
lstrcpy(buffer, *cfgFallbackIP ? cfgFallbackIP : "0.0.0.0"); return true;
if (cfgShowErrors)
{
CHAR message[512];
sprintf_s(message, "Could not resolve your IP address. %s", ex.what());
MessageBox(NULL, message, "fkNetcode", MB_ICONWARNING);
}
} }
return true; // not used
} }
void patch(int gameVersion) // ---- Patch ----
void patch(PEInfo& pe, int gameVersion)
{ {
fk::patchJump((PVOID)pe.Offset(0x00001799), 5, &patchResolveIP, fk::IJ_JUMP); // replace IP resolve with web service fk::patchJump((PVOID)pe.Offset(0x00001799), 5, &patchResolveIP, fk::IJ_JUMP); // replace IP resolve with web service
@ -98,12 +151,15 @@ void patch(int gameVersion)
} }
} }
// ---- Main ----
BOOL WINAPI DllMain(HMODULE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) BOOL WINAPI DllMain(HMODULE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
{ {
switch (fdwReason) switch (fdwReason)
{ {
case DLL_PROCESS_ATTACH: case DLL_PROCESS_ATTACH:
{ {
PEInfo pe;
int version = fk::getGameVersion(pe.FH->TimeDateStamp); int version = fk::getGameVersion(pe.FH->TimeDateStamp);
if (version == fk::GAME_VERSION_NONE) if (version == fk::GAME_VERSION_NONE)
{ {
@ -114,7 +170,7 @@ BOOL WINAPI DllMain(HMODULE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
else else
{ {
configure(); configure();
patch(version); patch(pe, version);
} }
} }
break; break;