phra's blog ~ Technical posts about InfoSec

Feb 04, 2020

x0rro — A PE/ELF/MachO Crypter for x86 and x86_64 Based on Radare2

Often AV software relies on simple signatures to detect malicious software and I needed an automated tool in order to confirm this behaviour and be able to quickly produce a working bypass. That’s why I wrote x0rro, a simple crypter based on Radare2 that supports both x86 and x86_64 architectures for PE, ELF and MachO executable formats.


Let’s identify our requirements in order to kick off the design phase:

  1. As our ideal use case, we want to be able to take an existing executable that prints the string Hello World! to stdout and produce a variant that doesn’t include anymore the string in the binary itself but still correctly prints it.

  2. Our goal is to be able to quickly produce variations of the same binary while maintaining its original behaviour.

  3. As a requirement, we would like to implement a solution that supports multiple operating systems and architectures.

  4. We also want to be able to select which sections of the executable binary we want to alter, potentially selecting only portions of specific sections.

  5. As a nice to have, we would like to avoid including specific libraries to deal with single executable formats and keep the codebase as much generic as we can.

  6. Another feature that we would like to have is the ability to choose between using a code cave or adding a new section to place our stub.

  7. Since we want to achieve a simple signature bypass, we won’t include any kind of anti-debug or anti-sandbox features in our crypter.

Research & Development

In order to fulfill our requirements, I decided to implement a software based on Radare2, the Libre and Portable Reverse Engineering Framework.

I chose TypeScript as language and NodeJS as runtime to be able to quickly prototype a Proof of Concept and the library R2Pipe to communicate with Radare2 (there are bindings available for the major languages, including JavaScript (NodeJS) and Python).

For some functionalities there are currently not available in Radare2, such as adding segments/sections and changing their permissions, we will resort on the Python library LIEF.

In order to obfuscate specific regions of the executable, we will use a simple 1-byte XOR encryption, that will be just enough to bypass static signatures: the main idea is to XOR them ahead of time and insert an assembly stub that will do the decryption at runtime.

On Linux and Mac Os X, we also need to invoke the mprotect syscall in order to enable rwx permissions on the memory pages that we want to encrypt/decrypt.

We also need to produce a valid Position Indipendent Code for our stub in order to support PIE executables:

The template for the x86 Linux will be something similar to the following:

; i386 syscall args: ebx ecx edx esi edi ebp
; 0x7d i386 mprotect { int mprotect(caddr_t addr, size_t len, int prot); }

    push edx
    push ecx
    push ebx
    push eax
    push ebp
    call _get_eip:
    pop ebp
    mov edx, 0x7 ; rwx
    mov ecx, {{{psize}}}
    lea ebx, [ebp + {{{page_start}}}]
    mov eax, 0x7d ; mprotect linux
    int 0x80
    lea edi, [ebp + {{{vaddr}}}]
    mov ecx, edi
    add ecx, {{{vsize}}}
    xor byte ptr [edi], {{{xor_key}}}
    inc edi
    cmp edi, ecx
    jl _xor_loop{{{name}}}
    lea edi, [ebp + {{{entry_point}}}]
    pop ebp
    pop eax
    pop ebx
    pop ecx
    pop edx
    jmp edi

and for x86_64 Linux:

; parameter order is: %rdi, %rsi, %rdx, %rcx, %r8, %r9, then push the rest on the stack in reverse order
; 74 AUE_MPROTECT { int mprotect(caddr_t addr, size_t len, int prot); }

    push rdi
    push rsi
    push rdx
    push rcx
    push rax
    lea rdi, [{{{page_start}}}]
    mov rsi, {{{psize}}}
    mov rdx, 0x7 ; rwx
    mov rax, 10 ; mprotect linux
    lea rdi, [{{{vaddr}}}]
    mov rcx, rdi
    add rcx, {{{vsize}}}
    xor byte ptr [rdi], {{{xor_key}}}
    inc rdi
    cmp rdi, rcx
    jl _xor_loop{{{name}}}
    pop rax
    pop rcx
    pop rdx
    pop rsi
    pop rdi
    jmp {{{entry_point}}}


After a couple of weeks of development, x0rro is now ready to be released and it supports the three major executable formats, i.e. ELF/PE/MachO, and both x86 and x86_64 architectures as per our requirements. Feel free to grab the source from GitHub or installing it directly with NPM.

Install Radare2 from master branch and make it available on the $PATH:

git clone --depth=1 https://github.com/radareorg/radare2.git
cd radare2
export PATH=~/bin/:$PATH

We also need to install LIEF library:

pip3 install lief

From sources:

git clone https://github.com/phra/x0rro.git
cd x0rro
npm i
./bin/run -h

From NPM:

npm i -g x0rro --ignore-scripts
x0rro -h

To view the usage of all the available commands, you can use the -h switch:

x0rro -h
x0rro cave -h
x0rro section -h
x0rro interactive -h

An example using the code cave technique to encrypt the .rodata section:

x0rro cave -s rodata my_file

And by adding a new section instead:

x0rro section -s rodata my_file

We can achieve the same result by using the interactive wizard, as shown here:

x0rro interactive my_file