aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorVaxry <[email protected]>2024-04-29 15:55:44 +0100
committerVaxry <[email protected]>2024-04-29 15:55:44 +0100
commit0c0907cfafa46dc0d26aed30361e2c00c35dcf6c (patch)
treedf7395538532fa2dc2051e1970791939ad2dfc15
parent33e0bb14786dc22a0c82eaaf097b469d3fdeceea (diff)
downloadHyprland-0c0907cfafa46dc0d26aed30361e2c00c35dcf6c.tar.gz
Hyprland-0c0907cfafa46dc0d26aed30361e2c00c35dcf6c.zip
Remove dependency on cc from the hooksystem
-rw-r--r--src/plugins/HookSystem.cpp117
1 files changed, 40 insertions, 77 deletions
diff --git a/src/plugins/HookSystem.cpp b/src/plugins/HookSystem.cpp
index 2fee1bc5..84faec4e 100644
--- a/src/plugins/HookSystem.cpp
+++ b/src/plugins/HookSystem.cpp
@@ -76,62 +76,56 @@ CFunctionHook::SAssembly CFunctionHook::fixInstructionProbeRIPCalls(const SInstr
// actually newline + 1
size_t lastAsmNewline = 0;
// needle for destination binary
- size_t currentDestinationOffset = 0;
- std::string assemblyBuilder;
+ size_t currentDestinationOffset = 0;
+
+ std::vector<char> finalBytes;
+ finalBytes.resize(probe.len);
+
for (auto& len : probe.insSizes) {
+ // copy original bytes to our finalBytes
+ for (size_t i = 0; i < len; ++i) {
+ finalBytes[currentDestinationOffset + i] = *(char*)(currentAddress + i);
+ }
+
std::string code = probe.assembly.substr(lastAsmNewline, probe.assembly.find("\n", lastAsmNewline) - lastAsmNewline);
if (code.contains("%rip")) {
- 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));
- const uint64_t OFFSET = (minusPresent ? -1 : 1) * configStringToInt(addr);
+ 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));
+ const int32_t OFFSET = (minusPresent ? -1 : 1) * configStringToInt(addr);
if (OFFSET == 0)
return {};
const uint64_t DESTINATION = currentAddress + OFFSET + len;
- if (code.starts_with("call")) {
- // call +0xdeadbeef(%rip)
- assemblyBuilder += std::format("pushq %rax\nmovabs $0x{:x}, %rax\ncallq *%rax\npopq %rax\n", DESTINATION);
- currentDestinationOffset += 14;
- } else if (code.starts_with("lea")) {
- // lea 0xdeadbeef(%rip), %rax
- assemblyBuilder += std::format("movabs $0x{:x}, {}\n", DESTINATION, tokens[2]);
- currentDestinationOffset += 10;
- } else {
- auto ADDREND = code.find("(%rip)");
- auto ADDRSTART = (code.substr(0, ADDREND).find_last_of(' '));
-
- if (ADDREND == std::string::npos || ADDRSTART == std::string::npos)
- return {};
-
- const uint64_t PREDICTEDRIP = (uint64_t)m_pTrampolineAddr + currentDestinationOffset + len;
- const bool POSITIVE = DESTINATION > PREDICTEDRIP;
- const uint64_t NEWRIPOFFSET = POSITIVE ? DESTINATION - PREDICTEDRIP : PREDICTEDRIP - DESTINATION;
-
- assemblyBuilder += std::format("{} {}0x{:x}{}\n", code.substr(0, ADDRSTART), POSITIVE ? '+' : '-', NEWRIPOFFSET, code.substr(ADDREND));
- currentDestinationOffset += len;
- }
- } else if (code.contains("invalid")) {
- std::vector<uint8_t> bytes;
- bytes.resize(len);
- memcpy(bytes.data(), (std::byte*)currentAddress, len);
- if (len == 4 && bytes[0] == 0xF3 && bytes[1] == 0x0F && bytes[2] == 0x1E && bytes[3] == 0xFA) {
- // F3 0F 1E FA = endbr64, udis doesn't understand that one
- assemblyBuilder += "endbr64\n";
- currentDestinationOffset += 4;
- } else {
- // raise error, unknown op
- std::string strBytes;
- for (auto& b : bytes) {
- strBytes += std::format("{:x} ", b);
- }
- Debug::log(ERR, "[functionhook] unknown bytes: {}", strBytes);
+ auto ADDREND = code.find("(%rip)");
+ auto ADDRSTART = (code.substr(0, ADDREND).find_last_of(' '));
+
+ if (ADDREND == std::string::npos || ADDRSTART == std::string::npos)
return {};
+
+ const uint64_t PREDICTEDRIP = (uint64_t)m_pTrampolineAddr + currentDestinationOffset + len;
+ 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) {
+ if (*(int32_t*)(currentAddress + i) == OFFSET) {
+ ripOffset = i;
+ break;
+ }
}
+
+ if (ripOffset == 0)
+ return {};
+
+ // fix offset in the final bytes. This doesn't care about endianness
+ *(int32_t*)&finalBytes[currentDestinationOffset + ripOffset] = NEWRIPOFFSET;
+
+ currentDestinationOffset += len;
} else {
- assemblyBuilder += code + "\n";
currentDestinationOffset += len;
}
@@ -139,38 +133,7 @@ CFunctionHook::SAssembly CFunctionHook::fixInstructionProbeRIPCalls(const SInstr
currentAddress += len;
}
- const auto RANDOMDIR = g_pCompositor->m_szInstancePath + "/" + g_pTokenManager->getRandomUUID();
-
- if (std::filesystem::exists(RANDOMDIR)) {
- Debug::log(ERR, "[hooksystem] random out dir exists??");
- return {};
- }
-
- if (mkdir(RANDOMDIR.c_str(), S_IRWXU) < 0)
- return {};
-
- if (!std::filesystem::exists(RANDOMDIR))
- return {};
-
- std::ofstream ofs(RANDOMDIR + "/.hookcode.asm", std::ios::trunc);
- ofs << assemblyBuilder;
- ofs.close();
- std::string ret = execAndGet(std::string{"cc -x assembler -c " + RANDOMDIR + "/.hookcode.asm -o " + RANDOMDIR + "/.hookbinary.o 2>&1 && objcopy -O binary -j .text " +
- RANDOMDIR + "/.hookbinary.o " + RANDOMDIR + "/.hookbinary2.o 2>&1"}
- .c_str());
- Debug::log(LOG, "[functionhook] assembler returned:\n{}", ret);
- if (!std::filesystem::exists(RANDOMDIR + "/.hookbinary2.o")) {
- std::filesystem::remove(RANDOMDIR + "/.hookcode.asm");
- std::filesystem::remove(RANDOMDIR + "/.hookbinary.asm");
- return {};
- }
-
- std::ifstream ifs(RANDOMDIR + "/.hookbinary2.o", std::ios::binary);
- returns = {std::vector<char>(std::istreambuf_iterator<char>(ifs), {})};
- ifs.close();
- std::filesystem::remove_all(RANDOMDIR);
-
- return returns;
+ return {finalBytes};
}
bool CFunctionHook::hook() {