Add script patcher and update protections (#588)

This commit is contained in:
maybegreat48
2022-11-12 18:35:28 +00:00
committed by GitHub
parent 4d2667f140
commit 74c8e8d70c
31 changed files with 610 additions and 172 deletions

View File

@ -0,0 +1,30 @@
#pragma once
namespace big
{
class script_data
{
std::uint32_t m_num_pages;
public:
std::uint32_t m_code_size;
std::uint8_t** m_bytecode;
script_data(std::uint32_t code_size, std::uint8_t** bytecode, std::uint32_t num_pages) :
m_code_size(code_size),
m_bytecode(bytecode),
m_num_pages(num_pages)
{
}
~script_data()
{
for (auto i = 0u; i < m_num_pages; i++)
{
delete[] m_bytecode[i];
}
delete[] m_bytecode;
}
};
}

View File

@ -0,0 +1,68 @@
#include "script_patch.hpp"
#include "script_data.hpp"
namespace big
{
script_patch::script_patch(rage::joaat_t script, const memory::pattern pattern, int32_t offset, std::vector<std::uint8_t> patch, bool* enable_bool) :
m_script(script),
m_pattern(pattern),
m_offset(offset),
m_patch(std::move(patch)),
m_bool(enable_bool),
m_ip(0)
{
}
std::uint8_t* script_patch::get_code_address(script_data* data, std::uint32_t index)
{
return &data->m_bytecode[index >> 14][index & 0x3FFF];
}
const std::optional<uint32_t> script_patch::get_code_location_by_pattern(script_data* data, const memory::pattern& pattern)
{
std::uint32_t code_size = data->m_code_size;
for (std::uint32_t i = 0; i < (code_size - pattern.m_bytes.size()); i++)
{
for (std::uint32_t j = 0; j < pattern.m_bytes.size(); j++)
if (pattern.m_bytes[j].has_value())
if (pattern.m_bytes[j].value() != *get_code_address(data, i + j))
goto incorrect;
return i;
incorrect:
continue;
}
return std::nullopt;
}
void script_patch::enable(script_data* data)
{
std::memcpy(get_code_address(data, m_ip), m_patch.data(), m_patch.size());
}
void script_patch::disable(script_data* data)
{
std::memcpy(get_code_address(data, m_ip), m_original.data(), m_original.size());
}
void script_patch::update(script_data* data)
{
if (m_ip == 0)
{
auto result = get_code_location_by_pattern(data, m_pattern);
if (!result.has_value())
LOG(FATAL) << "Failed to find pattern";
m_ip = result.value() + m_offset;
for (int i = 0; i < m_patch.size(); i++)
m_original.push_back(*get_code_address(data, m_ip + i));
}
if (!m_bool || *m_bool)
enable(data);
else
disable(data);
}
}

View File

@ -0,0 +1,29 @@
#pragma once
#include "memory/pattern.hpp"
namespace big
{
struct script_data;
class script_patch
{
rage::joaat_t m_script;
const memory::pattern m_pattern;
int32_t m_offset;
std::vector<uint8_t> m_patch;
std::vector<uint8_t> m_original;
bool* m_bool;
int32_t m_ip;
static std::uint8_t* get_code_address(script_data* data, std::uint32_t index);
static const std::optional<uint32_t> get_code_location_by_pattern(script_data* data, const memory::pattern& pattern);
void enable(script_data* data);
void disable(script_data* data);
public:
inline rage::joaat_t get_script() { return m_script; }
script_patch(rage::joaat_t script, const memory::pattern pattern, int32_t offset, std::vector<std::uint8_t> patch, bool* enable_bool);
void update(script_data* data);
};
}

View File

@ -0,0 +1,87 @@
#include <script/scrProgram.hpp>
#include "script_patcher_service.hpp"
#include "script_patch.hpp"
#include "script_data.hpp"
namespace big
{
script_data* script_patcher_service::get_data_for_script(rage::joaat_t script)
{
for (auto& p : m_script_data)
{
if (p.first == script)
{
return p.second.get();
}
}
return nullptr;
}
bool script_patcher_service::does_script_have_patches(rage::joaat_t script)
{
for (auto& p : m_script_patches)
{
if (p.get_script() == script)
return true;
}
return false;
}
void script_patcher_service::create_data_for_script(rage::scrProgram* program)
{
auto pages = new std::uint8_t * [program->get_num_code_pages()];
for (auto i = 0u; i < program->get_num_code_pages(); i++)
{
pages[i] = new std::uint8_t[program->get_code_page_size(i)];
std::memcpy(pages[i], program->get_code_page(i), program->get_code_page_size(i));
}
m_script_data.emplace(program->m_name_hash, std::make_unique<script_data>(program->m_code_size, pages, program->get_num_code_pages()));
}
void script_patcher_service::update_all_patches_for_script(rage::joaat_t script)
{
auto data = get_data_for_script(script);
for (auto& p : m_script_patches)
if (p.get_script() == script)
p.update(data);
}
void script_patcher_service::add_patch(script_patch&& patch)
{
m_script_patches.push_back(std::move(patch));
}
void script_patcher_service::on_script_load(rage::scrProgram* program)
{
if (get_data_for_script(program->m_name_hash) == nullptr && does_script_have_patches(program->m_name_hash))
{
create_data_for_script(program);
update_all_patches_for_script(program->m_name_hash);
}
}
std::uint8_t** script_patcher_service::get_script_bytecode(rage::joaat_t script)
{
if (auto data = get_data_for_script(script))
return data->m_bytecode;
return nullptr;
}
void script_patcher_service::update()
{
for (auto& p : m_script_patches)
{
auto data = get_data_for_script(p.get_script());
if (data)
{
p.update(data);
}
}
}
}

View File

@ -0,0 +1,26 @@
#pragma once
#include <script/scrProgram.hpp>
#include "memory/pattern.hpp"
#include "script_patch.hpp"
#include "script_data.hpp"
namespace big
{
class script_patcher_service
{
std::vector<script_patch> m_script_patches;
std::unordered_map<rage::joaat_t, std::unique_ptr<script_data>> m_script_data;
script_data* get_data_for_script(rage::joaat_t script);
bool does_script_have_patches(rage::joaat_t script);
void create_data_for_script(rage::scrProgram* program);
void update_all_patches_for_script(rage::joaat_t script);
public:
void add_patch(script_patch&& patch);
void on_script_load(rage::scrProgram* program);
std::uint8_t** get_script_bytecode(rage::joaat_t script);
void update();
};
inline script_patcher_service g_script_patcher_service;
}