mcpe-1.1-linux/src/hook.cpp
2026-01-16 23:23:28 +02:00

117 lines
3.5 KiB
C++

#include "hook.h"
#include <elf.h>
#include <stdio.h>
#include <string.h>
#include <vector>
#include <sys/mman.h>
#include <map>
extern "C" {
#include "../hybris/include/hybris/dlfcn.h"
#include "../hybris/src/jb/linker.h"
}
struct soinfo_hookinfo {
struct hook_section {
Elf32_Off addr, size;
};
std::vector<hook_section> hookSections;
};
std::map<soinfo*, soinfo_hookinfo> hookLibraries;
void addHookLibrary(void* ptr, std::string const& fileName) {
soinfo* lib = (soinfo*) ptr;
if (hookLibraries.count(lib) > 0)
return;
Elf32_Ehdr header;
FILE* file = fopen(fileName.c_str(), "r");
if (file == nullptr) {
printf("addHookLibrary: failed to open file\n");
return;
}
if (fread(&header, sizeof(Elf32_Ehdr), 1, file) != 1) {
printf("addHookLibrary: failed to read header\n");
fclose(file);
return;
}
fseek(file, (long) header.e_shoff, SEEK_SET);
char shdr[header.e_shentsize * header.e_shnum];
if (fread(&shdr, header.e_shentsize, header.e_shnum, file) != header.e_shnum) {
printf("addHookLibrary: failed to read shdr\n");
fclose(file);
return;
}
// find strtab
char* strtab = nullptr;
for (int i = 0; i < header.e_shnum; i++) {
Elf32_Shdr& entry = *((Elf32_Shdr*) &shdr[header.e_shentsize * i]);
if (entry.sh_type == SHT_STRTAB) {
strtab = new char[entry.sh_size];
fseek(file, (long) entry.sh_offset, SEEK_SET);
if (fread(strtab, 1, entry.sh_size, file) != entry.sh_size) {
printf("addHookLibrary: failed to read strtab\n");
fclose(file);
delete[] strtab;
return;
}
}
}
if (strtab == nullptr) {
printf("addHookLibrary: couldn't find strtab\n");
fclose(file);
return;
}
soinfo_hookinfo hi;
for (int i = 0; i < header.e_shnum; i++) {
Elf32_Shdr& entry = *((Elf32_Shdr*) &shdr[header.e_shentsize * i]);
char* entryName = &strtab[entry.sh_name];
if (strcmp(entryName, ".got") == 0 || strcmp(entryName, ".got.plt") == 0 ||
strcmp(entryName, ".data.rel.ro") == 0) {
hi.hookSections.push_back({entry.sh_addr, entry.sh_size});
}
}
hookLibraries[lib] = hi;
fclose(file);
delete[] strtab;
}
inline bool patchSection(Elf32_Addr base, Elf32_Word off, Elf32_Word size, void* sym, void* override) {
bool foundEntry = false;
unsigned long addr = base + off + 4;
while (addr < base + off + size) {
if (*((void**) addr) == sym) {
*((void**) addr) = override;
foundEntry = true;
}
addr += sizeof(void*);
}
return foundEntry;
}
bool patchLibrary(void* lib, void* sym, void* override) {
soinfo* si = (soinfo*) lib;
if (si == nullptr || hookLibraries.count(si) <= 0)
return false;
soinfo_hookinfo& hi = hookLibraries.at(si);
bool foundEntry = false;
for (auto& se : hi.hookSections) {
if (patchSection(si->base, se.addr, se.size, sym, override))
foundEntry = true;
}
return foundEntry;
}
void hookFunction(void* symbol, void* hook, void** original) {
*original = symbol;
bool foundEntry = false;
for (auto& handle : hookLibraries)
if (patchLibrary(handle.first, symbol, hook))
foundEntry = true;
if (!foundEntry)
printf("Failed to hook a symbol (%llu)\n", (long long int) symbol);
}