feat: Finalized IAT Obfuscation Feature Implementation

- Completed the implementation of the IAT obfuscation logic.
- Integrated AsmJit-based code emission for obfuscation.
- Obfuscated the PEB and its offset entries to evade automated scanning.
 - Added a randomized algorithm to generate a unique key for each iteration.
- Implemented runtime polymorphic IAT resolution to disrupt disassemblers and decompilers.
This commit is contained in:
keowu
2025-06-08 11:45:59 -03:00
parent 351756a1b4
commit 21cd08a327
2 changed files with 82 additions and 28 deletions

View File

@@ -186,22 +186,75 @@ void RyujinObfuscationCore::obfuscateIat() {
const uintptr_t next_instruction_address = orInstr.addressofinstruction + orInstr.instruction.info.length;
// Calculating the target address of the IAT using the memory immediate from the original instruction
const uint32_t iat_target_rva = (next_instruction_address + orInstr.instruction.operands->mem.disp.value) - m_ProcImageBase;
uint32_t iat_target_rva = (next_instruction_address + orInstr.instruction.operands->mem.disp.value) - m_ProcImageBase;
/*
Let's obfuscate our RVA
*/
// Generating two random bytes for the key
std::mt19937 rng(std::random_device{}());
// A single random value of 2 bytes (uint16_t)
std::uniform_int_distribution<uint16_t> dist(0, 0xFFFF);
uint16_t xorKey = dist(rng);
// Obfsucate the RVA with a XOR
iat_target_rva ^= xorKey;
// Obfuscate PEB offset from automatic scan
unsigned char PebGsOffset = 0x60 ^ (xorKey & 0xFF);
unsigned char ImageBasePeb = 0x10 ^ (xorKey & 0xFF);
// A new vector to store our corrected IAT
std::vector<ZyanU8> new_iat_call;
unsigned char pebRecoverModuleBase[24]{
0x65, 0x48, 0x8B, 0x04, 0x25, 0x60, 0x00, 0x00, 0x00, // mov rax, gs:60h
0x48, 0x8B, 0x40, 0x10, // mov rax, qword ptr ds:[rax+0x10]
0x48, 0x05, 0x00, 0x00, 0x00, 0x00, // add rax, 22228h
0x48, 0x8B, 0x00, //mov rax, qword ptr ds:[rax] -> Recover the IAT jump value stored in the data segment
0xFF, 0xD0//call rax
};
//Begin ASMJIT configuration
asmjit::JitRuntime runtime;
asmjit::CodeHolder code;
code.init(runtime.environment());
asmjit::x86::Assembler a(&code);
std::memcpy(&*(pebRecoverModuleBase + 15), &iat_target_rva, sizeof(uint32_t));
// 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);
new_iat_call.insert(new_iat_call.end(), std::begin(pebRecoverModuleBase), std::end(pebRecoverModuleBase));
// Adding the obfuscated offset of the PEB in the GS segment -> add rax, PebGsOffset
a.add(asmjit::x86::rax, PebGsOffset);
// Undoing the XOR operation with the obfuscated RAX value and the XOR key -> xor rax, lastByteXorKey
a.xor_(asmjit::x86::rax, asmjit::imm(xorKey & 0xFF));
// Accessing the resulting address to retrieve the PEB instance -> mov rax, [rax]
a.mov(asmjit::x86::rax, asmjit::x86::ptr(asmjit::x86::rax));
// Adding the obfuscated offset of the ImageBase field in the PEB -> add rax, ImageBasePeb
a.add(asmjit::x86::rax, ImageBasePeb);
// Undoing the XOR operation with the obfuscated value and the XOR key -> xor rax, lastByteXorKey
a.xor_(asmjit::x86::rax, asmjit::imm(xorKey & 0xFF));
// Accessing the resulting address to retrieve the PEB+ImageBase instance -> mov rax, [rax]
a.mov(asmjit::x86::rax, asmjit::x86::ptr(asmjit::x86::rax));
// Adding the RVA that points to the entry in the IAT -> add rax, imm32 -> Adding the offset of the IAT entry
a.add(asmjit::x86::rax, asmjit::imm(iat_target_rva));
// Undoing the XOR operation with the obfuscated value and the XOR key -> xor rax, xorKey
a.xor_(asmjit::x86::rax, asmjit::imm(xorKey));
// mov rax, [rax] -> retrieving the resolved address for the IAT entry by the OS loader
a.mov(asmjit::x86::rax, asmjit::x86::ptr(asmjit::x86::rax));
// call rax -> Calling the IAT
a.call(asmjit::x86::rax);
// Obtaining the new section buffer
auto& opcodeBuffer = code.sectionById(0)->buffer();
// Obtaining the pointer to the buffer of raw opcode data generated
const auto pOpcodeBuffer = opcodeBuffer.data();
// Reserving space in the IAT vector
new_iat_call.reserve(opcodeBuffer.size());
// Storing each opcode individually in the vector for our new IAT call
for (auto i = 0; i < opcodeBuffer.size(); ++i) new_iat_call.push_back(static_cast<ZyanU8>(pOpcodeBuffer[i]));
// Replacing opcodes of the call in question with the new ones
data.assign(new_iat_call.begin(), new_iat_call.end());
@@ -245,9 +298,8 @@ BOOL RyujinObfuscationCore::Run() {
}
/*
if (config.m_isVirtualized) todoAction();
if (config.m_isJunkCode) todoAction();
if (config.m_isVirtualized) todoAction();
*/
return TRUE;

View File

@@ -3,6 +3,8 @@
#include <vector>
#include <set>
#include <cstdint>
#include <random>
#include <functional>
#include <unordered_map>
#include <asmjit/asmjit.h>
#include <Zydis/Zydis.h>