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) {
/*
To "encrypt" all the obfuscated code:
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.
*/
// Logic to encrypt executable code.
for (auto& byte : opcodesWithRelocsFixed) byte ^= 0x37; // TODO: Make this better - XOR n<>o <20> criptografia.
// Logica para criptografar c<>digo execut<75>vel. // Entry point stub to decrypt the obfuscated code
for (auto& byte : opcodesWithRelocsFixed) std::vector<unsigned char> entryPoint = {
byte ^= 0x37; // TODO: Make this better - XOR n<>o <20> criptografia.
// Log 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",