feat: Initial implementation of Ryujin MiniVM virtualization
- Ryujin can now locate candidate instructions, convert them into VM bytecode, and insert the MiniVM entry point to enable execution of these bytecodes. - Minor bug fixes.
This commit is contained in:
@@ -133,37 +133,6 @@ void RyujinObfuscationCore::obfuscateIat() {
|
|||||||
*/
|
*/
|
||||||
if (m_unusedRegisters.size() == 0) return;
|
if (m_unusedRegisters.size() == 0) return;
|
||||||
|
|
||||||
auto findBlockId = [&](ZyanU8 uopcode, ZyanI64 value) -> std::pair<int, int> {
|
|
||||||
|
|
||||||
int block_id = 0;
|
|
||||||
int opcode_id = 0;
|
|
||||||
|
|
||||||
for (auto& block : m_proc.basic_blocks) {
|
|
||||||
|
|
||||||
opcode_id = 0;
|
|
||||||
|
|
||||||
for (auto& opcode : block.opcodes) {
|
|
||||||
|
|
||||||
auto data = opcode.data();
|
|
||||||
auto size = opcode.size();
|
|
||||||
|
|
||||||
if (data[0] == uopcode) //0xFF ?
|
|
||||||
|
|
||||||
if (std::memcmp(&*(data + 2), &value, sizeof(uint32_t)) == 0) // Is it the same memory immediate?
|
|
||||||
|
|
||||||
return std::make_pair(block_id, opcode_id);
|
|
||||||
|
|
||||||
|
|
||||||
opcode_id++;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
block_id++;
|
|
||||||
}
|
|
||||||
|
|
||||||
return std::make_pair(-1, -1);
|
|
||||||
};
|
|
||||||
|
|
||||||
for (auto& block : m_obfuscated_bb) {
|
for (auto& block : m_obfuscated_bb) {
|
||||||
|
|
||||||
for (auto& instr : block.instructions) {
|
for (auto& instr : block.instructions) {
|
||||||
@@ -171,7 +140,7 @@ void RyujinObfuscationCore::obfuscateIat() {
|
|||||||
if (instr.instruction.info.meta.category == ZYDIS_CATEGORY_CALL && instr.instruction.operands->type == ZYDIS_OPERAND_TYPE_MEMORY) {
|
if (instr.instruction.info.meta.category == ZYDIS_CATEGORY_CALL && instr.instruction.operands->type == ZYDIS_OPERAND_TYPE_MEMORY) {
|
||||||
|
|
||||||
// Finding the block info related to the obfuscated opcode
|
// Finding the block info related to the obfuscated opcode
|
||||||
auto block_info = findBlockId(instr.instruction.info.opcode, instr.instruction.operands->mem.disp.value);
|
auto block_info = findBlockId(instr.instruction.info.opcode, instr.instruction.operands->mem.disp.value, 2, sizeof(uint32_t));
|
||||||
|
|
||||||
// Call to an invalid IAT in the list of basic blocks
|
// Call to an invalid IAT in the list of basic blocks
|
||||||
if (block_info.first == -1 || block_info.second == -1) continue;
|
if (block_info.first == -1 || block_info.second == -1) continue;
|
||||||
@@ -438,7 +407,388 @@ void RyujinObfuscationCore::insertJunkCode() {
|
|||||||
|
|
||||||
void RyujinObfuscationCore::insertVirtualization() {
|
void RyujinObfuscationCore::insertVirtualization() {
|
||||||
|
|
||||||
//TODO
|
/*
|
||||||
|
1 - Converter instru<72><75>es do procedimento e seus basic blocks para o bytecode da VM(cada instru<72><75>o gera 8 bytes de bytecode).
|
||||||
|
2 - Substiuir a instru<72><75>o por uma call para a rotina de interpreta<74><61>o da VM e passar os bytecodes via RCX. (levar em considera<72><61>o o salvamento dos contextos de registradore e stack)
|
||||||
|
3 - Ser capaz de continuar a execu<63><75>o sem problemas integrando a rotina da VM com o c<>digo original a ser executado e n<>o ofuscado
|
||||||
|
|
||||||
|
4 - Essa rotina deve inserir a stub e bytecode da vm apenas. ap<61>s isso teremos um processamento antes de salvar e corrigir reloca<63><61>es
|
||||||
|
para sermos capazes de encontrar o padr<64>o da rotina de virtualiza<7A><61>o e colocar o endere<72>o real do interpretador da VM para que a mesma funcione.
|
||||||
|
|
||||||
|
|
||||||
|
Basicamente essa <20> uma single-vm que:
|
||||||
|
Analisa a instru<72><75>o em quest<73>o. extrair seu opcode e mapear para o da vm, extrair seus immediatos e armazenala em um unico conjunto
|
||||||
|
exemplo:
|
||||||
|
0x48 -> mov -> bytecode
|
||||||
|
rbx -> bytecode
|
||||||
|
10 -> valor
|
||||||
|
|
||||||
|
Exemplo de sa<73>da:
|
||||||
|
0x112210
|
||||||
|
|
||||||
|
Que sera atribuido ao valor de rcx:
|
||||||
|
|
||||||
|
push rcx
|
||||||
|
mov rcx, 112210h
|
||||||
|
call vmentry(mas um valor simbolico visto que n<>o seria inserido o offset immediato aqui)
|
||||||
|
-> rax resultado vai no registrado em quest<73>o que continuaria o fluxo de execu<63><75>o ou receberia o resultado, nesse exemplo: rbx
|
||||||
|
pop rcx
|
||||||
|
|
||||||
|
Dessa forma o c<>digo continuaria
|
||||||
|
*/
|
||||||
|
|
||||||
|
// <20> uma instru<72><75>o candidata a ser virtualizada pela minivm ??
|
||||||
|
auto isValidToSRyujinMiniVm = [&](RyujinInstruction instr) {
|
||||||
|
|
||||||
|
return instr.instruction.operands[0].type == ZYDIS_OPERAND_TYPE_REGISTER && instr.instruction.operands[1].type == ZYDIS_OPERAND_TYPE_IMMEDIATE;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Vamos mapear o registrador do Zydis para o ASMJIT
|
||||||
|
auto mapZydisToAsmjitGp = [&](ZydisRegister zydisReg) -> asmjit::x86::Gp {
|
||||||
|
|
||||||
|
switch (zydisReg) {
|
||||||
|
|
||||||
|
// RAX family
|
||||||
|
case ZYDIS_REGISTER_AL:
|
||||||
|
case ZYDIS_REGISTER_AH:
|
||||||
|
case ZYDIS_REGISTER_AX:
|
||||||
|
case ZYDIS_REGISTER_EAX:
|
||||||
|
case ZYDIS_REGISTER_RAX: return asmjit::x86::rax;
|
||||||
|
|
||||||
|
// RBX family
|
||||||
|
case ZYDIS_REGISTER_BL:
|
||||||
|
case ZYDIS_REGISTER_BH:
|
||||||
|
case ZYDIS_REGISTER_BX:
|
||||||
|
case ZYDIS_REGISTER_EBX:
|
||||||
|
case ZYDIS_REGISTER_RBX: return asmjit::x86::rbx;
|
||||||
|
|
||||||
|
// RCX family
|
||||||
|
case ZYDIS_REGISTER_CL:
|
||||||
|
case ZYDIS_REGISTER_CH:
|
||||||
|
case ZYDIS_REGISTER_CX:
|
||||||
|
case ZYDIS_REGISTER_ECX:
|
||||||
|
case ZYDIS_REGISTER_RCX: return asmjit::x86::rcx;
|
||||||
|
|
||||||
|
// RDX family
|
||||||
|
case ZYDIS_REGISTER_DL:
|
||||||
|
case ZYDIS_REGISTER_DH:
|
||||||
|
case ZYDIS_REGISTER_DX:
|
||||||
|
case ZYDIS_REGISTER_EDX:
|
||||||
|
case ZYDIS_REGISTER_RDX: return asmjit::x86::rdx;
|
||||||
|
|
||||||
|
// RSI family
|
||||||
|
case ZYDIS_REGISTER_SIL:
|
||||||
|
case ZYDIS_REGISTER_SI:
|
||||||
|
case ZYDIS_REGISTER_ESI:
|
||||||
|
case ZYDIS_REGISTER_RSI: return asmjit::x86::rsi;
|
||||||
|
|
||||||
|
// RDI family
|
||||||
|
case ZYDIS_REGISTER_DIL:
|
||||||
|
case ZYDIS_REGISTER_DI:
|
||||||
|
case ZYDIS_REGISTER_EDI:
|
||||||
|
case ZYDIS_REGISTER_RDI: return asmjit::x86::rdi;
|
||||||
|
|
||||||
|
// RBP family
|
||||||
|
case ZYDIS_REGISTER_BPL:
|
||||||
|
case ZYDIS_REGISTER_BP:
|
||||||
|
case ZYDIS_REGISTER_EBP:
|
||||||
|
case ZYDIS_REGISTER_RBP: return asmjit::x86::rbp;
|
||||||
|
|
||||||
|
// RSP family
|
||||||
|
case ZYDIS_REGISTER_SPL:
|
||||||
|
case ZYDIS_REGISTER_SP:
|
||||||
|
case ZYDIS_REGISTER_ESP:
|
||||||
|
case ZYDIS_REGISTER_RSP: return asmjit::x86::rsp;
|
||||||
|
|
||||||
|
// R8 family
|
||||||
|
case ZYDIS_REGISTER_R8B:
|
||||||
|
case ZYDIS_REGISTER_R8W:
|
||||||
|
case ZYDIS_REGISTER_R8D:
|
||||||
|
case ZYDIS_REGISTER_R8: return asmjit::x86::r8;
|
||||||
|
|
||||||
|
// R9 family
|
||||||
|
case ZYDIS_REGISTER_R9B:
|
||||||
|
case ZYDIS_REGISTER_R9W:
|
||||||
|
case ZYDIS_REGISTER_R9D:
|
||||||
|
case ZYDIS_REGISTER_R9: return asmjit::x86::r9;
|
||||||
|
|
||||||
|
// R10 family
|
||||||
|
case ZYDIS_REGISTER_R10B:
|
||||||
|
case ZYDIS_REGISTER_R10W:
|
||||||
|
case ZYDIS_REGISTER_R10D:
|
||||||
|
case ZYDIS_REGISTER_R10: return asmjit::x86::r10;
|
||||||
|
|
||||||
|
// R11 family
|
||||||
|
case ZYDIS_REGISTER_R11B:
|
||||||
|
case ZYDIS_REGISTER_R11W:
|
||||||
|
case ZYDIS_REGISTER_R11D:
|
||||||
|
case ZYDIS_REGISTER_R11: return asmjit::x86::r11;
|
||||||
|
|
||||||
|
// R12 family
|
||||||
|
case ZYDIS_REGISTER_R12B:
|
||||||
|
case ZYDIS_REGISTER_R12W:
|
||||||
|
case ZYDIS_REGISTER_R12D:
|
||||||
|
case ZYDIS_REGISTER_R12: return asmjit::x86::r12;
|
||||||
|
|
||||||
|
// R13 family
|
||||||
|
case ZYDIS_REGISTER_R13B:
|
||||||
|
case ZYDIS_REGISTER_R13W:
|
||||||
|
case ZYDIS_REGISTER_R13D:
|
||||||
|
case ZYDIS_REGISTER_R13: return asmjit::x86::r13;
|
||||||
|
|
||||||
|
// R14 family
|
||||||
|
case ZYDIS_REGISTER_R14B:
|
||||||
|
case ZYDIS_REGISTER_R14W:
|
||||||
|
case ZYDIS_REGISTER_R14D:
|
||||||
|
case ZYDIS_REGISTER_R14: return asmjit::x86::r14;
|
||||||
|
|
||||||
|
// R15 family
|
||||||
|
case ZYDIS_REGISTER_R15B:
|
||||||
|
case ZYDIS_REGISTER_R15W:
|
||||||
|
case ZYDIS_REGISTER_R15D:
|
||||||
|
case ZYDIS_REGISTER_R15: return asmjit::x86::r15;
|
||||||
|
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
// Vamos traduzir uma instru<72><75>o para o bytecode da MiniVm do Ryujin
|
||||||
|
auto translateToMiniVmBytecode = [&](ZydisRegister reg, ZyanU8 op, ZyanU64 value) {
|
||||||
|
|
||||||
|
ZyanU64 miniVmByteCode = 0;
|
||||||
|
|
||||||
|
switch (reg) {
|
||||||
|
|
||||||
|
case ZYDIS_REGISTER_EAX:
|
||||||
|
case ZYDIS_REGISTER_RAX: {
|
||||||
|
|
||||||
|
miniVmByteCode = 0x33; // reg = RAX
|
||||||
|
miniVmByteCode <<= 8;
|
||||||
|
miniVmByteCode |= op; // OP TYPE
|
||||||
|
miniVmByteCode <<= 8;
|
||||||
|
miniVmByteCode |= value; // valor
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ZYDIS_REGISTER_RBX: {
|
||||||
|
|
||||||
|
miniVmByteCode = 0x34; // reg = RBX
|
||||||
|
miniVmByteCode <<= 8;
|
||||||
|
miniVmByteCode |= op; // OP TYPE
|
||||||
|
miniVmByteCode <<= 8;
|
||||||
|
miniVmByteCode |= value; // valor
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ZYDIS_REGISTER_RCX: {
|
||||||
|
|
||||||
|
miniVmByteCode = 0x35; // reg = RCX
|
||||||
|
miniVmByteCode <<= 8;
|
||||||
|
miniVmByteCode |= op; // OP TYPE
|
||||||
|
miniVmByteCode <<= 8;
|
||||||
|
miniVmByteCode |= value; // valor
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ZYDIS_REGISTER_RDX: {
|
||||||
|
|
||||||
|
miniVmByteCode = 0x36; // reg = RDX
|
||||||
|
miniVmByteCode <<= 8;
|
||||||
|
miniVmByteCode |= op; // OP TYPE
|
||||||
|
miniVmByteCode <<= 8;
|
||||||
|
miniVmByteCode |= value; // valor
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ZYDIS_REGISTER_RSI: {
|
||||||
|
|
||||||
|
miniVmByteCode = 0x37; // reg = RSI
|
||||||
|
miniVmByteCode <<= 8;
|
||||||
|
miniVmByteCode |= op; // OP TYPE
|
||||||
|
miniVmByteCode <<= 8;
|
||||||
|
miniVmByteCode |= value; // valor
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ZYDIS_REGISTER_RDI: {
|
||||||
|
|
||||||
|
miniVmByteCode = 0x38; // reg = RDI
|
||||||
|
miniVmByteCode <<= 8;
|
||||||
|
miniVmByteCode |= op; // OP TYPE
|
||||||
|
miniVmByteCode <<= 8;
|
||||||
|
miniVmByteCode |= value; // valor
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ZYDIS_REGISTER_RBP: {
|
||||||
|
|
||||||
|
miniVmByteCode = 0x39; // reg = RBP
|
||||||
|
miniVmByteCode <<= 8;
|
||||||
|
miniVmByteCode |= op; // OP TYPE
|
||||||
|
miniVmByteCode <<= 8;
|
||||||
|
miniVmByteCode |= value; // valor
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ZYDIS_REGISTER_RSP: {
|
||||||
|
|
||||||
|
miniVmByteCode = 0x40; // reg = RSP
|
||||||
|
miniVmByteCode <<= 8;
|
||||||
|
miniVmByteCode |= op; // OP TYPE
|
||||||
|
miniVmByteCode <<= 8;
|
||||||
|
miniVmByteCode |= value; // valor
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ZYDIS_REGISTER_R8: {
|
||||||
|
|
||||||
|
miniVmByteCode = 0x41; // reg = R8
|
||||||
|
miniVmByteCode <<= 8;
|
||||||
|
miniVmByteCode |= op; // OP TYPE
|
||||||
|
miniVmByteCode <<= 8;
|
||||||
|
miniVmByteCode |= value; // valor
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ZYDIS_REGISTER_R9: {
|
||||||
|
|
||||||
|
miniVmByteCode = 0x42; // reg = R9
|
||||||
|
miniVmByteCode <<= 8;
|
||||||
|
miniVmByteCode |= op; // OP TYPE
|
||||||
|
miniVmByteCode <<= 8;
|
||||||
|
miniVmByteCode |= value; // valor
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ZYDIS_REGISTER_R10: {
|
||||||
|
|
||||||
|
miniVmByteCode = 0x43; // reg = R10
|
||||||
|
miniVmByteCode <<= 8;
|
||||||
|
miniVmByteCode |= op; // OP TYPE
|
||||||
|
miniVmByteCode <<= 8;
|
||||||
|
miniVmByteCode |= value; // valor
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ZYDIS_REGISTER_R11: {
|
||||||
|
|
||||||
|
miniVmByteCode = 0x44; // reg = R11
|
||||||
|
miniVmByteCode <<= 8;
|
||||||
|
miniVmByteCode |= op; // OP TYPE
|
||||||
|
miniVmByteCode <<= 8;
|
||||||
|
miniVmByteCode |= value; // valor
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ZYDIS_REGISTER_R12: {
|
||||||
|
|
||||||
|
miniVmByteCode = 0x45; // reg = R12
|
||||||
|
miniVmByteCode <<= 8;
|
||||||
|
miniVmByteCode |= op; // OP TYPE
|
||||||
|
miniVmByteCode <<= 8;
|
||||||
|
miniVmByteCode |= value; // valor
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ZYDIS_REGISTER_R13: {
|
||||||
|
|
||||||
|
miniVmByteCode = 0x46; // reg = R13
|
||||||
|
miniVmByteCode <<= 8;
|
||||||
|
miniVmByteCode |= op; // OP TYPE
|
||||||
|
miniVmByteCode <<= 8;
|
||||||
|
miniVmByteCode |= value; // valor
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ZYDIS_REGISTER_R14: {
|
||||||
|
|
||||||
|
miniVmByteCode = 0x47; // reg = R14
|
||||||
|
miniVmByteCode <<= 8;
|
||||||
|
miniVmByteCode |= op; // OP TYPE
|
||||||
|
miniVmByteCode <<= 8;
|
||||||
|
miniVmByteCode |= value; // valor
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ZYDIS_REGISTER_R15: {
|
||||||
|
|
||||||
|
miniVmByteCode = 0x48; // reg = R15
|
||||||
|
miniVmByteCode <<= 8;
|
||||||
|
miniVmByteCode |= op; // OP TYPE
|
||||||
|
miniVmByteCode <<= 8;
|
||||||
|
miniVmByteCode |= value; // valor
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return miniVmByteCode;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Inicializando o runtime do asmjit
|
||||||
|
asmjit::JitRuntime runtime;
|
||||||
|
|
||||||
|
for (auto& block : m_proc.basic_blocks) {
|
||||||
|
|
||||||
|
for (auto& instr : block.instructions) {
|
||||||
|
|
||||||
|
// Vector para armazenarmos os opcodes da MiniVm do Ryujin
|
||||||
|
std::vector<ZyanU8> minivm_enter;
|
||||||
|
|
||||||
|
// Operand type
|
||||||
|
ZyanU8 opType = 0;
|
||||||
|
|
||||||
|
// Encontrando o block info para o opcode atual
|
||||||
|
auto block_info = findBlockId(instr.instruction.info.opcode, instr.instruction.operands[1].imm.value.u, 2, sizeof(unsigned char));
|
||||||
|
|
||||||
|
// Caso n<>o encontremos
|
||||||
|
if (block_info.first == -1 || block_info.second == -1) continue;
|
||||||
|
|
||||||
|
// Recuperando os opcodes originais desta instru<72><75>o ao qual trabalhamos
|
||||||
|
auto& data = m_proc.basic_blocks[block_info.first].opcodes[block_info.second];
|
||||||
|
|
||||||
|
// Verificando por operands candidatos a serem virtualizados pela minivm
|
||||||
|
if (instr.instruction.info.mnemonic == ZYDIS_MNEMONIC_ADD && isValidToSRyujinMiniVm(instr)) opType = 1;
|
||||||
|
else if (instr.instruction.info.mnemonic == ZYDIS_MNEMONIC_SUB && isValidToSRyujinMiniVm(instr)) opType = 2;
|
||||||
|
else if (instr.instruction.info.mnemonic == ZYDIS_MNEMONIC_IMUL && isValidToSRyujinMiniVm(instr)) opType = 3;
|
||||||
|
else if (instr.instruction.info.mnemonic == ZYDIS_MNEMONIC_DIV && isValidToSRyujinMiniVm(instr)) opType = 4;
|
||||||
|
|
||||||
|
//Existe um VM Operator novo ?
|
||||||
|
if (opType != 0) {
|
||||||
|
|
||||||
|
// Inicializando para o asmjit gerar as instru<72><75>es de nossa minivm
|
||||||
|
asmjit::CodeHolder code;
|
||||||
|
code.init(runtime.environment());
|
||||||
|
asmjit::x86::Assembler a(&code);
|
||||||
|
|
||||||
|
a.push(asmjit::x86::rcx);
|
||||||
|
a.mov(asmjit::x86::rcx, translateToMiniVmBytecode(instr.instruction.operands[0].reg.value, opType, instr.instruction.operands[1].imm.value.u));
|
||||||
|
a.mov(asmjit::x86::rax, 0x8888888888888888); // Endere<72>o a ser substituido pelo endere<72>o da nossa minivm
|
||||||
|
a.call(asmjit::x86::rax);
|
||||||
|
a.mov(mapZydisToAsmjitGp(instr.instruction.operands[0].reg.value), asmjit::x86::rax);
|
||||||
|
a.pop(asmjit::x86::rcx);
|
||||||
|
|
||||||
|
auto& opcodeBuffer = code.sectionById(0)->buffer();
|
||||||
|
const auto pOpcodeBuffer = opcodeBuffer.data();
|
||||||
|
minivm_enter.reserve(opcodeBuffer.size());
|
||||||
|
|
||||||
|
// Armazenando cada opcocde individual no nosso vector da minivm
|
||||||
|
for (auto i = 0; i < opcodeBuffer.size(); ++i) minivm_enter.push_back(static_cast<ZyanU8>(pOpcodeBuffer[i]));
|
||||||
|
|
||||||
|
// Sobrescrevendo opcodes antigos pelos novos
|
||||||
|
data.assign(minivm_enter.begin(), minivm_enter.end());
|
||||||
|
|
||||||
|
std::printf("[!] Inserting a new MiniVm on %s\n", instr.instruction.text);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -458,21 +808,21 @@ BOOL RyujinObfuscationCore::Run() {
|
|||||||
//Update basic blocks view based on the new obfuscated
|
//Update basic blocks view based on the new obfuscated
|
||||||
this->updateBasicBlocksContext();
|
this->updateBasicBlocksContext();
|
||||||
|
|
||||||
//Obfuscate IAT for the configured procedures
|
if (m_config.m_isVirtualized) {
|
||||||
if (m_config.m_isIatObfuscation) {
|
|
||||||
|
|
||||||
// Obfuscate IAT
|
// Insert Virtualization
|
||||||
obfuscateIat();
|
insertVirtualization();
|
||||||
|
|
||||||
//Update our basic blocks context to rely 1-1 for the new obfuscated opcodes.
|
//Update our basic blocks context to rely 1-1 for the new obfuscated opcodes.
|
||||||
this->updateBasicBlocksContext();
|
this->updateBasicBlocksContext();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_config.m_isVirtualized) {
|
//Obfuscate IAT for the configured procedures
|
||||||
|
if (m_config.m_isIatObfuscation) {
|
||||||
|
|
||||||
// Insert Virtualization
|
// Obfuscate IAT
|
||||||
insertVirtualization();
|
obfuscateIat();
|
||||||
|
|
||||||
//Update our basic blocks context to rely 1-1 for the new obfuscated opcodes.
|
//Update our basic blocks context to rely 1-1 for the new obfuscated opcodes.
|
||||||
this->updateBasicBlocksContext();
|
this->updateBasicBlocksContext();
|
||||||
|
|||||||
@@ -32,6 +32,37 @@ private:
|
|||||||
std::vector<uint8_t> fix_branch_near_far_short(uint8_t original_opcode, uint64_t jmp_address, uint64_t target_address);
|
std::vector<uint8_t> 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);
|
uint32_t findOpcodeOffset(const uint8_t* data, size_t dataSize, const void* opcode, size_t opcodeSize);
|
||||||
|
|
||||||
|
inline std::pair<int, int> findBlockId(ZyanU8 uopcode, ZyanI64 value, ZyanU8 idx, ZyanU8 szData) {
|
||||||
|
|
||||||
|
int block_id = 0;
|
||||||
|
int opcode_id = 0;
|
||||||
|
|
||||||
|
for (auto& block : m_proc.basic_blocks) {
|
||||||
|
|
||||||
|
opcode_id = 0;
|
||||||
|
|
||||||
|
for (auto& opcode : block.opcodes) {
|
||||||
|
|
||||||
|
auto data = opcode.data();
|
||||||
|
auto size = opcode.size();
|
||||||
|
|
||||||
|
if (data[0] == uopcode) //0xFF ?
|
||||||
|
|
||||||
|
if (std::memcmp(&*(data + idx), &value, szData) == 0) // Is it the same memory immediate?
|
||||||
|
|
||||||
|
return std::make_pair(block_id, opcode_id);
|
||||||
|
|
||||||
|
|
||||||
|
opcode_id++;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
block_id++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::make_pair(-1, -1);
|
||||||
|
};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
RyujinObfuscationCore(const RyujinObfuscatorConfig& config, const RyujinProcedure& proc, uintptr_t ProcImageBase);
|
RyujinObfuscationCore(const RyujinObfuscatorConfig& config, const RyujinProcedure& proc, uintptr_t ProcImageBase);
|
||||||
void applyRelocationFixupsToInstructions(uintptr_t imageBase, DWORD virtualAddress, std::vector<unsigned char>& new_opcodes);
|
void applyRelocationFixupsToInstructions(uintptr_t imageBase, DWORD virtualAddress, std::vector<unsigned char>& new_opcodes);
|
||||||
|
|||||||
@@ -11,17 +11,17 @@ auto main() -> int {
|
|||||||
|
|
||||||
RyujinObfuscatorConfig config;
|
RyujinObfuscatorConfig config;
|
||||||
config.m_isIgnoreOriginalCodeRemove = FALSE;
|
config.m_isIgnoreOriginalCodeRemove = FALSE;
|
||||||
config.m_isJunkCode = TRUE;
|
config.m_isJunkCode = FALSE;
|
||||||
config.m_isRandomSection = FALSE;
|
config.m_isRandomSection = FALSE;
|
||||||
config.m_isVirtualized = TRUE;
|
config.m_isVirtualized = TRUE;
|
||||||
config.m_isIatObfuscation = TRUE;
|
config.m_isIatObfuscation = TRUE;
|
||||||
config.m_isEncryptObfuscatedCode = FALSE;
|
config.m_isEncryptObfuscatedCode = FALSE;
|
||||||
std::vector<std::string> procsToObfuscate{
|
std::vector<std::string> procsToObfuscate{
|
||||||
"main",
|
//"main"
|
||||||
"invoke_main",
|
//"invoke_main",
|
||||||
"sum",
|
"sum"
|
||||||
"__scrt_common_main",
|
// "__scrt_common_main",
|
||||||
"j___security_init_cookie"
|
// "j___security_init_cookie"
|
||||||
};
|
};
|
||||||
config.m_strProceduresToObfuscate.assign(procsToObfuscate.begin(), procsToObfuscate.end());
|
config.m_strProceduresToObfuscate.assign(procsToObfuscate.begin(), procsToObfuscate.end());
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user