• XSS.stack #1 – первый литературный журнал от юзеров форума

[C#] XObfuscator - Open Source .NET Obfuscator (SOURCE CODE)

USDeez

HDD-drive
Забанен
Регистрация
26.06.2025
Сообщения
45
Реакции
10
Пожалуйста, обратите внимание, что пользователь заблокирован
XObfuscator - Open Source .NET Obfuscator

Menu:
11.png


Features:
  • Control Flow Obfuscation: Rearranges code flow to confuse decompilers.​
  • Renaming Protection: Replaces meaningful names with random or thematic names.​
  • Proxy Methods: Redirects constants (integers, floats, strings) through proxy methods.​
  • Anti-Decompiler Protections: Includes Anti-DnSpy, Anti-De4dot, and Anti-Ildasm features.​
  • Junk Code Insertion: Adds meaningless code to inflate program size and complexity.​
  • Watermark Embedding: Adds a unique identifier to trace the program's origin.​
  • Opaque Predicates: Inserts always-true/false conditions to obscure logic.​
  • Field Encapsulation: Converts local variables into fields for added complexity.​
  • Fake Attributes: Injects misleading metadata to confuse reverse engineers.​

Скрытый контент для зарегистрированных пользователей.
 
Пожалуйста, обратите внимание, что пользователь заблокирован
C#:
private static Instruction[] GenerateJunkCode()
{
    int junkCodeLength = random.Next(3, 6); // Junk code block length
    var junkCode = new List<Instruction>();

    for (int i = 0; i < junkCodeLength; i++)
    {
        junkCode.Add(Instruction.Create(OpCodes.Ldstr, GenerateRandomString(10))); // Load random string
        junkCode.Add(Instruction.Create(OpCodes.Pop));                            // Remove it from the stack
        junkCode.Add(Instruction.Create(OpCodes.Ldc_I4, random.Next(1, 100)));    // Load a random integer
        junkCode.Add(Instruction.Create(OpCodes.Pop));                            // Remove it from the stack
    }

    return junkCode.ToArray();
}
Блоки мусорного кода, состоящие из push-pop'ов очень легко удалить автоматически, лучше было бы делать неявные предикаты, внутри которых используются поля и методы из внутренних или внешних классов.

C#:
// Checks if the opcode is an ldc.i4 opcode
private static bool IsLdcI4(OpCode opCode)
{
    return opCode == OpCodes.Ldc_I4 ||
    opCode == OpCodes.Ldc_I4_S ||
    opCode == OpCodes.Ldc_I4_0 ||
    opCode == OpCodes.Ldc_I4_1 ||
    opCode == OpCodes.Ldc_I4_2 ||
    opCode == OpCodes.Ldc_I4_3 ||
    opCode == OpCodes.Ldc_I4_4 ||
    opCode == OpCodes.Ldc_I4_5 ||
    opCode == OpCodes.Ldc_I4_6 ||
    opCode == OpCodes.Ldc_I4_7 ||
    opCode == OpCodes.Ldc_I4_8 ||
    opCode == OpCodes.Ldc_I4_M1;
}

// Extracts the integer value from an ldc.i4 instruction
private static int GetLdcI4Value(Instruction instr)
{
    // Handle shorthand opcodes
    if (instr.OpCode == OpCodes.Ldc_I4_0) return 0;
    if (instr.OpCode == OpCodes.Ldc_I4_1) return 1;
    if (instr.OpCode == OpCodes.Ldc_I4_2) return 2;
    if (instr.OpCode == OpCodes.Ldc_I4_3) return 3;
    if (instr.OpCode == OpCodes.Ldc_I4_4) return 4;
    if (instr.OpCode == OpCodes.Ldc_I4_5) return 5;
    if (instr.OpCode == OpCodes.Ldc_I4_6) return 6;
    if (instr.OpCode == OpCodes.Ldc_I4_7) return 7;
    if (instr.OpCode == OpCodes.Ldc_I4_8) return 8;
    if (instr.OpCode == OpCodes.Ldc_I4_M1) return -1;

    // Handle ldc.i4.s (short integers)
    if (instr.OpCode == OpCodes.Ldc_I4_S && instr.Operand is sbyte sbyteValue)
    {
    return sbyteValue; // Convert sbyte to int
    }

    // Handle regular ldc.i4 or ldc.i4.s with an operand
    if (instr.Operand is int intValue)
    {
    return intValue;
    }

    throw new InvalidOperationException($"Unsupported ldc.i4 opcode or operand: {instr.OpCode}");
}
Вот это делать не нужно, нужно до обработки метода сделать SimplifyMacros, а после обработки метода сделать OptimizeMacros. Ну и IntProtection тоже довольно просто сворачивается с помощью деобфускации через оптимизацию, да или просто забить свертку этих четырех паттернов.

C#:
public static void Obfuscate(ModuleDefMD module)
{
    // Rename the assembly and module metadata
    RenameAssembly(module.Assembly);

    foreach (var type in module.Types)
    {
        // Skip system/global types
        if (type.IsGlobalModuleType) continue;

        // Rename the namespace (declaring namespace for the type)
        if (!string.IsNullOrEmpty(type.Namespace))
        {
            type.Namespace = GenerateRandomNamespaceName();
        }

        // Rename the type itself
        if (!IsCriticalName(type.Name))
        {
            type.Name = GenerateRandomName();
        }

        foreach (var method in type.Methods)
        {
            // Skip methods without a body, constructors, or the entry point
            if (!method.HasBody || IsCriticalName(method.Name) || method.IsConstructor) continue;

            // Rename the method
            method.Name = GenerateRandomName();
        }

        foreach (var field in type.Fields)
        {
            // Skip system-critical fields
            if (IsCriticalName(field.Name)) continue;

            // Rename fields
            field.Name = GenerateRandomName();
        }
    }
}

// Determines if the name is critical and should not be renamed
private static bool IsCriticalName(string name)
{
    // Skip names like Main, .ctor, or static initializers
    return name == "Main" || name == ".ctor" || name.StartsWith("<");
}
Зачем проверять ".ctor", если все равно делаешь IsConstructor (который тебе проверит и ".ctor" и ".cctor")? Ну и похоже корректной обработки getter/setter нет?

C#:
// Pattern 1: Always true
var nopInstruction1 = Instruction.Create(OpCodes.Nop);
instructions.Add(Instruction.Create(OpCodes.Ldloc, localVariable)); // Load variable
instructions.Add(Instruction.Create(OpCodes.Dup));                 // Duplicate value
instructions.Add(Instruction.Create(OpCodes.Mul));                 // Square it
instructions.Add(Instruction.Create(OpCodes.Ldc_I4, 0));           // Load 0
instructions.Add(Instruction.Create(OpCodes.Sub));                 // Subtract
instructions.Add(Instruction.Create(OpCodes.Brfalse_S, nopInstruction1)); // Always true
instructions.Add(nopInstruction1);                                 // Add valid branch target
break;
Наконец-то дошел до неявных предикатов, и на тебе. Зачем добавлять неявный предикат, если внутри него стоит nop?
 
12.jpg
 


Напишите ответ...
  • Вставить:
Прикрепить файлы
Верх