5

I was wondering if anyone had come across a packer/protector which could be used for ELF binaries. There seem to be quite a few articles on writing packers and protectors for the PE format -- however, there don't seem to be very many for Linux.

This is just a hobby and so far I've come across1 which is seems to be a very basic(but neat) introduction to SMC.

Are there any resources/source code that you could point me to that I could refer and learn from?

8

Apart from the classix UPX, you should take a look at Burneye (With its crackers, UNFburninhell and Burndump) and elfuck. They are pretty old, but still interesting.

If you are interested about tricks that can be used, this is a good introduction by aczid, and I would also recommend Binary protection schemes for a more complete overview.

Someone also presented a CanSecWest a packer named Shiva that was broken at Blackhat. Unfortunately, there is no sources available.

  • 1
    any update on this list? Except UPX, those listed are really old and not maintained. – Krypton Jan 22 '16 at 4:06
  • Feel free to write your own if you're impatient ;) – jvoisin Jan 26 '16 at 17:40
  • 1
    Unfortunately many of the links above seem not to be working anymore. – Rui F Ribeiro Jan 24 '18 at 21:03
0

UPX is an open-source packer that works on ELF binaries.

0

Click on the tool names to download. Some will be source code only, others binary only. Use at your own risk.


There are 4 sections:

  1. experimental designs, which were developed to advance the state of the art in ELF binary protection or for research purposes
  2. tools resulting from personal projects or created for fun/as a hobby
  3. historically relevant protectors, now cracked/deprecated
  4. modern protectors - those known at the time of writing to be used out in the "real world", so to speak (outside of academia - in malware for example).

Experimental / Proof of Concept

  • dacryfile (2001)

    phrack article: Armouring the ELF: Binary encryption on the UNIX platform

    Dacryfile is a collection of tools which implement the following concept. The host file is encrypted from the start of the .text section, to the end of the .text segment. The file now has its object code and its read only data protected by encryption, while all its data and dynamic objects are open to inspection. The host file is injected with a parasite that will perform the runtime decryption. This parasite can be of arbitrary size because it is appended to the end of the .data segment.

    "Parasite code" refers to code inserted into the either the file on disk or the process image in memory in order to change the runtime behavior of the program. Various techniques that were historically used to accomplish this kind of code insertion are discussed in Silvio Cesare's article Unix Viruses (1999)

    The mechanism by which the parasite code appended to the ELF binary containing the encrypted code accomplished is referred to by the grugq as "subversive dynamic linking":

    The parasite itself is fairly simple, utilising the subversive dynamic linking Linux library to access libc functions, and rc4 to decrypt the host.

    This technique was detailed in his article Cheating the ELF, in which parasite code written to a dynamically linked executable to is able to make calls to library functions essentially by searching through the process's proc/self/maps file for glibc's shared object loading and unloading functions to then load the libraries of interest.


  • shiva 0.96 (2003) (binary only (protected))

    • Introduction Presentation
    • Defeat Presentation

      Implements the following features:

      • Outer obfuscation layer to thwart static analysis
      • AES encrpyted, password protected middle layer
      • Inner encrypted layer consisting of crypt blocks which may be memory-mapped on demand
      • TRAP flag detection to prevent single-stepping
      • forks and then the processes ptrace() each other, which prevents PTRACE_ATTACH
      • jumps into the middle of instructions
      • catches SIGTRAP
      • timing checks
      • INT3 instruction replacement

      Outside of these presentations, it has been difficult to find additional information besides some discussion in phrack articles on ELF runtime encryption/decryption. No source code is available, only the binary, which is protected.


  • cryptexec (2005)

    phrack article: cryptexec: Next-generation runtime binary encryption using on-demand function extraction. The source code is included at the end.

    Here runtime decryption is accomplished through a combination of a tracing function that uses a private stack, a disassembler and code emulation to read blocks of 24 bytes are read, decrypted, disassembled and then emulated. This ensures that no more than 24 bytes of unencrypted program code reside in memory while decrypting and executing the protected code.

    The tracing routine maintains two contexts: the traced context and its own context. The context consists of 8 32-bit general-purpose registers and flags. Other registers are not modified by the routine. Both contexts are held on the private stack (that is also used for calling C).

    The idea is to fetch, one at a time, instructions from the traced program and execute them natively. Intel instruction set has rather irregular encoding, so the XDE [5] disassembler engine is used to find both the real opcode and total instruction length. During experiments on FreeBSD (which uses LOCK- prefixed MOV instruction in its dynamic loader) I discovered a bug in XDE which is described and fixed below.

    We maintain our own EIP in traced_eip, round it down to the next lower 8-byte boundary and then decrypt 24 bytes into our own buffer. Then the disassembly takes place and the control is transferred to emulation routines via the opcode control table. All instructions, except control transfer, are executed natively (in traced context which is restored at appropriate time). After single instruction execution, the control is returned to our tracing routine.


  • CSPIM (2010)

    Also developed by Vrba (the designer of the aforementioned cryptexec), and presented in the paper Program Obfuscation by Strong Cryptography (the paper is paywalled but the code is on github and the Vrba's site):

    ...we present a program obfuscation method that is based on the combination of strong encryption of code and data and a CPU simulator(CSPIM) that implements the MIPS I instruction set. Our method is different from existing methods in that only a single word (32-bits) of the protected code or data is present as plain-text in main memory. Furthermore, our method allows the possibility of externally supplying the decryption key to the simulator.

    CSPIM

    The above diagram is from Enhancements to a virtual machine based code encryptor (no code available for this paper as far as I know).


Personal Projects

  • cryptelf (2003) by SLACKo

    Modifies binary by appending code to handle runtime decryption, changing the program entry point and changing the .note segment to LOAD. Encrypts the .text section by XORing its bytes with a key.


  • ELF Encrypter - Last update: 2013-03-12

    Appears to rely on classical runtime code injection or parasite code techniques to accomplish runtime decryption.

    The encrypted file (generated by the crypt-7lib program) will be decrypted at runtime by a shared library, directly linked to the binary or listed inLD_PRELOAD, during its initialization routine. The suite also contains programs to inject plain and encrypted code into ELF binaries.

    ELF-Encrypter 0.12

    • changed the data segment infection technique
    • added the code to correct section table offsets

  • ps2-packer (2013)

    Based on UPX.

    Just like UPX this tool is designed to help you create packed ELF to run on the PS2. It has a modular design, so anybody can write any kind of module to it. It actually has a zlib module, a lzo module, three ucl modules (n2b, n2d and n2e) and a null module, for demo purpose only.


  • midgetpack (2014)

    Midgetpack contains two modes of operation: password and curve25519 key exchange.

    The curve25519 is the real advantage of midgetpack. In this mode, you do not provide any password or key. Instead, a key file is generated at packing time. This key file must be used everytime you wish to use the binary. When you start the binary, it will give a challenge and expect a response. You copy/paste the challenge in the input of the mpkex tool and receive a response containing the encrypted key to the binary. This key exchange is protected by Curve25519 key exchange, the key is encrypted with aes-128 and the whole exchange is authenticated with HMAC-SHA256 to avoid generic man-in-the-middle attacks.


  • oplzkwp (2015)

    oplzkwp is a library for ELF obfuscation. It uses PRESENT and blake244 to encrypt your payload on the fly. Only the functions that are currently executed are decrypted in memory. Both Linux (x86) and Android (ARM) are supported.



  • ELFcrypt (2018)

    Simple ELF crypter. Uses RC4 encryption.



Historical

  • burneye (v1) by the Teso group (2002)

    The following summary is given in cryptexec: Next-generation runtime binary encryption using on-demand function extraction (more information is included in burneye's documentation):

    Similarly to Shiva, it has three layers: 1) obfuscation, 2) password-based encryption using RC4 and SHA1 (for generating the key from passphrase), and 3) the fingerprinting layer.

    The fingerprinting layer is the most interesting one: the data about the target system is collected (e.g. amount of memory, etc..) and made into a 'fingeprint'. The executable is encrypted taking the fingerprint into account so that the resulting binary can be run only on the host with the given fingerprint. There are two fingerprinting options:

    • Fingeprint tolerance can be specified so that Small deviations are allowed. That way, for example, the memory can be upgraded on the target system and the executable will still work. If the number of differences in the fingeprint is too large, the program won't work.

    • Seal: the program produced with this option will run on any system. However, the first time it is run, it creats a fingerprint of the host and 'seals' itself to that host. The original seal binary is securely deleted afterwards.

    The encrypted binary can also be made to delete itself when a certain environment variable is set during the program execution.


  • objobf aka burneye2 (2003)

    It reads one ELF relocateable object file and produces a functional equivalent output file, which is an obfuscated version of the input file. To do this, objobf breaks up all functions in the file to the basic block level. This representation is used to mutate the code while keeping it semantically equivalent. This involves dataflow analysis and basic block transformations. Afterwards, the basic block representation as control flow graph is linearized into a new object file, which is created from scratch.


  • elfuck

    Implements executable compression as well as encryption. Based on UPX and burneye.

    • ELFuck uses excellent Markus F.X.J. Oberhumer's compression algorithm, NRV2E which carries very good compression with tiny decompressor (about 128 bytes!). This algorithm family is stolen from UPX, with difference in that decompression is done in real time; ELFuck will decompress ELF directly to .text/.data segment and executes authentic ELF image from there, on other hand, UPX creates original ELF in /tmp and execve() it, so that we don't need any writeable filesystem at all.

    • Because ELFuck is 100%-ly based on stolen ideas, I also implemented this one of BurnEye. Someone may like to disallow other users to use/analyse your binary (public shells, root browsing user's homes). The algorithm is kinda simple, but seems to be pretty effective: We'll select some password; expand it using sha1 to 160 bit key. by this key we'll encrypt, using RC4 algorithm, whole binary (except the decrypting stub, of course). We'll also keep last 32bits of sha1 against original binary, in order to check password. When someone will execute such protected binary; the stub will ask for password, make hash of it and try to decrypt the binary back using this key. Then we'll make a hash of potentially decrypted binary, check it against the value we've saved while creating, and if matches, the binary is decrypted correctly (=right password) and we'll let it run.

Modern

The majority of modern ELF binaries are protected using UPX or a variant thereof. 1,2





Additional Information

A taxonomy of self-modifying code for obfuscation (2011) concisely summarizes some of these tools and discusses a variety of obfuscation techniques.

References

  1. Understanding Linux Malware

  2. Modern Linux Malware Exposed

  3. Unboxing Linux/Mumblehard (2015) - ESET

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy