parent
bf63bdab4f
commit
11571a5f10
Binary file not shown.
@ -0,0 +1,49 @@
|
||||
#include "dlsym_hook.h"
|
||||
#include "../ligma.h"
|
||||
|
||||
namespace ligma
|
||||
{
|
||||
namespace hook
|
||||
{
|
||||
auto get_dlsym_hooks() -> std::map<std::pair<void*, std::string_view>, void*>*
|
||||
{
|
||||
static std::map<std::pair<void*, std::string_view>, void*> hooks{};
|
||||
return &hooks;
|
||||
}
|
||||
|
||||
__attribute__((noinline))
|
||||
void* dlsym_bypass(void* handle, const char* symbol)
|
||||
{
|
||||
dlsym_mutex.lock();
|
||||
ligma::hook::disable(dlsym_ptr);
|
||||
const auto result =
|
||||
reinterpret_cast<decltype(&dlsym_bypass)>(dlsym_ptr)(handle, symbol);
|
||||
ligma::hook::enable(dlsym_ptr);
|
||||
dlsym_mutex.unlock();
|
||||
return result;
|
||||
}
|
||||
|
||||
__attribute__((noinline))
|
||||
void* dlsym_handler(void* handle, const char* symbol)
|
||||
{
|
||||
LOGI("dlsym hook called! handle = %p, symbol = %s", handle, symbol);
|
||||
try
|
||||
{
|
||||
return get_dlsym_hooks()->at({ handle, symbol });
|
||||
}
|
||||
catch (std::out_of_range& e)
|
||||
{}
|
||||
return dlsym_bypass(handle, symbol);
|
||||
}
|
||||
|
||||
void dlsym_unhook(const std::pair<void*, const char*>& symbol_data)
|
||||
{
|
||||
try
|
||||
{
|
||||
get_dlsym_hooks()->erase(symbol_data);
|
||||
}
|
||||
catch (std::out_of_range& e)
|
||||
{}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,45 @@
|
||||
#pragma once
|
||||
#include <mutex>
|
||||
#include <dlfcn.h>
|
||||
#include <string>
|
||||
#include <android/log.h>
|
||||
#include "shithook.h"
|
||||
|
||||
#define LOGI(...) ((void)__android_log_print(4, "ligma", __VA_ARGS__))
|
||||
#define LOGW(...) ((void)__android_log_print(5, "ligma", __VA_ARGS__))
|
||||
|
||||
namespace ligma
|
||||
{
|
||||
namespace hook
|
||||
{
|
||||
inline void* dlsym_ptr = nullptr;
|
||||
inline std::mutex dlsym_mutex;
|
||||
|
||||
void* dlsym_bypass(void* handle, const char* symbol);
|
||||
void* dlsym_handler(void* handle, const char* symbol);
|
||||
auto get_dlsym_hooks() -> std::map<std::pair<void*, std::string_view>, void*>*;
|
||||
void dlsym_unhook(const std::pair<void*, const char*>& symbol_data);
|
||||
|
||||
template <class T>
|
||||
inline void dlsym_hook(std::pair<void*, const char*> symbol_data, T* function_ptr)
|
||||
{
|
||||
static std::once_flag once;
|
||||
std::call_once(once, [&]()
|
||||
{
|
||||
make_hook((dlsym_ptr = dlsym(dlopen("libdl.so", RTLD_NOLOAD), "dlsym")), &dlsym_handler);
|
||||
make_hook(&dlsym, &dlsym_bypass);
|
||||
});
|
||||
|
||||
get_dlsym_hooks()->insert
|
||||
(
|
||||
{
|
||||
{
|
||||
symbol_data.first,
|
||||
std::string_view{ symbol_data.second }
|
||||
},
|
||||
reinterpret_cast<void*>(function_ptr)
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,62 @@
|
||||
#include "shithook.h"
|
||||
|
||||
namespace ligma
|
||||
{
|
||||
namespace hook
|
||||
{
|
||||
detour::detour(void* addr_to_hook, void* jmp_to, bool enable)
|
||||
:
|
||||
hook_addr(addr_to_hook),
|
||||
detour_addr(jmp_to),
|
||||
hook_installed(false)
|
||||
{
|
||||
reinterpret_cast<std::uint32_t*>(jmp_code)[0] = ARM_JMP_CODE; // LDR PC, [PC, #-4]
|
||||
reinterpret_cast<void**>(jmp_code)[1] = jmp_to;
|
||||
memcpy(org_bytes, hook_addr, sizeof(org_bytes));
|
||||
if (enable) install();
|
||||
}
|
||||
|
||||
detour::~detour()
|
||||
{
|
||||
uninstall();
|
||||
}
|
||||
|
||||
bool detour::installed() { return hook_installed; }
|
||||
void* detour::hook_address() { return hook_addr; }
|
||||
void* detour::detour_address() { return detour_addr; }
|
||||
|
||||
void detour::install()
|
||||
{
|
||||
if (hook_installed.load())
|
||||
return;
|
||||
|
||||
if (!mprotect(PAGE_START(hook_addr), getpagesize(), PROT_READ | PROT_WRITE | PROT_EXEC))
|
||||
{
|
||||
memcpy((void*)((long)hook_addr), jmp_code, sizeof(jmp_code));
|
||||
mprotect(PAGE_START(hook_addr), getpagesize(), PROT_READ | PROT_EXEC);
|
||||
cacheflush(reinterpret_cast<long>(hook_addr), reinterpret_cast<long>(hook_addr) + getpagesize(), NULL);
|
||||
hook_installed.exchange(true);
|
||||
}
|
||||
}
|
||||
|
||||
void detour::uninstall()
|
||||
{
|
||||
if (!hook_installed.load())
|
||||
return;
|
||||
|
||||
if (!mprotect(PAGE_START(hook_addr), getpagesize(), PROT_READ | PROT_WRITE | PROT_EXEC))
|
||||
{
|
||||
memcpy(hook_addr, org_bytes, sizeof(jmp_code));
|
||||
mprotect(PAGE_START(hook_addr), getpagesize(), PROT_READ | PROT_EXEC);
|
||||
cacheflush(reinterpret_cast<long>(hook_addr), reinterpret_cast<long>(hook_addr) + getpagesize(), NULL);
|
||||
hook_installed.exchange(false);
|
||||
}
|
||||
}
|
||||
|
||||
std::map<void*, std::unique_ptr<detour>>* get_hooks()
|
||||
{
|
||||
static std::map<void*, std::unique_ptr<detour>> hooks{};
|
||||
return &hooks;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,14 +1,11 @@
|
||||
#include <chrono>
|
||||
#include <thread>
|
||||
#include <assembly-csharp.dll/gamebase.h>
|
||||
#include <assembly-csharp.dll/gameengine.h>
|
||||
#include "bypass/bypass.h"
|
||||
|
||||
__attribute__((constructor))
|
||||
void init()
|
||||
{
|
||||
ligma::bypass::init([&](const std::uintptr_t il2cpp_base)
|
||||
ligma::bypass::init([&](std::uintptr_t il2cpp_base, void* module_handle) -> bool
|
||||
{
|
||||
LOGI("il2cpp base address = %p", il2cpp_base);
|
||||
LOGI("il2cpp base address = %p, module_handle = %p", il2cpp_base, module_handle);
|
||||
return false;
|
||||
});
|
||||
}
|
@ -1,69 +1,63 @@
|
||||
#include "utils.h"
|
||||
#include "../ligma.h"
|
||||
|
||||
namespace ligma
|
||||
{
|
||||
namespace utils
|
||||
{
|
||||
void on_image_load(const std::string& module_name, const std::function<void(const std::uintptr_t)>& callback)
|
||||
std::uintptr_t get_module_base(const char* module_name)
|
||||
{
|
||||
static std::once_flag once;
|
||||
std::call_once(once, [&]() {
|
||||
ligma::hook::make_hook(
|
||||
dlsym(dlopen("libdl.so", RTLD_NOLOAD), "dlopen"),
|
||||
reinterpret_cast<void*>(&dlopen_handler)
|
||||
);
|
||||
});
|
||||
get_callbacks()->insert({ module_name, callback });
|
||||
std::unique_ptr<FILE, decltype(&fclose)> maps_handle(fopen("/proc/self/maps", "r"), &fclose);
|
||||
char line[512], mod_name[64];
|
||||
std::uintptr_t base;
|
||||
while (fgets(line, sizeof(line), maps_handle.get()))
|
||||
if (std::sscanf(line, "%" PRIXPTR "-%*" PRIXPTR " %*s %*s %*s %*s %s", &base, mod_name))
|
||||
if (std::strstr(mod_name, module_name))
|
||||
return base;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
auto get_callbacks() -> std::map<std::string, std::function<void(const std::uintptr_t)>>*
|
||||
auto get_callbacks() -> std::map<std::string, std::function<bool(std::uintptr_t, void*)>>*
|
||||
{
|
||||
static std::map<std::string, std::function<void(const std::uintptr_t)>> callback_map{};
|
||||
static std::map<std::string, std::function<bool(std::uintptr_t, void*)>> callback_map{};
|
||||
return &callback_map;
|
||||
}
|
||||
|
||||
std::uintptr_t get_module_base(const char* module_name)
|
||||
{
|
||||
const auto maps_handle = fopen("/proc/self/maps", "r");
|
||||
char line[512];
|
||||
while (fgets(line, sizeof line, maps_handle))
|
||||
{
|
||||
std::uintptr_t base;
|
||||
char tmp[64];
|
||||
sscanf(line, "%" PRIXPTR "-%*" PRIXPTR " %*s %*s %*s %*s %s", &base, tmp);
|
||||
if (strstr(tmp, module_name))
|
||||
{
|
||||
fclose(maps_handle);
|
||||
return base;
|
||||
}
|
||||
}
|
||||
fclose(maps_handle);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
__attribute__((noinline))
|
||||
void* dlopen_handler(const char* filename, int flags)
|
||||
{
|
||||
dlopen_hook.second.lock();
|
||||
ligma::hook::disable(dlopen_hook.first);
|
||||
const auto result = dlopen(filename, reinterpret_cast<int>(RTLD_NEXT));
|
||||
if (ligma::utils::get_callbacks()->size())
|
||||
ligma::hook::enable(dlopen_hook.first);
|
||||
dlopen_hook.second.unlock();
|
||||
dlopen_mutex.lock();
|
||||
ligma::hook::disable(dlopen_ptr);
|
||||
const auto result = dlopen(filename, flags);
|
||||
ligma::hook::enable(dlopen_ptr);
|
||||
dlopen_mutex.unlock();
|
||||
|
||||
//
|
||||
// if there is a callback for this module, call it and then remove it.
|
||||
//
|
||||
for (const auto& [file_key, callback] : *ligma::utils::get_callbacks())
|
||||
{
|
||||
if (strstr(filename, file_key.c_str()))
|
||||
if (std::strstr(filename, file_key.c_str()))
|
||||
{
|
||||
// remove the callback before calling it, this prevents loops...
|
||||
ligma::utils::get_callbacks()->erase(file_key);
|
||||
callback(ligma::utils::get_module_base(file_key.c_str()));
|
||||
if (callback(ligma::utils::get_module_base(file_key.c_str()), result))
|
||||
on_image_load(file_key, callback); // add it back if we still want the callback...
|
||||
break;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void on_image_load(const std::string& module_name, const std::function<bool (std::uintptr_t, void*)>& callback)
|
||||
{
|
||||
static std::once_flag once;
|
||||
std::call_once(once, [&]()
|
||||
{
|
||||
ligma::hook::make_hook
|
||||
(
|
||||
(dlopen_ptr = dlsym(dlopen("libdl.so", RTLD_NOLOAD), "dlopen")),
|
||||
&dlopen_handler
|
||||
);
|
||||
});
|
||||
get_callbacks()->insert({ module_name, callback });
|
||||
}
|
||||
}
|
||||
}
|
@ -1,20 +1,23 @@
|
||||
#pragma once
|
||||
#include <functional>
|
||||
#include <fstream>
|
||||
#include <map>
|
||||
#include <functional>
|
||||
#include <inttypes.h>
|
||||
#include <dlfcn.h>
|
||||
#include <mutex>
|
||||
#include <string>
|
||||
#include <fstream>
|
||||
#include "../hooks/shithook.h"
|
||||
|
||||
namespace ligma
|
||||
{
|
||||
namespace utils
|
||||
{
|
||||
inline std::pair<void*, std::mutex> dlopen_hook;
|
||||
inline void* dlopen_ptr = nullptr;
|
||||
inline std::mutex dlopen_mutex;
|
||||
|
||||
std::uintptr_t get_module_base(const char* module_name);
|
||||
auto get_callbacks() -> std::map<std::string, std::function<void(const std::uintptr_t)>>*;
|
||||
void on_image_load(const std::string& module_name, const std::function<void(const std::uintptr_t)>& callback);
|
||||
void dlsym_hook(const std::string& symbol_name, void* function_ptr);
|
||||
auto get_callbacks() -> std::map<std::string, std::function<bool(std::uintptr_t, void*)>>*;
|
||||
void* dlopen_handler(const char* filename, int flags);
|
||||
void on_image_load(const std::string& module_name, const std::function<bool(std::uintptr_t, void*)>& callback);
|
||||
}
|
||||
}
|
Loading…
Reference in new issue