Hi,

I see more and more people making their « own » obfuscator. Most of them are koivm copy/paste, confuserex copy/paste or simple static protection. So, I’ll write my perfect obfuscator receipe. This is only my opinion and it’s only theorical, it’s much more difficult to code what I’ll advice you than to write this topic

The aim of obfuscation is to make the original code impossible to read and/or to crack so all simple line of code has to become harder to read.

  • Strings / Constants

One of the most importants objects are strings and constants. Looking for strings in a deobfuscated app make cracking easier so it’s very important to make them unreadable. Here are different levels of strength

  1. Using a simple algorithm to encrypt strings or constants (base64 or simple maths for constants)
  2. Using a password algorithm (AES, XOR, …)
  3. Hide strings/constants in a resource (str password = Res(0))
  4. Encrypt resource and use mutation to complexify reading the location in the resource
  5. Use x86 unmanaged code or/and native dll to decrypt the strings/constants
  6. Mix all that and store strings online with check to providing the value
  7. Add Anti-Invoke / StackTrace checker
  • Name of methods/types/fields/resources/…

When cracking of reading at the source code of an assembly, having the original name of methods, … make the task easier. So, let’s rename all

  1. Rename with non-ascii characters
  2. Rename with ascii characters
  3. Rename with simple characters (a, b, c, …) Attention to ambiguity
  4. Make an anti-renamer so that the app crashes as the methods got renamed
  • External calls hiding

It’s also important to hide call to external methods (MessageBox.Show, Application.Run, …)

  1. Using proxies
  2. Using calli
  3. Using Delegate/Dynamic Methods
  4. Mix both and applying complex mutations (for calli token for example)
  • Control Flow 

You can mix the blocks by randomixing their order but still executing them in the right order so the code become impossible to read by a human without calculation

  1. Using br.s IL Cflow
  2. Using if/else with junk blocks
  3. Using switch
  4. Using switch with complex mutation
  • Anti-Tamper

Ensure the integrity of your file is important. If the file is modified/tampered, it won’t run anymore

  1. Add checksum check
  2. Encrypting method bodies and decrypt it at runtime using checksum key
  • Resource Encryption

Resource are sometimes important so there’s some way to protect them

  1. Compress them
  2. Compress and Encrypt them using simple Algorithm
  3. Compress and Encrypt them using complex calculation and dynamic values
  • Junk Code/Instruction adder

This function not be abused. You can add some junk methods,  fields … And why not some junk instructions in the code itself. Pay attention, this feature reduce perfomance and increase exe size so I don’t recommend use it

  • Anti-Decompilers/Deobfuscators

To avoid your assembly being opened in dnspy, SAE, Ildasm, … you can use breaches in dnlib, Mono.cecil, … to make impossible to open your asm in a decompiler or to be used in deobfuscators

  • Fake-Attributes

You can add fake attributes to make deobfuscators detection wrong. This feature is a bit useless because advanced reverser won’t care of it

  • Anti-Dump/Debug

This part is really important for the next features. Using a good anti-debug/dump to avoid your file being opened in a debugger/dumped. These features require playing with the memory and the PE header

  • Packer/Compressor

This feature may compress the assembly by putting in into a stub and invoke the assembly entry-point

  1. Using .net stub
  2. Using .net stub and calculating entry-point before invoking it
  3. Using native stub
  4. Using native stub with multiple check before invoking the assembly
  • MSIL Encryption

You can’t crack an app if you do not see the code ! MSIL Encryption grab the methods bodies, encrypt them and restore them at runtime

  1. Restoring the methods at runtime
  2. Restoring methods with check
  3. Restoring methods only when needed
  • Virtualization

Virtualization is today maybe the most important feature. It take each opcodes and translate them into virtual opcodes which can only be read by a virtual machine

  1. Opcode in plain-text
  2. Opcode encrypted
  3. Dynamic OpCodes
  4. Custom OpCodes

If you can manage to implement the whole max feature, I ensure you that it’ll be very hard to unpack your application.

As you saw, I mentionned « complex mutation » several times. Yeah, I see more and more sizeof, Math.X, X.parse, … This is NOT complex mutation and it’s easy to remove. Complex mutation involve high  mathematics calculations (linear algebra, binary operations, complex expressions, …)

It’s late now so I may did some errors. Please contact me if you have any suggestion

discord : MindSystemm#4159