From dd22fc4aa978da6a38eacfb28cb25ba37681ba77 Mon Sep 17 00:00:00 2001 From: keowu Date: Wed, 16 Jul 2025 21:09:22 -0300 Subject: [PATCH] feat: Break Decompilers and Disassemblers feature - Ryujin can now break decompilers and disassemblers using a simple technique. This feature was inspired by a talk from BinjaDev at Off by One Conf. It will definitely be improved in the near future with more techniques. --- README.md | 2 +- .../RyujinCore/RyujinObfuscationCore.cc | 34 +++++++++++++++++++ .../RyujinCore/RyujinObfuscationCore.hh | 1 + 3 files changed, 36 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index ab25920..3df771d 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ - Anti-Debug User + Kernel - Troll Reversers(Exclusive) - Anti-Dump -- Anti-Disassembly(Planned - **TODO**) +- Anti-Disassembly + Anti-Decompiler - Custom Passes(Planned - **TODO**) --- diff --git a/RyujinCore/Ryujin/RyujinCore/RyujinObfuscationCore.cc b/RyujinCore/Ryujin/RyujinCore/RyujinObfuscationCore.cc index fd4edb7..c122c42 100644 --- a/RyujinCore/Ryujin/RyujinCore/RyujinObfuscationCore.cc +++ b/RyujinCore/Ryujin/RyujinCore/RyujinObfuscationCore.cc @@ -183,6 +183,9 @@ void RyujinObfuscationCore::obfuscateIat() { code.init(runtime.environment()); asmjit::x86::Assembler a(&code); + // Breaking Decompilers + insertBreakDecompilers(a); + // Using `rdgsbase rax` to store the base address of the GS segment in RAX -> rdgsbase rax a.emit(asmjit::x86::Inst::kIdRdgsbase, asmjit::x86::rax); @@ -216,6 +219,9 @@ void RyujinObfuscationCore::obfuscateIat() { // call rax -> Calling the IAT a.call(asmjit::x86::rax); + // Breaking Decompilers + insertBreakDecompilers(a); + // Obtaining the new section buffer auto& opcodeBuffer = code.sectionById(0)->buffer(); // Obtaining the pointer to the buffer of raw opcode data generated @@ -780,6 +786,9 @@ void RyujinObfuscationCore::insertVirtualization() { code.init(runtime.environment()); asmjit::x86::Assembler a(&code); + // Breaking Decompilers + insertBreakDecompilers(a); + // Saving the current value of RCX a.push(asmjit::x86::rcx); // Saving the current value of RDX @@ -815,6 +824,9 @@ void RyujinObfuscationCore::insertVirtualization() { // Restoring the original value of RCX a.pop(asmjit::x86::rcx); + // Breaking Decompilers + insertBreakDecompilers(a); + // Retrieving from ASMJIT’s JIT the resulting opcodes generated by our algorithm auto& opcodeBuffer = code.sectionById(0)->buffer(); const auto pOpcodeBuffer = opcodeBuffer.data(); @@ -1573,6 +1585,9 @@ void RyujinObfuscationCore::insertAntiDebug() { a.pop(asmjit::x86::rcx); a.pop(asmjit::x86::rax); + // Breaking Decompilers + insertBreakDecompilers(a); + // pop RFLAGS a.popfq(); @@ -1900,6 +1915,9 @@ void RyujinObfuscationCore::insertAntiDump() { a.pop(asmjit::x86::rcx); a.pop(asmjit::x86::rax); + // Breaking Decompilers + insertBreakDecompilers(a); + // pop RFLAGS a.popfq(); @@ -1931,6 +1949,22 @@ void RyujinObfuscationCore::updateBasicBlocksContext() { } +void RyujinObfuscationCore::insertBreakDecompilers(asmjit::x86::Assembler& a) { + + //Breaking Decompilers(https://youtu.be/6UlxrDYng88?t=1287) + a.push(asmjit::x86::rbx); + + std::vector breakDecompilerOneByteTrick{ + + 0xEB, 0xFF, 0xC3 + + }; + a.embed(breakDecompilerOneByteTrick.data(), breakDecompilerOneByteTrick.size()); + + a.pop(asmjit::x86::rbx); + +} + BOOL RyujinObfuscationCore::Run(bool& RyujinRunOncePass) { //Add padding spaces diff --git a/RyujinCore/Ryujin/RyujinCore/RyujinObfuscationCore.hh b/RyujinCore/Ryujin/RyujinCore/RyujinObfuscationCore.hh index 86bb376..008be33 100644 --- a/RyujinCore/Ryujin/RyujinCore/RyujinObfuscationCore.hh +++ b/RyujinCore/Ryujin/RyujinCore/RyujinObfuscationCore.hh @@ -31,6 +31,7 @@ private: void insertVirtualization(); void insertAntiDebug(); void insertAntiDump(); + void insertBreakDecompilers(asmjit::x86::Assembler& a); std::vector fix_branch_near_far_short(uint8_t original_opcode, uint64_t jmp_address, uint64_t target_address); uint32_t findOpcodeOffset(const uint8_t* data, size_t dataSize, const void* opcode, size_t opcodeSize);