mirror of
https://github.com/hyprwm/Hyprland
synced 2024-11-22 17:25:59 +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 ''
|
${lib.optionalString wrapRuntimeDeps ''
|
||||||
wrapProgram $out/bin/Hyprland \
|
wrapProgram $out/bin/Hyprland \
|
||||||
--suffix PATH : ${lib.makeBinPath [
|
--suffix PATH : ${lib.makeBinPath [
|
||||||
stdenv.cc
|
|
||||||
binutils
|
binutils
|
||||||
pciutils
|
pciutils
|
||||||
pkgconf
|
pkgconf
|
||||||
|
|
|
@ -76,62 +76,56 @@ CFunctionHook::SAssembly CFunctionHook::fixInstructionProbeRIPCalls(const SInstr
|
||||||
// actually newline + 1
|
// actually newline + 1
|
||||||
size_t lastAsmNewline = 0;
|
size_t lastAsmNewline = 0;
|
||||||
// needle for destination binary
|
// needle for destination binary
|
||||||
size_t currentDestinationOffset = 0;
|
size_t currentDestinationOffset = 0;
|
||||||
std::string assemblyBuilder;
|
|
||||||
|
std::vector<char> finalBytes;
|
||||||
|
finalBytes.resize(probe.len);
|
||||||
|
|
||||||
for (auto& len : probe.insSizes) {
|
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);
|
std::string code = probe.assembly.substr(lastAsmNewline, probe.assembly.find("\n", lastAsmNewline) - lastAsmNewline);
|
||||||
if (code.contains("%rip")) {
|
if (code.contains("%rip")) {
|
||||||
CVarList tokens{code, 0, 's'};
|
CVarList tokens{code, 0, 's'};
|
||||||
size_t plusPresent = tokens[1][0] == '+' ? 1 : 0;
|
size_t plusPresent = tokens[1][0] == '+' ? 1 : 0;
|
||||||
size_t minusPresent = 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));
|
std::string addr = tokens[1].substr((plusPresent || minusPresent), tokens[1].find("(%rip)") - (plusPresent || minusPresent));
|
||||||
const uint64_t OFFSET = (minusPresent ? -1 : 1) * configStringToInt(addr);
|
const int32_t OFFSET = (minusPresent ? -1 : 1) * configStringToInt(addr);
|
||||||
if (OFFSET == 0)
|
if (OFFSET == 0)
|
||||||
return {};
|
return {};
|
||||||
const uint64_t DESTINATION = currentAddress + OFFSET + len;
|
const uint64_t DESTINATION = currentAddress + OFFSET + len;
|
||||||
|
|
||||||
if (code.starts_with("call")) {
|
auto ADDREND = code.find("(%rip)");
|
||||||
// call +0xdeadbeef(%rip)
|
auto ADDRSTART = (code.substr(0, ADDREND).find_last_of(' '));
|
||||||
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)
|
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);
|
|
||||||
return {};
|
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 {
|
} else {
|
||||||
assemblyBuilder += code + "\n";
|
|
||||||
currentDestinationOffset += len;
|
currentDestinationOffset += len;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -139,38 +133,7 @@ CFunctionHook::SAssembly CFunctionHook::fixInstructionProbeRIPCalls(const SInstr
|
||||||
currentAddress += len;
|
currentAddress += len;
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto RANDOMDIR = g_pCompositor->m_szInstancePath + "/" + g_pTokenManager->getRandomUUID();
|
return {finalBytes};
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CFunctionHook::hook() {
|
bool CFunctionHook::hook() {
|
||||||
|
|
Loading…
Reference in a new issue