mirror of
https://gitlab.com/Syroot/Worms.git
synced 2025-03-04 01:15:21 +03:00
Move WormKit loaders, modules, and libraries to module sub folder. Add signature scanning and import replacing.
This commit is contained in:
parent
518207b7e6
commit
a99a883f6f
@ -49,13 +49,17 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = " Solution Items", " Solut
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Syroot.Worms.Worms2.GameServer", "tool\Syroot.Worms.Worms2.GameServer\Syroot.Worms.Worms2.GameServer.csproj", "{13ABF717-5809-441D-A5D8-66E1EE75A390}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "fkNetcode", "tool\fkNetcode\fkNetcode.vcxproj", "{C4138811-7CFA-4826-A3DD-AF2B618EAFC1}"
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Module Projects", "Module Projects", "{2A8C6AAA-BA1F-4FB6-A598-114930217B6C}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "FrontendKitWS", "tool\FrontendKitWS\FrontendKitWS.vcxproj", "{E391EA12-B929-466C-932F-DEF72B8CEB5D}"
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "WormKitTools", "module\WormKitTools\WormKitTools.vcxproj", "{068A8647-0A66-4E39-983B-43ACEAC5C937}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "wkUnlimiter", "tool\wkUnlimiter\wkUnlimiter.vcxproj", "{CDED4B7C-91DF-45D3-9704-DB8750BDAF5B}"
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "FrontendKitWS", "module\FrontendKitWS\FrontendKitWS.vcxproj", "{E391EA12-B929-466C-932F-DEF72B8CEB5D}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "WormKitTools", "tool\WormKitTools\FrontendKitLib.vcxproj", "{068A8647-0A66-4E39-983B-43ACEAC5C937}"
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "fkDesPatch", "module\fkDesPatch\fkDesPatch.vcxproj", "{6B4D57EA-4642-440A-AB62-2E011D7B64E1}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "fkNetcode", "module\fkNetcode\fkNetcode.vcxproj", "{C4138811-7CFA-4826-A3DD-AF2B618EAFC1}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "wkUnlimiter", "module\wkUnlimiter\wkUnlimiter.vcxproj", "{CDED4B7C-91DF-45D3-9704-DB8750BDAF5B}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
@ -131,22 +135,26 @@ Global
|
||||
{13ABF717-5809-441D-A5D8-66E1EE75A390}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{13ABF717-5809-441D-A5D8-66E1EE75A390}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{13ABF717-5809-441D-A5D8-66E1EE75A390}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{C4138811-7CFA-4826-A3DD-AF2B618EAFC1}.Debug|Any CPU.ActiveCfg = Debug|Win32
|
||||
{C4138811-7CFA-4826-A3DD-AF2B618EAFC1}.Debug|Any CPU.Build.0 = Debug|Win32
|
||||
{C4138811-7CFA-4826-A3DD-AF2B618EAFC1}.Release|Any CPU.ActiveCfg = Release|Win32
|
||||
{C4138811-7CFA-4826-A3DD-AF2B618EAFC1}.Release|Any CPU.Build.0 = Release|Win32
|
||||
{E391EA12-B929-466C-932F-DEF72B8CEB5D}.Debug|Any CPU.ActiveCfg = Debug|Win32
|
||||
{E391EA12-B929-466C-932F-DEF72B8CEB5D}.Debug|Any CPU.Build.0 = Debug|Win32
|
||||
{E391EA12-B929-466C-932F-DEF72B8CEB5D}.Release|Any CPU.ActiveCfg = Release|Win32
|
||||
{E391EA12-B929-466C-932F-DEF72B8CEB5D}.Release|Any CPU.Build.0 = Release|Win32
|
||||
{CDED4B7C-91DF-45D3-9704-DB8750BDAF5B}.Debug|Any CPU.ActiveCfg = Debug|Win32
|
||||
{CDED4B7C-91DF-45D3-9704-DB8750BDAF5B}.Debug|Any CPU.Build.0 = Debug|Win32
|
||||
{CDED4B7C-91DF-45D3-9704-DB8750BDAF5B}.Release|Any CPU.ActiveCfg = Release|Win32
|
||||
{CDED4B7C-91DF-45D3-9704-DB8750BDAF5B}.Release|Any CPU.Build.0 = Release|Win32
|
||||
{068A8647-0A66-4E39-983B-43ACEAC5C937}.Debug|Any CPU.ActiveCfg = Debug|Win32
|
||||
{068A8647-0A66-4E39-983B-43ACEAC5C937}.Debug|Any CPU.Build.0 = Debug|Win32
|
||||
{068A8647-0A66-4E39-983B-43ACEAC5C937}.Release|Any CPU.ActiveCfg = Release|Win32
|
||||
{068A8647-0A66-4E39-983B-43ACEAC5C937}.Release|Any CPU.Build.0 = Release|Win32
|
||||
{E391EA12-B929-466C-932F-DEF72B8CEB5D}.Debug|Any CPU.ActiveCfg = Debug|Win32
|
||||
{E391EA12-B929-466C-932F-DEF72B8CEB5D}.Debug|Any CPU.Build.0 = Debug|Win32
|
||||
{E391EA12-B929-466C-932F-DEF72B8CEB5D}.Release|Any CPU.ActiveCfg = Release|Win32
|
||||
{E391EA12-B929-466C-932F-DEF72B8CEB5D}.Release|Any CPU.Build.0 = Release|Win32
|
||||
{6B4D57EA-4642-440A-AB62-2E011D7B64E1}.Debug|Any CPU.ActiveCfg = Debug|Win32
|
||||
{6B4D57EA-4642-440A-AB62-2E011D7B64E1}.Debug|Any CPU.Build.0 = Debug|Win32
|
||||
{6B4D57EA-4642-440A-AB62-2E011D7B64E1}.Release|Any CPU.ActiveCfg = Release|Win32
|
||||
{6B4D57EA-4642-440A-AB62-2E011D7B64E1}.Release|Any CPU.Build.0 = Release|Win32
|
||||
{C4138811-7CFA-4826-A3DD-AF2B618EAFC1}.Debug|Any CPU.ActiveCfg = Debug|Win32
|
||||
{C4138811-7CFA-4826-A3DD-AF2B618EAFC1}.Debug|Any CPU.Build.0 = Debug|Win32
|
||||
{C4138811-7CFA-4826-A3DD-AF2B618EAFC1}.Release|Any CPU.ActiveCfg = Release|Win32
|
||||
{C4138811-7CFA-4826-A3DD-AF2B618EAFC1}.Release|Any CPU.Build.0 = Release|Win32
|
||||
{CDED4B7C-91DF-45D3-9704-DB8750BDAF5B}.Debug|Any CPU.ActiveCfg = Debug|Win32
|
||||
{CDED4B7C-91DF-45D3-9704-DB8750BDAF5B}.Debug|Any CPU.Build.0 = Debug|Win32
|
||||
{CDED4B7C-91DF-45D3-9704-DB8750BDAF5B}.Release|Any CPU.ActiveCfg = Release|Win32
|
||||
{CDED4B7C-91DF-45D3-9704-DB8750BDAF5B}.Release|Any CPU.Build.0 = Release|Win32
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
@ -169,10 +177,11 @@ Global
|
||||
{212F8090-9775-4098-BD44-9ABC01FBE553} = {99E56312-A064-4AD3-8443-0B56A5F76E6B}
|
||||
{1FAB6B9F-2585-46DC-81C0-579DC808C389} = {0B9B0B74-3EB1-46A4-BCCC-F2D6AE59A9EE}
|
||||
{13ABF717-5809-441D-A5D8-66E1EE75A390} = {0B9B0B74-3EB1-46A4-BCCC-F2D6AE59A9EE}
|
||||
{C4138811-7CFA-4826-A3DD-AF2B618EAFC1} = {0B9B0B74-3EB1-46A4-BCCC-F2D6AE59A9EE}
|
||||
{E391EA12-B929-466C-932F-DEF72B8CEB5D} = {0B9B0B74-3EB1-46A4-BCCC-F2D6AE59A9EE}
|
||||
{CDED4B7C-91DF-45D3-9704-DB8750BDAF5B} = {0B9B0B74-3EB1-46A4-BCCC-F2D6AE59A9EE}
|
||||
{068A8647-0A66-4E39-983B-43ACEAC5C937} = {0B9B0B74-3EB1-46A4-BCCC-F2D6AE59A9EE}
|
||||
{068A8647-0A66-4E39-983B-43ACEAC5C937} = {2A8C6AAA-BA1F-4FB6-A598-114930217B6C}
|
||||
{E391EA12-B929-466C-932F-DEF72B8CEB5D} = {2A8C6AAA-BA1F-4FB6-A598-114930217B6C}
|
||||
{6B4D57EA-4642-440A-AB62-2E011D7B64E1} = {2A8C6AAA-BA1F-4FB6-A598-114930217B6C}
|
||||
{C4138811-7CFA-4826-A3DD-AF2B618EAFC1} = {2A8C6AAA-BA1F-4FB6-A598-114930217B6C}
|
||||
{CDED4B7C-91DF-45D3-9704-DB8750BDAF5B} = {2A8C6AAA-BA1F-4FB6-A598-114930217B6C}
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {1CD4EDE2-A5FB-4A58-A850-3506AB7E7B69}
|
||||
|
@ -93,7 +93,7 @@
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="src\wkConfig.cpp" />
|
||||
<ClCompile Include="src\wkIni.cpp" />
|
||||
<ClCompile Include="src\wkPatch.cpp" />
|
||||
<ClCompile Include="src\wkUtils.cpp" />
|
||||
<ClCompile Include="src\pch.cpp">
|
||||
@ -103,13 +103,14 @@
|
||||
<ClCompile Include="src\wkExe.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="include\wkConfig.h" />
|
||||
<ClInclude Include="include\wkIni.h" />
|
||||
<ClInclude Include="include\wkPatch.h" />
|
||||
<ClInclude Include="include\wkUtils.h" />
|
||||
<ClInclude Include="include\wkExe.h" />
|
||||
<ClInclude Include="src\pch.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="include\wkExe.inl" />
|
||||
<None Include="include\wkPatch.inl" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
@ -18,9 +18,6 @@
|
||||
<ClCompile Include="src\pch.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\wkConfig.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\wkUtils.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
@ -30,14 +27,14 @@
|
||||
<ClCompile Include="src\wkExe.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="src\wkIni.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="src\pch.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\wkConfig.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\wkUtils.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
@ -47,10 +44,16 @@
|
||||
<ClInclude Include="include\wkExe.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="include\wkIni.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="include\wkPatch.inl">
|
||||
<Filter>Header Files</Filter>
|
||||
</None>
|
||||
<None Include="include\wkExe.inl">
|
||||
<Filter>Header Files</Filter>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
</Project>
|
88
src/module/WormKitTools/include/wkExe.h
Normal file
88
src/module/WormKitTools/include/wkExe.h
Normal file
@ -0,0 +1,88 @@
|
||||
#pragma once
|
||||
#include <stdint.h>
|
||||
#include <string>
|
||||
#include <Windows.h>
|
||||
#include "wkPatch.h"
|
||||
|
||||
namespace wk
|
||||
{
|
||||
enum JumpType
|
||||
{
|
||||
JT_JMP, // jmp (0xE9)
|
||||
JT_CALL, // call (0xE8)
|
||||
JT_FARJMP, // farjump (0xEA)
|
||||
JT_FARCALL, // farcall (0x9A)
|
||||
JT_PUSHRET, // pushret
|
||||
};
|
||||
|
||||
struct Exe
|
||||
{
|
||||
public:
|
||||
// ---- FIELDS -------------------------------------------------------------------------------------------------
|
||||
|
||||
HANDLE Handle;
|
||||
PIMAGE_DOS_HEADER DosHeader;
|
||||
PIMAGE_NT_HEADERS NtHeader;
|
||||
PIMAGE_FILE_HEADER FileHeader;
|
||||
PIMAGE_OPTIONAL_HEADER OptHeader;
|
||||
|
||||
// ---- CONSTRUCTORS & DESTRUCTOR ------------------------------------------------------------------------------
|
||||
|
||||
Exe(HMODULE hModule = NULL);
|
||||
|
||||
// ---- METHODS ------------------------------------------------------------------------------------------------
|
||||
|
||||
/// <summary>
|
||||
/// Returns the offset of the first match of the given signature. It must take the form "12 FF ?? EB 34", where
|
||||
/// two question marks represent a wildcard.
|
||||
/// </summary>
|
||||
/// <param name="signature">The signature to find.</param>
|
||||
/// <returns>The offset of the first match of the signature.</returns>
|
||||
ULONG_PTR find(std::string signature);
|
||||
|
||||
/// <summary>
|
||||
/// Returns the offset of the first match of the given signature. It is an array of bytes, where all values
|
||||
/// being negative or bigger than 0xFF represent a wildcard.
|
||||
/// </summary>
|
||||
/// <param name="signature">The signature to find.</param>
|
||||
/// <returns>The offset of the first match of the signature.</returns>
|
||||
ULONG_PTR find(int16_t signature[], size_t signatureSize); // any non-uint8_t value is a wildcard
|
||||
|
||||
/// <summary>
|
||||
/// Writes the given value to the specified offset.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of the value to write.</typeparam>
|
||||
/// <param name="offset">The relative address at which to write the value.</param>
|
||||
/// <param name="value">The value to write.</param>
|
||||
template <class T> void set(ULONG_PTR offset, T value);
|
||||
|
||||
/// <summary>
|
||||
/// Replaces the given import with the specified hook, which must have the same signature.
|
||||
/// </summary>
|
||||
/// <param name="import">The imported method to replace.</param>
|
||||
/// <param name="hook">The method to replace the import with.</param>
|
||||
void setImp(LPVOID import, LPVOID hook);
|
||||
|
||||
/// <summary>
|
||||
/// Writes a jump to the given callee at the specified offset.
|
||||
/// </summary>
|
||||
/// <param name="offset">The relative address at which to write the value.</param>
|
||||
/// <param name="size">The number of bytes overwritten for the jump opcode.</param>
|
||||
/// <param name="callee">The called method.</param>
|
||||
/// <param name="jumpType">The type of the jump to insert.</param>
|
||||
void setJmp(ULONG_PTR offset, SIZE_T size, LPVOID callee, DWORD jumpType);
|
||||
|
||||
/// <summary>
|
||||
/// Nops out the given number of bytes at the specified offset.
|
||||
/// </summary>
|
||||
/// <param name="offset">The relative address at which to nop out code.</param>
|
||||
/// <param name="size">The number of bytes to nop out.</param>
|
||||
void setNop(ULONG_PTR offset, SIZE_T size);
|
||||
|
||||
private:
|
||||
LPVOID getAddress(ULONG_PTR offset);
|
||||
PIMAGE_IMPORT_DESCRIPTOR getImports();
|
||||
};
|
||||
}
|
||||
|
||||
#include "wkExe.inl"
|
9
src/module/WormKitTools/include/wkExe.inl
Normal file
9
src/module/WormKitTools/include/wkExe.inl
Normal file
@ -0,0 +1,9 @@
|
||||
namespace wk
|
||||
{
|
||||
template <class T>
|
||||
void Exe::set(ULONG_PTR offset, T newValue)
|
||||
{
|
||||
Patch patch(getAddress(offset), sizeof(T));
|
||||
patch.write(newValue);
|
||||
}
|
||||
}
|
@ -3,10 +3,10 @@
|
||||
|
||||
namespace wk
|
||||
{
|
||||
class Config
|
||||
class Ini
|
||||
{
|
||||
public:
|
||||
Config(LPCSTR fileName);
|
||||
Ini(LPCSTR fileName);
|
||||
|
||||
void get(LPCSTR category, LPCSTR key, BOOL& result, UINT fallback) const;
|
||||
void get(LPCSTR category, LPCSTR key, UINT& result, UINT fallback) const;
|
31
src/module/WormKitTools/include/wkPatch.h
Normal file
31
src/module/WormKitTools/include/wkPatch.h
Normal file
@ -0,0 +1,31 @@
|
||||
#pragma once
|
||||
#include <Windows.h>
|
||||
|
||||
namespace wk
|
||||
{
|
||||
struct Patch
|
||||
{
|
||||
public:
|
||||
// ---- FIELDS -------------------------------------------------------------------------------------------------
|
||||
|
||||
ULONG_PTR position;
|
||||
|
||||
// ---- CONSTRUCTORS & DESTRUCTOR ------------------------------------------------------------------------------
|
||||
|
||||
Patch(LPVOID address, SIZE_T size);
|
||||
~Patch();
|
||||
|
||||
// ---- METHODS ------------------------------------------------------------------------------------------------
|
||||
|
||||
void close() const;
|
||||
template <class T> void write(const T& value);
|
||||
|
||||
private:
|
||||
// ---- FIELDS -------------------------------------------------------------------------------------------------
|
||||
LPBYTE _address;
|
||||
SIZE_T _size;
|
||||
DWORD _oldProtect;
|
||||
};
|
||||
}
|
||||
|
||||
#include "wkPatch.inl"
|
@ -14,21 +14,28 @@ namespace wk
|
||||
GAMEID_W2_1_05 = GAMEID_W2 | 0x010500,
|
||||
GAMEID_W2_1_05_BR = GAMEID_W2_1_05 | 0x10, // Worms2 1.05 Br
|
||||
GAMEID_W2_1_05_EN = GAMEID_W2_1_05 | 0x20, // Worms2 1.05 Du, En, Fr, It, Po, Sp, Sw
|
||||
GAMEID_W2_1_05_GE = GAMEID_W2_1_05 | 0x30, // Worms2 1.05
|
||||
GAMEID_W2_1_05_NA = GAMEID_W2_1_05 | 0x40, // Worms2 1.05
|
||||
GAMEID_W2_1_05_SA = GAMEID_W2_1_05 | 0x50, // Worms2 1.05
|
||||
GAMEID_W2_1_05_GE = GAMEID_W2_1_05 | 0x30, // Worms2 1.05 De
|
||||
GAMEID_W2_1_05_NA = GAMEID_W2_1_05 | 0x40, // Worms2 1.05 NA
|
||||
GAMEID_W2_1_05_SA = GAMEID_W2_1_05 | 0x50, // Worms2 1.05 SA
|
||||
GAMEID_W2_1_07 = GAMEID_W2 | 0x010700,
|
||||
GAMEID_W2_1_07_TRY = GAMEID_W2_1_07 | 0x60, // Worms2 1.07 Trymedia
|
||||
GAMEID_W2_LAST = GAMEID_W2_1_07_TRY,
|
||||
|
||||
GAMEID_WA = 0x30000000,
|
||||
GAMEID_WA_3_6_31 = GAMEID_WA | 0x030630, // Worms Armageddon 3.6.31
|
||||
GAMEID_WA_3_7_2_1 = GAMEID_WA | 0x030721, // Worms Armageddon 3.7.2.1
|
||||
GAMEID_WA_3_8 = GAMEID_WA | 0x030800,
|
||||
GAMEID_WA_3_8_CD = GAMEID_WA_3_8 | 0x10, // Worms Armageddon 3.8 CD
|
||||
GAMEID_WA_LAST = GAMEID_WA_3_8_CD,
|
||||
|
||||
GAMEID_WWP = 0x40000000,
|
||||
GAMEID_WWP_LAST = GAMEID_WWP,
|
||||
|
||||
GAMEID_OW = 0x50000000,
|
||||
GAMEID_OW_LAST = GAMEID_OW,
|
||||
|
||||
GAMEID_WWPA = 0x60000000,
|
||||
GAMEID_WWPA_LAST = GAMEID_WWPA,
|
||||
};
|
||||
|
||||
int getGameID(DWORD timeDateStamp);
|
160
src/module/WormKitTools/src/wkExe.cpp
Normal file
160
src/module/WormKitTools/src/wkExe.cpp
Normal file
@ -0,0 +1,160 @@
|
||||
#include "wkExe.h"
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <stdexcept>
|
||||
#include <vector>
|
||||
|
||||
namespace wk
|
||||
{
|
||||
// ---- CONSTRUCTORS & DESTRUCTOR ----------------------------------------------------------------------------------
|
||||
|
||||
Exe::Exe(HMODULE hModule)
|
||||
{
|
||||
Handle = hModule == NULL ? GetModuleHandleA(NULL) : hModule;
|
||||
DosHeader = (PIMAGE_DOS_HEADER)Handle;
|
||||
NtHeader = (PIMAGE_NT_HEADERS)((DWORD)DosHeader + DosHeader->e_lfanew);
|
||||
FileHeader = (PIMAGE_FILE_HEADER)&NtHeader->FileHeader;
|
||||
OptHeader = (PIMAGE_OPTIONAL_HEADER)&NtHeader->OptionalHeader;
|
||||
}
|
||||
|
||||
// ---- METHODS (PUBLIC) -------------------------------------------------------------------------------------------
|
||||
|
||||
ULONG_PTR Exe::find(std::string signature)
|
||||
{
|
||||
std::istringstream iss(signature);
|
||||
std::istream_iterator<std::string> begin(iss), end;
|
||||
std::vector<std::string> tokens(begin, end);
|
||||
|
||||
std::vector<int16_t> sig;
|
||||
for (auto& token : tokens)
|
||||
sig.push_back(token == "??" ? -1 : std::stoi(token, 0, 16));
|
||||
|
||||
return find(&sig[0], sig.size());
|
||||
}
|
||||
|
||||
ULONG_PTR Exe::find(int16_t signature[], size_t signatureSize)
|
||||
{
|
||||
PIMAGE_SECTION_HEADER sections = IMAGE_FIRST_SECTION(NtHeader);
|
||||
for (int index = 0; index < FileHeader->NumberOfSections; index++)
|
||||
{
|
||||
if (sections[index].Characteristics != (IMAGE_SCN_CNT_CODE | IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ))
|
||||
continue;
|
||||
LPBYTE code = (LPBYTE)(ULONG_PTR)Handle + sections[index].VirtualAddress;
|
||||
LPBYTE last = &code[sections[index].SizeOfRawData - signatureSize];
|
||||
for (; code < last; code++)
|
||||
{
|
||||
bool found = true;
|
||||
for (size_t i = 0; i < signatureSize; i++)
|
||||
{
|
||||
if (signature[i] < 0x00 || signature[i] > 0xFF || code[i] == (BYTE)signature[i])
|
||||
{
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
found = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (found)
|
||||
return (ULONG_PTR)code - (ULONG_PTR)Handle;
|
||||
}
|
||||
}
|
||||
throw std::exception("Could not find signature.");
|
||||
}
|
||||
|
||||
void Exe::setImp(LPVOID import, LPVOID hook)
|
||||
{
|
||||
bool success = false;
|
||||
PIMAGE_IMPORT_DESCRIPTOR imports = getImports();
|
||||
if (!imports)
|
||||
throw std::exception("Import patching failed, import table not found.");
|
||||
|
||||
while (imports->Characteristics)
|
||||
{
|
||||
PIMAGE_THUNK_DATA thunk = (PIMAGE_THUNK_DATA)((ULONG_PTR)Handle + imports->OriginalFirstThunk);
|
||||
PIMAGE_THUNK_DATA table = (PIMAGE_THUNK_DATA)((ULONG_PTR)Handle + imports->FirstThunk);
|
||||
while (thunk->u1.Ordinal)
|
||||
{
|
||||
if (table->u1.Function == (ULONG_PTR)import)
|
||||
{
|
||||
Patch patch(&table->u1.Function, sizeof(ULONG_PTR));
|
||||
patch.write(hook);
|
||||
success = true;
|
||||
}
|
||||
thunk++;
|
||||
table++;
|
||||
}
|
||||
imports++;
|
||||
}
|
||||
|
||||
if (!success)
|
||||
throw std::exception("Import patching failed, import not found.");
|
||||
}
|
||||
|
||||
void Exe::setJmp(ULONG_PTR offset, SIZE_T size, LPVOID callee, DWORD jumpType)
|
||||
{
|
||||
Patch patch(getAddress(offset), size);
|
||||
|
||||
if (size >= 5 && offset)
|
||||
{
|
||||
BYTE opSize, opCode;
|
||||
switch (jumpType)
|
||||
{
|
||||
case JT_PUSHRET: opSize = 6; opCode = 0x68; break;
|
||||
case JT_FARJMP: opSize = 7; opCode = 0xEA; break;
|
||||
case JT_FARCALL: opSize = 7; opCode = 0x9A; break;
|
||||
case JT_CALL: opSize = 5; opCode = 0xE8; break;
|
||||
default: opSize = 5; opCode = 0xE9; break;
|
||||
}
|
||||
|
||||
if (size < opSize)
|
||||
throw std::exception("Not enough space to patch opcode.");
|
||||
|
||||
patch.write(opCode);
|
||||
switch (opSize)
|
||||
{
|
||||
case 7:
|
||||
patch.write((ULONG)callee);
|
||||
patch.write<WORD>(0x23);
|
||||
break;
|
||||
case 6:
|
||||
patch.write((ULONG)callee);
|
||||
patch.write<BYTE>(0xC3);
|
||||
break;
|
||||
default:
|
||||
patch.write((ULONG)callee - (ULONG_PTR)offset - 5);
|
||||
break;
|
||||
}
|
||||
for (DWORD i = opSize; i < size; i++)
|
||||
patch.write((uint8_t)0x90);
|
||||
}
|
||||
}
|
||||
|
||||
void Exe::setNop(ULONG_PTR offset, SIZE_T size)
|
||||
{
|
||||
Patch patch(getAddress(offset), size);
|
||||
while (size--)
|
||||
patch.write((uint8_t)0x90);
|
||||
}
|
||||
|
||||
// ---- METHODS (PRIVATE) ------------------------------------------------------------------------------------------
|
||||
|
||||
LPVOID Exe::getAddress(ULONG_PTR offset)
|
||||
{
|
||||
return (LPVOID)((ULONG_PTR)Handle + offset);
|
||||
}
|
||||
|
||||
PIMAGE_IMPORT_DESCRIPTOR Exe::getImports()
|
||||
{
|
||||
if ((FileHeader->SizeOfOptionalHeader
|
||||
>= FIELD_OFFSET(IMAGE_OPTIONAL_HEADER, DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT + 1]))
|
||||
&& OptHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress
|
||||
&& OptHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].Size)
|
||||
{
|
||||
return (PIMAGE_IMPORT_DESCRIPTOR)((ULONG_PTR)Handle
|
||||
+ OptHeader->DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
}
|
@ -1,38 +1,38 @@
|
||||
#include "wkConfig.h"
|
||||
#include "wkIni.h"
|
||||
#include <stdio.h>
|
||||
|
||||
namespace wk
|
||||
{
|
||||
Config::Config(LPCSTR fileName)
|
||||
Ini::Ini(LPCSTR fileName)
|
||||
{
|
||||
GetModuleFileName(NULL, _filePath, MAX_PATH);
|
||||
char* sepIdx = strrchr(_filePath, '\\') + 1;
|
||||
strcpy_s(sepIdx, MAX_PATH - (int)(sepIdx - _filePath), fileName);
|
||||
}
|
||||
|
||||
void Config::get(LPCSTR category, LPCSTR key, BOOL& result, UINT fallback) const
|
||||
void Ini::get(LPCSTR category, LPCSTR key, BOOL& result, UINT fallback) const
|
||||
{
|
||||
result = GetPrivateProfileInt(category, key, fallback, _filePath);
|
||||
}
|
||||
|
||||
void Config::get(LPCSTR category, LPCSTR key, UINT& result, UINT fallback) const
|
||||
void Ini::get(LPCSTR category, LPCSTR key, UINT& result, UINT fallback) const
|
||||
{
|
||||
result = GetPrivateProfileInt(category, key, fallback, _filePath);
|
||||
}
|
||||
|
||||
void Config::get(LPCSTR category, LPCSTR key, LPSTR result, INT resultLength, LPCSTR fallback) const
|
||||
void Ini::get(LPCSTR category, LPCSTR key, LPSTR result, INT resultLength, LPCSTR fallback) const
|
||||
{
|
||||
GetPrivateProfileString(category, key, fallback, result, resultLength, _filePath);
|
||||
}
|
||||
|
||||
void Config::set(LPCSTR category, LPCSTR key, UINT value) const
|
||||
void Ini::set(LPCSTR category, LPCSTR key, UINT value) const
|
||||
{
|
||||
CHAR buffer[32];
|
||||
sprintf_s(buffer, "%d", value);
|
||||
WritePrivateProfileString(category, key, buffer, _filePath);
|
||||
}
|
||||
|
||||
void Config::set(LPCSTR category, LPCSTR key, LPCSTR value) const
|
||||
void Ini::set(LPCSTR category, LPCSTR key, LPCSTR value) const
|
||||
{
|
||||
WritePrivateProfileString(category, key, value, _filePath);
|
||||
}
|
32
src/module/WormKitTools/src/wkPatch.cpp
Normal file
32
src/module/WormKitTools/src/wkPatch.cpp
Normal file
@ -0,0 +1,32 @@
|
||||
#include "wkPatch.h"
|
||||
#include <stdexcept>
|
||||
|
||||
namespace wk
|
||||
{
|
||||
// ---- CONSTRUCTORS & DESTRUCTOR ----------------------------------------------------------------------------------
|
||||
|
||||
Patch::Patch(LPVOID address, SIZE_T size)
|
||||
: _address((LPBYTE)address)
|
||||
, _size(size)
|
||||
, position(0)
|
||||
{
|
||||
if (!_address || !_size)
|
||||
throw std::invalid_argument("Address and size must not be 0.");
|
||||
if (!VirtualProtect(_address, _size, PAGE_EXECUTE_READWRITE, &_oldProtect))
|
||||
throw std::exception("VirtualProtect failed, call GetLastError for more info.");
|
||||
}
|
||||
|
||||
Patch::~Patch()
|
||||
{
|
||||
close();
|
||||
}
|
||||
|
||||
// ---- METHODS (PUBLIC) -------------------------------------------------------------------------------------------
|
||||
|
||||
void Patch::close() const
|
||||
{
|
||||
DWORD oldProtect;
|
||||
if (!VirtualProtect(_address, _size, _oldProtect, &oldProtect))
|
||||
throw std::exception("VirtualProtect failed, call GetLastError for more info.");
|
||||
}
|
||||
};
|
@ -14,6 +14,8 @@ namespace wk
|
||||
case 0x3528DA98: return GAMEID_W2_1_05_NA;
|
||||
case 0x3528DBDA: return GAMEID_W2_1_05_SA;
|
||||
case 0x3587BE19: return GAMEID_W2_1_07_TRY;
|
||||
case 0x4CE25091: return GAMEID_WA_3_6_31;
|
||||
case 0x513D83BC: return GAMEID_WA_3_7_2_1;
|
||||
case 0x5EF04515: return GAMEID_WA_3_8_CD;
|
||||
default: return GAMEID_NONE;
|
||||
}
|
99
src/module/fkDesPatch/fkDesPatch.vcxproj
Normal file
99
src/module/fkDesPatch/fkDesPatch.vcxproj
Normal file
@ -0,0 +1,99 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|Win32">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<VCProjectVersion>16.0</VCProjectVersion>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
<ProjectGuid>{6b4d57ea-4642-440a-ab62-2e011d7b64e1}</ProjectGuid>
|
||||
<RootNamespace>fkDesPatch</RootNamespace>
|
||||
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v142</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>MultiByte</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="Shared">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
<OutDir>bin\$(Configuration)\</OutDir>
|
||||
<IntDir>obj\$(Configuration)\</IntDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
<OutDir>bin\$(Configuration)\</OutDir>
|
||||
<IntDir>obj\$(Configuration)\</IntDir>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;FKDESPATCH_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<AdditionalIncludeDirectories>$(ProjectDir)..\WormKitTools\include\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableUAC>false</EnableUAC>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;FKDESPATCH_EXPORTS;_WINDOWS;_USRDLL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<ConformanceMode>true</ConformanceMode>
|
||||
<AdditionalIncludeDirectories>$(ProjectDir)..\WormKitTools\include\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableUAC>false</EnableUAC>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="main.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\WormKitTools\WormKitTools.vcxproj">
|
||||
<Project>{068a8647-0a66-4e39-983b-43aceac5c937}</Project>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
84
src/module/fkDesPatch/main.cpp
Normal file
84
src/module/fkDesPatch/main.cpp
Normal file
@ -0,0 +1,84 @@
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <stdint.h>
|
||||
#include <Windows.h>
|
||||
#include "wkExe.h"
|
||||
#include "wkIni.h"
|
||||
#include "wkUtils.h"
|
||||
|
||||
// ---- Initialization ----
|
||||
|
||||
BOOL iniAutoOssett;
|
||||
|
||||
void init()
|
||||
{
|
||||
wk::Ini ini("fkDesPatch.ini");
|
||||
|
||||
// Load INI settings.
|
||||
ini.get("Frontend", "AutoOssett", iniAutoOssett, FALSE);
|
||||
|
||||
// Ensure INI file has been created with default setting.
|
||||
ini.set("Frontend", "AutoOssett", iniAutoOssett);
|
||||
}
|
||||
|
||||
// ---- Patch ----
|
||||
|
||||
void patch(wk::Exe& exe, int gameVersion)
|
||||
{
|
||||
if (gameVersion == wk::GAMEID_W2_1_07_TRY)
|
||||
{
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
// getAddress file to code 0x400C02
|
||||
if (iniAutoOssett)
|
||||
exe.set(0x000446A2, (uint8_t)0xEB);
|
||||
}
|
||||
}
|
||||
|
||||
// ---- Main ----
|
||||
|
||||
int getVersion(DWORD timeDateStamp)
|
||||
{
|
||||
int id = wk::getGameID(timeDateStamp);
|
||||
switch (id)
|
||||
{
|
||||
case wk::GAMEID_W2_1_05_BR:
|
||||
case wk::GAMEID_W2_1_05_EN:
|
||||
case wk::GAMEID_W2_1_05_GE:
|
||||
case wk::GAMEID_W2_1_05_NA:
|
||||
case wk::GAMEID_W2_1_05_SA:
|
||||
case wk::GAMEID_W2_1_07_TRY:
|
||||
return id;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
BOOL WINAPI DllMain(HMODULE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
|
||||
{
|
||||
switch (fdwReason)
|
||||
{
|
||||
case DLL_PROCESS_ATTACH:
|
||||
{
|
||||
wk::Exe exe;
|
||||
int version = getVersion(exe.FileHeader->TimeDateStamp);
|
||||
if (version)
|
||||
{
|
||||
init();
|
||||
patch(exe, version);
|
||||
}
|
||||
else
|
||||
{
|
||||
MessageBox(NULL, "fkDesPatch is incompatible with your game version. Please run the 1.05 patch or 1.07 "
|
||||
"release of Worms 2. Otherwise, you can delete the module to remove this warning.", "fkDesPatch",
|
||||
MB_ICONWARNING);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case DLL_PROCESS_DETACH:
|
||||
break;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
@ -98,7 +98,7 @@
|
||||
<ResourceCompile Include="fkNetcode.rc" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\WormKitTools\FrontendKitLib.vcxproj">
|
||||
<ProjectReference Include="..\WormKitTools\WormKitTools.vcxproj">
|
||||
<Project>{068a8647-0a66-4e39-983b-43aceac5c937}</Project>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
@ -2,36 +2,36 @@
|
||||
#include <Windows.h>
|
||||
#include <WinInet.h>
|
||||
#include <winsock.h>
|
||||
#include "wkConfig.h"
|
||||
#include "wkIni.h"
|
||||
#include "wkExe.h"
|
||||
#include "wkPatch.h"
|
||||
#include "wkUtils.h"
|
||||
|
||||
// ---- Configuration ----
|
||||
// ---- Initialization ----
|
||||
|
||||
CHAR cfgFallbackIP[16];
|
||||
CHAR cfgServiceUrl[MAX_PATH];
|
||||
BOOL cfgShowErrors;
|
||||
CHAR iniFallbackIP[16];
|
||||
CHAR iniServiceUrl[MAX_PATH];
|
||||
BOOL iniShowErrors;
|
||||
|
||||
void configure()
|
||||
void init()
|
||||
{
|
||||
wk::Config config("fkNetcode.ini");
|
||||
wk::Ini ini("fkNetcode.ini");
|
||||
|
||||
// Load INI settings.
|
||||
config.get("AddressResolval", "FallbackIP", cfgFallbackIP, 16);
|
||||
config.get("AddressResolval", "ServiceUrl", cfgServiceUrl, MAX_PATH, "http://ip.syroot.com");
|
||||
config.get("AddressResolval", "ShowErrors", cfgShowErrors, TRUE);
|
||||
ini.get("AddressResolval", "FallbackIP", iniFallbackIP, 16);
|
||||
ini.get("AddressResolval", "ServiceUrl", iniServiceUrl, MAX_PATH, "http://ip.syroot.com");
|
||||
ini.get("AddressResolval", "ShowErrors", iniShowErrors, TRUE);
|
||||
|
||||
// Ensure INI file has been created with default setting.
|
||||
config.set("AddressResolval", "FallbackIP", cfgFallbackIP);
|
||||
config.set("AddressResolval", "ServiceUrl", cfgServiceUrl);
|
||||
config.set("AddressResolval", "ShowErrors", cfgShowErrors);
|
||||
ini.set("AddressResolval", "FallbackIP", iniFallbackIP);
|
||||
ini.set("AddressResolval", "ServiceUrl", iniServiceUrl);
|
||||
ini.set("AddressResolval", "ShowErrors", iniShowErrors);
|
||||
|
||||
// Validate fallback IP.
|
||||
BYTE b;
|
||||
if (*cfgFallbackIP && sscanf_s(cfgFallbackIP, "%hhu.%hhu.%hhu.%hhu", &b, &b, &b, &b) != 4)
|
||||
if (*iniFallbackIP && sscanf_s(iniFallbackIP, "%hhu.%hhu.%hhu.%hhu", &b, &b, &b, &b) != 4)
|
||||
{
|
||||
*cfgFallbackIP = NULL;
|
||||
*iniFallbackIP = NULL;
|
||||
MessageBox(NULL, "Invalid fallback IP setting in fkNetcode.ini has been ignored.", "fkNetcode", MB_ICONWARNING);
|
||||
}
|
||||
}
|
||||
@ -50,14 +50,14 @@ bool resolveIPCached(LPSTR buffer)
|
||||
|
||||
bool resolveIPExternal(LPSTR buffer)
|
||||
{
|
||||
if (!*cfgServiceUrl)
|
||||
if (!*iniServiceUrl)
|
||||
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))
|
||||
{
|
||||
if (hFile = InternetOpenUrl(hInternet, cfgServiceUrl, NULL, 0,
|
||||
if (hFile = InternetOpenUrl(hInternet, iniServiceUrl, NULL, 0,
|
||||
INTERNET_FLAG_NO_COOKIES | INTERNET_FLAG_NO_CACHE_WRITE | INTERNET_FLAG_RELOAD, NULL))
|
||||
{
|
||||
DWORD responseLength = 0;
|
||||
@ -84,7 +84,7 @@ bool resolveIPExternal(LPSTR buffer)
|
||||
DWORD error = GetLastError();
|
||||
if (hFile) InternetCloseHandle(hFile);
|
||||
if (hInternet) InternetCloseHandle(hInternet);
|
||||
if (error && cfgShowErrors)
|
||||
if (error && iniShowErrors)
|
||||
{
|
||||
CHAR msg[512];
|
||||
sprintf_s(msg, "Could not resolve your IP through the web service. %s", wk::getErrorMessage(error).c_str());
|
||||
@ -95,9 +95,9 @@ bool resolveIPExternal(LPSTR buffer)
|
||||
|
||||
bool resolveIPFallback(LPSTR buffer)
|
||||
{
|
||||
if (!*cfgFallbackIP)
|
||||
if (!*iniFallbackIP)
|
||||
return false;
|
||||
lstrcpy(buffer, cfgFallbackIP);
|
||||
lstrcpy(buffer, iniFallbackIP);
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -136,19 +136,19 @@ bool __stdcall patchResolveIP(LPSTR buffer, int bufferLength)
|
||||
|
||||
void patch(wk::Exe& exe, int gameVersion)
|
||||
{
|
||||
wk::Patch::jump(exe.Offset(0x00001799), 5, &patchResolveIP, wk::IJ_JUMP); // replace IP resolve with web service
|
||||
exe.setJmp(0x00001799, 5, &patchResolveIP, wk::JT_JMP); // replace IP resolve with web service
|
||||
|
||||
if (gameVersion == wk::GAMEID_W2_1_07_TRY)
|
||||
{
|
||||
wk::Patch::nops(exe.Offset(0x00053B96), 5); // prevent overriding IP with user name
|
||||
wk::Patch::nops(exe.Offset(0x00054693), 5); // prevent overriding IP with NAT IP
|
||||
wk::Patch::nops(exe.Offset(0x00054635), 11); // useless sleep when connecting to server
|
||||
exe.setNop(0x00053B96, 5); // prevent overriding IP with user name
|
||||
exe.setNop(0x00054693, 5); // prevent overriding IP with NAT IP
|
||||
exe.setNop(0x00054635, 11); // useless sleep when connecting to server
|
||||
}
|
||||
else
|
||||
{
|
||||
wk::Patch::nops(exe.Offset(0x00053E96), 5); // prevent overriding IP with user name
|
||||
wk::Patch::nops(exe.Offset(0x00054935), 11); // useless sleep when connecting to server
|
||||
wk::Patch::nops(exe.Offset(0x00054993), 5); // prevent overriding IP with NAT IP
|
||||
exe.setNop(0x00053E96, 5); // prevent overriding IP with user name
|
||||
exe.setNop(0x00054935, 11); // useless sleep when connecting to server
|
||||
exe.setNop(0x00054993, 5); // prevent overriding IP with NAT IP
|
||||
}
|
||||
}
|
||||
|
||||
@ -181,7 +181,7 @@ BOOL WINAPI DllMain(HMODULE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
|
||||
int version = getVersion(exe.FileHeader->TimeDateStamp);
|
||||
if (version)
|
||||
{
|
||||
configure();
|
||||
init();
|
||||
patch(exe, version);
|
||||
}
|
||||
else
|
132
src/module/wkUnlimiter/main.cpp
Normal file
132
src/module/wkUnlimiter/main.cpp
Normal file
@ -0,0 +1,132 @@
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <stdint.h>
|
||||
#include <Windows.h>
|
||||
#include "wkConfig.h"
|
||||
#include "wkExe.h"
|
||||
#include "wkUtils.h"
|
||||
|
||||
// ---- Initialization ----
|
||||
|
||||
BOOL iniAllowMultiInstance;
|
||||
BOOL iniEnableAllControls;
|
||||
BOOL iniShowAllControls;
|
||||
BOOL iniUnlockCamera;
|
||||
BOOL iniUnlockCursor;
|
||||
|
||||
void init(int gameID)
|
||||
{
|
||||
wk::Ini ini("wkUnlimiter.ini");
|
||||
|
||||
// Load INI settings.
|
||||
ini.get("Common", "AllowMultiInstance", iniAllowMultiInstance, TRUE);
|
||||
ini.get("Frontend", "EnableAllControls", iniEnableAllControls, TRUE);
|
||||
ini.get("Frontend", "ShowAllControls", iniShowAllControls, FALSE);
|
||||
if (gameID == wk::GAMEID_WA_3_8_CD)
|
||||
{
|
||||
ini.get("Game", "UnlockCamera", iniUnlockCamera, TRUE);
|
||||
ini.get("Game", "UnlockCursor", iniUnlockCursor, TRUE);
|
||||
}
|
||||
|
||||
// Ensure INI file has been created with default setting.
|
||||
ini.set("Common", "AllowMultiInstance", iniAllowMultiInstance);
|
||||
ini.set("Frontend", "EnableAllControls", iniEnableAllControls);
|
||||
ini.set("Frontend", "ShowAllControls", iniShowAllControls);
|
||||
if (gameID == wk::GAMEID_WA_3_8_CD)
|
||||
{
|
||||
ini.set("Game", "UnlockCamera", iniUnlockCamera);
|
||||
ini.set("Game", "UnlockCursor", iniUnlockCursor);
|
||||
}
|
||||
}
|
||||
|
||||
// ---- Patch ----
|
||||
|
||||
HANDLE WINAPI Kernel32_CreateSemaphoreA(LPSECURITY_ATTRIBUTES lpSemaphoreAttributes, LONG lInitialCount,
|
||||
LONG lMaximumCount, LPCSTR lpName)
|
||||
{
|
||||
HANDLE handle = CreateSemaphoreA(lpSemaphoreAttributes, lInitialCount, lMaximumCount, lpName);
|
||||
SetLastError(ERROR_SUCCESS);
|
||||
return handle;
|
||||
}
|
||||
|
||||
void patch(wk::Exe& exe, int gameID)
|
||||
{
|
||||
if (iniAllowMultiInstance)
|
||||
{
|
||||
// Requires WormKitDS as game loads modules after this
|
||||
exe.setImp(CreateSemaphoreA, Kernel32_CreateSemaphoreA);
|
||||
}
|
||||
if (iniEnableAllControls)
|
||||
{
|
||||
// CWnd::EnableWindow(bEnable) -> CWnd::EnableWindow(TRUE)
|
||||
exe.set(exe.find("C2 04 00 8B 49 50 8B 01 FF A0 A8") - 13, 0x9090016A);
|
||||
}
|
||||
if (iniShowAllControls)
|
||||
{
|
||||
// CWnd::ShowWindow(bShow) -> CWnd::ShowWindow(TRUE)
|
||||
exe.set(exe.find("C2 04 00 8B 49 50 8B 01 FF A0 A0") - 13, 0x9090016A);
|
||||
}
|
||||
if (iniUnlockCamera)
|
||||
{
|
||||
exe.setNop(exe.find("89 13 EB 06 3B C7 7E 02"), 2); // X- axis
|
||||
exe.setNop(exe.find("89 3B 8B 43 04 3B C1 7D 09 5F 5E"), 2); // X+ axis
|
||||
exe.setNop(exe.find("89 4B 04 5B C2 14 00 3B C6 7E 03"), 3); // Y- axis
|
||||
exe.setNop(exe.find("89 73 04 5F 5E 5B C2 14 00"), 3); // Y+ axis
|
||||
}
|
||||
if (iniUnlockCursor)
|
||||
{
|
||||
exe.setNop(0x00159A72, 6); // X- axis 1
|
||||
exe.setNop(0x00159A8F, 6); // X+ axis 1
|
||||
exe.setNop(0x00159AE5, 6); // Y+ axis 1
|
||||
exe.setNop(0x00159B00, 10); // Y- axis 1 cave
|
||||
exe.setNop(0x00159B19, 6); // Y- axis 1 island
|
||||
exe.setNop(0x00159EAD, 6); // X- axis 2
|
||||
exe.setNop(0x00159ECA, 6); // X+ axis 2
|
||||
exe.setNop(0x00159EE7, 6); // Y+ axis 2
|
||||
exe.setNop(0x00159F02, 10); // Y- axis 2 cave
|
||||
exe.setNop(0x00159F1B, 6); // Y- axis 2 island
|
||||
}
|
||||
}
|
||||
|
||||
// ---- Main ----
|
||||
|
||||
int getVersion(DWORD timeDateStamp)
|
||||
{
|
||||
int id = wk::getGameID(timeDateStamp);
|
||||
switch (id)
|
||||
{
|
||||
case wk::GAMEID_WA_3_6_31:
|
||||
case wk::GAMEID_WA_3_7_2_1:
|
||||
case wk::GAMEID_WA_3_8_CD:
|
||||
return id;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
BOOL WINAPI DllMain(HMODULE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
|
||||
{
|
||||
switch (fdwReason)
|
||||
{
|
||||
case DLL_PROCESS_ATTACH:
|
||||
{
|
||||
wk::Exe exe;
|
||||
int version = getVersion(exe.FileHeader->TimeDateStamp);
|
||||
if (version)
|
||||
{
|
||||
init(version);
|
||||
patch(exe, version);
|
||||
}
|
||||
else
|
||||
{
|
||||
MessageBox(NULL, "wkUnlimiter is incompatible with your game version. Please run the 3.6.31.0, "
|
||||
"3.7.2.1, or 3.8 CD release of Worms Armageddon. Otherwise, you can delete the module to remove "
|
||||
"this warning.", "wkUnlimiter", MB_ICONWARNING);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case DLL_PROCESS_DETACH:
|
||||
break;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
@ -3,36 +3,36 @@
|
||||
|
||||
namespace wk
|
||||
{
|
||||
Config::Config(LPCSTR fileName)
|
||||
Ini::Ini(LPCSTR fileName)
|
||||
{
|
||||
GetModuleFileName(NULL, _filePath, MAX_PATH);
|
||||
char* sepIdx = strrchr(_filePath, '\\') + 1;
|
||||
strcpy_s(sepIdx, MAX_PATH - (int)(sepIdx - _filePath), fileName);
|
||||
}
|
||||
|
||||
void Config::get(LPCSTR category, LPCSTR key, BOOL& result, UINT fallback) const
|
||||
void Ini::get(LPCSTR category, LPCSTR key, BOOL& result, UINT fallback) const
|
||||
{
|
||||
result = GetPrivateProfileInt(category, key, fallback, _filePath);
|
||||
}
|
||||
|
||||
void Config::get(LPCSTR category, LPCSTR key, UINT& result, UINT fallback) const
|
||||
void Ini::get(LPCSTR category, LPCSTR key, UINT& result, UINT fallback) const
|
||||
{
|
||||
result = GetPrivateProfileInt(category, key, fallback, _filePath);
|
||||
}
|
||||
|
||||
void Config::get(LPCSTR category, LPCSTR key, LPSTR result, INT resultLength, LPCSTR fallback) const
|
||||
void Ini::get(LPCSTR category, LPCSTR key, LPSTR result, INT resultLength, LPCSTR fallback) const
|
||||
{
|
||||
GetPrivateProfileString(category, key, fallback, result, resultLength, _filePath);
|
||||
}
|
||||
|
||||
void Config::set(LPCSTR category, LPCSTR key, UINT value) const
|
||||
void Ini::set(LPCSTR category, LPCSTR key, UINT value) const
|
||||
{
|
||||
CHAR buffer[32];
|
||||
sprintf_s(buffer, "%d", value);
|
||||
WritePrivateProfileString(category, key, buffer, _filePath);
|
||||
}
|
||||
|
||||
void Config::set(LPCSTR category, LPCSTR key, LPCSTR value) const
|
||||
void Ini::set(LPCSTR category, LPCSTR key, LPCSTR value) const
|
||||
{
|
||||
WritePrivateProfileString(category, key, value, _filePath);
|
||||
}
|
@ -3,10 +3,10 @@
|
||||
|
||||
namespace wk
|
||||
{
|
||||
class Config
|
||||
class Ini
|
||||
{
|
||||
public:
|
||||
Config(LPCSTR fileName);
|
||||
Ini(LPCSTR fileName);
|
||||
|
||||
void get(LPCSTR category, LPCSTR key, BOOL& result, UINT fallback) const;
|
||||
void get(LPCSTR category, LPCSTR key, UINT& result, UINT fallback) const;
|
@ -93,7 +93,7 @@
|
||||
<ClInclude Include="wkConfig.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\WormKitTools\FrontendKitLib.vcxproj">
|
||||
<ProjectReference Include="..\WormKitTools\WormKitTools.vcxproj">
|
||||
<Project>{068a8647-0a66-4e39-983b-43aceac5c937}</Project>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
@ -1,21 +0,0 @@
|
||||
#pragma once
|
||||
#include <Windows.h>
|
||||
|
||||
namespace wk
|
||||
{
|
||||
struct Exe
|
||||
{
|
||||
public:
|
||||
HANDLE Handle;
|
||||
IMAGE_DOS_HEADER* DosHeader;
|
||||
IMAGE_NT_HEADERS* NtHeader;
|
||||
IMAGE_FILE_HEADER* FileHeader;
|
||||
IMAGE_OPTIONAL_HEADER* OptionalHeader;
|
||||
|
||||
Exe(HMODULE hModule = NULL);
|
||||
|
||||
ULONG_PTR Offset(ULONG_PTR off);
|
||||
BOOL IsCode(LPVOID ptr);
|
||||
BOOL IsData(LPVOID ptr);
|
||||
};
|
||||
}
|
@ -1,37 +0,0 @@
|
||||
#pragma once
|
||||
#include <Windows.h>
|
||||
|
||||
namespace wk
|
||||
{
|
||||
enum InsertJump
|
||||
{
|
||||
IJ_JUMP, // Insert a jump (0xE9) with patchJump
|
||||
IJ_CALL, // Insert a call (0xE8) with patchJump
|
||||
IJ_FARJUMP, // Insert a farjump (0xEA) with patchJump
|
||||
IJ_FARCALL, // Insert a farcall (0x9A) with patchJump
|
||||
IJ_PUSHRET, // Insert a pushret with patchJump
|
||||
};
|
||||
|
||||
struct Patch
|
||||
{
|
||||
public:
|
||||
ULONG_PTR position;
|
||||
|
||||
Patch(ULONG_PTR address, SIZE_T size);
|
||||
~Patch();
|
||||
|
||||
void close() const;
|
||||
template <class T> void write(const T& value);
|
||||
|
||||
static void byte(ULONG_PTR address, BYTE newValue);
|
||||
static void nops(ULONG_PTR address, SIZE_T size);
|
||||
static void jump(ULONG_PTR address, SIZE_T size, PVOID callee, DWORD jumpType);
|
||||
|
||||
private:
|
||||
LPBYTE _address;
|
||||
SIZE_T _size;
|
||||
DWORD _oldProtect;
|
||||
};
|
||||
}
|
||||
|
||||
#include "wkPatch.inl"
|
@ -1,30 +0,0 @@
|
||||
#include "wkExe.h"
|
||||
|
||||
namespace wk
|
||||
{
|
||||
Exe::Exe(HMODULE hModule)
|
||||
{
|
||||
Handle = hModule == 0 ? GetModuleHandleA(NULL) : hModule;
|
||||
DosHeader = (IMAGE_DOS_HEADER*)Handle;
|
||||
NtHeader = (IMAGE_NT_HEADERS*)((DWORD)DosHeader + DosHeader->e_lfanew);
|
||||
FileHeader = (IMAGE_FILE_HEADER*)&NtHeader->FileHeader;
|
||||
OptionalHeader = (IMAGE_OPTIONAL_HEADER*)&NtHeader->OptionalHeader;
|
||||
}
|
||||
|
||||
ULONG_PTR Exe::Offset(ULONG_PTR off)
|
||||
{
|
||||
return (DWORD)Handle + off;
|
||||
}
|
||||
|
||||
BOOL Exe::IsCode(LPVOID ptr)
|
||||
{
|
||||
return DWORD(ptr) >= Offset(OptionalHeader->BaseOfCode)
|
||||
&& DWORD(ptr) < Offset(OptionalHeader->BaseOfCode) + OptionalHeader->SizeOfCode;
|
||||
}
|
||||
|
||||
BOOL Exe::IsData(LPVOID ptr)
|
||||
{
|
||||
return DWORD(ptr) >= Offset(OptionalHeader->BaseOfData)
|
||||
&& DWORD(ptr) < Offset(OptionalHeader->BaseOfData) + OptionalHeader->SizeOfInitializedData + OptionalHeader->SizeOfUninitializedData;
|
||||
}
|
||||
}
|
@ -1,80 +0,0 @@
|
||||
#include "wkPatch.h"
|
||||
#include <stdexcept>
|
||||
|
||||
namespace wk
|
||||
{
|
||||
Patch::Patch(ULONG_PTR address, SIZE_T size)
|
||||
: _address(reinterpret_cast<LPBYTE>(address))
|
||||
, _size(size)
|
||||
, position(0)
|
||||
{
|
||||
if (!_address || !_size)
|
||||
throw std::invalid_argument("Address and size must not be 0.");
|
||||
if (!VirtualProtect(_address, _size, PAGE_EXECUTE_READWRITE, &_oldProtect))
|
||||
throw std::exception("VirtualProtect failed, call GetLastError for more info.");
|
||||
}
|
||||
|
||||
Patch::~Patch()
|
||||
{
|
||||
close();
|
||||
}
|
||||
|
||||
void Patch::close() const
|
||||
{
|
||||
DWORD oldProtect;
|
||||
if (!VirtualProtect(_address, _size, _oldProtect, &oldProtect))
|
||||
throw std::exception("VirtualProtect failed, call GetLastError for more info.");
|
||||
}
|
||||
|
||||
void Patch::byte(ULONG_PTR address, BYTE newValue)
|
||||
{
|
||||
wk::Patch patch(address, 1);
|
||||
patch.write(newValue);
|
||||
}
|
||||
|
||||
void Patch::nops(ULONG_PTR address, SIZE_T size)
|
||||
{
|
||||
wk::Patch patch(address, size);
|
||||
while (size--)
|
||||
patch.write<BYTE>(0x90);
|
||||
}
|
||||
|
||||
void Patch::jump(ULONG_PTR address, SIZE_T size, PVOID callee, DWORD jumpType)
|
||||
{
|
||||
wk::Patch patch(address, size);
|
||||
|
||||
if (size >= 5 && address)
|
||||
{
|
||||
BYTE opSize, opCode;
|
||||
switch (jumpType)
|
||||
{
|
||||
case IJ_PUSHRET: opSize = 6; opCode = 0x68; break;
|
||||
case IJ_FARJUMP: opSize = 7; opCode = 0xEA; break;
|
||||
case IJ_FARCALL: opSize = 7; opCode = 0x9A; break;
|
||||
case IJ_CALL: opSize = 5; opCode = 0xE8; break;
|
||||
default: opSize = 5; opCode = 0xE9; break;
|
||||
}
|
||||
|
||||
if (size < opSize)
|
||||
throw std::exception("Not enough space to patch opcode.");
|
||||
|
||||
patch.write(opCode);
|
||||
switch (opSize)
|
||||
{
|
||||
case 7:
|
||||
patch.write((ULONG)callee);
|
||||
patch.write<WORD>(0x23);
|
||||
break;
|
||||
case 6:
|
||||
patch.write((ULONG)callee);
|
||||
patch.write<BYTE>(0xC3);
|
||||
break;
|
||||
default:
|
||||
patch.write((ULONG)callee - address - 5);
|
||||
break;
|
||||
}
|
||||
for (DWORD i = opSize; i < size; i++)
|
||||
patch.write<BYTE>(0x90);
|
||||
}
|
||||
}
|
||||
};
|
@ -1,108 +0,0 @@
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <Windows.h>
|
||||
#include "wkConfig.h"
|
||||
#include "wkExe.h"
|
||||
#include "wkPatch.h"
|
||||
#include "wkUtils.h"
|
||||
|
||||
// ---- Configuration ----
|
||||
|
||||
BOOL cfgAllowMultiInstance;
|
||||
BOOL cfgEnableAllControls;
|
||||
BOOL cfgUnlockCamera;
|
||||
BOOL cfgUnlockCursor;
|
||||
|
||||
void configure()
|
||||
{
|
||||
wk::Config config("wkUnlimiter.ini");
|
||||
|
||||
// Load INI settings.
|
||||
config.get("Common", "AllowMultiInstance", cfgAllowMultiInstance, TRUE);
|
||||
config.get("Frontend", "EnableAllControls", cfgEnableAllControls, TRUE);
|
||||
config.get("Game", "UnlockCamera", cfgUnlockCamera, TRUE);
|
||||
config.get("Game", "UnlockCursor", cfgUnlockCursor, TRUE);
|
||||
|
||||
// Ensure INI file has been created with default setting.
|
||||
config.set("Common", "AllowMultiInstance", cfgAllowMultiInstance);
|
||||
config.set("Frontend", "EnableAllControls", cfgEnableAllControls);
|
||||
config.set("Game", "UnlockCamera", cfgUnlockCamera);
|
||||
config.set("Game", "UnlockCursor", cfgUnlockCursor);
|
||||
}
|
||||
|
||||
// ---- Patch ----
|
||||
|
||||
void patch(wk::Exe& exe, int gameVersion)
|
||||
{
|
||||
if (cfgAllowMultiInstance)
|
||||
{
|
||||
wk::Patch patch(exe.Offset(0x000E7AD1), 1);
|
||||
patch.write((char)0xEB); // Requires WormKitDS as game executable loads modules after this patched out check.
|
||||
}
|
||||
if (cfgEnableAllControls)
|
||||
{
|
||||
wk::Patch patch(exe.Offset(0x001C5D26), 4);
|
||||
patch.write(0x9090016A); // CWnd::EnableWindow(bEnable) -> CWnd::EnableWindow(TRUE)
|
||||
}
|
||||
if (cfgUnlockCamera)
|
||||
{
|
||||
wk::Patch::nops(exe.Offset(0x00142A89), 2); // X- axis
|
||||
wk::Patch::nops(exe.Offset(0x00142A91), 2); // X+ axis
|
||||
wk::Patch::nops(exe.Offset(0x00142AA7), 3); // Y- axis
|
||||
wk::Patch::nops(exe.Offset(0x00142A9C), 3); // Y+ axis
|
||||
}
|
||||
if (cfgUnlockCursor)
|
||||
{
|
||||
wk::Patch::nops(exe.Offset(0x00159EAD), 6); // X- axis 1
|
||||
wk::Patch::nops(exe.Offset(0x00159A72), 6); // X- axis 2
|
||||
wk::Patch::nops(exe.Offset(0x00159ECA), 6); // X+ axis 1
|
||||
wk::Patch::nops(exe.Offset(0x00159A8F), 6); // X+ axis 2
|
||||
wk::Patch::nops(exe.Offset(0x00159B00), 10); // Y- axis 1 cave
|
||||
wk::Patch::nops(exe.Offset(0x00159F02), 10); // Y- axis 2 cave
|
||||
wk::Patch::nops(exe.Offset(0x00159B19), 6); // Y- axis 1 island
|
||||
wk::Patch::nops(exe.Offset(0x00159F1B), 6); // Y- axis 2 island
|
||||
wk::Patch::nops(exe.Offset(0x00159AE5), 6); // Y+ axis 1
|
||||
wk::Patch::nops(exe.Offset(0x00159EE7), 6); // Y+ axis 2
|
||||
}
|
||||
}
|
||||
|
||||
// ---- Main ----
|
||||
|
||||
int getVersion(DWORD timeDateStamp)
|
||||
{
|
||||
int id = wk::getGameID(timeDateStamp);
|
||||
switch (id)
|
||||
{
|
||||
case wk::GAMEID_WA_3_8_CD:
|
||||
return id;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
BOOL WINAPI DllMain(HMODULE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
|
||||
{
|
||||
switch (fdwReason)
|
||||
{
|
||||
case DLL_PROCESS_ATTACH:
|
||||
{
|
||||
wk::Exe exe;
|
||||
int version = getVersion(exe.FileHeader->TimeDateStamp);
|
||||
if (version)
|
||||
{
|
||||
configure();
|
||||
patch(exe, version);
|
||||
}
|
||||
else
|
||||
{
|
||||
MessageBox(NULL, "wkUnlimiter is incompatible with your game version. Please run the 3.8 CD release of "
|
||||
"Worms Armageddon. Otherwise, you can delete the module to remove this warning.", "wkUnlimiter",
|
||||
MB_ICONWARNING);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case DLL_PROCESS_DETACH:
|
||||
break;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user