[aim1mod] Initial patching.

This commit is contained in:
lzwdgc 2024-02-05 19:32:35 +03:00
parent 1d2e981bdd
commit 47fc2215fb

View file

@ -8,6 +8,47 @@
#include <set> #include <set>
#include <print> #include <print>
constexpr auto aim_exe = "aim.exe"sv;
using byte_array = std::vector<uint8_t>;
struct patcher {
};
auto operator""_bin(const char *ptr, uint64_t len) {
byte_array ret;
auto lines = split_lines(ptr);
for (auto &&line : lines) {
auto d = line.substr(0, line.find(';'));
auto bytes = split_string(d, " \r\n");
for (auto &&v : bytes) {
if (v.size() != 2) {
throw std::runtime_error{"bad input string"};
}
auto hex2int1 = [](auto c) {
if (isdigit(c)) {
return c - '0';
} else if (isupper(c)) {
return c - 'A' + 10;
} else {
return c - 'a' + 10;
}
};
auto hex2int = [&](auto c) {
auto v = hex2int1(c);
if (v < 0 || v > 15) {
throw std::runtime_error{"bad input char"};
}
return v;
};
auto d1 = hex2int(v[0]);
auto d2 = hex2int(v[1]);
ret.push_back((d1 << 4) | d2);
}
}
return ret;
}
struct mod_maker { struct mod_maker {
enum class file_type { enum class file_type {
unknown, unknown,
@ -30,10 +71,12 @@ struct mod_maker {
mod_maker(const std::string &name) : name{name} { mod_maker(const std::string &name) : name{name} {
detect_game_dir(fs::current_path()); detect_game_dir(fs::current_path());
detect_tools(); detect_tools();
prepare_injections();
} }
mod_maker(const std::string &name, const path &dir) : name{name} { mod_maker(const std::string &name, const path &dir) : name{name} {
detect_game_dir(dir); detect_game_dir(dir);
detect_tools(); detect_tools();
prepare_injections();
} }
void replace(const path &fn, const std::string &from, const std::string &to) { void replace(const path &fn, const std::string &from, const std::string &to) {
@ -57,7 +100,7 @@ struct mod_maker {
void apply() { void apply() {
std::vector<std::string> files; std::vector<std::string> files;
for (auto &&p : files_to_mod) { for (auto &&p : files_to_mod) {
if (p.filename() == "aim.exe") { if (p.filename() == aim_exe) {
continue; continue;
} }
files.push_back(p.string()); files.push_back(p.string());
@ -88,6 +131,73 @@ struct mod_maker {
#undef ENABLE_DISABLE_FUNC #undef ENABLE_DISABLE_FUNC
private: private:
static void memcpy(auto &ptr, const byte_array &data) {
::memcpy(ptr, data.data(), data.size());
ptr += data.size();
}
static auto memmem(auto ptr, auto sz, const byte_array &bytes) {
sz -= bytes.size();
for (int i = 0; i < sz; ++i) {
if (memcmp(ptr + i, bytes.data(), bytes.size()) == 0) {
return ptr + i;
}
}
throw std::runtime_error{"not found"};
}
static auto memreplace(auto base, auto sz, const byte_array &from, const byte_array &to) {
if (from.size() != to.size()) {
throw std::runtime_error{"size mismatch"};
}
auto ptr = memmem(base, sz, from);
byte_array old;
old.resize(from.size());
::memcpy(old.data(), ptr, old.size());
::memcpy(ptr, to.data(), to.size());
return std::tuple{ptr, old};
}
static auto make_insn_with_address(auto &&insn, uint32_t addr) {
byte_array arr(insn.size() + sizeof(addr));
::memcpy(arr.data(), insn.data(), insn.size());
*(uint32_t *)(&arr[insn.size()]) = addr;
return arr;
}
void prepare_injections() {
create_backup_exe_file();
primitives::templates2::mmap_file<uint8_t> f{find_real_filename(aim_exe), primitives::templates2::mmap_file<uint8_t>::rw{}};
constexpr uint32_t trampoline_base = 0x00025100;
constexpr uint32_t trampoline_target = 0x001207f0;
constexpr uint32_t code_base = 0x00401000;
constexpr uint32_t data_base = 0x00540000;
constexpr uint32_t free_data_base = 0x006929C0;
//constexpr uint32_t our_data = 0x00550FD0;
constexpr uint32_t our_data = 0x005207F0;
//constexpr uint32_t free_data_base_real = 0x140000 + our_data - 0x00540000;
auto ptr = f.p + trampoline_target;
//strcpy((char *)f.p + free_data_base_real, "aim_fixes-0.0.1.dll");
strcpy((char *)ptr, "aim_fixes-0.0.1.dll");
ptr += 0x20;
const auto jumppad = "68 30 B8 51 00"_bin; // push offset SEH_425100
uint32_t jump_offset = ptr - f.p - trampoline_base - jumppad.size() * 2;
auto [oldaddr, oldcode] = memreplace(f.p, f.sz, jumppad, make_insn_with_address("e9"_bin, jump_offset));
memcpy(ptr, jumppad); // put our removed insn
memcpy(ptr, R"(
60 ; pusha
)"_bin);
auto push_dll_name = make_insn_with_address("68"_bin, our_data);
memcpy(ptr, push_dll_name); //
memcpy(ptr, R"(
8B 3D D8 10 52 00 ; mov edi, ds:LoadLibraryA - not working ; but do not remove, it does not work without it
bf 30 0f 91 75 ; mov edi, 0x75910f30 - load direct adress
; edi has wrong address after prev. insn, so we fix it manually
81 EF 00 BD 00 00 ; sub edi, 0BD00h
)"_bin);
memcpy(ptr, R"(
FF D7 ; call edi
61 ; popa
)"_bin);
memcpy(ptr, make_insn_with_address("e9"_bin, -(ptr - f.p - trampoline_base - jumppad.size())));
}
path find_real_filename(path fn) const { path find_real_filename(path fn) const {
auto s = fn.wstring(); auto s = fn.wstring();
boost::to_lower(s); boost::to_lower(s);
@ -95,7 +205,7 @@ private:
if (fs::exists(fn)) { if (fs::exists(fn)) {
return fn; return fn;
} }
if (fn == "aim.exe") { if (fn == aim_exe) {
return game_dir / fn; return game_dir / fn;
} }
@ -148,10 +258,19 @@ private:
} }
// from https://github.com/Solant/aim-patches // from https://github.com/Solant/aim-patches
void free_camera(uint8_t val) { void free_camera(uint8_t val) {
patch("aim.exe", 0x1F805, val); create_backup_exe_file();
patch(aim_exe, 0x1F805, val);
} }
void win_key(uint8_t val) { void win_key(uint8_t val) {
patch("aim.exe", 0x4A40D, val); create_backup_exe_file();
patch(aim_exe, 0x4A40D, val);
}
void create_backup_exe_file() {
auto fn = find_real_filename(aim_exe);
auto backup = path{fn} += ".orig";
if (!fs::exists(backup)) {
fs::copy_file(fn, backup);
}
} }
template <typename T> template <typename T>
void patch_raw(path fn, uint32_t offset, T val) const { void patch_raw(path fn, uint32_t offset, T val) const {
@ -199,7 +318,7 @@ private:
return p; return p;
} }
void unpak(const path &p) const { void unpak(const path &p) const {
if (fs::exists(make_unpak_dir(p.filename()))) { if (fs::exists(make_unpak_dir(p))) {
return; return;
} }
run_p4_tool("unpaker", p); run_p4_tool("unpaker", p);
@ -223,7 +342,7 @@ private:
c.execute(); c.execute();
} }
void detect_game_dir(const path &dir) { void detect_game_dir(const path &dir) {
const auto aim1_exe = "aim.exe"sv; const auto aim1_exe = aim_exe;
if (fs::exists(dir / aim1_exe)) { if (fs::exists(dir / aim1_exe)) {
game_dir = dir; game_dir = dir;
} else if (fs::exists(dir.parent_path() / aim1_exe)) { } else if (fs::exists(dir.parent_path() / aim1_exe)) {