mirror of
https://github.com/hyprwm/Hyprland
synced 2024-12-22 14:09:48 +01:00
pluginAPI/hooks: Remove dependency on cc from the hooksystem (#5801)
* Remove dependency on cc from the hooksystem * Nix: remove cc from wrapper --------- Co-authored-by: Mihai Fufezan <mihai@fufexan.net>
This commit is contained in:
parent
5edc32930d
commit
62ae2b3f40
2 changed files with 39 additions and 77 deletions
|
@ -148,7 +148,6 @@ in
|
|||
${lib.optionalString wrapRuntimeDeps ''
|
||||
wrapProgram $out/bin/Hyprland \
|
||||
--suffix PATH : ${lib.makeBinPath [
|
||||
stdenv.cc
|
||||
binutils
|
||||
pciutils
|
||||
pkgconf
|
||||
|
|
|
@ -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(' '));
|
||||
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);
|
||||
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() {
|
||||
|
|
Loading…
Reference in a new issue