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:
@@ -159,7 +159,7 @@ void RyujinObfuscationCore::obfuscateIat() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return std::make_pair(-1, -1);
|
return std::make_pair(-1, -1);
|
||||||
};
|
};
|
||||||
|
|
||||||
for (auto& block : m_obfuscated_bb) {
|
for (auto& block : m_obfuscated_bb) {
|
||||||
|
|
||||||
@@ -186,22 +186,75 @@ void RyujinObfuscationCore::obfuscateIat() {
|
|||||||
const uintptr_t next_instruction_address = orInstr.addressofinstruction + orInstr.instruction.info.length;
|
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
|
// 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
|
// A new vector to store our corrected IAT
|
||||||
std::vector<ZyanU8> new_iat_call;
|
std::vector<ZyanU8> new_iat_call;
|
||||||
|
|
||||||
unsigned char pebRecoverModuleBase[24]{
|
//Begin ASMJIT configuration
|
||||||
0x65, 0x48, 0x8B, 0x04, 0x25, 0x60, 0x00, 0x00, 0x00, // mov rax, gs:60h
|
asmjit::JitRuntime runtime;
|
||||||
0x48, 0x8B, 0x40, 0x10, // mov rax, qword ptr ds:[rax+0x10]
|
asmjit::CodeHolder code;
|
||||||
0x48, 0x05, 0x00, 0x00, 0x00, 0x00, // add rax, 22228h
|
code.init(runtime.environment());
|
||||||
0x48, 0x8B, 0x00, //mov rax, qword ptr ds:[rax] -> Recover the IAT jump value stored in the data segment
|
asmjit::x86::Assembler a(&code);
|
||||||
0xFF, 0xD0//call rax
|
|
||||||
};
|
|
||||||
|
|
||||||
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
|
// Replacing opcodes of the call in question with the new ones
|
||||||
data.assign(new_iat_call.begin(), new_iat_call.end());
|
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_isJunkCode) todoAction();
|
||||||
|
if (config.m_isVirtualized) todoAction();
|
||||||
*/
|
*/
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
|||||||
@@ -3,6 +3,8 @@
|
|||||||
#include <vector>
|
#include <vector>
|
||||||
#include <set>
|
#include <set>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
#include <random>
|
||||||
|
#include <functional>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include <asmjit/asmjit.h>
|
#include <asmjit/asmjit.h>
|
||||||
#include <Zydis/Zydis.h>
|
#include <Zydis/Zydis.h>
|
||||||
|
|||||||
Reference in New Issue
Block a user