This commit is contained in:
Skull Merlin 2022-05-24 04:34:44 +03:00
parent b75cc48ee0
commit 9ffc0e07f8
18 changed files with 342 additions and 27 deletions

29
README.md Normal file
View 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

Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

View File

@ -42,7 +42,7 @@ namespace auth
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_in.pbData = reinterpret_cast<uint8_t*>(input.data());

View File

@ -11,7 +11,9 @@
#include <utils/hook.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
{
@ -36,7 +38,7 @@ namespace branding
localized_strings::override("LUA_MENU_MULTIPLAYER_CAPS", "IW7-MOD: MULTIPLAYER");
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

View File

@ -59,7 +59,7 @@ namespace game_console
std::vector<std::string> matches{};
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()
{

View 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)

View File

@ -0,0 +1,7 @@
#pragma once
#include <utils/nt.hpp>
namespace steam_proxy
{
const utils::nt::library& get_overlay_module();
}

View 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)

View File

@ -0,0 +1,6 @@
#pragma once
namespace system_check
{
bool is_valid();
}

View File

@ -18,7 +18,6 @@ namespace demonware
this->register_task(12, &bdStorage::unk12);
this->map_publisher_resource("motd-.*\\.txt", DW_MOTD);
// this->map_publisher_resource("ffotd-.*\\.ff", DW_FASTFILE);
this->map_publisher_resource("playlists(_.+)?\\.aggr", DW_PLAYLISTS);
}

View File

@ -62,7 +62,6 @@ FARPROC load_binary(uint64_t* base_address)
void remove_crash_file()
{
utils::io::remove_file("__iw7-mod");
utils::io::remove_file("__iw7_ship");
}
@ -104,16 +103,6 @@ void limit_parallel_dll_loading()
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()
{
ShowWindow(GetConsoleWindow(), SW_HIDE);
@ -140,9 +129,6 @@ int main()
try
{
//apply_proper_directory();
//remove_crash_file();
if (!component_loader::post_start()) return 0;
uint64_t base_address{};

View File

@ -6,10 +6,9 @@
#define IMAGE_LOGO 301
#define DW_MOTD 302
#define DW_FASTFILE 303
#define DW_PLAYLISTS 304
#define DW_PLAYLISTS 303
#define TLS_DLL 305
#define RUNNER 306
#define TLS_DLL 304
#define RUNNER 305
#define ICON_IMAGE 307
#define ICON_IMAGE 306

View File

@ -98,9 +98,8 @@ ID_ICON ICON "resources/icon.ico"
IMAGE_SPLASH BITMAP "resources/splash.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_PLAYLISTS RCDATA "resources/dw/playlists_tu12.aggr"
DW_PLAYLISTS RCDATA "resources/dw/playlists_tu23.aggr"
#ifdef _DEBUG
TLS_DLL RCDATA "../../build/bin/x64/Debug/tlsdll.dll"

View File

@ -1 +1 @@
blank
Welcome to ^3IW7-Mod

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 107 KiB

After

Width:  |  Height:  |  Size: 37 KiB