user3273328
user3273328

Reputation: 1

Error: Illegal Instruction of shellcode (at&t) for helloworld.

I am trying to learn how to write shellcode. After searching around, I wrote my own shellcode for hello world. I think the logic is correct, but somehow when I compile the wrapper with the shellcode, it always gives me "illegal instruction".

Could anybody help me to check what is wrong with this code:

Shellcode

    .section .data
    .section .text

    .globl _start

        jmp dummy 

     _start:
            # write(1, message, 13)
            mov     $4, %al                # system call 4 is write
            mov     $1, %bl                # file handle 1 is stdout
            popl    %ecx
            mov     $12, %dl               # number of bytes to write
            int     $0x80                   # invoke operating system code

            # exit(0)
            xor     %eax, %eax
            mov     $1, %al                # system call 1 is exit
            xor     %ebx, %ebx              # we want return code 0
            int     $0x80                   # invoke operating system code

    dummy:
        call _start
        .string  "Hello, World"

After running objdump:

    file format elf32-i386


    Disassembly of section .text:

    00000000 <_start-0x2>:
       0:   eb 11                   jmp    13 <dummy>

    00000002 <_start>:
       2:   b0 04                   mov    $0x4,%al
       4:   b3 01                   mov    $0x1,%bl
       6:   59                      pop    %ecx
       7:   b2 0c                   mov    $0xc,%dl
       9:   cd 80                   int    $0x80
       b:   31 c0                   xor    %eax,%eax
       d:   b0 01                   mov    $0x1,%al
       f:   31 db                   xor    %ebx,%ebx
      11:   cd 80                   int    $0x80

    00000013 <dummy>:
      13:   e8 fc ff ff ff          call   14 <dummy+0x1>
      18:   48                      dec    %eax
      19:   65                      gs
      1a:   6c                      insb   (%dx),%es:(%edi)
      1b:   6c                      insb   (%dx),%es:(%edi)
      1c:   6f                      outsl  %ds:(%esi),(%dx)
      1d:   2c 20                   sub    $0x20,%al
      1f:   57                      push   %edi
      20:   6f                      outsl  %ds:(%esi),(%dx)
      21:   72 6c                   jb     8f <dummy+0x7c>
      23:   64                      fs
        ...

The C Wrapper I used

    char code[] = "\xeb\x11"
                    "\xb0\x04"
                    "\xb3\x01"
                    "\x59"
                    "\xb2\x0c"
                    "\xcd\x80"
                    "\x31\xc0"
                    "\xb0\x01"
                    "\x31\xdb"
                    "\xcd\x80"
                    "\xe8\xfc\xff\xff\xff"
                    "\x48\x65\x6c\x6c\x6f\x2c\x20\x57\x6f\x72\x6c\x64";



    void main() {
            int (*func)();
            func = (int(*)()) code;
            (int) (*func)();
    }

Upvotes: 0

Views: 1195

Answers (1)

Jonathon Reinhart
Jonathon Reinhart

Reputation: 137398

There are several problems with your code.

First and foremost, you're only setting the low byte of all of the parameter registers (namely al, bl, and dl). You need to set the full 32 bits. When you execute the way it is now, whatever is left in the remaining 24 bits gets passed to the kernel.

Also, in your C code, the call is not correct:

"\xe8\xfc\xff\xff\xff"

That's essentially call $+1 which is the second byte of the call instruction, which is why you're getting the illegal instruction.

I'm not sure how you arrived at the byte in your code variable, but you need to re-assemble.


Tested with gcc 4.7.2 on Fedora 17, with gcc -m32. (Sorry, I only use Intel syntax)

char code[] __attribute__((section(".text"))) = 
    "\xeb\x17"                   // jmp $+19 
    "\xB8\x04\x00\x00\x00"       // mov eax, 4   ; (sys_write)
    "\x31\xDB"                   // xor ebx, ebx
    "\x43"                       // inc ebx
    "\x59"                       // pop ecx      ; (addr of string pushed by call below)
    "\x31\xD2"                   // xor edx, edx
    "\xb2\x0c"                   // mov dl, 0Ch  ; (length of string)
    "\xcd\x80"                   // int 80h

    "\x31\xc0"                   // xor eax, eax
    "\xb0\x01"                   // mov al, 1    ; (sys_exit)
    "\x31\xdb"                   // xor ebx, ebx
    "\xcd\x80"                   // int 80h
    "\xe8\xe4\xff\xff\xff"       // call $-23
    "\x48\x65\x6c\x6c\x6f\x2c\x20\x57\x6f\x72\x6c\x64\x00";  // "Hello, World"

void main() {
    int (*func)();
    func = (int(*)()) code;
    (int) (*func)();
}

Note that there are certainly ways to make the code smaller, but that is of course left as an exercise for the reader.


If you're going to play around with hand-tweaked assembly like this, be prepared to debug, debug, debug. Learn how to use GDB now, or you will be forever helpless. Set a breakpoint on the beginning of the assembly (b code) and step through it. You'll quickly see what went wrong.

Upvotes: 2

Related Questions