commit
0ec6ece213
29
README.md
Normal file
29
README.md
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
# <p align="center">IW7-Mod</p>
|
||||||
|
|
||||||
|
<p align="center">
|
||||||
|
<img src="assets/github/banner.png?raw=true" width="900" />
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<h3><p align="center">Nothing has been worked yet<br><br>Feel free to make a PR</p></h3>
|
||||||
|
|
||||||
|
## Compile from source
|
||||||
|
|
||||||
|
- Clone the Git repo. Do NOT download it as ZIP, that won't work.
|
||||||
|
- Update the submodules and run `premake5 vs2022` or simply use the delivered `generate.bat`.
|
||||||
|
- Build via solution file in `build\iw7-mod.sln`.
|
||||||
|
|
||||||
|
### Premake arguments
|
||||||
|
|
||||||
|
| Argument | Description |
|
||||||
|
|:----------------------------|:-----------------------------------------------|
|
||||||
|
| `--copy-to=PATH` | Optional, copy the EXE to a custom folder after build, define the path here if wanted. |
|
||||||
|
| `--dev-build` | Enable development builds of the client. |
|
||||||
|
|
||||||
|
<br/>
|
||||||
|
|
||||||
|
## Disclaimer
|
||||||
|
|
||||||
|
This software has been created purely for the purposes of
|
||||||
|
academic research. It is not intended to be used to attack
|
||||||
|
other systems. Project maintainers are not responsible or
|
||||||
|
liable for misuse of the software. Use responsibly.
|
BIN
assets/github/banner.png
Normal file
BIN
assets/github/banner.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 56 KiB |
@ -42,7 +42,7 @@ namespace auth
|
|||||||
|
|
||||||
std::string get_protected_data()
|
std::string get_protected_data()
|
||||||
{
|
{
|
||||||
std::string input = "X-Labs-H1Mod-Auth";
|
std::string input = "X-Labs-IW7MOD-Auth";
|
||||||
|
|
||||||
DATA_BLOB data_in{}, data_out{};
|
DATA_BLOB data_in{}, data_out{};
|
||||||
data_in.pbData = reinterpret_cast<uint8_t*>(input.data());
|
data_in.pbData = reinterpret_cast<uint8_t*>(input.data());
|
||||||
|
@ -11,7 +11,9 @@
|
|||||||
#include <utils/hook.hpp>
|
#include <utils/hook.hpp>
|
||||||
#include <utils/string.hpp>
|
#include <utils/string.hpp>
|
||||||
|
|
||||||
// fonts/default.otf, fonts/defaultBold.otf, fonts/fira_mono_regular.ttf, fonts/fira_mono_bold.ttf
|
// Fonts are used in game:
|
||||||
|
// fonts/blender_pro_bold.ttf, fonts/blender_pro_book.ttf, fonts/blender_pro_heavy.ttf, fonts/blender_pro_medium.ttf
|
||||||
|
// fonts/changelingneo-regular.ttf, fonts/dev.ttf, fonts/fira_mono_bold.ttf, fonts/fira_mono_regular.ttf, fonts/iw6_digital.ttf
|
||||||
|
|
||||||
namespace branding
|
namespace branding
|
||||||
{
|
{
|
||||||
@ -36,7 +38,7 @@ namespace branding
|
|||||||
localized_strings::override("LUA_MENU_MULTIPLAYER_CAPS", "IW7-MOD: MULTIPLAYER");
|
localized_strings::override("LUA_MENU_MULTIPLAYER_CAPS", "IW7-MOD: MULTIPLAYER");
|
||||||
localized_strings::override("LUA_MENU_ALIENS_CAPS", "IW7-MOD: ZOMBIES");
|
localized_strings::override("LUA_MENU_ALIENS_CAPS", "IW7-MOD: ZOMBIES");
|
||||||
|
|
||||||
//dvars::override::set_string("version", utils::string::va("H1-Mod %s", VERSION));
|
//dvars::override::set_string("version", utils::string::va("IW7-Mod %s", VERSION));
|
||||||
|
|
||||||
//ui_get_formatted_build_number_hook.create(0x1DF300_b, ui_get_formatted_build_number_stub); can't find
|
//ui_get_formatted_build_number_hook.create(0x1DF300_b, ui_get_formatted_build_number_stub); can't find
|
||||||
|
|
||||||
|
@ -59,7 +59,7 @@ namespace game_console
|
|||||||
std::vector<std::string> matches{};
|
std::vector<std::string> matches{};
|
||||||
|
|
||||||
float color_white[4] = { 1.0f, 1.0f, 1.0f, 1.0f };
|
float color_white[4] = { 1.0f, 1.0f, 1.0f, 1.0f };
|
||||||
float color_title[4] = { 0.9f, 0.0f, 0.9f, 1.0f };
|
float color_title[4] = { 0.9f, 0.9f, 0.0f, 1.0f };
|
||||||
|
|
||||||
void clear()
|
void clear()
|
||||||
{
|
{
|
||||||
|
188
src/client/component/steam_proxy.cpp
Normal file
188
src/client/component/steam_proxy.cpp
Normal file
@ -0,0 +1,188 @@
|
|||||||
|
#include <std_include.hpp>
|
||||||
|
#include "loader/component_loader.hpp"
|
||||||
|
#include "steam_proxy.hpp"
|
||||||
|
#include "scheduler.hpp"
|
||||||
|
|
||||||
|
#include <utils/nt.hpp>
|
||||||
|
#include <utils/flags.hpp>
|
||||||
|
#include <utils/string.hpp>
|
||||||
|
#include <utils/binary_resource.hpp>
|
||||||
|
|
||||||
|
#include "game/game.hpp"
|
||||||
|
|
||||||
|
#include "steam/interface.hpp"
|
||||||
|
#include "steam/steam.hpp"
|
||||||
|
|
||||||
|
namespace steam_proxy
|
||||||
|
{
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
utils::binary_resource runner_file(RUNNER, "runner.exe");
|
||||||
|
|
||||||
|
bool is_disabled()
|
||||||
|
{
|
||||||
|
static const auto disabled = utils::flags::has_flag("nosteam");
|
||||||
|
return disabled;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class component final : public component_interface
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void post_load() override
|
||||||
|
{
|
||||||
|
if (game::environment::is_dedi() || is_disabled())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this->load_client();
|
||||||
|
this->clean_up_on_error();
|
||||||
|
|
||||||
|
#ifndef DEV_BUILD
|
||||||
|
try
|
||||||
|
{
|
||||||
|
this->start_mod("\xF0\x9F\x8E\xAE IW7-Mod ", 292730);
|
||||||
|
}
|
||||||
|
catch (std::exception& e)
|
||||||
|
{
|
||||||
|
printf("Steam: %s\n", e.what());
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void pre_destroy() override
|
||||||
|
{
|
||||||
|
if (this->steam_client_module_)
|
||||||
|
{
|
||||||
|
if (this->steam_pipe_)
|
||||||
|
{
|
||||||
|
if (this->global_user_)
|
||||||
|
{
|
||||||
|
this->steam_client_module_.invoke<void>("Steam_ReleaseUser", this->steam_pipe_,
|
||||||
|
this->global_user_);
|
||||||
|
}
|
||||||
|
|
||||||
|
this->steam_client_module_.invoke<bool>("Steam_BReleaseSteamPipe", this->steam_pipe_);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const utils::nt::library& get_overlay_module() const
|
||||||
|
{
|
||||||
|
return steam_overlay_module_;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
utils::nt::library steam_client_module_{};
|
||||||
|
utils::nt::library steam_overlay_module_{};
|
||||||
|
|
||||||
|
steam::interface client_engine_ {};
|
||||||
|
steam::interface client_user_ {};
|
||||||
|
steam::interface client_utils_ {};
|
||||||
|
|
||||||
|
void* steam_pipe_ = nullptr;
|
||||||
|
void* global_user_ = nullptr;
|
||||||
|
|
||||||
|
void* load_client_engine() const
|
||||||
|
{
|
||||||
|
if (!this->steam_client_module_) return nullptr;
|
||||||
|
|
||||||
|
for (auto i = 1; i > 0; ++i)
|
||||||
|
{
|
||||||
|
std::string name = utils::string::va("CLIENTENGINE_INTERFACE_VERSION%03i", i);
|
||||||
|
auto* const client_engine = this->steam_client_module_
|
||||||
|
.invoke<void*>("CreateInterface", name.data(), nullptr);
|
||||||
|
if (client_engine) return client_engine;
|
||||||
|
}
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void load_client()
|
||||||
|
{
|
||||||
|
const std::filesystem::path steam_path = steam::SteamAPI_GetSteamInstallPath();
|
||||||
|
if (steam_path.empty()) return;
|
||||||
|
|
||||||
|
utils::nt::library::load(steam_path / "tier0_s64.dll");
|
||||||
|
utils::nt::library::load(steam_path / "vstdlib_s64.dll");
|
||||||
|
this->steam_overlay_module_ = utils::nt::library::load(steam_path / "gameoverlayrenderer64.dll");
|
||||||
|
this->steam_client_module_ = utils::nt::library::load(steam_path / "steamclient64.dll");
|
||||||
|
if (!this->steam_client_module_) return;
|
||||||
|
|
||||||
|
this->client_engine_ = load_client_engine();
|
||||||
|
if (!this->client_engine_) return;
|
||||||
|
|
||||||
|
this->steam_pipe_ = this->steam_client_module_.invoke<void*>("Steam_CreateSteamPipe");
|
||||||
|
this->global_user_ = this->steam_client_module_.invoke<void*>(
|
||||||
|
"Steam_ConnectToGlobalUser", this->steam_pipe_);
|
||||||
|
this->client_user_ = this->client_engine_.invoke<void*>(8, this->steam_pipe_, this->global_user_);
|
||||||
|
// GetIClientUser
|
||||||
|
this->client_utils_ = this->client_engine_.invoke<void*>(14, this->steam_pipe_); // GetIClientUtils
|
||||||
|
}
|
||||||
|
|
||||||
|
void start_mod(const std::string& title, size_t app_id)
|
||||||
|
{
|
||||||
|
if (!this->client_utils_ || !this->client_user_) return;
|
||||||
|
|
||||||
|
if (!this->client_user_.invoke<bool>("BIsSubscribedApp", app_id))
|
||||||
|
{
|
||||||
|
app_id = 480; // Spacewar
|
||||||
|
}
|
||||||
|
|
||||||
|
this->client_utils_.invoke<void>("SetAppIDForCurrentPipe", app_id, false);
|
||||||
|
|
||||||
|
char our_directory[MAX_PATH] = {0};
|
||||||
|
GetCurrentDirectoryA(sizeof(our_directory), our_directory);
|
||||||
|
|
||||||
|
const auto path = runner_file.get_extracted_file();
|
||||||
|
const std::string cmdline = utils::string::va("\"%s\" -proc %d", path.data(), GetCurrentProcessId());
|
||||||
|
|
||||||
|
steam::game_id game_id;
|
||||||
|
game_id.raw.type = 1; // k_EGameIDTypeGameMod
|
||||||
|
game_id.raw.app_id = app_id & 0xFFFFFF;
|
||||||
|
|
||||||
|
const auto* mod_id = "H1-Mod";
|
||||||
|
game_id.raw.mod_id = *reinterpret_cast<const unsigned int*>(mod_id) | 0x80000000;
|
||||||
|
|
||||||
|
this->client_user_.invoke<bool>("SpawnProcess", path.data(), cmdline.data(), our_directory,
|
||||||
|
&game_id.bits, title.data(), 0, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void clean_up_on_error()
|
||||||
|
{
|
||||||
|
scheduler::schedule([this]()
|
||||||
|
{
|
||||||
|
if (this->steam_client_module_
|
||||||
|
&& this->steam_pipe_
|
||||||
|
&& this->global_user_
|
||||||
|
&& this->steam_client_module_.invoke<bool>("Steam_BConnected", this->global_user_,
|
||||||
|
this->steam_pipe_)
|
||||||
|
&& this->steam_client_module_.invoke<bool>("Steam_BLoggedOn", this->global_user_, this->steam_pipe_)
|
||||||
|
)
|
||||||
|
{
|
||||||
|
return scheduler::cond_continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
this->client_engine_ = nullptr;
|
||||||
|
this->client_user_ = nullptr;
|
||||||
|
this->client_utils_ = nullptr;
|
||||||
|
|
||||||
|
this->steam_pipe_ = nullptr;
|
||||||
|
this->global_user_ = nullptr;
|
||||||
|
|
||||||
|
this->steam_client_module_ = utils::nt::library{nullptr};
|
||||||
|
|
||||||
|
return scheduler::cond_end;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const utils::nt::library& get_overlay_module()
|
||||||
|
{
|
||||||
|
// TODO: Find a better way to do this
|
||||||
|
return component_loader::get<component>()->get_overlay_module();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
REGISTER_COMPONENT(steam_proxy::component)
|
7
src/client/component/steam_proxy.hpp
Normal file
7
src/client/component/steam_proxy.hpp
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <utils/nt.hpp>
|
||||||
|
|
||||||
|
namespace steam_proxy
|
||||||
|
{
|
||||||
|
const utils::nt::library& get_overlay_module();
|
||||||
|
}
|
100
src/client/component/system_check.cpp
Normal file
100
src/client/component/system_check.cpp
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
#include <std_include.hpp>
|
||||||
|
#include "loader/component_loader.hpp"
|
||||||
|
#include "system_check.hpp"
|
||||||
|
|
||||||
|
#include "game/game.hpp"
|
||||||
|
|
||||||
|
#include <utils/io.hpp>
|
||||||
|
#include <utils/cryptography.hpp>
|
||||||
|
|
||||||
|
namespace system_check
|
||||||
|
{
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
std::string read_zone(const std::string& name)
|
||||||
|
{
|
||||||
|
std::string data{};
|
||||||
|
if (utils::io::read_file(name, &data))
|
||||||
|
{
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (utils::io::read_file("zone/" + name, &data))
|
||||||
|
{
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string hash_zone(const std::string& name)
|
||||||
|
{
|
||||||
|
const auto data = read_zone(name);
|
||||||
|
return utils::cryptography::sha256::compute(data, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool verify_hashes(const std::unordered_map<std::string, std::string>& zone_hashes)
|
||||||
|
{
|
||||||
|
for (const auto& zone_hash : zone_hashes)
|
||||||
|
{
|
||||||
|
const auto hash = hash_zone(zone_hash.first);
|
||||||
|
if (hash != zone_hash.second)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool is_system_valid()
|
||||||
|
{
|
||||||
|
static std::unordered_map<std::string, std::string> mp_zone_hashes =
|
||||||
|
{
|
||||||
|
{"patch_common_mp.ff", "E263215ADF7B93A28769E6A9909D7710F5351B4F7586FF69EE0BFA9D62A247C9"},
|
||||||
|
};
|
||||||
|
|
||||||
|
static std::unordered_map<std::string, std::string> sp_zone_hashes =
|
||||||
|
{
|
||||||
|
// Steam doesn't necessarily deliver this file :(
|
||||||
|
{"patch_common.ff", "A427FDFBFCF16B0BA662459383C48AE15C884B9B44C61C12B98E062FBC4C6DB3"},
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
return verify_hashes(mp_zone_hashes) && (game::environment::is_dedi() || verify_hashes(sp_zone_hashes));
|
||||||
|
}
|
||||||
|
|
||||||
|
void verify_binary_version()
|
||||||
|
{
|
||||||
|
const auto value = *reinterpret_cast<DWORD*>(0x1337_b);
|
||||||
|
if (value != 0xB43C9275)
|
||||||
|
{
|
||||||
|
throw std::runtime_error("Unsupported Call of Duty: Infinite Warfare version");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool is_valid()
|
||||||
|
{
|
||||||
|
static auto valid = is_system_valid();
|
||||||
|
return valid;
|
||||||
|
}
|
||||||
|
|
||||||
|
class component final : public component_interface
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
void post_load() override
|
||||||
|
{
|
||||||
|
verify_binary_version();
|
||||||
|
|
||||||
|
if (!is_valid())
|
||||||
|
{
|
||||||
|
MessageBoxA(nullptr, "Your game files are outdated or unsupported.\n"
|
||||||
|
"Please get the latest officially supported Call of Duty: Modern Warfare Remastered files, or you will get random crashes and issues.",
|
||||||
|
"Invalid game files!", MB_ICONINFORMATION);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
REGISTER_COMPONENT(system_check::component)
|
6
src/client/component/system_check.hpp
Normal file
6
src/client/component/system_check.hpp
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace system_check
|
||||||
|
{
|
||||||
|
bool is_valid();
|
||||||
|
}
|
@ -18,7 +18,6 @@ namespace demonware
|
|||||||
this->register_task(12, &bdStorage::unk12);
|
this->register_task(12, &bdStorage::unk12);
|
||||||
|
|
||||||
this->map_publisher_resource("motd-.*\\.txt", DW_MOTD);
|
this->map_publisher_resource("motd-.*\\.txt", DW_MOTD);
|
||||||
// this->map_publisher_resource("ffotd-.*\\.ff", DW_FASTFILE);
|
|
||||||
this->map_publisher_resource("playlists(_.+)?\\.aggr", DW_PLAYLISTS);
|
this->map_publisher_resource("playlists(_.+)?\\.aggr", DW_PLAYLISTS);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -62,7 +62,6 @@ FARPROC load_binary(uint64_t* base_address)
|
|||||||
|
|
||||||
void remove_crash_file()
|
void remove_crash_file()
|
||||||
{
|
{
|
||||||
utils::io::remove_file("__iw7-mod");
|
|
||||||
utils::io::remove_file("__iw7_ship");
|
utils::io::remove_file("__iw7_ship");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -104,16 +103,6 @@ void limit_parallel_dll_loading()
|
|||||||
RegCloseKey(key);
|
RegCloseKey(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
// solution for other processes that may launch the mod
|
|
||||||
void apply_proper_directory()
|
|
||||||
{
|
|
||||||
char module_path[MAX_PATH];
|
|
||||||
GetModuleFileNameA(nullptr, module_path, MAX_PATH);
|
|
||||||
PathRemoveFileSpecA(module_path);
|
|
||||||
SetCurrentDirectoryA(module_path);
|
|
||||||
SetDllDirectoryA(module_path);
|
|
||||||
}
|
|
||||||
|
|
||||||
int main()
|
int main()
|
||||||
{
|
{
|
||||||
ShowWindow(GetConsoleWindow(), SW_HIDE);
|
ShowWindow(GetConsoleWindow(), SW_HIDE);
|
||||||
@ -140,9 +129,6 @@ int main()
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
//apply_proper_directory();
|
|
||||||
//remove_crash_file();
|
|
||||||
|
|
||||||
if (!component_loader::post_start()) return 0;
|
if (!component_loader::post_start()) return 0;
|
||||||
|
|
||||||
uint64_t base_address{};
|
uint64_t base_address{};
|
||||||
|
@ -6,10 +6,9 @@
|
|||||||
#define IMAGE_LOGO 301
|
#define IMAGE_LOGO 301
|
||||||
|
|
||||||
#define DW_MOTD 302
|
#define DW_MOTD 302
|
||||||
#define DW_FASTFILE 303
|
#define DW_PLAYLISTS 303
|
||||||
#define DW_PLAYLISTS 304
|
|
||||||
|
|
||||||
#define TLS_DLL 305
|
#define TLS_DLL 304
|
||||||
#define RUNNER 306
|
#define RUNNER 305
|
||||||
|
|
||||||
#define ICON_IMAGE 307
|
#define ICON_IMAGE 306
|
||||||
|
@ -98,9 +98,8 @@ ID_ICON ICON "resources/icon.ico"
|
|||||||
IMAGE_SPLASH BITMAP "resources/splash.bmp"
|
IMAGE_SPLASH BITMAP "resources/splash.bmp"
|
||||||
IMAGE_LOGO BITMAP "resources/logo.bmp"
|
IMAGE_LOGO BITMAP "resources/logo.bmp"
|
||||||
|
|
||||||
DW_FASTFILE RCDATA "resources/dw/ffotd-1.15.1.ff"
|
|
||||||
DW_MOTD RCDATA "resources/dw/motd-english.txt"
|
DW_MOTD RCDATA "resources/dw/motd-english.txt"
|
||||||
DW_PLAYLISTS RCDATA "resources/dw/playlists_tu12.aggr"
|
DW_PLAYLISTS RCDATA "resources/dw/playlists_tu23.aggr"
|
||||||
|
|
||||||
#ifdef _DEBUG
|
#ifdef _DEBUG
|
||||||
TLS_DLL RCDATA "../../build/bin/x64/Debug/tlsdll.dll"
|
TLS_DLL RCDATA "../../build/bin/x64/Debug/tlsdll.dll"
|
||||||
|
Binary file not shown.
@ -1 +1 @@
|
|||||||
blank
|
Welcome to ^3IW7-Mod
|
Binary file not shown.
BIN
src/client/resources/dw/playlists_tu23.aggr
Normal file
BIN
src/client/resources/dw/playlists_tu23.aggr
Normal file
Binary file not shown.
Binary file not shown.
Before Width: | Height: | Size: 107 KiB After Width: | Height: | Size: 37 KiB |
Loading…
Reference in New Issue
Block a user