feat: Implement full logic for the "Encrypt Obfuscated Code" feature

- The encryption feature in Ryujin is now fully implemented and functional. Currently, it uses a simple XOR-based algorithm for encryption and decryption. This approach will be improved in the future to enhance security.
- The feature overrides the Original Entry Point (OEP) with a new stub that decrypts all obfuscated code at runtime, then transfers control to the original entry point to continue normal execution.
This commit is contained in:
keowu
2025-06-20 16:01:10 -03:00
parent 06d5d8751b
commit 83a8d2a2b9
4 changed files with 169 additions and 15 deletions

View File

@@ -164,7 +164,44 @@ bool Ryujin::run(const RyujinObfuscatorConfig& config) {
// Ryujin MiniVM Routine // Ryujin MiniVM Routine
std::vector<unsigned char> miniVmEnter { std::vector<unsigned char> miniVmEnter {
/*
#pragma optimize("", off)
__declspec(noinline) __declspec(safebuffers)uintptr_t miniVmExecute(uintptr_t rcx, uintptr_t rdx) {
unsigned char reg = (rdx >> 16) & 0xFF;
unsigned char op = (rdx >> 8) & 0xFF;
uint64_t value = rdx & 0xFF;
uintptr_t result = rcx;
switch (op) {
case 1:
result += value;
break;
case 2:
result -= value;
break;
case 3:
result *= value;
break;
case 4:
result /= value;
break;
default:
result = 0;
break;
}
return result;
}
#pragma optimize("", on)
*/
0x48, 0x89, 0x54, 0x24, 0x10, 0x48, 0x89, 0x4C, 0x24, 0x08, 0x48, 0x83, 0x48, 0x89, 0x54, 0x24, 0x10, 0x48, 0x89, 0x4C, 0x24, 0x08, 0x48, 0x83,
0xEC, 0x28, 0x48, 0x8B, 0x44, 0x24, 0x38, 0x48, 0xC1, 0xE8, 0x10, 0x48, 0xEC, 0x28, 0x48, 0x8B, 0x44, 0x24, 0x38, 0x48, 0xC1, 0xE8, 0x10, 0x48,
0x25, 0xFF, 0x00, 0x00, 0x00, 0x88, 0x44, 0x24, 0x01, 0x48, 0x8B, 0x44, 0x25, 0xFF, 0x00, 0x00, 0x00, 0x88, 0x44, 0x24, 0x01, 0x48, 0x8B, 0x44,
@@ -224,24 +261,132 @@ bool Ryujin::run(const RyujinObfuscatorConfig& config) {
} }
// Encrypt all obfuscated code // Encrypt all obfuscated code
/*
Para "encriptar" todo o c<>digo ofuscado:
1 - Vamos criptografar byte por byte do nosso vector que carrega os novos opcodes para a section.
2 - Vamos inserir a stub que descriptografa e seus referidos opcodes no vector de novos opcodes.
3 - Vamos substituir o entrypoint original pela nossa stub. e nossa stub vai saltar no entrypoint original ap<61>s desofuscar.
4 - Teremos o c<>digo pronto a ser devidamente executado.
*/
if (config.m_isEncryptObfuscatedCode) { if (config.m_isEncryptObfuscatedCode) {
// Logica para criptografar c<>digo execut<75>vel. /*
for (auto& byte : opcodesWithRelocsFixed) To "encrypt" all the obfuscated code:
byte ^= 0x37; // TODO: Make this better - XOR n<>o <20> criptografia. 1 - We will encrypt byte by byte of our vector that contains the new opcodes for the section.
2 - We will insert the stub that decrypts and its respective opcodes into the vector of new opcodes.
3 - We will replace the original entry point with our stub. Our stub will jump to the original entry point after deobfuscation.
4 - We will then have the code ready to be properly executed.
*/
// Log // Logic to encrypt executable code.
for (auto& byte : opcodesWithRelocsFixed) byte ^= 0x37; // TODO: Make this better - XOR n<>o <20> criptografia.
// Entry point stub to decrypt the obfuscated code
std::vector<unsigned char> entryPoint = {
0x40, 0x57, 0x48, 0x81, 0xEC, 0xA0, 0x00, 0x00, 0x00, 0x65, 0x48, 0x8B,
0x04, 0x25, 0x60, 0x00, 0x00, 0x00, 0x48, 0x89, 0x44, 0x24, 0x70, 0x48,
0x83, 0x7C, 0x24, 0x70, 0x00, 0x75, 0x05, 0xE9, 0x0A, 0x03, 0x00, 0x00,
0x48, 0x8B, 0x44, 0x24, 0x70, 0x48, 0x8B, 0x40, 0x10, 0x48, 0x89, 0x44,
0x24, 0x58, 0x48, 0x83, 0x7C, 0x24, 0x58, 0x00, 0x75, 0x05, 0xE9, 0xEF,
0x02, 0x00, 0x00, 0x48, 0x8B, 0x44, 0x24, 0x58, 0x48, 0x89, 0x44, 0x24,
0x78, 0x48, 0x8B, 0x44, 0x24, 0x78, 0x0F, 0xB7, 0x00, 0x3D, 0x4D, 0x5A,
0x00, 0x00, 0x74, 0x05, 0xE9, 0xD1, 0x02, 0x00, 0x00, 0x48, 0x8B, 0x44,
0x24, 0x78, 0x48, 0x63, 0x40, 0x3C, 0x48, 0x8B, 0x4C, 0x24, 0x58, 0x48,
0x03, 0xC8, 0x48, 0x8B, 0xC1, 0x48, 0x89, 0x44, 0x24, 0x60, 0x48, 0x8B,
0x44, 0x24, 0x60, 0x81, 0x38, 0x50, 0x45, 0x00, 0x00, 0x74, 0x05, 0xE9,
0xA6, 0x02, 0x00, 0x00, 0x48, 0x8B, 0x44, 0x24, 0x60, 0x0F, 0xB7, 0x40,
0x06, 0x66, 0x89, 0x44, 0x24, 0x48, 0x48, 0x8B, 0x44, 0x24, 0x60, 0x0F,
0xB7, 0x40, 0x14, 0x48, 0x8B, 0x4C, 0x24, 0x60, 0x48, 0x8D, 0x44, 0x01,
0x18, 0x48, 0x89, 0x44, 0x24, 0x50, 0x48, 0x8D, 0x44, 0x24, 0x38, 0x48,
0x8B, 0xF8, 0x33, 0xC0, 0xB9, 0x09, 0x00, 0x00, 0x00, 0xF3, 0xAA, 0xC6,
0x44, 0x24, 0x20, 0x2E, 0xC6, 0x44, 0x24, 0x21, 0x52, 0xC6, 0x44, 0x24,
0x22, 0x79, 0xC6, 0x44, 0x24, 0x23, 0x75, 0xC6, 0x44, 0x24, 0x24, 0x6A,
0xC6, 0x44, 0x24, 0x25, 0x69, 0xC6, 0x44, 0x24, 0x26, 0x6E, 0xC6, 0x44,
0x24, 0x27, 0x00, 0x48, 0x8D, 0x44, 0x24, 0x28, 0x48, 0x8B, 0xF8, 0x33,
0xC0, 0xB9, 0x01, 0x00, 0x00, 0x00, 0xF3, 0xAA, 0x48, 0xB8, 0x99, 0x99,
0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x48, 0x89, 0x84, 0x24, 0x90, 0x00,
0x00, 0x00, 0x48, 0xB8, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88,
0x48, 0x89, 0x84, 0x24, 0x88, 0x00, 0x00, 0x00, 0xC7, 0x44, 0x24, 0x4C,
0x00, 0x00, 0x00, 0x00, 0xEB, 0x18, 0x8B, 0x44, 0x24, 0x4C, 0xFF, 0xC0,
0x89, 0x44, 0x24, 0x4C, 0x48, 0x8B, 0x44, 0x24, 0x50, 0x48, 0x83, 0xC0,
0x28, 0x48, 0x89, 0x44, 0x24, 0x50, 0x0F, 0xB7, 0x44, 0x24, 0x48, 0x39,
0x44, 0x24, 0x4C, 0x0F, 0x8D, 0xE1, 0x01, 0x00, 0x00, 0xC7, 0x44, 0x24,
0x30, 0x00, 0x00, 0x00, 0x00, 0xEB, 0x0A, 0x8B, 0x44, 0x24, 0x30, 0xFF,
0xC0, 0x89, 0x44, 0x24, 0x30, 0x83, 0x7C, 0x24, 0x30, 0x08, 0x7D, 0x19,
0x48, 0x63, 0x44, 0x24, 0x30, 0x48, 0x63, 0x4C, 0x24, 0x30, 0x48, 0x8B,
0x54, 0x24, 0x50, 0x0F, 0xB6, 0x04, 0x02, 0x88, 0x44, 0x0C, 0x38, 0xEB,
0xD6, 0xB8, 0x01, 0x00, 0x00, 0x00, 0x48, 0x6B, 0xC0, 0x08, 0xC6, 0x44,
0x04, 0x38, 0x00, 0x48, 0x8B, 0x44, 0x24, 0x50, 0x8B, 0x40, 0x0C, 0x89,
0x44, 0x24, 0x68, 0x48, 0x8B, 0x44, 0x24, 0x50, 0x8B, 0x40, 0x08, 0x89,
0x44, 0x24, 0x6C, 0x8B, 0x44, 0x24, 0x68, 0x48, 0x8B, 0x4C, 0x24, 0x58,
0x48, 0x03, 0xC8, 0x48, 0x8B, 0xC1, 0x48, 0x89, 0x84, 0x24, 0x80, 0x00,
0x00, 0x00, 0xB8, 0x01, 0x00, 0x00, 0x00, 0x48, 0x6B, 0xC0, 0x00, 0x0F,
0xBE, 0x44, 0x04, 0x38, 0xB9, 0x01, 0x00, 0x00, 0x00, 0x48, 0x6B, 0xC9,
0x00, 0x0F, 0xBE, 0x4C, 0x0C, 0x20, 0x3B, 0xC1, 0x0F, 0x85, 0x47, 0x01,
0x00, 0x00, 0xB8, 0x01, 0x00, 0x00, 0x00, 0x48, 0x6B, 0xC0, 0x01, 0x0F,
0xBE, 0x44, 0x04, 0x38, 0xB9, 0x01, 0x00, 0x00, 0x00, 0x48, 0x6B, 0xC9,
0x01, 0x0F, 0xBE, 0x4C, 0x0C, 0x20, 0x3B, 0xC1, 0x0F, 0x85, 0x23, 0x01,
0x00, 0x00, 0xB8, 0x01, 0x00, 0x00, 0x00, 0x48, 0x6B, 0xC0, 0x02, 0x0F,
0xBE, 0x44, 0x04, 0x38, 0xB9, 0x01, 0x00, 0x00, 0x00, 0x48, 0x6B, 0xC9,
0x02, 0x0F, 0xBE, 0x4C, 0x0C, 0x20, 0x3B, 0xC1, 0x0F, 0x85, 0xFF, 0x00,
0x00, 0x00, 0xB8, 0x01, 0x00, 0x00, 0x00, 0x48, 0x6B, 0xC0, 0x03, 0x0F,
0xBE, 0x44, 0x04, 0x38, 0xB9, 0x01, 0x00, 0x00, 0x00, 0x48, 0x6B, 0xC9,
0x03, 0x0F, 0xBE, 0x4C, 0x0C, 0x20, 0x3B, 0xC1, 0x0F, 0x85, 0xDB, 0x00,
0x00, 0x00, 0xB8, 0x01, 0x00, 0x00, 0x00, 0x48, 0x6B, 0xC0, 0x04, 0x0F,
0xBE, 0x44, 0x04, 0x38, 0xB9, 0x01, 0x00, 0x00, 0x00, 0x48, 0x6B, 0xC9,
0x04, 0x0F, 0xBE, 0x4C, 0x0C, 0x20, 0x3B, 0xC1, 0x0F, 0x85, 0xB7, 0x00,
0x00, 0x00, 0xB8, 0x01, 0x00, 0x00, 0x00, 0x48, 0x6B, 0xC0, 0x05, 0x0F,
0xBE, 0x44, 0x04, 0x38, 0xB9, 0x01, 0x00, 0x00, 0x00, 0x48, 0x6B, 0xC9,
0x05, 0x0F, 0xBE, 0x4C, 0x0C, 0x20, 0x3B, 0xC1, 0x0F, 0x85, 0x93, 0x00,
0x00, 0x00, 0xB8, 0x01, 0x00, 0x00, 0x00, 0x48, 0x6B, 0xC0, 0x06, 0x0F,
0xBE, 0x44, 0x04, 0x38, 0xB9, 0x01, 0x00, 0x00, 0x00, 0x48, 0x6B, 0xC9,
0x06, 0x0F, 0xBE, 0x4C, 0x0C, 0x20, 0x3B, 0xC1, 0x75, 0x73, 0xC7, 0x44,
0x24, 0x34, 0x00, 0x00, 0x00, 0x00, 0xEB, 0x0A, 0x8B, 0x44, 0x24, 0x34,
0xFF, 0xC0, 0x89, 0x44, 0x24, 0x34, 0x48, 0x63, 0x44, 0x24, 0x34, 0x8B,
0x4C, 0x24, 0x6C, 0x48, 0x2B, 0x8C, 0x24, 0x88, 0x00, 0x00, 0x00, 0x48,
0x3B, 0xC1, 0x73, 0x26, 0x48, 0x63, 0x44, 0x24, 0x34, 0x48, 0x8B, 0x8C,
0x24, 0x80, 0x00, 0x00, 0x00, 0x0F, 0xB6, 0x04, 0x01, 0x83, 0xF0, 0x37,
0x48, 0x63, 0x4C, 0x24, 0x34, 0x48, 0x8B, 0x94, 0x24, 0x80, 0x00, 0x00,
0x00, 0x88, 0x04, 0x0A, 0xEB, 0xBA, 0x48, 0x8B, 0x84, 0x24, 0x90, 0x00,
0x00, 0x00, 0x48, 0x8B, 0x4C, 0x24, 0x58, 0x48, 0x03, 0xC8, 0x48, 0x8B,
0xC1, 0x48, 0x89, 0x84, 0x24, 0x98, 0x00, 0x00, 0x00, 0xFF, 0x94, 0x24,
0x98, 0x00, 0x00, 0x00, 0x90, 0xE9, 0xF8, 0xFD, 0xFF, 0xFF, 0x48, 0x81,
0xC4, 0xA0, 0x00, 0x00, 0x00, 0x5F, 0xC3
};
// Parsing the PE file
auto imgDos = reinterpret_cast<PIMAGE_DOS_HEADER>(peSections.mappedPeDiskBaseAddress());
auto ntHeader = reinterpret_cast<PIMAGE_NT_HEADERS>(reinterpret_cast<uint8_t*>(imgDos) + imgDos->e_lfanew);
// Finding the OEP (Original Entry Point) to store it
DWORD OEP = ntHeader->OptionalHeader.AddressOfEntryPoint;
// Storing the size of the entry point stub, which will be the only non-encrypted code in the obfuscated code section
SIZE_T sizeOep = entryPoint.size();
// Setting a new entry point as the entry point stub that will decrypt the obfuscated executable code
ntHeader->OptionalHeader.AddressOfEntryPoint = peSections.getRyujinSectionVA() + offsetVA;
// Modifying the stub to adapt to the OEP of the original entry point
std::vector<unsigned char> pattern = {
0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99
};
auto it = std::search(entryPoint.begin(), entryPoint.end(), pattern.begin(), pattern.end());
std::memset(&*(it), 0, 8);
std::memcpy(&*(it), &OEP, sizeof(OEP));
/*
Modifying the stub to adapt and ignore the entry point stub decryption code itself,
in a way that skips its size so it doesn<73>t break the stub
when it decrypts the executable code.
*/
pattern.assign({
0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88
});
it = std::search(entryPoint.begin(), entryPoint.end(), pattern.begin(), pattern.end());
std::memset(&*(it), 0, 8);
std::memcpy(&*(it), &sizeOep, sizeof(sizeOep));
// Inserting the opcodes of our stub into our vector along with the rest of the obfuscated and encrypted code
opcodesWithRelocsFixed.insert(opcodesWithRelocsFixed.end(), entryPoint.begin(), entryPoint.end());
// Log to inform the user that our code has been properly encrypted.
std::printf("[!] OEP: %llx - Inserting Decryption code routine on: %llx\n", imgNt->OptionalHeader.AddressOfEntryPoint, offsetVA); std::printf("[!] OEP: %llx - Inserting Decryption code routine on: %llx\n", imgNt->OptionalHeader.AddressOfEntryPoint, offsetVA);
} }
//Process new opcodes //Process new opcodes

View File

@@ -69,7 +69,15 @@ BOOL RyujinPESections::AddNewSection(const std::string& strInputFilePath, char c
m_ntHeader->OptionalHeader.FileAlignment m_ntHeader->OptionalHeader.FileAlignment
); );
m_newSection.Characteristics = IMAGE_SCN_CNT_CODE | IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ; m_newSection.PointerToRelocations = JACKPOTNUMBER;
m_newSection.NumberOfRelocations = JACKPOTNUMBER;
m_newSection.PointerToLinenumbers = JACKPOTNUMBER;
m_newSection.NumberOfLinenumbers = JACKPOTNUMBER;
m_newSection.Characteristics = IMAGE_SCN_CNT_CODE | IMAGE_SCN_MEM_EXECUTE | IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE;
return TRUE; return TRUE;
} }

View File

@@ -7,6 +7,7 @@
#include "RyujinUtils.hh" #include "RyujinUtils.hh"
#define ALIGN_UP(value, alignment) ((value + alignment - 1) & ~(alignment - 1)) #define ALIGN_UP(value, alignment) ((value + alignment - 1) & ~(alignment - 1))
#define JACKPOTNUMBER 0x777
class RyujinPESections { class RyujinPESections {

View File

@@ -15,7 +15,7 @@ auto main() -> int {
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 = TRUE;
std::vector<std::string> procsToObfuscate{ std::vector<std::string> procsToObfuscate{
"sum", "sum",
"sub", "sub",