My goal is to create shellcode that calls WinExec
and launches notepad.exe
. The bare bones code is (although actually surrounded by some other gcc
produced assembly):
push 0x00646170
push 0x65746F6E
push 5
lea eax, [esp + 0x4]
push eax
call 0x76E137C0
add esp, 32
It pushes "notepad\0" onto the stack, then 5, then the address of the "notepad"
string, then finally calls 0x76E137C0
. 0x76E137C0
is the address WinExec
seems to reside at when ASLR is disabled on my machine (A 32-bit Windows 10 VM).
I'm taking this code, assembling it using gcc
(simply gcc shell.c -o shell.exe
), then objdump
ing it. Once I find the instructions, I take the bytes it shows:
40141e: 68 70 61 64 00 push $0x646170
401423: 68 6e 6f 74 65 push $0x65746f6e
401428: 6a 05 push $0x5
40142a: 8d 44 24 04 lea 0x4(%esp),%eax
40142e: 50 push %eax
40142f: e8 8c 23 a1 76 call 76e137c0 <.debug_str+0x76a027c0>
401434: 83 c4 20 add $0x20,%esp
Then I'm turning that into a string of bytes, and attempting to execute it:
#include <windows.h>
#include <winbase.h>
int main() {
char* shellcode =
"\x68\x70\x61\x64\x00\x68\x6e\x6f\x74\x65\x6a\x05\x8d\x44\x24\x04\x50\xe8\xbc\x37\xe1\x76\x83\xc4\x20";
((void(*)())shellcode)();
return 0;
}
The problem is, if I then compile the above simple C program and run it, nothing happens. If I open it in Immunity and step though, I can see that the instructions were preserved, except for the address:
The address is in the wrong module, and seemingly part way through a function. If I step down and into the call
, I get an access violation. If however I restart, and in Immunity I replace the call 77218816
with call 0x76E137C0
, then have it continue, it works fine and notepad pops up.
I can't tell why the address is changing though while nothing else is. Does anyone see what I may be doing that's off?
The whole initial assembly is
.file "shell.c"
.intel_syntax noprefix
.text
.def ___main; .scl 2; .type 32; .endef
.section .rdata,"dr"
.align 4
LC0:
.ascii "notepad\0"
.text
.globl _main
.def _main; .scl 2; .type 32; .endef
_main:
lea ecx, [esp+4]
and esp, -16
push DWORD PTR [ecx-4]
push ebp
mov ebp, esp
push ecx
push 0x00646170
push 0x65746F6E
push 5
lea eax, [esp + 0x4]
push eax
call 0x76E137C0
add esp, 32
sub esp, 8
mov eax, 0
mov ecx, DWORD PTR [ebp-4]
leave
lea esp, [ecx-4]
ret
Using call
like that is EIP-relative. You're not running your shellcode at the same address you compiled it for, so it can't call
out of itself like that. For a quick-and-dirty workaround, you can do mov eax, 0x76E137C0
and then call eax
, which is absolute.