Search code examples
windowsassemblyx86exploitshellcode

Can not understand how my shellcode works. Shellcode for windows OS( not Linux!) to open calc.exe


I’ve got a shellcode. It opens calculator in my buffer overflow program.

0:  eb 16                   jmp    0x18
2:  5b                      pop    ebx
3:  31 c0                   xor    eax,eax
5:  50                      push   eax
6:  53                      push   ebx
7:  bb 4d 11 86 7c          mov    ebx,0x7c86114d
c:  ff d3                   call   ebx
e:  31 c0                   xor    eax,eax
10: 50                      push   eax
11: bb ea cd 81 7c          mov    ebx,0x7c81cdea
16: ff d3                   call   ebx
18: e8 e5 ff ff ff          call   0x2
1d: 63 61 6c                arpl   WORD PTR [ecx+0x6c],sp
20: 63 2e                   arpl   WORD PTR [esi],bp
22: 65 78 65                gs js  0x8a
25: 00 90 90 90 90 90       add    BYTE PTR [eax-0x6f6f6f70],dl
2b: 90                      nop
2c: 90                      nop
2d: 90                      nop
2e: 90                      nop
2f: 90                      nop

Apart from the main question being “What does this shellcode do line by line”, I am particularly interested in:

  1. The jmp operation, why and where does my program jump?
  2. The arpl stuff, I see it for the first time and google does not help me much... Same with GS operation

Solution

  • The jmp 0x18 is a relative jump to offset 0x18, which is practically the end of your code. It then calls address 0x2 (again, relative). This call places the "return address" on the stack, so it could be popped from it, giving you a clue about the address in which this relative shellcode is being executed. And indeed, the pop ebx at offset 0x2 is getting the address from the stack.

    I said that 0x18 is the end of the code, because the lines after it are data bytes and not asm opcodes. This is why you see arpl. If you look at the hex values of the bytes, you will see:

    calc.exe\0 ==> 0x63 0x61 0x63 0x6c 0x2e 0x65 0x78 0x65 0x00
    

    Edited:

    The full flow of the shellcode is:

    1. jmp 0x18 - jump to to the last code instruction of the shellcode
    2. call 0x2 - returns to offset 2, and stores the address of offset 0x1D on the stack
    3. pop ebx - ebx := address from the stack, which is the address of the string "calc.exe"
    4. xor eax,eax - common opcode to zero the register: eax := 0
    5. push eax - push the value 0 as the second argument for a future function call
    6. push ebx - push the pointer to "calc.exe" as the first argument for a future function call
    7. mov ebx,0x7c86114d - ebx will be a fixed address (probably WinExec)
    8. call ebx - call the function: WinExec("calc.exe", 0)
    9. xor eax,eax - again, eax := 0
    10. push eax - push the value 0 as the first argument for a future function call
    11. mov ebx,0x7c81cdea - ebx will be a fixed address (probably exit)
    12. call ebx - call the function: exit(0)