Skip to content

Latest commit

 

History

22 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Obfuscator

Cross-platform binary obfuscation, anti-reversing, anti-debugging and av-bypass framework for Windows and Linux

Description

This framework provides a preprocessor that modifies C source code by inserting ASM and C based code snippets for binary obfuscation, anti-reversing, anti-debugging and av-bypass purposes. It uses predefined templates to create variations of code snippets.

Templates

The framework provides two types of snippet templates based on the ASM and C codebase. In turn, C templates can include references to ASM templates. Templates are located in the tpl directory. The internal directory win contains Windows-specific code snippets, linux contains Linux-specific code snippets, and cross contains cross-platform code snippets.

The following common templates structure is used for each supported operating system:

  • win / linux / cross
    • dbgs
      • asm
      • c
    • snds
      • asm
      • c
    • vmds
      • asm
      • c

The obfuscation ASM snippets are common to all operating systems and are located in the cross subdirectory:

  • cross
    • obfs

ASM template represents the content of the C language asm volatile() compiler instruction with assembly code. Its code uses framework-based instructions for obfuscation logic.

C template represents the body of a C language function. Its code uses framework-based instructions for obfuscation logic, API calls, and more.

Snippets

The framework contains four types of snippets:

  • Obfuscation snippets (obfs) are used for binary obfuscation. They contain dummy assembly code that does nothing, and their only purpose is to obfuscate the application's logic. These snippets can only contain ASM code templates. To insert such snippets into C code, use the {{obf:*}} instruction
  • Anti-Debugging snippets (dbgs) are used to determine whether an application is being debugged. These snippets may contain ASM and C code templates. To insert such snippets into C code, use the {{dbg:*}} instruction
  • Sandbox Detection snippets (snds) are used to determine whether the application is running in an antivirus sandbox. These snippets may contain ASM and C code templates. To insert such snippets into C code, use the {{snd:*}} instruction
  • Virtual Machine Detection snippets (vmds) are used to detect guest operating systems running under a virtual machine. These snippets may contain ASM and C code templates. To insert such snippets into C code, use the {{vmd:*}} instruction

In the provided framework-based instructions can be used asterisk {{obf:*}} to insert any snippet, snippet name {{snd:clone}} or a comma separated list with the snippet names {{snd:clone,rdtsc}}. Spaces are not allowed, names may contain letters, numbers and underscores. The snippet name is the same as the template file name without the *.c extension. Snippets with different types and codebases can use the same names.

Warning! Cross-platform code snippets that have the same type, language, and name as OS-specific snippets cause a collision and should be renamed.

Code

The framework contains three common cross-platform C code templates and three corresponding subtemplates for each supported operating system, located in the tpl/code directory:

  • header.c template contains all the framework logic that should be inserted into the resulting C file. Use the {{header}} instruction to place this code in the C source file
  • api.c template contains all the logic related to the API calls (kernel32.dll for Windows and libc.so for Linux) and decryption functions. This code will be placed in the C source file via the header template
  • shell.c template contains logic related to the shellcode execution. This code will be placed in the C source file via the header template if the shellcode is provided in the command prompt. Shellcode should be called from code using the {{shell-exec}} instruction.

Win32 API Calls

The framework provides two types of instructions for API calls from core libraries. Instructions for calls with {{api-n:<name>}}(...) and without {{api-0:<name>}}() arguments. Each instruction should contain the API function name {{api-n:Sleep}}(1), {{api-0:GetLastError}}(). The function name will be encrypted and added to the source code. Before calling a function, its name will be decrypted and filled with zero bytes after use.

To call API functions, the framework uses a special caller entity that should be initialized once in the project's main function and then passed as a parameter to every function that uses API calls or C code snippets. The following instructions can be used to work with the API caller:

  • {{caller-init}} initializes the caller variable
  • {{caller-var}} inserts the caller variable. Use it to pass the caller variable to the function as a parameter
  • {{caller-ptr}} inserts the caller pointer. Use it to pass the caller pointer to the function as a parameter
  • {{caller-decl-var}} inserts the caller variable declaration. Use it to declare the caller function parameter as a variable
  • {{caller-decl-ptr}} inserts the caller pointer declaration. Use it to declare the caller function parameter as a pointer
  • {{caller-cast}} declares the caller variable and initializes it by casting from a pointer. Use it in case of API callback functions with arguments of type void *
  • {{caller-kernel}} gets the kernel32.dll / libc.so core module handle from the caller variable. Use it to access the core module when needed
  • {{caller-proc}} calls the GetProcAddress / dlsym function from the caller variable. It is used to get API functions from modules other than the core one
  • {{caller-exit}} calls the ExitProcess() / exit() function. It is useful in case of cross-platform development, when the C snippet is not dependent on the operating system

Constants

The framework allows to insert a random constant into the source code using the following instructions:

  • {{value:byte}} inserts a 8-bit random integer value
  • {{value:uuid}} inserts a random UUID as a string of hexadecimal numbers without delimiters
  • {{value:guid}} inserts a random UUID in the Windows format with braces and delimiters

Strings

The framework allows to encrypt string variables used in the source code. To declare and encrypt a string, use the following instruction {{str-alloc:<var>:<value>}}. This instruction allows to declare a string variable using its name and value {{str-alloc:lpName:Text}}. The variable name can contain letters, numbers, and underscores. The characters { and } in the string text must be escaped with \, for example \{ and \}. An already created string variable can be reassigned using the {{str-realloc:<var>:<value>}} instruction with the same parameters. After use, the string should be released using the {{str-free:<var>}} instruction, passing the name of the string variable.

Shellcode

Calling shellcode is an additional feature of this framework. Pass shellcode as a base64 string by using -shell command prompt argument. Use the Metasploit tool msfvenom with the argument -f base64 to generate any type of shellcode.

ASM Snippets

This type of snippets represents the content of the C language asm volatile() compiler instruction with assembly code. Use the "memory" clobber to add the memory barrier. The ASM snippet provides two types of framework-based instructions:

  • {{ops}} inserts dummy assembly instructions that obfuscate the binary. The number of instructions varies from 0 to the value of the -ops argument passed on the command prompt. Pass 0 to tell the framework not to generate dummy instructions
  • {{reg:<number>:<size>}} instruction tells the framework to insert a random register to add polymorphism to the fragment. The first argument specifies the register number. The same template will generate different assembly code each time. Up to 10 (numbers from 0 to 9 can be used) general purpose registers can be inserted: rax, rbx, rcx, rdx, rsi, rdi, r8, r9, r10, r11. The second argument tells the framework the size of the register: without argument - the preprocessor inserts a QWORD register, d - inserts a DWORD register, w - inserts a WORD register, b inserts a BYTE register

The framework generates several variants of ASM snippets and inserts them into the resulting source file as inline C functions with names constructed according to the following pattern {type}_asm_{name}_{number}.

C Snippets

This type of snippets represents the body of a C function that takes a caller parameter. The caller is passed to the function by value for better binary obfuscation. The C snippet allows to use any ASM fragments, call API functions and execute shellcode. The framework generates several variants of C snippets and inserts them into the resulting source file as inline C functions with names constructed according to the following pattern {type}_c_{name}_{number}.

Available Snippets

  • cross
    • obfs
      • 00, 01, 02, 03, 04, 05 - six code obfuscation snippets that implement obfuscation techniques such as: Logic Flow Obfuscation, NOP Obfuscation, Anti-Disassembler Code Obfuscation, Trampolines and Instruction Permutations
    • snds
      • c
        • memory - allocation of a huge amount (~200 MB) of memory to force the AV sandbox analysis to end
    • vmds
      • asm
        • cpuid - detecting the presence of a VM by checking some flags returned by CPUID(1) instruction
  • linux
    • dbgs
      • c
        • check_tracer_pid - checking TracerPid from the /proc/self/status file to see if there is a debugger or tracer attached to this process via ptrace
    • snds
      • asm
        • clone - creating a copy of the executing process using the fork syscall
  • win
    • dbgs
      • asm
        • debug_flag - direct debugger detection by analyzing the PEB structure
        • heap_flags - checking the Flags and ForceFlags heap fields, which are affected by the presence of a debugger
        • nt_global_flag - checking of NtGlobalFlag by analyzing the PEB structure
      • c
        • check_remote_debugger_present - calling CheckRemoteDebuggerPresent Win32 API function
        • heap_protection - checking the end of the allocated heap block
        • is_debugger_present - calling IsDebuggerPresent Win32 API function
        • nt_query_information_process - checking information from the process by calling ntdll!NtQueryInformationProcess Win32 API function
    • snds
      • c
        • clone - creating a copy of the executing process
        • load_library - loading a non-existent dynamic library to cheat the sandbox
        • query_performance_counter - detecting the difference between the specified and actual process sleep time using the QueryPerformanceCounter Win32 API call
        • rdtsc - detecting the difference between the specified and actual process sleep time using the rdtsc CPU instruction
    • vmds
      • c
        • virtual_box - detecting the presence of the VirtualBox by checking the existence of the pseudo-device \\.\VBoxMiniRdrDN on the system

Execution

The framework provides the following comand prompt arguments:

  • -help shows framewor command line help
  • -dir sets the working directory with the tpls folder. May be useful if the binary is called from another location
  • -tpl sets a C file with a template for processing
  • -os sets the operating system for compilation
  • -ops sets the maximum number of random operations for the ASM fragment
  • -obfs, -dbgs, -snds, -vmds set the number of variants for each snippet type
  • -shell sets a Base64 string with shellcode. Use msfvenom -f base64 ... to generate

Example

This repository contains two sample loader templates for Linux and Windows, demonstrating the framework's capabilities. Use the Makefile from the examples/linux/loader or examples/win/loader directory to create and compile the obfuscated binary. Each Makefile contains the following commands:

  • install - compile the obfuscation framework using the installed Go compiler
  • source - generate the resulting C file with the obfuscated source code
  • loader - compile the obfuscated C file
  • clean - clean compiled executables
  • all - run the clean + loader commands

The Linux example uses shellcode to execute the whoami command. The Windows example uses shellcode to run the default calculator. Both shellcodes were generated using the Metasploit framework.

Disclaimer

This project is provided for informational purposes only. The author is not responsible for its malicious use.

Project Support

You can support this project by donating to the following Ethereum wallet:

ethereum:0x0468DcdE81b69b87ea0A546faA6c5aae2F4FE30b

ethereum:0x0468DcdE81b69b87ea0A546faA6c5aae2F4FE30b

About

Cross-platform binary obfuscation, anti-reversing, anti-debugging and av-bypass framework for Windows and Linux

Topics

Resources

Stars

17 stars

Watchers

1 watching

Forks

Releases

Used by

Contributors

Languages