SkillAgentSearch skills...

ELFREVGO

Anti-analysis tool that obfuscates ELF files

Install / Use

/learn @Trigleos/ELFREVGO
About this skill

Quality Score

0/100

Supported Platforms

Universal

README

ELFREVGO

ELFREVGO is a anti-analysis tool that helps to obfuscate ELF files. It operates on already compiled ELFs and is a great tool to create challenges for CTFs or if you just want to make a Reverse Engineer's life a bit harder. Currently, it implements 5 different techniques of obfuscation that are more or less easy to reverse (there's only so much you can change without breaking execution) that are detailed a bit further down.

INSTALLATION

There's an already compiled version in the bin folder, if you want to compile it yourself, you can go into the src folder and run go build ELFREVGO.go ELF_Parser.go

EXAMPLES

There's an example C script in the example folder as well as a shell script that compiles the script into different types of ELF files.

OBFUSCATION TYPES

ELFREVGO will be demonstrated on the example_nopie ELF file. Here's the source code:

#include <stdio.h>
#include <stdlib.h>


int custom_printf(char* input) /*This is the function we want to call instead of system*/
{
	printf("This is custom\n");
	printf("%s",input);
	return 1;
}

int main()
{
	int x = system("Test\n");  /*This is the call to system we want to replace*/
	printf("%i\n",x);
}

Compile this script using the following command:

gcc -no-pie example.c -o example_nopie

It runs fine even though it says that it can't find the command Test (this is fine, we'll fix this later).

CLASS OBFUSCATION

Each ELF file specifies in its header if it is a 64 bit or a 32 bit executable. ELFREVGO has the -b flag that changes this class

./ELFREVGO -f example_nopie -b -o example_output

If we run example_output, it still produces the same output as before. However, dissassemblers and debuggers have problems interpreting the file:

gdb

"example_output": not in executable format: file format not recognized
(gdb) run
Starting program:  
No executable file specified.
Use the "file" or "exec-file" command.
(gdb) break main
No symbol table is loaded.  Use the "file" command.

radare2

WARNING: get_sections_from_phdr: assertion 'bin && bin->phdr' failed (line 2819)
WARNING: get_sections_from_phdr: assertion 'bin && bin->phdr' failed (line 2819)
WARNING: get_sections_from_phdr: assertion 'bin && bin->phdr' failed (line 2819)
 -- Hang in there, Baby!
[0x00401090]> aa
[Cannot find function at 0x00401090 sym. and entry0 (aa)
[x] Analyze all flags starting with sym. and entry0 (aa)
[0x00401090]> afl
[0x00401090]> s main
Cannot seek to unknown address 'main'

ltrace

ltrace ./example_output 
"./example_output" is ELF from incompatible architecture

Reversing the obfuscation

Reversing this change isn't that hard, the reverse engineer just needs to change a single value in the ELF header. | complexity score | time score | impact score |--|--|--| | ★★☆☆☆ | 10 minutes |★★★★☆

DATA OBFUSCATION

Each ELF file specifies in its header if its values are to be interpreted as Big Endian or Little Endian. ELFREVGO has the -e flag that changes the endianness

./ELFREVGO -f example_nopie -e -o example_output

example_output still produces the same output as before and also can't be dissassembled with gdb or radare2.

Reversing the obfuscation

Reversing this change again isn't that hard, the reverse engineer just needs to change a single value in the ELF header. | complexity score | time score | impact score |--|--|--| | ★★☆☆☆ | 10 minutes |★★★★☆

SECTION TYPE OBFUSCATION

Every section in an ELF file has a certain type specified in the section header that determines their function. ELFREVGO can overwrite these section types with the flag -t

./ELFREVGO -f example_nopie -t -o example_output

example_output still runs fine, however it affects gdb (radare2 in this case is unaffected by the change)

gdb

BFD: warning: example_output has a corrupt string table index - ignoring
Reading symbols from example_output...
(No debugging symbols found in example_output)
(gdb) break main
No symbol table is loaded.  Use the "file" command.
Make breakpoint pending on future shared library load? (y or [n]) n
(gdb) run
Starting program: example_output 
[Detaching after vfork from child process 2939]
sh: 1: Test: not found
32512

gdb cannot load the symbols due to the obfuscation so we cannot set a breakpoint on main

ltrace

ltrace ./example_output 
Couldn't get name of section #1 from "/proc/2986/exe": invalid section

readelf

There are 31 section headers, starting at offset 0x39c0:

Section Headers:
  [Nr] Name              Type             Address           Offset
       Size              EntSize          Flags  Link  Info  Align
  [ 0]                   NULL             0000000000000000  00000000
       0000000000000000  0000000000000000           0     0     0
  [ 1] .interp           NULL             0000000000400318  00000318
       000000000000001c  0000000000000000   A       0     0     1
  [ 2] .note.gnu.propert NULL             0000000000400338  00000338
       0000000000000020  0000000000000000   A       0     0     8
  [ 3] .note.gnu.build-i NULL             0000000000400358  00000358
       0000000000000024  0000000000000000   A       0     0     4
  [ 4] .note.ABI-tag     NULL             000000000040037c  0000037c
       0000000000000020  0000000000000000   A       0     0     4
  [ 5] .gnu.hash         NULL             00000000004003a0  000003a0
       000000000000001c  0000000000000000   A       6     0     8
readelf: Warning: [ 6]: Unexpected value (1) in info field.
  [ 6] .dynsym           NULL             00000000004003c0  000003c0
       0000000000000090  0000000000000018   A       7     1     8
  [ 7] .dynstr           NULL             0000000000400450  00000450
       000000000000004b  0000000000000000   A       0     0     1
  [ 8] .gnu.version      NULL             000000000040049c  0000049c
       000000000000000c  0000000000000002   A       6     0     2

Reversing the obfuscation

Reversing this change requires some knowledge about section types. You could compare the section types with a normal ELF file and recuperate them but you first need to find the problem that's causing gdb and ltrace to not be able to work correctly. | complexity score | time score | impact score |--|--|--| | ★★★★☆ | 30 minutes |★★★☆☆

SECTION NAME OBFUSCATION

Every section has also a name that's specified in the section header. ELFREVGO can overwrite these names using the -n flag.

./ELFREVGO -f example_nopie -n -o example_output

This obfuscation doesn't affect any debugger or dissassembler but it affects readelf a bit

readelf

Section Headers:
  [Nr] Name              Type             Address           Offset
       Size              EntSize          Flags  Link  Info  Align
  [ 0]                   NULL             0000000000000000  00000000
       0000000000000000  0000000000000000           0     0     0
  [ 1]                   PROGBITS         0000000000400318  00000318
       000000000000001c  0000000000000000   A       0     0     1
  [ 2]                   NOTE             0000000000400338  00000338
       0000000000000020  0000000000000000   A       0     0     8
  [ 3]                   NOTE             0000000000400358  00000358
       0000000000000024  0000000000000000   A       0     0     4
  [ 4]                   NOTE             000000000040037c  0000037c
       0000000000000020  0000000000000000   A       0     0     4
  [ 5]                   GNU_HASH         00000000004003a0  000003a0
       000000000000001c  0000000000000000   A       6     0     8
  [ 6]                   DYNSYM           00000000004003c0  000003c0
       0000000000000090  0000000000000018   A       7     1     8
Section to Segment mapping:
  Segment Sections...
   00     
   01      
   02                
   03          
   04        
   05            
   06      
   07      
   08       
   09      
   10      
   11     
   12   

Reversing the obfuscation

Reversing this change requires parsing the section header string table and getting the offsets for each section name. This could take some time but can be done pretty much instantaneously with a script and comparing it with an obfuscated ELF file. | complexity score | time score | impact score |--|--|--| | ★★★★☆ | 30 minutes |★☆☆☆☆

GOT OBFUSCATION

The last obfuscation technique is a bit special because it requires preparations in the source code. There needs to be a replacee and a replacement

Replacee: A library function such as system that needs to be actually called in the compiled ELF (Attention: not every library function can be used. Due to optimisations by the compiler, some calls to library functions are replaced with simple assembly code. strlen is one such function that is prone to being replaced by an assembly routine). In our example script, we use system

Replacement: A user-defined function that should be called intead of the library function. In our example script, we use custom_printf

When we have those two prepared, we can use the -g flags to overwrite the GOT entries

  • -g overwrite GOT address
  • -gd name of the library function
  • -gf name of the user-defined function
  • -gx hex address of the user-defined function in case ELF is stripped
./ELFREVGO -f example_nopie -g -gd system -gf custom_printf -o example_output

Now we can also run example_output and get different output

./example_output 
This is custom
Test
1

This obfuscation greatly affects static analysis. Dissassembly shows that we are calling system but in reality we are calling custom_printf. An ELF would probably need to be run and then analyzed before any reverse engineer would see the change in the GOT.

rad

Related Skills

View on GitHub
GitHub Stars39
CategoryDevelopment
Updated4d ago
Forks6

Languages

Go

Security Score

80/100

Audited on Apr 3, 2026

No findings