feat: Refactored code for Ryujin console arguments, fixed typos, and resolved instruction-padding logic issues. Fixed temporary variable bug in MBA equivalence generation and more

- Fixed bugs reported by third parties (instruction-override issues, padding-space logic, and more)
- Corrected typos (translated comments/examples to English)
- Fully refactored the Ryujin console (arguments now handled via the argparser library)
- MBA pass: fixed equivalence-logic issues when generating MBA instructions for original operations
- Updated DemoObfuscation usage examples
This commit is contained in:
keowu
2025-11-19 21:07:19 -03:00
parent bc91576ecb
commit 04063714da
11 changed files with 2720 additions and 119 deletions

View File

@@ -7,126 +7,116 @@
#include <iomanip>
#include "RyujinCore.hh"
#include "RyujinCustomPasses.hh"
#include "th3rd/argparse.hh"
auto print_help() -> void {
std::cout << R"(Ryujin Obfuscator CLI
Usage:
RyujinConsole.exe --input <exe_path> --pdb <pdb_path> --output <output_path> [options]
Options:
--input <exe> Input binary to obfuscate (required)
--pdb <pdb> Path to the PDB file (required)
--output <exe> Output path for obfuscated binary (required)
--virtualize Enable virtualization
--junk Add junk code
--encrypt Encrypt obfuscated code
--iat Enable IAT obfuscation
--random-section Use random PE section
--keep-original Keep original code (don't remove it)
--AntiDebug Inserts anti-debugging capabilities and terminates the protected binary if a debugger is detected.
--Troll Crashes the entire OS if a debugger is detected (requires --AntiDebug).
--AntiDump Inserts anti-dump mechanisms that break the binary in memory, making dumps harder to analyze.
--MemoryProtection Protects obfuscated code against in-memory or on-disk patching.
--HVPass Protect some parts of Ryujin using Microsoft Hypervisor APIs
--procs <comma,separated,names> Procedures to obfuscate (default: main, invoke_main, ...)
--help Show this help message
In Action Usage Example:
RyujinConsole.exe --input C:\\Users\\Keowu\\Documents\\GitHub\\Ryujin\\compiled\\release\\DemoObfuscation.exe --pdb C:\\Users\\Keowu\\Documents\\GitHub\\Ryujin\\compiled\\release\\RyujinConsole.pdb --output C:\\Users\\Keowu\\Documents\\GitHub\\Ryujin\\compiled\\release\\DemoObfuscation.ryujin.exe --virtualize --junk --encrypt --AntiDebug --troll --AntiDump --iat --HVPass --procs main,sub,subadd,sum,invoke_main,__scrt_common_main,j___security_init_cookie
)";
}
auto has_flag(const std::unordered_map<std::string, std::string>& args, const std::string& flag) -> bool {
return args.find(flag) != args.end();
}
auto parse_args(int argc, char* argv[]) -> std::unordered_map<std::string, std::string> {
std::unordered_map<std::string, std::string> options;
for (int i = 1; i < argc; ++i) {
std::string key = argv[i];
if (key.rfind("--", 0) == 0)
if (i + 1 < argc && argv[i + 1][0] != '-') options[key] = argv[++i]; else options[key] = "true"; // Flag-only
}
return options;
}
auto main(int argc, char* argv[]) -> int {
auto args = parse_args(argc, argv);
argparse::ArgumentParser ryujinargs("RyujinConsole", "1.1");
ryujinargs.add_description("Ryujin Obfuscator CLI - Bin2Bin");
ryujinargs.add_epilog(R"(In Action Usage Example:
if (has_flag(args, "--help") || argc == 1) {
Normal Passes:
RyujinConsole.exe --input DemoObfuscation.exe --pdb DemoObfuscation.pdb --output DemoObfuscation.ryujin.exe --virtualize --junk --encrypt --AntiDebug --troll --AntiDump --iat --HVPass --procs main,sub,subadd,sum,invoke_main,__scrt_common_main,j___security_init_cookie
print_help();
With Custom Passes(MBA Example From Ryujin Paper):
RyujinConsole.exe --input DemoObfuscation.exe --pdb DemoObfuscation.pdb --output DemoObfuscation.ryujin.exe --procs main,sub,subadd,sum,invoke_main,__scrt_common_main,j___security_init_cookie,mba_sub,mba_subadd,mba_sum,mba_f01,mba_f02,mba_f03,mba_f04,mba_f05,mba_f06,mba_f07,mba_f08,mba_f09,mba_f10,mba_f11,mba_f12,mba_f13,mba_f14,mba_f15,mba_f16,mba_f17,mba_f18,mba_f19,mba_f20,mba_f21,mba_f22,mba_f23,mba_f24,mba_f25,mba_f26,mba_f27,mba_f28,mba_f29,mba_f30,mba_f31,mba_f32,mba_f33,mba_f34,mba_f35,mba_f36,mba_f37,mba_f38,mba_f39,mba_f40,mba_f41,mba_f42,mba_f43,mba_f44,mba_f45,mba_f46,mba_f47,mba_f48,mba_f49,mba_f50,mba_f51,mba_f52,mba_f53,mba_f54,mba_f55,mba_f56,mba_f57,mba_f58,mba_f59,mba_f60,mba_f61,mba_f62,mba_f63,mba_f64,mba_f65,mba_f66,mba_f67,mba_f68,mba_f69,mba_f70,mba_f71,mba_f72,mba_f73,mba_f74,mba_f75,mba_f76,mba_f77,mba_f78,mba_f79,mba_f80,mba_f81,mba_f82,mba_f83,mba_f84,mba_f85,mba_f86,mba_f87,mba_f88,mba_f89,mba_f90,mba_f91,mba_f92,mba_f93,mba_f94,mba_f95,mba_f96,mba_f97,mba_f98,mba_f99,mba_f100
)");
// Mandatory arguments
ryujinargs.add_argument("--input").required().help("Input binary to obfuscate");
ryujinargs.add_argument("--pdb").required().help("Path to the PDB file");
ryujinargs.add_argument("--output").required().help("Output path for obfuscated binary");
// Obfuscation configs customized args
ryujinargs.add_argument("--virtualize").help("Enable virtualization").default_value(false).implicit_value(true);
ryujinargs.add_argument("--junk").help("Add junk code").default_value(false).implicit_value(true);
ryujinargs.add_argument("--encrypt").help("Encrypt obfuscated code").default_value(false).implicit_value(true);
ryujinargs.add_argument("--iat").help("Enable IAT obfuscation").default_value(false).implicit_value(true);
ryujinargs.add_argument("--random-section").help("Use random PE section").default_value(false).implicit_value(true);
ryujinargs.add_argument("--keep-original").help("Keep original code (don't remove it)").default_value(false).implicit_value(true);
ryujinargs.add_argument("--AntiDebug").help("Inserts anti-debugging capabilities and terminates the protected binary if a debugger is detected").default_value(false).implicit_value(true);
ryujinargs.add_argument("--troll").help("Crashes the entire OS if a debugger is detected (requires --AntiDebug)").default_value(false).implicit_value(true);
ryujinargs.add_argument("--AntiDump").help("Inserts anti-dump mechanisms that break the binary in memory, making dumps harder to analyze").default_value(false).implicit_value(true);
ryujinargs.add_argument("--MemoryProtection").help("Protects obfuscated code against in-memory or on-disk patching").default_value(false).implicit_value(true);
ryujinargs.add_argument("--HVPass").help("Protect some parts of Ryujin using Microsoft Hypervisor APIs").default_value(false).implicit_value(true);
ryujinargs.add_argument("--MutateMiniVM").help("Perform the mutation and add full junk code to the Ryujin MiniVM stub, regardless of whether it<69>s the normal version or the HV pass").default_value(false).implicit_value(true);
ryujinargs.add_argument("--procs").help("Procedures to obfuscate (comma-separated, e.g., main,invoke_main,...)").default_value(std::string(""));
// Parse arguments for obfuscation
try {
ryujinargs.parse_args(argc, argv);
} catch (const std::exception& err) {
std::cout << "Error when parsing arguments: " << err.what() << "\n\n";
std::cout << ryujinargs << "\n";
return 0;
}
auto input = args["--input"];
auto pdb = args["--pdb"];
auto output = args["--output"];
if (input.empty() || pdb.empty() || output.empty()) {
std::cerr << "Error: --input, --pdb, and --output are required.\n";
print_help();
return 0;
}
// Extracting mandatory arguments
auto input = ryujinargs.get<std::string>("--input");
auto pdb = ryujinargs.get<std::string>("--pdb");
auto output = ryujinargs.get<std::string>("--output");
// Configure RyujinObfuscatorConfig
RyujinObfuscatorConfig config;
config.m_isIgnoreOriginalCodeRemove = has_flag(args, "--keep-original");
config.m_isJunkCode = has_flag(args, "--junk");
config.m_isRandomSection = has_flag(args, "--random-section");
config.m_isVirtualized = has_flag(args, "--virtualize");
config.m_isIatObfuscation = has_flag(args, "--iat");
config.m_isEncryptObfuscatedCode = has_flag(args, "--encrypt");
config.m_isTrollRerversers = has_flag(args, "--troll");
config.m_isAntiDebug = has_flag(args, "--AntiDebug");
config.m_isAntiDump = has_flag(args, "--AntiDump");
config.m_isMemoryProtection = has_flag(args, "--MemoryProtection");
config.m_isHVPass = has_flag(args, "--HVPass");
config.m_isIgnoreOriginalCodeRemove = ryujinargs.get<bool>("--keep-original");
config.m_isJunkCode = ryujinargs.get<bool>("--junk");
config.m_isRandomSection = ryujinargs.get<bool>("--random-section");
config.m_isVirtualized = ryujinargs.get<bool>("--virtualize");
config.m_isIatObfuscation = ryujinargs.get<bool>("--iat");
config.m_isEncryptObfuscatedCode = ryujinargs.get<bool>("--encrypt");
config.m_isTrollRerversers = ryujinargs.get<bool>("--troll");
config.m_isAntiDebug = ryujinargs.get<bool>("--AntiDebug");
config.m_isAntiDump = ryujinargs.get<bool>("--AntiDump");
config.m_isMemoryProtection = ryujinargs.get<bool>("--MemoryProtection");
config.m_isHVPass = ryujinargs.get<bool>("--HVPass");
config.m_isMutateMiniVM = ryujinargs.get<bool>("--MutateMiniVM");
// Registering a new custom pass for invocation via callback
// Register custom passes for Ryujin
config.RegisterCallback(RyujinCustomPasses::RyujinCustomPassDemo);
// Registering MBA Obfuscation Custom Pass
config.RegisterCallback(RyujinCustomPasses::RyujinMBAObfuscationPass);
if (has_flag(args, "--procs")) {
auto rawList = args["--procs"];
// Parsing candidates procedures for obfuscation
auto procsArg = ryujinargs.get<std::string>("--procs");
if (!procsArg.empty()) {
size_t start = 0;
size_t end = 0;
int index = 0;
while ((end = rawList.find(',', start)) != std::string::npos && index < MAX_PROCEDURES) {
auto procName = rawList.substr(start, end - start);
while ((end = procsArg.find(',', start)) != std::string::npos && index < MAX_PROCEDURES) {
auto procName = procsArg.substr(start, end - start);
strncpy_s(config.m_strProceduresToObfuscate.procedures[index], procName.c_str(), MAX_PROCEDURE_NAME_LEN - 1);
++index;
start = end + 1;
}
if (index < MAX_PROCEDURES) {
auto procName = rawList.substr(start);
auto procName = procsArg.substr(start);
strncpy_s(config.m_strProceduresToObfuscate.procedures[index], procName.c_str(), MAX_PROCEDURE_NAME_LEN - 1);
++index;
}
config.m_strProceduresToObfuscate.procedureCount = index;
}
else {
print_help();
std::cout << "Error: --procs is required.\n\n";
std::cout << ryujinargs << "\n";
return 0;
}
// Run obfuscator
auto bSuccess = config.RunRyujin(input, pdb, output, config);
std::printf("Ryujin core returned: %d\n", bSuccess);

View File

@@ -118,6 +118,8 @@
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<LanguageStandard>stdcpplatest</LanguageStandard>
<LanguageStandard_C>stdclatest</LanguageStandard_C>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
@@ -133,6 +135,8 @@
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<LanguageStandard>stdcpplatest</LanguageStandard>
<LanguageStandard_C>stdclatest</LanguageStandard_C>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
@@ -148,6 +152,7 @@
<ItemGroup>
<ClInclude Include="RyujinCore.hh" />
<ClInclude Include="RyujinCustomPasses.hh" />
<ClInclude Include="th3rd\argparse.hh" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">

View File

@@ -5,13 +5,14 @@
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
<Extensions>cpp;c;cc;cxx;c++;cppm;ixx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
</Filter>
<Filter Include="Header Files">
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
<Extensions>h;hh;hpp;hxx;h++;hm;inl;inc;ipp;xsd</Extensions>
<Filter Include="th3rd">
<UniqueIdentifier>{618b6637-1d52-4832-8991-c207a41fb604}</UniqueIdentifier>
</Filter>
<Filter Include="Resource Files">
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
<Filter Include="Core Header">
<UniqueIdentifier>{bd62ddb7-0ef8-419d-b2f2-cb08025256e5}</UniqueIdentifier>
</Filter>
<Filter Include="Custom Passes">
<UniqueIdentifier>{5f9ba3be-d3ae-43b8-8e74-4a34bbae91ba}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
@@ -20,11 +21,14 @@
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="th3rd\argparse.hh">
<Filter>th3rd</Filter>
</ClInclude>
<ClInclude Include="RyujinCore.hh">
<Filter>Header Files</Filter>
<Filter>Core Header</Filter>
</ClInclude>
<ClInclude Include="RyujinCustomPasses.hh">
<Filter>Header Files</Filter>
<Filter>Custom Passes</Filter>
</ClInclude>
</ItemGroup>
</Project>

View File

@@ -36,6 +36,7 @@ public:
bool m_isAntiDump; // Enable Anti Dump technic for Ryujin protected binary
bool m_isMemoryProtection; // Memory CRC32 protection
bool m_isHVPass; // Run some features of ryujin using Microsoft Hypervisor Framework API
bool m_isMutateMiniVM; // Perform the mutation and add full junk code to the Ryujin MiniVM stub, regardless of whether it<69>s the normal version or the HV pass.
RyujinObfuscatorProcs m_strProceduresToObfuscate; // Names of the procedures to obfuscate
RyujinCallbacks m_callbacks; // Ryujin Custom Pass Callbacks

View File

@@ -100,7 +100,7 @@ namespace RyujinCustomPasses {
if (proc->name.find("mba_") == std::string::npos) return;
std::printf("[RyujinMBAObfuscationPass] Processando equivalencia MBA em %s\n", proc->name.c_str());
std::printf("[RyujinMBAObfuscationPass] Processing MBA equivalence for %s\n", proc->name.c_str());
// Starting decoder
ZydisDecoder decoder;
@@ -261,12 +261,15 @@ namespace RyujinCustomPasses {
auto tmp_tmp = asmjit::x86::r8;
auto tmp_extra = asmjit::x86::r9;
auto result_reg = asmjit::x86::r10; // Final result holder por big int operations
// Save context
a.push(asmjit::x86::rax);
a.push(asmjit::x86::rcx);
a.push(asmjit::x86::rdx);
a.push(asmjit::x86::r8);
a.push(asmjit::x86::r9);
a.push(asmjit::x86::r10);
a.mov(tmp_x, dest64);
@@ -326,7 +329,7 @@ namespace RyujinCustomPasses {
}
a.mov(dest64, tmp_x);
a.mov(result_reg, tmp_x);
}
else if (instruction.mnemonic == ZYDIS_MNEMONIC_SUB) {
@@ -366,7 +369,7 @@ namespace RyujinCustomPasses {
}
a.mov(dest64, tmp_x);
a.mov(result_reg, tmp_x);
}
else if (instruction.mnemonic == ZYDIS_MNEMONIC_XOR) {
@@ -408,7 +411,7 @@ namespace RyujinCustomPasses {
}
a.mov(dest64, tmp_x);
a.mov(result_reg, tmp_x);
}
else if (instruction.mnemonic == ZYDIS_MNEMONIC_AND) {
@@ -450,7 +453,7 @@ namespace RyujinCustomPasses {
}
a.mov(dest64, tmp_x);
a.mov(result_reg, tmp_x);
}
else if (instruction.mnemonic == ZYDIS_MNEMONIC_OR) {
@@ -489,16 +492,19 @@ namespace RyujinCustomPasses {
}
a.mov(dest64, tmp_x);
a.mov(result_reg, tmp_x);
}
// Retrieving context...
a.pop(asmjit::x86::r10);
a.pop(asmjit::x86::r9);
a.pop(asmjit::x86::r8);
a.pop(asmjit::x86::rdx);
a.pop(asmjit::x86::rcx);
a.pop(asmjit::x86::rax);
a.mov(dest64, result_reg); // Move back result to dest64 from result operation
// Generating new opcodes processed by the MBA algorithm
auto section = code.sectionById(0);
if (!section || section->buffer().empty()) {

File diff suppressed because it is too large Load Diff

View File

@@ -38,6 +38,7 @@ public:
bool m_isAntiDump; // Enable Anti Dump technic for Ryujin protected binary
bool m_isMemoryProtection; // Memory CRC32 protection
bool m_isHVPass; // Run some features of ryujin using Microsoft Hypervisor Framework API
bool m_isMutateMiniVM; // Perform the mutation and add full junk code to the Ryujin MiniVM stub, regardless of whether it<69>s the normal version or the HV pass.
RyujinObfuscatorProcs m_strProceduresToObfuscate; // Names of the procedures to obfuscate
RyujinCallbacks m_callbacks; // Ryujin Custom Pass Callbacks

View File

@@ -2280,25 +2280,29 @@ bool Ryujin::run(const RyujinObfuscatorConfig& config, const std::shared_ptr<Ryu
}
// Obfuscating MiniVMMStub/MiniVM normal to difficult RE
RyujinProcedure proc;
proc.name = "MiniVMStub";
proc.address = 0x00;
proc.size = miniVmEnter.size();
// Create MiniVM basic blocks
RyujinBasicBlockerBuilder MiniVMbb(ZYDIS_MACHINE_MODE_LONG_64, ZydisStackWidth_::ZYDIS_STACK_WIDTH_64);
proc.basic_blocks = MiniVMbb.createBasicBlocks(miniVmEnter.data(), proc.size, proc.address);
// Configure the MiniVM to obfuscate
RyujinObfuscatorConfig minivmmCfg{ 0 };
minivmmCfg.m_isJunkCode = true;
// Setup Obfuscation Core & Run Pass
RyujinObfuscationCore obfc(minivmmCfg, proc, 0x00);
// Running ryujinminivmobfuscation to protect RyujinMiniVm
auto procProcessed = obfc.RunMiniVmObfuscation();
// Assign MiniVm obfuscated into MiniVmEnter
miniVmEnter.assign(procProcessed.begin(), procProcessed.end());
// Deleting ryujin obfuscation core instance
obfc.~RyujinObfuscationCore();
if (config.m_isMutateMiniVM) {
// Obfuscating MiniVMMStub/MiniVM normal to difficult RE
RyujinProcedure proc;
proc.name = "MiniVMStub";
proc.address = 0x00;
proc.size = miniVmEnter.size();
// Create MiniVM basic blocks
RyujinBasicBlockerBuilder MiniVMbb(ZYDIS_MACHINE_MODE_LONG_64, ZydisStackWidth_::ZYDIS_STACK_WIDTH_64);
proc.basic_blocks = MiniVMbb.createBasicBlocks(miniVmEnter.data(), proc.size, proc.address);
// Configure the MiniVM to obfuscate
RyujinObfuscatorConfig minivmmCfg{ 0 };
minivmmCfg.m_isJunkCode = true;
// Setup Obfuscation Core & Run Pass
RyujinObfuscationCore obfc(minivmmCfg, proc, 0x00);
// Running ryujinminivmobfuscation to protect RyujinMiniVm
auto procProcessed = obfc.RunMiniVmObfuscation();
// Assign MiniVm obfuscated into MiniVmEnter
miniVmEnter.assign(procProcessed.begin(), procProcessed.end());
// Deleting ryujin obfuscation core instance
obfc.~RyujinObfuscationCore();
}
// Inserting the Ryujin MiniVm stub at the beginning of Ryujin section
opcodesWithRelocsFixed.insert(opcodesWithRelocsFixed.end(), miniVmEnter.begin(), miniVmEnter.end());

View File

@@ -2505,7 +2505,7 @@ BOOL RyujinObfuscationCore::Run(bool& RyujinRunOncePass) {
//Update basic blocks view based on the new obfuscated
this->updateBasicBlocksContext();
if (m_config.m_isAntiDebug) {
if (m_config.m_isAntiDebug && !m_config.m_isJunkCode) {
/*
There is no need to obfuscate the anti-debug stub code. the junk code/mutation itself will handle that during processing.

View File

@@ -36,6 +36,7 @@ public:
bool m_isAntiDump; // Enable Anti Dump technic for Ryujin protected binary
bool m_isMemoryProtection; // Memory CRC32 protection
bool m_isHVPass; // Run some features of ryujin using Microsoft Hypervisor Framework API
bool m_isMutateMiniVM; // Perform the mutation and add full junk code to the Ryujin MiniVM stub, regardless of whether it<69>s the normal version or the HV pass.
RyujinObfuscatorProcs m_strProceduresToObfuscate; // Names of the procedures to obfuscate
RyujinCallbacks m_callbacks; // Ryujin Custom Pass Callbacks

View File

@@ -4,7 +4,7 @@
#include <string>
#include <cstdint>
// Test MBA with: RyujinConsole.exe --input DemoObfuscation.exe --pdb DemoObfuscation.pdb --output DemoObfuscation.ryujin.exe --iat --procs main,mba_sub,mba_subadd,mba_sum,mba_f01,mba_f02,mba_f03,mba_f04,mba_f05,mba_f06,mba_f07,mba_f08,mba_f09,mba_f10,mba_f11,mba_f12,mba_f13,mba_f14,mba_f15,mba_f16,mba_f17,mba_f18,mba_f19,mba_f20,mba_f21,mba_f22,mba_f23,mba_f24,mba_f25,mba_f26,mba_f27,mba_f28,mba_f29,mba_f30,mba_f31,mba_f32,mba_f33,mba_f34,mba_f35,mba_f36,mba_f37,mba_f38,mba_f39,mba_f40,mba_f41,mba_f42,mba_f43,mba_f44,mba_f45,mba_f46,mba_f47,mba_f48,mba_f49,mba_f50,mba_f51,mba_f52,mba_f53,mba_f54,mba_f55,mba_f56,mba_f57,mba_f58,mba_f59,mba_f60,mba_f61,mba_f62,mba_f63,mba_f64,mba_f65,mba_f66,mba_f67,mba_f68,mba_f69,mba_f70,mba_f71,mba_f72,mba_f73,mba_f74,mba_f75,mba_f76,mba_f77,mba_f78,mba_f79,mba_f80,mba_f81,mba_f82,mba_f83,mba_f84,mba_f85,mba_f86,mba_f87,mba_f88,mba_f89,mba_f90,mba_f91,mba_f92,mba_f93,mba_f94,mba_f95,mba_f96,mba_f97,mba_f98,mba_f99,mba_f100,mba_encrypt32,invoke_main,__scrt_common_main,j___security_init_cookie
// Test MBA with: RyujinConsole.exe --input DemoObfuscation.exe --pdb DemoObfuscation.pdb --output DemoObfuscation.ryujin.exe --procs main,sub,subadd,sum,invoke_main,__scrt_common_main,j___security_init_cookie,mba_sub,mba_subadd,mba_sum,mba_f01,mba_f02,mba_f03,mba_f04,mba_f05,mba_f06,mba_f07,mba_f08,mba_f09,mba_f10,mba_f11,mba_f12,mba_f13,mba_f14,mba_f15,mba_f16,mba_f17,mba_f18,mba_f19,mba_f20,mba_f21,mba_f22,mba_f23,mba_f24,mba_f25,mba_f26,mba_f27,mba_f28,mba_f29,mba_f30,mba_f31,mba_f32,mba_f33,mba_f34,mba_f35,mba_f36,mba_f37,mba_f38,mba_f39,mba_f40,mba_f41,mba_f42,mba_f43,mba_f44,mba_f45,mba_f46,mba_f47,mba_f48,mba_f49,mba_f50,mba_f51,mba_f52,mba_f53,mba_f54,mba_f55,mba_f56,mba_f57,mba_f58,mba_f59,mba_f60,mba_f61,mba_f62,mba_f63,mba_f64,mba_f65,mba_f66,mba_f67,mba_f68,mba_f69,mba_f70,mba_f71,mba_f72,mba_f73,mba_f74,mba_f75,mba_f76,mba_f77,mba_f78,mba_f79,mba_f80,mba_f81,mba_f82,mba_f83,mba_f84,mba_f85,mba_f86,mba_f87,mba_f88,mba_f89,mba_f90,mba_f91,mba_f92,mba_f93,mba_f94,mba_f95,mba_f96,mba_f97,mba_f98,mba_f99,mba_f100
static uint32_t mba_f01(uint32_t x) { return x + 0x9E3779B1u; }
static uint32_t mba_f02(uint32_t x) { return x - 0x3C6EF372u; }
static uint32_t mba_f03(uint32_t x) { return x * 1664525u; }