feat: Functional MiniVM Entry and Stable VM Stub for Running Virtualized Bytecode (To Be Improved in Future Commits)
- Ryujin can now interpret MiniVM bytecode. It inserts the MiniVM entry routine's RVA to enable execution of the VM interpreter. - This is just the initial implementation and will be significantly improved in future commits. We're pushing our first working solution for now.
This commit is contained in:
@@ -156,8 +156,43 @@ bool Ryujin::run(const RyujinObfuscatorConfig& config) {
|
|||||||
RyujinPESections peSections;
|
RyujinPESections peSections;
|
||||||
peSections.AddNewSection(m_strInputFilePath, chSectionName);
|
peSections.AddNewSection(m_strInputFilePath, chSectionName);
|
||||||
|
|
||||||
uintptr_t offsetVA = 0;
|
uintptr_t offsetVA = 0, miniVmEnterAddress = 0;
|
||||||
std::vector<unsigned char> opcodesWithRelocsFixed;
|
std::vector<unsigned char> opcodesWithRelocsFixed;
|
||||||
|
|
||||||
|
//Insert minivm enter routine
|
||||||
|
if (config.m_isVirtualized) {
|
||||||
|
|
||||||
|
std::vector<unsigned char> miniVmEnter{
|
||||||
|
|
||||||
|
0x48, 0x89, 0x4C, 0x24, 0x08, 0x48, 0x83, 0xEC, 0x28, 0x48, 0x8B, 0x44,
|
||||||
|
0x24, 0x30, 0x48, 0xC1, 0xE8, 0x10, 0x48, 0x25, 0xFF, 0x00, 0x00, 0x00,
|
||||||
|
0x88, 0x44, 0x24, 0x01, 0x48, 0x8B, 0x44, 0x24, 0x30, 0x48, 0xC1, 0xE8,
|
||||||
|
0x08, 0x48, 0x25, 0xFF, 0x00, 0x00, 0x00, 0x88, 0x04, 0x24, 0x48, 0x8B,
|
||||||
|
0x44, 0x24, 0x30, 0x48, 0x25, 0xFF, 0x00, 0x00, 0x00, 0x48, 0x89, 0x44,
|
||||||
|
0x24, 0x10, 0x48, 0xC7, 0x44, 0x24, 0x08, 0x00, 0x00, 0x00, 0x00, 0x0F,
|
||||||
|
0xB6, 0x04, 0x24, 0x88, 0x44, 0x24, 0x04, 0x80, 0x7C, 0x24, 0x04, 0x01,
|
||||||
|
0x74, 0x17, 0x80, 0x7C, 0x24, 0x04, 0x02, 0x74, 0x27, 0x80, 0x7C, 0x24,
|
||||||
|
0x04, 0x03, 0x74, 0x37, 0x80, 0x7C, 0x24, 0x04, 0x04, 0x74, 0x42, 0xEB,
|
||||||
|
0x53, 0x48, 0x8B, 0x44, 0x24, 0x10, 0x48, 0x8B, 0x4C, 0x24, 0x08, 0x48,
|
||||||
|
0x03, 0xC8, 0x48, 0x8B, 0xC1, 0x48, 0x89, 0x44, 0x24, 0x08, 0xEB, 0x45,
|
||||||
|
0x48, 0x8B, 0x44, 0x24, 0x10, 0x48, 0x8B, 0x4C, 0x24, 0x08, 0x48, 0x2B,
|
||||||
|
0xC8, 0x48, 0x8B, 0xC1, 0x48, 0x89, 0x44, 0x24, 0x08, 0xEB, 0x2E, 0x48,
|
||||||
|
0x8B, 0x44, 0x24, 0x08, 0x48, 0x0F, 0xAF, 0x44, 0x24, 0x10, 0x48, 0x89,
|
||||||
|
0x44, 0x24, 0x08, 0xEB, 0x1C, 0x33, 0xD2, 0x48, 0x8B, 0x44, 0x24, 0x08,
|
||||||
|
0x48, 0xF7, 0x74, 0x24, 0x10, 0x48, 0x89, 0x44, 0x24, 0x08, 0xEB, 0x09,
|
||||||
|
0x48, 0xC7, 0x44, 0x24, 0x08, 0x00, 0x00, 0x00, 0x00, 0x48, 0x8B, 0x44,
|
||||||
|
0x24, 0x08, 0x48, 0x83, 0xC4, 0x28, 0xC3
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
opcodesWithRelocsFixed.insert(opcodesWithRelocsFixed.end(), miniVmEnter.begin(), miniVmEnter.end());
|
||||||
|
|
||||||
|
miniVmEnterAddress = peSections.getRyujinSectionVA();
|
||||||
|
|
||||||
|
offsetVA += miniVmEnter.size();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
for (auto& obc : processed_procs) {
|
for (auto& obc : processed_procs) {
|
||||||
|
|
||||||
auto tempValued = obc.getProcessedProc().getUpdateOpcodes();
|
auto tempValued = obc.getProcessedProc().getUpdateOpcodes();
|
||||||
@@ -168,6 +203,9 @@ bool Ryujin::run(const RyujinObfuscatorConfig& config) {
|
|||||||
// Removing and adding a jump in the original procedure and removing original opcodes for a jump to the new obfuscated code
|
// Removing and adding a jump in the original procedure and removing original opcodes for a jump to the new obfuscated code
|
||||||
obc.removeOldOpcodeRedirect(peSections.mappedPeDiskBaseAddress(), peSections.getRyujinMappedPeSize(), reinterpret_cast<uintptr_t>(imgDos) + peSections.getRyujinSectionVA() + offsetVA, config.m_isIgnoreOriginalCodeRemove);
|
obc.removeOldOpcodeRedirect(peSections.mappedPeDiskBaseAddress(), peSections.getRyujinMappedPeSize(), reinterpret_cast<uintptr_t>(imgDos) + peSections.getRyujinSectionVA() + offsetVA, config.m_isIgnoreOriginalCodeRemove);
|
||||||
|
|
||||||
|
// Inserindo MiniVMEnter
|
||||||
|
if (config.m_isVirtualized) obc.InsertMiniVmEnterProcedureAddress(reinterpret_cast<uintptr_t>(imgDos), miniVmEnterAddress, tempValued);
|
||||||
|
|
||||||
// Destructing class
|
// Destructing class
|
||||||
obc.~RyujinObfuscationCore();
|
obc.~RyujinObfuscationCore();
|
||||||
|
|
||||||
|
|||||||
@@ -440,7 +440,9 @@ void RyujinObfuscationCore::insertVirtualization() {
|
|||||||
// <20> uma instru<72><75>o candidata a ser virtualizada pela minivm ??
|
// <20> uma instru<72><75>o candidata a ser virtualizada pela minivm ??
|
||||||
auto isValidToSRyujinMiniVm = [&](RyujinInstruction instr) {
|
auto isValidToSRyujinMiniVm = [&](RyujinInstruction instr) {
|
||||||
|
|
||||||
return instr.instruction.operands[0].type == ZYDIS_OPERAND_TYPE_REGISTER && instr.instruction.operands[1].type == ZYDIS_OPERAND_TYPE_IMMEDIATE;
|
return instr.instruction.operands[0].type == ZYDIS_OPERAND_TYPE_REGISTER && instr.instruction.operands[1].type == ZYDIS_OPERAND_TYPE_IMMEDIATE &&
|
||||||
|
//Ignorando registradores e opera<72><61>es de stack
|
||||||
|
(instr.instruction.operands[0].reg.value != ZYDIS_REGISTER_RSP && instr.instruction.operands[0].reg.value != ZYDIS_REGISTER_RBP);
|
||||||
};
|
};
|
||||||
|
|
||||||
// Vamos mapear o registrador do Zydis para o ASMJIT
|
// Vamos mapear o registrador do Zydis para o ASMJIT
|
||||||
@@ -766,8 +768,13 @@ void RyujinObfuscationCore::insertVirtualization() {
|
|||||||
asmjit::x86::Assembler a(&code);
|
asmjit::x86::Assembler a(&code);
|
||||||
|
|
||||||
a.push(asmjit::x86::rcx);
|
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::rcx, translateToMiniVmBytecode(instr.instruction.operands[0].reg.value, opType, instr.instruction.operands[1].imm.value.u)); //TODO: e se o reg ex: rax j<> tiver uma valor para um add, devemos armazenar rax tamb<6D>m ?
|
||||||
a.mov(asmjit::x86::rax, 0x8888888888888888); // Endere<72>o a ser substituido pelo endere<72>o da nossa minivm
|
a.emit(asmjit::x86::Inst::kIdRdgsbase, asmjit::x86::rax);
|
||||||
|
a.add(asmjit::x86::rax, 0x60);
|
||||||
|
a.mov(asmjit::x86::rax, asmjit::x86::ptr(asmjit::x86::rax));
|
||||||
|
a.add(asmjit::x86::rax, 0x10);
|
||||||
|
a.mov(asmjit::x86::rax, asmjit::x86::ptr(asmjit::x86::rax));
|
||||||
|
a.add(asmjit::x86::rax, asmjit::imm(0x88));
|
||||||
a.call(asmjit::x86::rax);
|
a.call(asmjit::x86::rax);
|
||||||
a.mov(mapZydisToAsmjitGp(instr.instruction.operands[0].reg.value), asmjit::x86::rax);
|
a.mov(mapZydisToAsmjitGp(instr.instruction.operands[0].reg.value), asmjit::x86::rax);
|
||||||
a.pop(asmjit::x86::rcx);
|
a.pop(asmjit::x86::rcx);
|
||||||
@@ -1143,6 +1150,25 @@ void RyujinObfuscationCore::applyRelocationFixupsToInstructions(uintptr_t imageB
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void RyujinObfuscationCore::InsertMiniVmEnterProcedureAddress(uintptr_t imageBase, uintptr_t virtualAddress, std::vector<unsigned char>& new_opcodes) {
|
||||||
|
|
||||||
|
//Inserting Ryujin MiniVm Address on each vm entry reference
|
||||||
|
if (m_config.m_isVirtualized) {
|
||||||
|
auto size = new_opcodes.size();
|
||||||
|
auto data = new_opcodes.data();
|
||||||
|
|
||||||
|
unsigned char ucSignature[]{ 0x48, 0x05, 0x88, 0x00, 0x00, 0x00 };
|
||||||
|
|
||||||
|
for (auto i = 0; i < size; i++)
|
||||||
|
if (std::memcmp(&*(data + i), ucSignature, 6) == 0) {
|
||||||
|
std::printf("FIND!!\n");
|
||||||
|
std::memset(&*(data + i + 2), 0, 4);
|
||||||
|
std::memcpy(&*(data + i + 2), &virtualAddress, sizeof(uint32_t));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
void RyujinObfuscationCore::removeOldOpcodeRedirect(uintptr_t newMappedPE, std::size_t szMapped, uintptr_t newObfuscatedAddress, bool isIgnoreOriginalCodeRemove) {
|
void RyujinObfuscationCore::removeOldOpcodeRedirect(uintptr_t newMappedPE, std::size_t szMapped, uintptr_t newObfuscatedAddress, bool isIgnoreOriginalCodeRemove) {
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
@@ -67,6 +67,7 @@ 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);
|
||||||
void removeOldOpcodeRedirect(uintptr_t newMappedPE, std::size_t szMapped, uintptr_t newObfuscatedAddress, bool isIgnoreOriginalCodeRemove = false);
|
void removeOldOpcodeRedirect(uintptr_t newMappedPE, std::size_t szMapped, uintptr_t newObfuscatedAddress, bool isIgnoreOriginalCodeRemove = false);
|
||||||
|
void InsertMiniVmEnterProcedureAddress(uintptr_t imageBase, uintptr_t virtualAddress, std::vector<unsigned char>& new_opcodes);
|
||||||
BOOL Run();
|
BOOL Run();
|
||||||
RyujinProcedure getProcessedProc();
|
RyujinProcedure getProcessedProc();
|
||||||
~RyujinObfuscationCore();
|
~RyujinObfuscationCore();
|
||||||
|
|||||||
@@ -11,17 +11,17 @@ auto main() -> int {
|
|||||||
|
|
||||||
RyujinObfuscatorConfig config;
|
RyujinObfuscatorConfig config;
|
||||||
config.m_isIgnoreOriginalCodeRemove = FALSE;
|
config.m_isIgnoreOriginalCodeRemove = FALSE;
|
||||||
config.m_isJunkCode = FALSE;
|
config.m_isJunkCode = TRUE;
|
||||||
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"
|
"sum",
|
||||||
//"invoke_main",
|
"main",
|
||||||
"sum"
|
"invoke_main"
|
||||||
// "__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