2023-02-27 12:32:38 +00:00
|
|
|
#include "HookSystem.hpp"
|
2023-11-26 18:33:53 +00:00
|
|
|
#include "../debug/Log.hpp"
|
2024-06-11 17:17:45 +02:00
|
|
|
#include "../helpers/varlist/VarList.hpp"
|
2024-04-28 18:28:19 +01:00
|
|
|
#include "../managers/TokenManager.hpp"
|
2025-01-17 15:21:35 +00:00
|
|
|
#include "../helpers/MiscFunctions.hpp"
|
2023-02-27 12:32:38 +00:00
|
|
|
|
|
|
|
|
#define register
|
|
|
|
|
#include <udis86.h>
|
|
|
|
|
#undef register
|
|
|
|
|
#include <sys/mman.h>
|
|
|
|
|
#include <unistd.h>
|
|
|
|
|
#include <cstring>
|
2024-04-04 18:50:37 +01:00
|
|
|
#include <fstream>
|
2024-04-28 18:58:31 +01:00
|
|
|
#include <sys/stat.h>
|
|
|
|
|
#include <sys/types.h>
|
2023-02-27 12:32:38 +00:00
|
|
|
|
2025-05-03 16:06:24 +02:00
|
|
|
CFunctionHook::CFunctionHook(HANDLE owner, void* source, void* destination) : m_source(source), m_destination(destination), m_owner(owner) {
|
2024-12-07 18:51:18 +01:00
|
|
|
;
|
2023-02-27 12:32:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
CFunctionHook::~CFunctionHook() {
|
2025-05-03 16:06:24 +02:00
|
|
|
if (m_active)
|
2023-02-27 12:32:38 +00:00
|
|
|
unhook();
|
|
|
|
|
}
|
|
|
|
|
|
2023-12-27 11:43:04 +01:00
|
|
|
CFunctionHook::SInstructionProbe CFunctionHook::getInstructionLenAt(void* start) {
|
2023-02-27 12:32:38 +00:00
|
|
|
ud_t udis;
|
|
|
|
|
|
|
|
|
|
ud_init(&udis);
|
|
|
|
|
ud_set_mode(&udis, 64);
|
2023-12-27 11:43:04 +01:00
|
|
|
ud_set_syntax(&udis, UD_SYN_ATT);
|
2023-02-27 12:32:38 +00:00
|
|
|
|
|
|
|
|
size_t curOffset = 1;
|
|
|
|
|
size_t insSize = 0;
|
|
|
|
|
while (true) {
|
2025-08-14 19:44:56 +05:00
|
|
|
ud_set_input_buffer(&udis, sc<uint8_t*>(start), curOffset);
|
2023-02-27 12:32:38 +00:00
|
|
|
insSize = ud_disassemble(&udis);
|
|
|
|
|
if (insSize != curOffset)
|
|
|
|
|
break;
|
|
|
|
|
curOffset++;
|
|
|
|
|
}
|
|
|
|
|
|
2023-02-27 18:34:44 +00:00
|
|
|
// check for RIP refs
|
|
|
|
|
std::string ins;
|
|
|
|
|
if (const auto CINS = ud_insn_asm(&udis); CINS)
|
|
|
|
|
ins = std::string(CINS);
|
|
|
|
|
|
2023-12-27 11:43:04 +01:00
|
|
|
return {insSize, ins};
|
2023-02-27 12:32:38 +00:00
|
|
|
}
|
|
|
|
|
|
2023-12-27 11:43:04 +01:00
|
|
|
CFunctionHook::SInstructionProbe CFunctionHook::probeMinimumJumpSize(void* start, size_t min) {
|
2023-02-27 12:32:38 +00:00
|
|
|
|
2023-12-27 11:43:04 +01:00
|
|
|
size_t size = 0;
|
|
|
|
|
|
|
|
|
|
std::string instrs = "";
|
|
|
|
|
std::vector<size_t> sizes;
|
2023-02-27 12:32:38 +00:00
|
|
|
|
|
|
|
|
while (size <= min) {
|
|
|
|
|
// find info about this instruction
|
2025-08-14 19:44:56 +05:00
|
|
|
auto probe = getInstructionLenAt(sc<uint8_t*>(start) + size);
|
2023-12-27 11:43:04 +01:00
|
|
|
sizes.push_back(probe.len);
|
|
|
|
|
size += probe.len;
|
|
|
|
|
instrs += probe.assembly + "\n";
|
2023-02-27 12:32:38 +00:00
|
|
|
}
|
|
|
|
|
|
2023-12-27 11:43:04 +01:00
|
|
|
return {size, instrs, sizes};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
CFunctionHook::SAssembly CFunctionHook::fixInstructionProbeRIPCalls(const SInstructionProbe& probe) {
|
2024-04-04 18:50:37 +01:00
|
|
|
SAssembly returns;
|
|
|
|
|
|
2023-12-27 11:43:04 +01:00
|
|
|
// analyze the code and fix what we know how to.
|
2025-08-14 19:44:56 +05:00
|
|
|
uint64_t currentAddress = rc<uint64_t>(m_source);
|
2023-12-27 11:43:04 +01:00
|
|
|
// actually newline + 1
|
2024-04-04 18:50:37 +01:00
|
|
|
size_t lastAsmNewline = 0;
|
|
|
|
|
// needle for destination binary
|
2024-04-30 02:54:43 +01:00
|
|
|
size_t currentDestinationOffset = 0;
|
|
|
|
|
|
|
|
|
|
std::vector<char> finalBytes;
|
|
|
|
|
finalBytes.resize(probe.len);
|
|
|
|
|
|
2024-08-26 17:25:39 +02:00
|
|
|
for (auto const& len : probe.insSizes) {
|
2023-12-27 11:43:04 +01:00
|
|
|
|
2024-04-30 02:54:43 +01:00
|
|
|
// copy original bytes to our finalBytes
|
|
|
|
|
for (size_t i = 0; i < len; ++i) {
|
2025-08-14 19:44:56 +05:00
|
|
|
finalBytes[currentDestinationOffset + i] = *rc<char*>(currentAddress + i);
|
2024-04-30 02:54:43 +01:00
|
|
|
}
|
|
|
|
|
|
2024-12-07 18:51:18 +01:00
|
|
|
std::string code = probe.assembly.substr(lastAsmNewline, probe.assembly.find('\n', lastAsmNewline) - lastAsmNewline);
|
2023-12-27 11:43:04 +01:00
|
|
|
if (code.contains("%rip")) {
|
2024-11-18 23:53:38 +00:00
|
|
|
CVarList tokens{code, 0, 's'};
|
|
|
|
|
size_t plusPresent = tokens[1][0] == '+' ? 1 : 0;
|
|
|
|
|
size_t minusPresent = tokens[1][0] == '-' ? 1 : 0;
|
|
|
|
|
std::string addr = tokens[1].substr((plusPresent || minusPresent), tokens[1].find("(%rip)") - (plusPresent || minusPresent));
|
|
|
|
|
auto addrResult = configStringToInt(addr);
|
|
|
|
|
if (!addrResult)
|
|
|
|
|
return {};
|
|
|
|
|
const int32_t OFFSET = (minusPresent ? -1 : 1) * *addrResult;
|
2023-12-27 11:43:04 +01:00
|
|
|
if (OFFSET == 0)
|
|
|
|
|
return {};
|
|
|
|
|
const uint64_t DESTINATION = currentAddress + OFFSET + len;
|
|
|
|
|
|
2024-04-30 02:54:43 +01:00
|
|
|
auto ADDREND = code.find("(%rip)");
|
|
|
|
|
auto ADDRSTART = (code.substr(0, ADDREND).find_last_of(' '));
|
|
|
|
|
|
|
|
|
|
if (ADDREND == std::string::npos || ADDRSTART == std::string::npos)
|
2023-12-28 13:36:09 +01:00
|
|
|
return {};
|
2024-04-30 02:54:43 +01:00
|
|
|
|
2025-10-07 12:37:21 +01:00
|
|
|
const uint64_t PREDICTEDRIP = rc<uint64_t>(m_landTrampolineAddr) + currentDestinationOffset + len;
|
2024-04-30 02:54:43 +01:00
|
|
|
const int32_t NEWRIPOFFSET = DESTINATION - PREDICTEDRIP;
|
|
|
|
|
|
|
|
|
|
size_t ripOffset = 0;
|
|
|
|
|
|
|
|
|
|
// find %rip usage offset from beginning
|
|
|
|
|
for (int i = len - 4 /* 32-bit */; i > 0; --i) {
|
2025-08-14 19:44:56 +05:00
|
|
|
if (*rc<int32_t*>(currentAddress + i) == OFFSET) {
|
2024-04-30 02:54:43 +01:00
|
|
|
ripOffset = i;
|
|
|
|
|
break;
|
|
|
|
|
}
|
2023-12-28 13:36:09 +01:00
|
|
|
}
|
2024-04-30 02:54:43 +01:00
|
|
|
|
|
|
|
|
if (ripOffset == 0)
|
|
|
|
|
return {};
|
|
|
|
|
|
|
|
|
|
// fix offset in the final bytes. This doesn't care about endianness
|
2025-08-14 19:44:56 +05:00
|
|
|
*rc<int32_t*>(&finalBytes[currentDestinationOffset + ripOffset]) = NEWRIPOFFSET;
|
2024-04-30 02:54:43 +01:00
|
|
|
|
|
|
|
|
currentDestinationOffset += len;
|
2023-12-27 11:43:04 +01:00
|
|
|
} else {
|
2024-04-04 18:50:37 +01:00
|
|
|
currentDestinationOffset += len;
|
2023-12-27 11:43:04 +01:00
|
|
|
}
|
|
|
|
|
|
2024-12-07 18:51:18 +01:00
|
|
|
lastAsmNewline = probe.assembly.find('\n', lastAsmNewline) + 1;
|
2023-12-27 11:43:04 +01:00
|
|
|
currentAddress += len;
|
|
|
|
|
}
|
|
|
|
|
|
2024-04-30 02:54:43 +01:00
|
|
|
return {finalBytes};
|
2023-02-27 12:32:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool CFunctionHook::hook() {
|
|
|
|
|
|
|
|
|
|
// check for unsupported platforms
|
|
|
|
|
#if !defined(__x86_64__)
|
|
|
|
|
return false;
|
|
|
|
|
#endif
|
|
|
|
|
|
2025-10-07 12:37:21 +01:00
|
|
|
// jmp rel32
|
|
|
|
|
// offset for relative addr: 1
|
|
|
|
|
static constexpr uint8_t RELATIVE_JMP_ADDRESS[] = {0xE9, 0x00, 0x00, 0x00, 0x00};
|
|
|
|
|
static constexpr size_t RELATIVE_JMP_ADDRESS_OFFSET = 1;
|
|
|
|
|
// movabs $0,%rax | jmpq *rax
|
2023-02-27 18:34:44 +00:00
|
|
|
static constexpr uint8_t ABSOLUTE_JMP_ADDRESS[] = {0x48, 0xB8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xE0};
|
|
|
|
|
static constexpr size_t ABSOLUTE_JMP_ADDRESS_OFFSET = 2;
|
2023-02-27 12:32:38 +00:00
|
|
|
// nop
|
|
|
|
|
static constexpr uint8_t NOP = 0x90;
|
|
|
|
|
|
2025-10-07 12:37:21 +01:00
|
|
|
// alloc trampolines
|
2024-04-04 18:50:37 +01:00
|
|
|
const auto MAX_TRAMPOLINE_SIZE = HOOK_TRAMPOLINE_MAX_SIZE; // we will never need more.
|
2025-10-07 12:37:21 +01:00
|
|
|
m_launchTrampolineAddr = rc<void*>(g_pFunctionHookSystem->getAddressForTrampo());
|
|
|
|
|
m_landTrampolineAddr = rc<void*>(g_pFunctionHookSystem->getAddressForTrampo());
|
2024-04-04 18:50:37 +01:00
|
|
|
|
2023-12-27 11:43:04 +01:00
|
|
|
// probe instructions to be trampolin'd
|
|
|
|
|
SInstructionProbe probe;
|
2023-11-26 17:53:51 +00:00
|
|
|
try {
|
2025-10-07 12:37:21 +01:00
|
|
|
probe = probeMinimumJumpSize(m_source, sizeof(RELATIVE_JMP_ADDRESS));
|
2023-11-26 17:53:51 +00:00
|
|
|
} catch (std::exception& e) { return false; }
|
2023-02-27 12:32:38 +00:00
|
|
|
|
2023-12-27 11:43:04 +01:00
|
|
|
const auto PROBEFIXEDASM = fixInstructionProbeRIPCalls(probe);
|
|
|
|
|
|
2025-05-31 23:49:50 +05:00
|
|
|
if (PROBEFIXEDASM.bytes.empty()) {
|
2023-12-27 19:27:15 +01:00
|
|
|
Debug::log(ERR, "[functionhook] failed, unsupported asm / failed assembling:\n{}", probe.assembly);
|
2023-12-27 11:43:04 +01:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2025-10-14 19:31:49 +01:00
|
|
|
if (std::abs(rc<int64_t>(m_source) - rc<int64_t>(m_landTrampolineAddr)) > 2000000000 /* 2 GB */) {
|
|
|
|
|
Debug::log(ERR, "[functionhook] failed, source and trampo are over 2GB apart");
|
2025-10-07 12:37:21 +01:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2023-12-27 11:43:04 +01:00
|
|
|
const size_t HOOKSIZE = PROBEFIXEDASM.bytes.size();
|
|
|
|
|
const size_t ORIGSIZE = probe.len;
|
|
|
|
|
|
2025-10-07 12:37:21 +01:00
|
|
|
const auto TRAMPOLINE_SIZE = sizeof(RELATIVE_JMP_ADDRESS) + HOOKSIZE;
|
2024-04-04 18:50:37 +01:00
|
|
|
|
|
|
|
|
if (TRAMPOLINE_SIZE > MAX_TRAMPOLINE_SIZE) {
|
|
|
|
|
Debug::log(ERR, "[functionhook] failed, not enough space in trampo to alloc:\n{}", probe.assembly);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2023-02-27 12:32:38 +00:00
|
|
|
|
2025-06-19 11:58:07 +02:00
|
|
|
m_originalBytes.resize(ORIGSIZE);
|
|
|
|
|
memcpy(m_originalBytes.data(), m_source, ORIGSIZE);
|
2023-02-27 19:17:58 +00:00
|
|
|
|
2025-10-07 12:37:21 +01:00
|
|
|
// populate land trampoline
|
|
|
|
|
memcpy(m_landTrampolineAddr, PROBEFIXEDASM.bytes.data(), HOOKSIZE); // first, original but fixed func bytes
|
|
|
|
|
memcpy(sc<uint8_t*>(m_landTrampolineAddr) + HOOKSIZE, RELATIVE_JMP_ADDRESS, sizeof(RELATIVE_JMP_ADDRESS)); // then, jump to source
|
|
|
|
|
|
|
|
|
|
// populate short jump addr
|
|
|
|
|
*rc<int32_t*>(sc<uint8_t*>(m_landTrampolineAddr) + TRAMPOLINE_SIZE - sizeof(RELATIVE_JMP_ADDRESS) + RELATIVE_JMP_ADDRESS_OFFSET) =
|
|
|
|
|
sc<int64_t>((sc<uint8_t*>(m_source) + probe.len) // jump to source + probe len (skip header)
|
|
|
|
|
- (sc<uint8_t*>(m_landTrampolineAddr) + TRAMPOLINE_SIZE) // from trampo + size - jmp (not - size because jmp is rel to rip after instr)
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
// populate launch trampoline
|
|
|
|
|
memcpy(m_launchTrampolineAddr, ABSOLUTE_JMP_ADDRESS, sizeof(ABSOLUTE_JMP_ADDRESS)); // long jump to our hk
|
2023-02-27 12:32:38 +00:00
|
|
|
|
2025-10-07 12:37:21 +01:00
|
|
|
// populate long jump addr
|
|
|
|
|
*rc<uint64_t*>(sc<uint8_t*>(m_launchTrampolineAddr) + ABSOLUTE_JMP_ADDRESS_OFFSET) = rc<uint64_t>(m_destination); // long jump to hk fn
|
2023-02-27 12:32:38 +00:00
|
|
|
|
2025-10-07 12:37:21 +01:00
|
|
|
// make short jump to launch trampoile
|
2024-01-01 17:05:26 -05:00
|
|
|
const auto PAGESIZE_VAR = sysconf(_SC_PAGE_SIZE);
|
2025-08-14 19:44:56 +05:00
|
|
|
const uint8_t* PROTSTART = sc<uint8_t*>(m_source) - (rc<uint64_t>(m_source) % PAGESIZE_VAR);
|
|
|
|
|
const size_t PROTLEN = std::ceil(sc<float>(ORIGSIZE + (rc<uint64_t>(m_source) - rc<uint64_t>(PROTSTART))) / sc<float>(PAGESIZE_VAR)) * PAGESIZE_VAR;
|
|
|
|
|
mprotect(const_cast<uint8_t*>(PROTSTART), PROTLEN, PROT_READ | PROT_WRITE | PROT_EXEC);
|
2025-10-07 12:37:21 +01:00
|
|
|
memcpy(m_source, RELATIVE_JMP_ADDRESS, sizeof(RELATIVE_JMP_ADDRESS));
|
2023-02-27 12:32:38 +00:00
|
|
|
|
2025-10-07 12:37:21 +01:00
|
|
|
size_t currentOp = sizeof(RELATIVE_JMP_ADDRESS);
|
2025-08-14 19:44:56 +05:00
|
|
|
memset(sc<uint8_t*>(m_source) + currentOp, NOP, ORIGSIZE - currentOp);
|
2023-02-27 12:32:38 +00:00
|
|
|
|
2025-10-07 12:37:21 +01:00
|
|
|
// populate short jump addr
|
|
|
|
|
*rc<int32_t*>(sc<uint8_t*>(m_source) + RELATIVE_JMP_ADDRESS_OFFSET) = sc<int32_t>( //
|
|
|
|
|
rc<uint64_t>(m_launchTrampolineAddr) // jump to the launch trampoline which jumps to hk
|
|
|
|
|
- (rc<uint64_t>(m_source) + 5) // from source
|
|
|
|
|
);
|
2023-02-27 12:32:38 +00:00
|
|
|
|
|
|
|
|
// revert mprot
|
2025-08-14 19:44:56 +05:00
|
|
|
mprotect(const_cast<uint8_t*>(PROTSTART), PROTLEN, PROT_READ | PROT_EXEC);
|
2023-02-27 12:32:38 +00:00
|
|
|
|
2025-10-07 12:37:21 +01:00
|
|
|
// set original addr to land trampo addr
|
|
|
|
|
m_original = m_landTrampolineAddr;
|
2023-02-27 12:32:38 +00:00
|
|
|
|
2025-10-07 12:37:21 +01:00
|
|
|
m_active = true;
|
|
|
|
|
m_hookLen = ORIGSIZE;
|
2023-02-27 12:32:38 +00:00
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool CFunctionHook::unhook() {
|
|
|
|
|
// check for unsupported platforms
|
|
|
|
|
#if !defined(__x86_64__)
|
|
|
|
|
return false;
|
|
|
|
|
#endif
|
|
|
|
|
|
2025-05-03 16:06:24 +02:00
|
|
|
if (!m_active)
|
2023-02-27 12:32:38 +00:00
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
// allow write to src
|
2025-08-14 19:44:56 +05:00
|
|
|
mprotect(sc<uint8_t*>(m_source) - rc<uint64_t>(m_source) % sysconf(_SC_PAGE_SIZE), sysconf(_SC_PAGE_SIZE), PROT_READ | PROT_WRITE | PROT_EXEC);
|
2023-02-27 12:32:38 +00:00
|
|
|
|
|
|
|
|
// write back original bytes
|
2025-06-19 11:58:07 +02:00
|
|
|
memcpy(m_source, m_originalBytes.data(), m_hookLen);
|
2023-02-27 12:32:38 +00:00
|
|
|
|
|
|
|
|
// revert mprot
|
2025-08-14 19:44:56 +05:00
|
|
|
mprotect(sc<uint8_t*>(m_source) - rc<uint64_t>(m_source) % sysconf(_SC_PAGE_SIZE), sysconf(_SC_PAGE_SIZE), PROT_READ | PROT_EXEC);
|
2023-02-27 12:32:38 +00:00
|
|
|
|
|
|
|
|
// reset vars
|
2025-10-07 12:37:21 +01:00
|
|
|
m_active = false;
|
|
|
|
|
m_hookLen = 0;
|
|
|
|
|
m_landTrampolineAddr = nullptr; // no unmapping, it's managed by the HookSystem
|
|
|
|
|
m_launchTrampolineAddr = nullptr; // no unmapping, it's managed by the HookSystem
|
|
|
|
|
m_original = nullptr;
|
2025-06-19 11:58:07 +02:00
|
|
|
m_originalBytes.clear();
|
2023-02-27 12:32:38 +00:00
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
CFunctionHook* CHookSystem::initHook(HANDLE owner, void* source, void* destination) {
|
2025-05-03 16:06:24 +02:00
|
|
|
return m_hooks.emplace_back(makeUnique<CFunctionHook>(owner, source, destination)).get();
|
2023-02-27 12:32:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool CHookSystem::removeHook(CFunctionHook* hook) {
|
2025-05-03 16:06:24 +02:00
|
|
|
std::erase_if(m_hooks, [&](const auto& other) { return other.get() == hook; });
|
2023-02-27 12:32:38 +00:00
|
|
|
return true; // todo: make false if not found
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CHookSystem::removeAllHooksFrom(HANDLE handle) {
|
2025-05-03 16:06:24 +02:00
|
|
|
std::erase_if(m_hooks, [&](const auto& other) { return other->m_owner == handle; });
|
2023-03-04 15:02:40 +01:00
|
|
|
}
|
2024-04-04 18:50:37 +01:00
|
|
|
|
|
|
|
|
static uintptr_t seekNewPageAddr() {
|
|
|
|
|
const uint64_t PAGESIZE_VAR = sysconf(_SC_PAGE_SIZE);
|
|
|
|
|
auto MAPS = std::ifstream("/proc/self/maps");
|
|
|
|
|
|
|
|
|
|
uint64_t lastStart = 0, lastEnd = 0;
|
|
|
|
|
|
2024-12-26 11:29:42 +01:00
|
|
|
bool anchoredToHyprland = false;
|
|
|
|
|
|
2024-04-04 18:50:37 +01:00
|
|
|
std::string line;
|
|
|
|
|
while (std::getline(MAPS, line)) {
|
|
|
|
|
CVarList props{line, 0, 's', true};
|
|
|
|
|
|
|
|
|
|
uint64_t start = 0, end = 0;
|
|
|
|
|
if (props[0].empty()) {
|
|
|
|
|
Debug::log(WARN, "seekNewPageAddr: unexpected line in self maps");
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
CVarList startEnd{props[0], 0, '-', true};
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
start = std::stoull(startEnd[0], nullptr, 16);
|
|
|
|
|
end = std::stoull(startEnd[1], nullptr, 16);
|
|
|
|
|
} catch (std::exception& e) {
|
|
|
|
|
Debug::log(WARN, "seekNewPageAddr: unexpected line in self maps: {}", line);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Debug::log(LOG, "seekNewPageAddr: page 0x{:x} - 0x{:x}", start, end);
|
|
|
|
|
|
|
|
|
|
if (lastStart == 0) {
|
|
|
|
|
lastStart = start;
|
|
|
|
|
lastEnd = end;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
2025-10-14 13:39:22 +01:00
|
|
|
if (!anchoredToHyprland && line.contains("Hyprland")) {
|
|
|
|
|
Debug::log(LOG, "seekNewPageAddr: Anchored to hyprland at 0x{:x}", start);
|
|
|
|
|
anchoredToHyprland = true;
|
|
|
|
|
} else if (start - lastEnd > PAGESIZE_VAR * 2) {
|
|
|
|
|
if (!anchoredToHyprland) {
|
2024-12-26 11:29:42 +01:00
|
|
|
Debug::log(LOG, "seekNewPageAddr: skipping gap 0x{:x}-0x{:x}, not anchored to Hyprland code pages yet.", lastEnd, start);
|
|
|
|
|
lastStart = start;
|
|
|
|
|
lastEnd = end;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
2024-04-04 18:50:37 +01:00
|
|
|
Debug::log(LOG, "seekNewPageAddr: found gap: 0x{:x}-0x{:x} ({} bytes)", lastEnd, start, start - lastEnd);
|
|
|
|
|
MAPS.close();
|
|
|
|
|
return lastEnd;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
lastStart = start;
|
|
|
|
|
lastEnd = end;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
MAPS.close();
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
uint64_t CHookSystem::getAddressForTrampo() {
|
|
|
|
|
// yes, technically this creates a memory leak of 64B every hook creation. But I don't care.
|
|
|
|
|
// tracking all the users of the memory would be painful.
|
2024-04-05 13:56:53 +02:00
|
|
|
// Nobody will hook 100k times, and even if, that's only 6.4 MB. Nothing.
|
2024-04-04 18:50:37 +01:00
|
|
|
|
|
|
|
|
SAllocatedPage* page = nullptr;
|
2025-05-03 16:06:24 +02:00
|
|
|
for (auto& p : m_pages) {
|
2024-04-04 18:50:37 +01:00
|
|
|
if (p.used + HOOK_TRAMPOLINE_MAX_SIZE > p.len)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
page = &p;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!page)
|
2025-05-03 16:06:24 +02:00
|
|
|
page = &m_pages.emplace_back();
|
2024-04-04 18:50:37 +01:00
|
|
|
|
|
|
|
|
if (!page->addr) {
|
|
|
|
|
// allocate it
|
|
|
|
|
Debug::log(LOG, "getAddressForTrampo: Allocating new page for hooks");
|
|
|
|
|
const uint64_t PAGESIZE_VAR = sysconf(_SC_PAGE_SIZE);
|
|
|
|
|
const auto BASEPAGEADDR = seekNewPageAddr();
|
|
|
|
|
for (int attempt = 0; attempt < 2; ++attempt) {
|
2024-04-05 17:16:09 +01:00
|
|
|
for (int i = 0; i <= 2; ++i) {
|
2024-04-04 18:50:37 +01:00
|
|
|
const auto PAGEADDR = BASEPAGEADDR + i * PAGESIZE_VAR;
|
|
|
|
|
|
2025-08-14 19:44:56 +05:00
|
|
|
page->addr = rc<uint64_t>(mmap(rc<void*>(PAGEADDR), PAGESIZE_VAR, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0));
|
2024-04-04 18:50:37 +01:00
|
|
|
page->len = PAGESIZE_VAR;
|
|
|
|
|
page->used = 0;
|
|
|
|
|
|
|
|
|
|
Debug::log(LOG, "Attempted to allocate 0x{:x}, got 0x{:x}", PAGEADDR, page->addr);
|
|
|
|
|
|
2025-08-14 19:44:56 +05:00
|
|
|
if (page->addr == rc<uint64_t>(MAP_FAILED))
|
2024-04-04 18:50:37 +01:00
|
|
|
continue;
|
|
|
|
|
if (page->addr != PAGEADDR && attempt == 0) {
|
2025-08-14 19:44:56 +05:00
|
|
|
munmap(rc<void*>(page->addr), PAGESIZE_VAR);
|
2024-04-04 18:50:37 +01:00
|
|
|
page->addr = 0;
|
|
|
|
|
page->len = 0;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
if (page->addr)
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const auto ADDRFORCONSUMER = page->addr + page->used;
|
|
|
|
|
|
|
|
|
|
page->used += HOOK_TRAMPOLINE_MAX_SIZE;
|
|
|
|
|
|
|
|
|
|
Debug::log(LOG, "getAddressForTrampo: Returning addr 0x{:x} for page at 0x{:x}", ADDRFORCONSUMER, page->addr);
|
|
|
|
|
|
|
|
|
|
return ADDRFORCONSUMER;
|
2025-01-17 15:21:35 +00:00
|
|
|
}
|