diff --git a/ObfuGuard/ObfuGuard.vcxproj b/ObfuGuard/ObfuGuard.vcxproj
index 99631ee..1718ca8 100644
--- a/ObfuGuard/ObfuGuard.vcxproj
+++ b/ObfuGuard/ObfuGuard.vcxproj
@@ -164,6 +164,7 @@
+
diff --git a/ObfuGuard/ObfuGuard.vcxproj.filters b/ObfuGuard/ObfuGuard.vcxproj.filters
index a26b56b..211a3a4 100644
--- a/ObfuGuard/ObfuGuard.vcxproj.filters
+++ b/ObfuGuard/ObfuGuard.vcxproj.filters
@@ -74,6 +74,9 @@
+
+ Header Files
+
Header Files\pe
diff --git a/ObfuGuard/cfflattening/cfflattening.cpp b/ObfuGuard/cfflattening/cfflattening.cpp
index 0a9767f..8202697 100644
--- a/ObfuGuard/cfflattening/cfflattening.cpp
+++ b/ObfuGuard/cfflattening/cfflattening.cpp
@@ -111,7 +111,7 @@ bool obfuscatecff::apply_control_flow_flattening(std::vectorfunc_id, { 0x50 });
push_rax.inst_id = first_inst_id;
- push_rax.is_first_instruction = false;
+ push_rax.is_first_instruction = true;
auto it = func->instructions.insert(func->instructions.begin(), push_rax);
instruction_t push_f{}; push_f.load(func->func_id, { 0x66, 0x9C });
it = func->instructions.insert(it + 1, push_f);
@@ -196,6 +196,8 @@ bool obfuscatecff::apply_control_flow_flattening(std::vectorinstructions.end() - 1)->inst_id;
});
+ if (last_inst == func->instructions.end()) continue;
+
// Find the next block in the execution chain
auto next_block_iter = std::find_if(blocks.begin(), blocks.end(),
[&](const basic_block& blk) { return blk.block_id == block_iter->next_block; });
diff --git a/ObfuGuard/constants.h b/ObfuGuard/constants.h
new file mode 100644
index 0000000..a504c40
--- /dev/null
+++ b/ObfuGuard/constants.h
@@ -0,0 +1,35 @@
+#pragma once
+#include
+
+namespace ObfuGuard {
+
+ // PE format constants
+ constexpr uint32_t PE_FILE_ALIGNMENT = 0x200;
+ constexpr uint32_t PE_SECTION_ALIGNMENT = 0x1000;
+ constexpr uint32_t PE_MAX_SECTIONS = 96;
+ constexpr uint32_t PE_SECTION_SAFETY_MARGIN = 10;
+ constexpr uint32_t PE_RESERVED_SYSTEM_SECTIONS = 5;
+ constexpr uint32_t PE_HEADER_SIZE = 0x1000;
+ constexpr uint32_t MAX_PE_IMAGE_SIZE = 512 * 1024 * 1024;
+
+ // CFF obfuscation constants
+ constexpr uint32_t CFF_SECTION_SIZE = 10'000'000;
+ constexpr const char* CFF_SECTION_NAME = ".0Cff";
+ constexpr const char* CFF_DEV_SECTION_NAME = ".0Dev";
+
+ // Junk code injection constants
+ constexpr uint32_t MAX_JUNK_ITERATIONS = 500;
+ constexpr uint32_t MIN_TRAMPOLINE_PATCH_SIZE = 5;
+ constexpr uint32_t MAX_TRAMPOLINE_PATCH_SIZE = 0x1000;
+ constexpr uint32_t MAX_FUNC_SCAN_SIZE = 8192;
+ constexpr uint32_t DEFAULT_SECTION_SIZE = 0x1000;
+ constexpr uint32_t LARGE_BINARY_SIZE_THRESHOLD = 350 * 1024;
+ constexpr uint32_t MIN_FUNCTION_SIZE = 5;
+
+ // PDB constants
+ constexpr uint64_t SYM_LOAD_BASE_ADDRESS = 0x10000000;
+
+ // Instruction format buffer
+ constexpr size_t INSTRUCTION_FORMAT_BUFFER_SIZE = 256;
+
+}
diff --git a/ObfuGuard/func2rva/func2rva.cpp b/ObfuGuard/func2rva/func2rva.cpp
index b8db5f4..cb0dac1 100644
--- a/ObfuGuard/func2rva/func2rva.cpp
+++ b/ObfuGuard/func2rva/func2rva.cpp
@@ -92,25 +92,13 @@ namespace FuncToRVA { // Namespace for resolving functions to RVAs
// Return list of resolved functions. If not initialized, return empty list and report error.
const std::vector& RVAResolver::get_functions_info() const {
if (!is_initialized_) {
- static std::vector empty_list;
- std::cerr << "Error: RVAResolver has not been initialized. Please call initialize() first." << std::endl;
- return empty_list;
+ throw std::runtime_error("RVAResolver has not been initialized. Please call initialize() first.");
}
return resolved_functions_list_;
}
- // Display list of functions, let user select one function to get RVA
- bool RVAResolver::select_function_rva_interactive(uint32_t& out_rva) {
- if (!is_initialized_) {
- std::cerr << "Error: RVAResolver has not been initialized. Please call initialize() first." << std::endl;
- return false;
- }
-
- if (resolved_functions_list_.empty()) {
- std::cout << "Info: No functions from PDB available to select." << std::endl;
- return false;
- }
-
+ // Display the function table (header, columns, and all rows)
+ void RVAResolver::display_function_table() const {
std::cout << "\nAvailable functions from PDB for file: " << pe_path_str_ << std::endl;
std::cout << "PE ImageBase: 0x" << std::hex << image_base_ << std::dec << std::endl;
if (has_text_section_for_reference_) {
@@ -140,6 +128,21 @@ namespace FuncToRVA { // Namespace for resolving functions to RVAs
<< func_info.name << std::endl;
}
std::cout << "----------------------------------------------------------------------------------------------------" << std::endl;
+ }
+
+ // Display list of functions, let user select one function to get RVA
+ bool RVAResolver::select_function_rva_interactive(uint32_t& out_rva) {
+ if (!is_initialized_) {
+ std::cerr << "Error: RVAResolver has not been initialized. Please call initialize() first." << std::endl;
+ return false;
+ }
+
+ if (resolved_functions_list_.empty()) {
+ std::cout << "Info: No functions from PDB available to select." << std::endl;
+ return false;
+ }
+
+ display_function_table();
int choice = 0;
while (true) {
@@ -196,35 +199,7 @@ namespace FuncToRVA { // Namespace for resolving functions to RVAs
return false;
}
- std::cout << "\nAvailable functions from PDB for file: " << pe_path_str_ << std::endl;
- std::cout << "PE ImageBase: 0x" << std::hex << image_base_ << std::dec << std::endl;
- if (has_text_section_for_reference_) {
- std::cout << "Using PDB offsets relative to '.text' section (RVA: 0x"
- << std::hex << text_section_rva_ << std::dec << ")" << std::endl;
- }
- else {
- std::cout << "Warning: '.text' section not found. Displayed RVAs may be PDB offsets or 0 if unable to compute." << std::endl;
- }
- std::cout << "----------------------------------------------------------------------------------------------------" << std::endl;
- std::cout << std::setw(7) << "No." << " | "
- << std::setw(12) << "RVA (Hex)" << " | "
- << std::setw(12) << "Offset (Hex)" << " | "
- << std::setw(10) << "Size" << " | "
- << "Function Name" << std::endl;
- std::cout << "----------------------------------------------------------------------------------------------------" << std::endl;
-
- for (size_t i = 0; i < resolved_functions_list_.size(); ++i) {
- const auto& func_info = resolved_functions_list_[i];
- std::cout << std::setw(7) << std::left << i + 1 << " | "
- << "0x" << std::hex << std::setw(10) << std::left << func_info.rva
- << " | "
- << "0x" << std::hex << std::setw(10) << std::left << func_info.pdb_offset
- << " | "
- << std::dec << std::setw(10) << std::left << func_info.size
- << " | "
- << func_info.name << std::endl;
- }
- std::cout << "----------------------------------------------------------------------------------------------------" << std::endl;
+ display_function_table();
std::string input_str;
while (true) {
diff --git a/ObfuGuard/func2rva/func2rva.h b/ObfuGuard/func2rva/func2rva.h
index 8ecf174..eaa96c9 100644
--- a/ObfuGuard/func2rva/func2rva.h
+++ b/ObfuGuard/func2rva/func2rva.h
@@ -47,6 +47,7 @@ namespace FuncToRVA {
bool has_text_section_for_reference_ = false; // Flag indicating if .text section exists
bool load_pe_and_parse_pdb();
+ void display_function_table() const;
};
// Display function list from PE file and allow user to select one function, returns RVA of that function.
diff --git a/ObfuGuard/junkcode/junkcode.cpp b/ObfuGuard/junkcode/junkcode.cpp
index 7887b4b..d6f8ed8 100644
--- a/ObfuGuard/junkcode/junkcode.cpp
+++ b/ObfuGuard/junkcode/junkcode.cpp
@@ -212,16 +212,18 @@ bool TrampolineInjector::get_and_relocate_original_function_code(
<< ", New rel offset: 0x" << new_relative_offset << std::dec << std::endl;*/
}
else {
- std::cout << "";
- /*std::cerr << "Error: Cannot relocate " << (insn[0].bytes[0] == 0xE8 ? "CALL" : "JMP")
+ std::cerr << "Warning: Cannot relocate " << (insn[0].bytes[0] == 0xE8 ? "CALL" : "JMP")
<< " at VA 0x" << std::hex << old_instr_va
- << " - target too far (offset: 0x" << new_relative_offset_64 << ")" << std::dec << std::endl;*/
+ << " - relative offset 0x" << new_relative_offset_64
+ << " exceeds INT32 range. Skipping relocation for this instruction."
+ << std::dec << std::endl;
+ // Skip relocation: keep original bytes to avoid crash from wrong offset
+ std::vector original_instr_bytes(insn[0].bytes, insn[0].bytes + insn[0].size);
+ instr_bytes = original_instr_bytes;
}
}
else if (insn[0].bytes[0] == 0xFF) {
- std::cout << "";
- /*std::cout << "Warning: Indirect CALL/JMP at VA 0x" << std::hex << insn[0].address
- << " - may need manual verification" << std::dec << std::endl;*/
+ // Indirect CALL/JMP -- no relocation needed
}
}
else if (op->type == X86_OP_MEM && is_64_bit) {
@@ -324,114 +326,109 @@ bool TrampolineInjector::create_new_section(const std::string& section_name, uin
// Create ASM instruction sequence that doesn't affect logic (junk) to insert into code
std::string TrampolineInjector::get_random_junk_instruction() {
- std::vector junk_instructions;
-
- if (is_64_bit) {
- junk_instructions = {
- // Basic no-op equivalents
- "mov rax, rax",
- "mov rbx, rbx",
- "mov rcx, rcx",
- "mov rdx, rdx",
-
- // Self-canceling operation pairs
- "add r8, 0x10; sub r8, 0x10",
- "add r9, 0x20; sub r9, 0x20",
- "add r10, 0x30; sub r10, 0x30",
- "add r11, 0x40; sub r11, 0x40",
- "add r12, 0x50; sub r12, 0x50",
- "add r13, 0x60; sub r13, 0x60",
- "add r14, 0x70; sub r14, 0x70",
- "add r15, 0x80; sub r15, 0x80",
-
- // Reversed
- "sub r8, 0x15; add r8, 0x15",
- "sub r9, 0x25; add r9, 0x25",
- "sub r10, 0x35; add r10, 0x35",
- "sub r11, 0x45; add r11, 0x45",
-
- // More complex math sequences
- "add r8, 0x100; sub r8, 0x80; sub r8, 0x80",
- "sub r9, 0x200; add r9, 0x100; add r9, 0x100",
- "add r10, 0x50; add r10, 0x50; sub r10, 0xA0",
-
- // Simple XOR patterns
- "xor r8, 0x1234; xor r8, 0x1234",
- "xor r9, 0x5678; xor r9, 0x5678",
- "xor r10, 0x9ABC; xor r10, 0x9ABC",
- "xor r11, 0xDEF0; xor r11, 0xDEF0",
-
- // Bit rotation pairs (safe — rotate is fully reversible)
- "rol r8, 3; ror r8, 3",
- "ror r9, 5; rol r9, 5",
- "rol r10, 7; ror r10, 7",
- "ror r11, 4; rol r11, 4",
-
- // Cross-register stack
- "push r8; push r9; pop r9; pop r8",
-
- // Bitwise operations that don't change value
- "or r8, 0",
- "and r8, -1",
- "or r9, 0",
- "and r9, -1",
- "or r10, 0",
- "and r10, -1",
-
- // rol/ror operations that don't change value
- "rol r8, 1; ror r8, 1",
- "rol r9, 2; ror r9, 2",
- "ror r10, 3; rol r10, 3",
- "ror r11, 4; rol r11, 4",
-
- // INC/DEC pairs
- "inc r8; dec r8",
- "inc r9; dec r9",
- "dec r10; inc r10",
- "dec r11; inc r11",
-
- // Multiple operations that don't change value
- "push r8; pop r8; push r9; pop r9",
- "add r8, 1; add r8, 1; sub r8, 2",
- "sub r9, 5; add r9, 3; add r9, 2",
-
- };
- }
- else {
- junk_instructions = {
- "mov eax, eax",
- "mov ebx, ebx",
- "mov ecx, ecx",
- "mov edx, edx",
- "mov esi, esi",
- "mov edi, edi",
-
- "add esi, 0x10; sub esi, 0x10",
- "add edi, 0x20; sub edi, 0x20",
- "sub esi, 0x15; add esi, 0x15",
- "sub edi, 0x25; add edi, 0x25",
-
- "xor esi, 0x1234; xor esi, 0x1234",
- "xor edi, 0x5678; xor edi, 0x5678",
-
- "push esi; pop esi",
- "push edi; pop edi",
- "push eax; push ebx; pop ebx; pop eax",
-
- "test esi, esi",
- "test edi, edi",
- "cmp esi, esi",
- "cmp edi, edi",
- "lea esi, [esi]",
- "lea edi, [edi]",
- "inc esi; dec esi",
- "inc edi; dec edi",
- "rol esi, 1; ror esi, 1",
- "rol edi, 2; ror edi, 2"
- };
- }
-
- return junk_instructions[rand() % junk_instructions.size()];
+ static const std::vector junk_64bit = {
+ // Basic no-op equivalents
+ "mov rax, rax",
+ "mov rbx, rbx",
+ "mov rcx, rcx",
+ "mov rdx, rdx",
+
+ // Self-canceling operation pairs
+ "add r8, 0x10; sub r8, 0x10",
+ "add r9, 0x20; sub r9, 0x20",
+ "add r10, 0x30; sub r10, 0x30",
+ "add r11, 0x40; sub r11, 0x40",
+ "add r12, 0x50; sub r12, 0x50",
+ "add r13, 0x60; sub r13, 0x60",
+ "add r14, 0x70; sub r14, 0x70",
+ "add r15, 0x80; sub r15, 0x80",
+
+ // Reversed
+ "sub r8, 0x15; add r8, 0x15",
+ "sub r9, 0x25; add r9, 0x25",
+ "sub r10, 0x35; add r10, 0x35",
+ "sub r11, 0x45; add r11, 0x45",
+
+ // More complex math sequences
+ "add r8, 0x100; sub r8, 0x80; sub r8, 0x80",
+ "sub r9, 0x200; add r9, 0x100; add r9, 0x100",
+ "add r10, 0x50; add r10, 0x50; sub r10, 0xA0",
+
+ // Simple XOR patterns
+ "xor r8, 0x1234; xor r8, 0x1234",
+ "xor r9, 0x5678; xor r9, 0x5678",
+ "xor r10, 0x9ABC; xor r10, 0x9ABC",
+ "xor r11, 0xDEF0; xor r11, 0xDEF0",
+
+ // Bit rotation pairs (safe -- rotate is fully reversible)
+ "rol r8, 3; ror r8, 3",
+ "ror r9, 5; rol r9, 5",
+ "rol r10, 7; ror r10, 7",
+ "ror r11, 4; rol r11, 4",
+
+ // Cross-register stack
+ "push r8; push r9; pop r9; pop r8",
+
+ // Bitwise operations that don't change value
+ "or r8, 0",
+ "and r8, -1",
+ "or r9, 0",
+ "and r9, -1",
+ "or r10, 0",
+ "and r10, -1",
+
+ // rol/ror operations that don't change value
+ "rol r8, 1; ror r8, 1",
+ "rol r9, 2; ror r9, 2",
+ "ror r10, 3; rol r10, 3",
+ "ror r11, 4; rol r11, 4",
+
+ // INC/DEC pairs
+ "inc r8; dec r8",
+ "inc r9; dec r9",
+ "dec r10; inc r10",
+ "dec r11; inc r11",
+
+ // Multiple operations that don't change value
+ "push r8; pop r8; push r9; pop r9",
+ "add r8, 1; add r8, 1; sub r8, 2",
+ "sub r9, 5; add r9, 3; add r9, 2",
+ };
+
+ static const std::vector junk_32bit = {
+ "mov eax, eax",
+ "mov ebx, ebx",
+ "mov ecx, ecx",
+ "mov edx, edx",
+ "mov esi, esi",
+ "mov edi, edi",
+
+ "add esi, 0x10; sub esi, 0x10",
+ "add edi, 0x20; sub edi, 0x20",
+ "sub esi, 0x15; add esi, 0x15",
+ "sub edi, 0x25; add edi, 0x25",
+
+ "xor esi, 0x1234; xor esi, 0x1234",
+ "xor edi, 0x5678; xor edi, 0x5678",
+
+ "push esi; pop esi",
+ "push edi; pop edi",
+ "push eax; push ebx; pop ebx; pop eax",
+
+ "test esi, esi",
+ "test edi, edi",
+ "cmp esi, esi",
+ "cmp edi, edi",
+ "lea esi, [esi]",
+ "lea edi, [edi]",
+ "inc esi; dec esi",
+ "inc edi; dec edi",
+ "rol esi, 1; ror esi, 1",
+ "rol edi, 2; ror edi, 2"
+ };
+
+ const auto& pool = is_64_bit ? junk_64bit : junk_32bit;
+ return pool[rand() % pool.size()];
}
// Fill remaining memory space with NOPs (no-operation)
@@ -503,6 +500,65 @@ void TrampolineInjector::fill_remaining_space_with_nops(uint64_t address, size_t
}
}
+// Patch a region with random junk instructions, returns bytes written
+size_t TrampolineInjector::patch_junk_region(ks_engine* ks, uint64_t start_address, size_t region_size, const LIEF::PE::Section& section) {
+ const size_t MAX_JUNK_ITERATIONS = 500;
+ uint64_t current_address = start_address;
+ size_t remaining = region_size;
+ size_t iteration_count = 0;
+
+ uint64_t section_start_va = image_base + section.virtual_address();
+ uint64_t section_end_va = section_start_va + section.virtual_size();
+
+ while (remaining > 0 && iteration_count < MAX_JUNK_ITERATIONS) {
+ iteration_count++;
+
+ std::string junk_asm = get_random_junk_instruction();
+ unsigned char* junk_encode = nullptr;
+ size_t junk_asm_size = 0;
+ size_t junk_count = 0;
+
+ if (ks_asm(ks, junk_asm.c_str(), current_address, &junk_encode, &junk_asm_size, &junk_count) == KS_ERR_OK && junk_count > 0) {
+ if (junk_asm_size <= remaining) {
+ // Check bounds before patching
+ uint64_t patch_end = current_address + junk_asm_size;
+
+ if (patch_end > section_end_va) {
+ std::cerr << "Error: Junk patch would exceed section bounds. Stopping." << std::endl;
+ ks_free(junk_encode);
+ break;
+ }
+
+ std::vector junk_bytes(junk_encode, junk_encode + junk_asm_size);
+ binary->patch_address(current_address, junk_bytes);
+
+ current_address += junk_asm_size;
+ remaining -= junk_asm_size;
+ ks_free(junk_encode);
+ }
+ else {
+ ks_free(junk_encode);
+ fill_remaining_space_with_nops(current_address, remaining);
+ current_address += remaining;
+ remaining = 0;
+ }
+ }
+ else {
+ fill_remaining_space_with_nops(current_address, remaining);
+ current_address += remaining;
+ remaining = 0;
+ }
+ }
+
+ if (iteration_count >= MAX_JUNK_ITERATIONS && remaining > 0) {
+ std::cerr << "Warning: Maximum junk iterations reached. Filling remaining space with NOPs." << std::endl;
+ fill_remaining_space_with_nops(current_address, remaining);
+ current_address += remaining;
+ }
+
+ return current_address - start_address;
+}
+
// Create a JMP from original address to relocated code, insert junk to hide
bool TrampolineInjector::create_trampoline(uint64_t original_func_va, uint64_t new_func_va, size_t original_size) {
ks_engine* ks;
@@ -622,65 +678,8 @@ bool TrampolineInjector::create_trampoline(uint64_t original_func_va, uint64_t n
uint64_t current_address = original_func_va;
- // Patch junk code before JMP instruction with iteration limit
- size_t remaining_before = junk_before_size;
- size_t junk_iteration_count = 0;
- const size_t MAX_JUNK_ITERATIONS = 500; // Limit iterations to prevent infinite loops
-
- /*std::cout << "Phase 1: Adding " << remaining_before << " bytes of junk before JMP..." << std::endl;*/
-
- while (remaining_before > 0 && junk_iteration_count < MAX_JUNK_ITERATIONS) {
- junk_iteration_count++;
-
- std::string junk_asm = get_random_junk_instruction();
- unsigned char* junk_encode = nullptr;
- size_t junk_asm_size = 0;
- size_t junk_count = 0;
-
- if (ks_asm(ks, junk_asm.c_str(), current_address, &junk_encode, &junk_asm_size, &junk_count) == KS_ERR_OK && junk_count > 0) {
- if (junk_asm_size <= remaining_before) {
- // CHECK BOUNDS BEFORE PATCHING
- uint64_t patch_end = current_address + junk_asm_size;
- uint64_t section_start_va = image_base + original_section->virtual_address();
- uint64_t section_end_va = section_start_va + original_section->virtual_size();
-
- if (patch_end > section_end_va) {
- std::cerr << "Error: Junk patch would exceed section bounds. Stopping." << std::endl;
- ks_free(junk_encode);
- break;
- }
-
- std::vector junk_bytes(junk_encode, junk_encode + junk_asm_size);
- binary->patch_address(current_address, junk_bytes);
-
- /*std::cout << " Added junk: " << junk_asm
- << " (" << junk_asm_size << " bytes) at VA 0x"
- << std::hex << current_address << std::dec << std::endl;*/
-
- current_address += junk_asm_size;
- remaining_before -= junk_asm_size;
- ks_free(junk_encode);
- }
- else {
- ks_free(junk_encode);
- fill_remaining_space_with_nops(current_address, remaining_before);
- current_address += remaining_before;
- remaining_before = 0;
- }
- }
- else {
- fill_remaining_space_with_nops(current_address, remaining_before);
- current_address += remaining_before;
- remaining_before = 0;
- }
- }
-
- // Check if iteration limit is exceeded
- if (junk_iteration_count >= MAX_JUNK_ITERATIONS) {
- std::cerr << "Warning: Maximum junk iterations reached. Filling remaining space with NOPs." << std::endl;
- fill_remaining_space_with_nops(current_address, remaining_before);
- current_address += remaining_before;
- }
+ // Patch junk code before JMP instruction
+ current_address += patch_junk_region(ks, current_address, junk_before_size, *original_section);
// Patch JMP instruction at current address
/*std::cout << "Phase 2: Patching JMP at VA 0x" << std::hex << current_address
@@ -700,64 +699,8 @@ bool TrampolineInjector::create_trampoline(uint64_t original_func_va, uint64_t n
binary->patch_address(current_address, jmp_bytes);
current_address += jmp_size;
- // Patch junk code after JMP instruction with iteration limit
- size_t remaining_after = junk_after_size;
- junk_iteration_count = 0; // Reset counter
-
- /*std::cout << "Phase 3: Adding " << remaining_after << " bytes of junk after JMP..." << std::endl;*/
-
- // If no junk after JMP instruction, fill with NOPs
- while (remaining_after > 0 && junk_iteration_count < MAX_JUNK_ITERATIONS) {
- junk_iteration_count++;
-
- std::string junk_asm = get_random_junk_instruction();
- unsigned char* junk_encode = nullptr;
- size_t junk_asm_size = 0;
- size_t junk_count = 0;
-
- if (ks_asm(ks, junk_asm.c_str(), current_address, &junk_encode, &junk_asm_size, &junk_count) == KS_ERR_OK && junk_count > 0) {
- if (junk_asm_size <= remaining_after) {
- // CHECK BOUNDS BEFORE PATCHING
- uint64_t patch_end = current_address + junk_asm_size;
- uint64_t section_start_va = image_base + original_section->virtual_address();
- uint64_t section_end_va = section_start_va + original_section->virtual_size();
-
- if (patch_end > section_end_va) {
- std::cerr << "Error: Final junk patch would exceed section bounds. Stopping." << std::endl;
- ks_free(junk_encode);
- break;
- }
-
- std::vector junk_bytes(junk_encode, junk_encode + junk_asm_size);
- binary->patch_address(current_address, junk_bytes);
-
- /*std::cout << " Added junk: " << junk_asm
- << " (" << junk_asm_size << " bytes) at VA 0x"
- << std::hex << current_address << std::dec << std::endl;*/
-
- current_address += junk_asm_size;
- remaining_after -= junk_asm_size;
- ks_free(junk_encode);
- }
- else {
- ks_free(junk_encode);
- fill_remaining_space_with_nops(current_address, remaining_after);
- remaining_after = 0;
- }
- }
- else {
- fill_remaining_space_with_nops(current_address, remaining_after);
- remaining_after = 0;
- }
- }
-
- // Check if iteration limit is exceeded
- if (junk_iteration_count >= MAX_JUNK_ITERATIONS) {
- std::cerr << "Warning: Maximum final junk iterations reached. Filling remaining space with NOPs." << std::endl;
- fill_remaining_space_with_nops(current_address, remaining_after);
- }
-
- /*std::cout << "Completed advanced trampoline with embedded JMP" << std::endl;*/
+ // Patch junk code after JMP instruction
+ patch_junk_region(ks, current_address, junk_after_size, *original_section);
ks_close(ks);
return true;
}
diff --git a/ObfuGuard/junkcode/junkcode.h b/ObfuGuard/junkcode/junkcode.h
index 76e54a6..969cda9 100644
--- a/ObfuGuard/junkcode/junkcode.h
+++ b/ObfuGuard/junkcode/junkcode.h
@@ -9,6 +9,8 @@
#include
#include
+#include
+
// Forward declaration
namespace LIEF {
namespace PE {
@@ -43,6 +45,7 @@ class TrampolineInjector {
std::string get_random_junk_instruction();
void fill_remaining_space_with_nops(uint64_t address, size_t size);
+ size_t patch_junk_region(ks_engine* ks, uint64_t start_address, size_t region_size, const LIEF::PE::Section& section);
std::string generate_unique_section_name(const std::string& function_name, int index);
public:
diff --git a/ObfuGuard/obfuscatecff/obfuscatecff.cpp b/ObfuGuard/obfuscatecff/obfuscatecff.cpp
index 9b718a1..a5608ea 100644
--- a/ObfuGuard/obfuscatecff/obfuscatecff.cpp
+++ b/ObfuGuard/obfuscatecff/obfuscatecff.cpp
@@ -6,10 +6,7 @@
#include
#include
-#define REG_PAIR(zreg, areg) { ZYDIS_REGISTER_##zreg, x86::areg }
-
-ZydisFormatter formatter;
-ZydisDecoder decoder;
+#define REG_PAIR(zreg, areg) { ZYDIS_REGISTER_##zreg, asmjit::x86::areg }
int obfuscatecff::instruction_id = 0;
int obfuscatecff::function_iterator = 0;
@@ -35,21 +32,19 @@ obfuscatecff::obfuscatecff(pe64* pe)
throw std::runtime_error("failed to init formatter");
}
-// Initialize function list from pdbparser with function_t structure
-void obfuscatecff::create_functions(std::vectorfunctions) {
+void obfuscatecff::create_functions(const std::vector& functions) {
- auto text_section = this->pe->get_section(".text"); // find .text section in PE file
+ auto text_section = this->pe->get_section(".text");
if (!text_section)
throw std::runtime_error("couldn't find .text section");
- std::vectorvisited_rvas; // list of analyzed RVAs
+ std::unordered_set visited_rvas;
- // initialize functions in PE file from pdbparser
- for (auto function : functions) {
- if (function.obfuscate == false) // skip function if not marked for obfuscation
+ for (const auto& function : functions) {
+ if (!function.obfuscate)
continue;
- if (std::find(visited_rvas.begin(), visited_rvas.end(), function.offset) != visited_rvas.end()) // skip if RVA already analyzed
+ if (visited_rvas.count(function.offset))
continue;
if (function.size < 5) // skip if function size is too small
continue;
@@ -63,7 +58,7 @@ void obfuscatecff::create_functions(std::vectorfunctions) {
int current_func_id = function_iterator++;
function_t new_function(current_func_id, function.name, function.offset, function.size);
- new_function.ctfflattening = function.ctfflattening;
+ new_function.cff_flattening = function.cff_flattening;
std::vector runtime_addresses;
@@ -84,7 +79,7 @@ void obfuscatecff::create_functions(std::vectorfunctions) {
new_function.inst_id_index[new_instruction.inst_id] = inst_index;
}
- visited_rvas.push_back(function.offset); // mark RVA as analyzed
+ visited_rvas.insert(function.offset);
this->functions.push_back(new_function); // add new function to the function list
for (auto runtime_address = runtime_addresses.begin(); runtime_address != runtime_addresses.end(); ++runtime_address) {
@@ -548,7 +543,7 @@ void obfuscatecff::run(PIMAGE_SECTION_HEADER new_section, bool obfuscate_entry_p
if (func->has_jumptables)
continue;
- if (func->ctfflattening)
+ if (func->cff_flattening)
this->apply_control_flow_flattening(func);
}
@@ -564,7 +559,7 @@ void obfuscatecff::run(PIMAGE_SECTION_HEADER new_section, bool obfuscate_entry_p
}
-uint32_t obfuscatecff::get_added_size() { // total memory obfuscated
+uint32_t obfuscatecff::get_added_size() const {
return this->total_size_used;
}
diff --git a/ObfuGuard/obfuscatecff/obfuscatecff.h b/ObfuGuard/obfuscatecff/obfuscatecff.h
index b09ca33..3e8741f 100644
--- a/ObfuGuard/obfuscatecff/obfuscatecff.h
+++ b/ObfuGuard/obfuscatecff/obfuscatecff.h
@@ -7,14 +7,11 @@
#include
#include
#include
-using namespace asmjit;
-
-class obfuscatecff { // Class that performs control flow flattening obfuscation
+class obfuscatecff {
private:
- struct instruction_t; // Structure describing a machine instruction
- struct function_t; // Structure describing a function
-
pe64* pe;
+ ZydisFormatter formatter;
+ ZydisDecoder decoder;
struct func_id_instr_id {
int func_id;
int inst_index;
@@ -25,12 +22,12 @@ class obfuscatecff { // Class that performs control flow flattening obfuscation
static int instruction_id;
static int function_iterator;
- static std::unordered_map lookupmap;
+ static std::unordered_map lookupmap;
- // generate code using asmjit
- JitRuntime rt;
- CodeHolder code;
- x86::Assembler assm;
+ // generate code using asmjit
+ asmjit::JitRuntime rt;
+ asmjit::CodeHolder code;
+ asmjit::x86::Assembler assm;
std::vector functions;
@@ -65,11 +62,11 @@ class obfuscatecff { // Class that performs control flow flattening obfuscation
public:
obfuscatecff(pe64* pe);
- void create_functions(std::vector functions);
+ void create_functions(const std::vector& functions);
void run(PIMAGE_SECTION_HEADER new_section, bool obfuscate_entry_point);
- uint32_t get_added_size();
+ uint32_t get_added_size() const;
struct instruction_t {
int inst_id;
@@ -119,11 +116,11 @@ class obfuscatecff { // Class that performs control flow flattening obfuscation
uint32_t offset;
uint32_t size;
- function_t(int func_id, std::string name, uint32_t offset, uint32_t size)
+ function_t(int func_id, const std::string& name, uint32_t offset, uint32_t size)
: func_id(func_id), name(name), offset(offset), size(size) {
};
- bool ctfflattening = true;
+ bool cff_flattening = true;
bool has_jumptables = false;
};
};
\ No newline at end of file
diff --git a/ObfuGuard/pdbparser/pdbparser.h b/ObfuGuard/pdbparser/pdbparser.h
index 5771bff..8c73662 100644
--- a/ObfuGuard/pdbparser/pdbparser.h
+++ b/ObfuGuard/pdbparser/pdbparser.h
@@ -27,7 +27,7 @@ class pdbparser {
std::string name;
uint32_t size = 0;
bool obfuscate = true;
- bool ctfflattening = true;
+ bool cff_flattening = true;
};
pdbparser(pe64* pe);