I have some C++ code executing shellcode on a Windows 7 SP1 (32-bit) virtual machine. The shellcode is meant to run the Windows ShellExecute function.
ShellExecute(0,"open","cmd",NULL,0,SW_MAXIMIZE);
Here is the shellcode. In it, the CALLed address is reversed (because x86 is little-endian). However, the PUSHed strings ('cmd' and 'open') are not. Why?
#include <windows.h>
char code[] =
"\x68\x63\x6d\x64\x00" // PUSH "cmd" - string already terminated
"\x8B\xDC" // MOV EBX, ESP:
// puts the pointer to the text "cmd" into ebx
"\x6A\x00" // PUSH the string terminator for 'open'
"\x68\x6f\x70\x65\x6e" // PUSH "open" onto the stack
"\x8B\xCC" // MOV ECX, ESP:
// puts the pointer to the text "open" into ecx
"\x6A\x03" // PUSH 3: Push the last argument
"\x33\xC0" // xor eax, eax: zero out eax
"\x50" // PUSH EAX: push second to last argument - 0
"\x50" // PUSH EAX: push third to last argument - 0
"\x53" // PUSH EBX: push pointer to string 'cmd' <---- not reversed
"\x51" // PUSH ECX: push pointer to string 'open' <---- not reversed
"\x50" // PUSH EAX: push the first argument - 0
"\xB8\xc0\x87\x8e\x76" // MOV EAX,0x768e87c0: move ShellExecuteA <---- reversed
// address into EAX
"\xff\xD0" // CALL EAX: call the function ShellExecuteA
; // Terminates the C instruction
int main(int argc, char **argv)
{
LoadLibraryA("Shell32.dll"); // Load shell32.dll library
int (*func)();
func = (int (*)()) code;
(int)(*func)();
}
CALL vs. PUSH?
Is it because of the different operations, CALL and PUSH? That doesn't seem to be the base because in this post (albeit on a Linux machine), the PUSHed strings are reversed.
Windows vs. Linux?
But in this article (on a Windows machine), the PUSHed strings are not reversed (like in my shellcode). So is it an OS thing? If so, that's still confusing because endianness is tied to architecture, and I assume all these examples are running on an x86 machine.