Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 7 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -88,13 +88,13 @@ ninja
```

## Credits
| Credits | |
| ---------------------------------------------------------- | ---------------------------------------------------------------------- |
| Pocakking | [BigBaseV2](https://github.com/Pocakking/BigBaseV2) |
| spankerincrease(gir489) | [BigBaseV2-fix](https://bitbucket.org/gir489/bigbasev2-fix) |
| [YimMenu](https://github.com/YimMenu/YimMenu) contributors | Updates for newer GTA V versions, most of the code is stolen from them |
| FSL | Saved my save, help with profile stats, help with casino chips |
| tupoy-ya | Being stupid |
| Credits | |
| ---------------------------------------------------------- | ---------------------------------------------------------------------------------------------------- |
| Pocakking | [BigBaseV2](https://github.com/Pocakking/BigBaseV2) |
| spankerincrease(gir489) | [BigBaseV2-fix](https://bitbucket.org/gir489/bigbasev2-fix) |
| [YimMenu](https://github.com/YimMenu/YimMenu) contributors | Updates for newer GTA V versions, most of the code is stolen from them |
| FSL | Saved my save, help with profile stats, help with casino chips, create_native based native hook idea |
| tupoy-ya | Being stupid |

## License
This project is licensed under [GNU GENERAL PUBLIC LICENSE Version 2](https://www.gnu.org/licenses/old-licenses/gpl-2.0.txt) because i stole a lot of code from YimMenu.
10,486 changes: 5,356 additions & 5,130 deletions src/crossmap.hpp

Large diffs are not rendered by default.

4 changes: 1 addition & 3 deletions src/hooking/hooking.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ namespace big
}

detour_hook_helper::add<hooks::run_script_threads>("Script hook", (void*)g_pointers->m_run_script_threads);
detour_hook_helper::add<hooks::init_native_tables>("Init Native Tables", (void*)g_pointers->m_init_native_tables);
detour_hook_helper::add<hooks::create_native>("Create Native", (void*)g_pointers->m_create_native);

if(!g_is_enhanced)
{
Expand Down Expand Up @@ -112,8 +112,6 @@ namespace big

bool hooks::run_script_threads(std::uint32_t ops_to_execute)
{
g_native_invoker.cache_handlers();

if (g_running)
{
g_script_mgr.tick();
Expand Down
3 changes: 2 additions & 1 deletion src/hooking/hooking.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,17 @@
#include "gta/fwddec.hpp"
#include "vmt_hook.hpp"

#include <script/scrNativeHandler.hpp>
#include <MinHook.h>

namespace big
{
struct hooks
{
static bool run_script_threads(std::uint32_t ops_to_execute);
static bool init_native_tables(rage::scrProgram* program);

static uint32_t network_can_access_multiplayer(uint32_t a1, uint64_t* a2);
static void create_native(void* a1, rage::scrNativeHash native_hash, rage::scrNativeHandler native_func);

static void create_stat(void* p1, const char** name);
static bool mp_stats_save(void* _this, uint32_t p2, uint32_t p3, uint32_t p4, uint32_t p5, uint32_t p6);
Expand Down
35 changes: 35 additions & 0 deletions src/hooks/script/create_native.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
#include "crossmap.hpp"
#include "hooking/hooking.hpp"
#include "invoker.hpp"
#include "native_hooks/native_hooks.hpp"

namespace big
{
rage::scrNativeHash get_community_hash_from_game_hash(rage::scrNativeHash hash)
{
for (const rage::scrNativePair& mapping : g_crossmap)
{
if (mapping.second == hash)
{
return mapping.first;
}
}

return hash;
}

void hooks::create_native(void* a1, rage::scrNativeHash native_hash, rage::scrNativeHandler native_handler)
{
rage::scrNativeHash community_hash = get_community_hash_from_game_hash(native_hash);

g_native_invoker.add_native_handler(community_hash, native_handler);

auto hooked_handler = g_native_hooks->get_hooked_handler(community_hash);
if (hooked_handler.has_value())
{
native_handler = hooked_handler.value();
}

g_hooking->get_original<hooks::create_native>()(a1, native_hash, native_handler);
}
}
26 changes: 0 additions & 26 deletions src/hooks/script/init_native_tables.cpp

This file was deleted.

39 changes: 4 additions & 35 deletions src/invoker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,38 +18,14 @@ namespace big
m_args = &m_arg_stack[0];
}

void native_invoker::cache_handlers()
void native_invoker::add_native_handler(rage::scrNativeHash hash, rage::scrNativeHandler handler)
{
if (m_handlers_cached) [[likely]]
return;

size_t i = 0;
for (const rage::scrNativePair& mapping : g_crossmap)
{
m_handler_cache[i] = (rage::scrNativeHandler)mapping.second;
++i;
}
auto program = reinterpret_cast<rage::scrProgram*>(calloc(1, sizeof(rage::scrProgram)));
program->m_native_count = m_handler_cache.size();
program->m_native_entrypoints = m_handler_cache.data();
g_hooking->get_original<hooks::init_native_tables>()(program);
free(program);

m_handlers_cached = true;
m_handler_cache[hash] = handler;
}

rage::scrNativeHandler native_invoker::get_native_handler(rage::scrNativeHash hash)
{
cache_handlers();

size_t i = 0;
for (const rage::scrNativePair& mapping : g_crossmap)
{
if(mapping.second == hash) break;
++i;
}

return m_handler_cache[i];
return m_handler_cache[hash];
}

void fix_vectors(native_call_context& call_context)
Expand All @@ -71,16 +47,9 @@ namespace big

void native_invoker::end_call(rage::scrNativeHash hash)
{
size_t i = 0;
for (const rage::scrNativePair& mapping : g_crossmap)
{
if(mapping.first == hash) break;
++i;
}

try
{
rage::scrNativeHandler handler = m_handler_cache.at(i);
rage::scrNativeHandler handler = m_handler_cache.at(hash);

// return address checks are no longer a thing
handler(&m_call_context);
Expand Down
5 changes: 2 additions & 3 deletions src/invoker.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ namespace big
explicit native_invoker() = default;
~native_invoker() = default;

void cache_handlers();
void add_native_handler(rage::scrNativeHash hash, rage::scrNativeHandler handler);
rage::scrNativeHandler get_native_handler(rage::scrNativeHash hash);

void begin_call();
Expand All @@ -55,8 +55,7 @@ namespace big

public:
native_call_context m_call_context;
static inline std::array<rage::scrNativeHandler, sizeof(g_crossmap) / sizeof(rage::scrNativePair)> m_handler_cache;
bool m_handlers_cached = false;
static inline std::unordered_map<rage::scrNativeHash, rage::scrNativeHandler> m_handler_cache;
};

inline native_invoker g_native_invoker;
Expand Down
143 changes: 7 additions & 136 deletions src/native_hooks/native_hooks.cpp
Original file line number Diff line number Diff line change
@@ -1,114 +1,15 @@
/**
* @file native_hooks.cpp
* @brief Hooks to native functions.
*
* @copyright GNU General Public License Version 2.
* This file is part of YimMenu.
* YimMenu is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any later version.
* YimMenu is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
* You should have received a copy of the GNU General Public License along with YimMenu. If not, see <https://www.gnu.org/licenses/>.
*/

#include "native_hooks.hpp"

#include "all_scripts.hpp"
#include "crossmap.hpp"
#include "fm_maintain_cloud_header_data.hpp"
#include "script_save.hpp"

#include <optional>
#include <script/scrProgram.hpp>
#include <script/scrProgramTable.hpp>

namespace big
{
static bool map_native(rage::scrNativeHash* hash)
{
for (auto const& mapping : g_crossmap)
{
if (mapping.first == *hash)
{
*hash = mapping.second;
return true;
}
}

return false;
}

native_hook::native_hook(rage::scrProgram* program, const std::unordered_map<rage::scrNativeHash, rage::scrNativeHandler>& native_replacements)
{
hook_instance(program, native_replacements);
}

native_hook::~native_hook()
{
if (m_handler_hook)
{
m_handler_hook->disable();
m_handler_hook.reset();
}

if (m_vmt_hook)
{
m_vmt_hook->disable();
m_vmt_hook.reset();
}
}

void native_hook::hook_instance(rage::scrProgram* program, const std::unordered_map<rage::scrNativeHash, rage::scrNativeHandler>& native_replacements)
{
m_program = program;
m_vmt_hook = std::make_unique<vmt_hook>(m_program, 9);
m_vmt_hook->hook(6, (void*)&scrprogram_dtor);
m_vmt_hook->enable();

m_handler_hook = std::make_unique<vmt_hook>(&m_program->m_native_entrypoints, m_program->m_native_count);
m_handler_hook->enable();

std::unordered_map<rage::scrNativeHandler, rage::scrNativeHandler> handler_replacements;

for (auto& [replacement_hash, replacement_handler] : native_replacements)
{
auto native = replacement_hash;
map_native(&native);

auto og_handler = g_native_invoker.get_native_handler(native);
if (!og_handler)
continue;

handler_replacements[og_handler] = replacement_handler;
}

for (int i = 0; i < m_program->m_native_count; i++)
{
if (auto it = handler_replacements.find((rage::scrNativeHandler)program->m_native_entrypoints[i]);
it != handler_replacements.end())
{
m_handler_hook->hook(i, (void*)it->second);
}
}
}

void native_hook::scrprogram_dtor(rage::scrProgram* this_, char free_memory)
{
if (auto it = g_native_hooks->m_native_hooks.find(this_); it != g_native_hooks->m_native_hooks.end())
{
auto og_func = it->second->m_vmt_hook->get_original<decltype(&native_hook::scrprogram_dtor)>(6);
it->second->m_vmt_hook->disable();
it->second->m_vmt_hook.reset();
it->second->m_handler_hook->disable();
it->second->m_handler_hook.reset();
g_native_hooks->m_native_hooks.erase(it);
og_func(this_, free_memory);
}
else
{
LOG(FATAL) << "Cannot find hook for program";
}
}

constexpr auto ALL_SCRIPT_HASH = RAGE_JOAAT("ALL_SCRIPTS");

native_hooks::native_hooks()
{
add_native_detour(0x7D2708796355B20B, all_scripts::RETURN_FALSE); // NET_GAMESERVER_USE_SERVER_TRANSACTIONS
Expand Down Expand Up @@ -156,58 +57,28 @@ namespace big
add_native_detour(0x158C16F5E4CF41F8, all_scripts::RETURN_TRUE); // NETWORK_CASINO_CAN_BET
add_native_detour(0x930DE22F07B1CCE3, all_scripts::RETURN_FALSE); // SC_PROFANITY_GET_STRING_STATUS

for (int i = 0; i < 176; i++)
{
rage::scrProgram* program = g_pointers->m_script_programs[i];
if (program != nullptr && program->m_code_blocks && program->m_code_size)
{
hook_program(program);
}
}

g_native_hooks = this;
}

native_hooks::~native_hooks()
{
m_native_hooks.clear();
g_native_hooks = nullptr;
}

void native_hooks::add_native_detour(rage::scrNativeHash hash, rage::scrNativeHandler detour)
{
add_native_detour(ALL_SCRIPT_HASH, hash, detour);
m_native_detours[hash] = detour;
}

void native_hooks::add_native_detour(rage::joaat_t script_hash, rage::scrNativeHash hash, rage::scrNativeHandler detour)
std::optional<rage::scrNativeHandler> native_hooks::get_hooked_handler(rage::scrNativeHash hash)
{
if (const auto& it = m_native_registrations.find(script_hash); it != m_native_registrations.end())
try
{
it->second.emplace_back(hash, detour);
return;
return m_native_detours.at(hash);
}

m_native_registrations.emplace(script_hash, std::vector<native_detour>({{hash, detour}}));
}

void native_hooks::hook_program(rage::scrProgram* program)
{
std::unordered_map<rage::scrNativeHash, rage::scrNativeHandler> native_replacements;
const auto script_hash = program->m_name_hash;

// Functions that need to be detoured for all scripts
if (const auto& pair = m_native_registrations.find(ALL_SCRIPT_HASH); pair != m_native_registrations.end())
for (const auto& native_hook_reg : pair->second)
native_replacements.insert(native_hook_reg);

// Functions that only need to be detoured for a specific script
if (const auto& pair = m_native_registrations.find(script_hash); pair != m_native_registrations.end())
for (const auto& native_hook_reg : pair->second)
native_replacements.insert(native_hook_reg);

if (!native_replacements.empty())
catch (const std::out_of_range& ex)
{
m_native_hooks.emplace(program, std::make_unique<native_hook>(program, native_replacements));
return std::nullopt;
}
}
}
Loading