diff --git a/README.md b/README.md index 8aeddaf..ab25920 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,9 @@ **Ryūjin Protector** is an open-source **Bin2Bin** obfuscation, protection, and DRM tool for **Windows PE** binaries targeting the **Intel x64 architecture(Only)**. -![Ryūjin Protector Banner](imgs/ryujinreadme.png) +

+ Ryūjin Protector Banner +

--- @@ -14,13 +16,14 @@ - Mathematical Operators Virtualization(aka: Ryūjin MiniVM) - Obfuscated code Encryption(Using TeaDelKew Algorithm) - Anti-Debug User + Kernel -- Anti-Dump -- Anti-Disassembly(Planned) - Troll Reversers(Exclusive) +- Anti-Dump +- Anti-Disassembly(Planned - **TODO**) +- Custom Passes(Planned - **TODO**) --- -## Goals +## Demos and Presentations Ryūjin was designed and developed for the study of obfuscators with Bin2Bin capabilities, making it a viable project for use by third parties as well as serious information security students. This includes: Commercial Developers, Indie Developers/Cheat Developers, Anti-Cheat Developers, Malware Developers, Malware Analysts, and Security Researchers. @@ -30,6 +33,18 @@ Ryūjin was designed and developed for the study of obfuscators with Bin2Bin cap This is only a small demo with only one Ryūjin feature, others feature together produce a better result. +**Really Easy to Use:** + +**Ryūjin** is extremely easy to use — you can choose between the GUI mode or the CLI mode. Both will produce the same result in a precise, functional, and stable way. + +GUI Mode Demonstration: +![Ryūjin Protector Demo GUI](imgs/demo1.png) + +CLI Mode Demonstration: +![Ryūjin Protector Demo Console](imgs/demo2.png) + +For both options, you will need exclusively a PE file (Apanas, executable, for now) along with a PDB file containing the symbols for that PE file, so that you can protect and generate a new binary. Additionally, you can consult the WIKI at any time to discover other options and possibilities, such as custom passes. + --- ## Getting Started diff --git a/RyujinCore/Ryujin/RyujinCore/RyujinObfuscationCore.cc b/RyujinCore/Ryujin/RyujinCore/RyujinObfuscationCore.cc index 7d87b09..fd4edb7 100644 --- a/RyujinCore/Ryujin/RyujinCore/RyujinObfuscationCore.cc +++ b/RyujinCore/Ryujin/RyujinCore/RyujinObfuscationCore.cc @@ -1648,6 +1648,102 @@ void RyujinObfuscationCore::insertAntiDump() { // Add the AntiDump stub std::vector antiDumpShellcode = { + /* + #pragma optimize("", off) + __declspec(noinline) __declspec(safebuffers) void AntiDumpShell() { + + #ifdef _M_X64 + auto* peb = reinterpret_cast(__readgsqword(0x60)); + #else + auto* peb = reinterpret_cast(__readfsdword(0x30)); + #endif + if (!peb || !peb->Ldr) return; + + wchar_t ntdllStr[] { 'n','t','d','l','l','.','d','l','l', 0 }; + char ntprotStr[] { 'N','t','P','r','o','t','e','c','t','V','i','r','t','u','a','l','M','e','m','o','r','y', 0 }; + + NtProtectVirtualMemory_t pNtProtect = nullptr; + + auto* head = &peb->Ldr->InMemoryOrderModuleList; + for (auto* link = head->Flink; link != head; link = link->Flink) { + + auto* entry = CONTAINING_RECORD(link, LDR_DATA_TABLE_ENTRY, InMemoryOrderLinks); + if (!entry->BaseDllName.Buffer) continue; + + auto* modName = entry->BaseDllName.Buffer; + auto* target = ntdllStr; + bool matched = true; + for (; *target && *modName; ++target, ++modName) { + + auto ca = (*modName >= 'A' && *modName <= 'Z') ? *modName + 0x20 : *modName; + auto cb = (*target >= 'A' && *target <= 'Z') ? *target + 0x20 : *target; + + if (ca != cb) { matched = false; break; } + + } + + if (!matched || *target || *modName) continue; + + auto* base = reinterpret_cast(entry->DllBase); + auto* dos = reinterpret_cast(base); + auto* nt = reinterpret_cast(base + dos->e_lfanew); + auto& ed = nt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT]; + if (!ed.VirtualAddress) return; + + auto* exp = reinterpret_cast(base + ed.VirtualAddress); + auto* names = reinterpret_cast(base + exp->AddressOfNames); + auto* ords = reinterpret_cast(base + exp->AddressOfNameOrdinals); + auto* funcs = reinterpret_cast(base + exp->AddressOfFunctions); + + for (auto i = 0; i < exp->NumberOfNames; i++) { + + auto* fn = reinterpret_cast(base + names[i]); + + bool match = true; + for (auto j = 0; ntprotStr[j] || fn[j]; ++j) + if (ntprotStr[j] != fn[j]) { match = false; break; } + + if (match) { + + pNtProtect = reinterpret_cast(base + funcs[ords[i]]); + + break; + } + + + } + break; + + } + + if (!pNtProtect) return; + + auto* imgDos = reinterpret_cast(peb->ImageBaseAddress); + auto* ntHeaders = reinterpret_cast(reinterpret_cast(imgDos) + imgDos->e_lfanew); + auto* sectionHeaders = IMAGE_FIRST_SECTION(ntHeaders); + + auto headerSize = sizeof(IMAGE_DOS_HEADER); + ULONG oldProtect; + PVOID baseAddr = imgDos; + + if (pNtProtect(reinterpret_cast(-1), &baseAddr, &headerSize, PAGE_READWRITE, &oldProtect) == 0) { + + for (auto i = 0; i < ntHeaders->FileHeader.NumberOfSections; ++i) { + + auto* ptr = reinterpret_cast(§ionHeaders[i]); + + for (auto j = 0; j < sizeof(IMAGE_SECTION_HEADER); ++j) + *ptr++ = 0; + + } + + pNtProtect(reinterpret_cast(-1), &baseAddr, &headerSize, oldProtect, &oldProtect); + + } + + } + #pragma optimize("", on) + */ 0x48, 0x81, 0xEC, 0x48, 0x01, 0x00, 0x00, 0x65, 0x48, 0x8B, 0x04, 0x25, 0x60, 0x00, 0x00, 0x00, 0x48, 0x89, 0x84, 0x24, 0x98, 0x00, 0x00, 0x00, 0x48, 0x83, 0xBC, 0x24, 0x98, 0x00, 0x00, 0x00, 0x00, 0x74, 0x0F, 0x48, diff --git a/imgs/demo1.png b/imgs/demo1.png new file mode 100644 index 0000000..660242b Binary files /dev/null and b/imgs/demo1.png differ diff --git a/imgs/demo2.png b/imgs/demo2.png new file mode 100644 index 0000000..feef4cb Binary files /dev/null and b/imgs/demo2.png differ