Question

Going through http://hackoftheday.securitytube.net/2013/04/demystifying-execve-shellcode-stack.html

I understood the nasm program which invokes execve and was trying to re-write it.

Some background information:

int execve(const char *filename, char *const argv[], char *const envp[]);

So, eax = 11 (function call number for execve), ebx should point to char* filename, ecx should point to argv[] (which will be the same as ebx since the first argument is the *filename itself e.g. "/bin/sh" in this case), and edx will point to envp[] (null in this case).

Original nasm code:

global _start

section .text
_start:

xor eax, eax
push eax

; PUSH //bin/sh in reverse i.e. hs/nib//

push 0x68732f6e
push 0x69622f2f

mov ebx, esp

push eax
mov edx, esp

push ebx
mov ecx, esp

mov al, 11
int 0x80

The stack is as follows:

enter image description here

Now i tried to optimize this by reducing a few instructions. I agree that till mov ebx, esp the code will remain the same. However, since ecx will need to point to ebx, I can re-write the code as follows:

global _start

section .text
_start:

xor eax, eax
push eax

; PUSH //bin/sh in reverse i.e. hs/nib//

push 0x68732f6e
push 0x69622f2f
mov ebx, esp

mov ecx,ebx

push eax
mov edx, esp

mov al, 11
int 0x80

However, I get a segmentation fault when I run my re-written code.

My stack is as follows: enter image description here

Any ideas why the re-written code does not work? I've ran gdb also and the address values are according to my thinking, but it just won't run.

Was it helpful?

Solution

In both cases ebx is pointing to the string "//bin/sh". The equivalent of C code like this:

char *EBX = "//bin/sh";  

But in your first example, ecx is set to the address of a pointer to that string. The equivalent of C code like this:

char *temp = "//bin/sh"; // push ebx
char **ECX = &temp;      // mov ecx, esp

While in your second example, ecx is just set to the same value as ebx.

char *ECX = "//bin/sh";

The two examples are thus fundamentally different, with ecx have two completely different types and values.

Update:

I should add that technically ecx is an array of char pointers (the argv argument), not just a pointer to a char pointer. You're actually building up a two item array on the stack.

char *argv[2];
argv[1] = NULL;         // push eax, eax being zero
argv[0] = "//bin/sh";   // push ebx
ECX = argv;             // mov ecx,esp

It's just that half of that array is doubling as the envp argument too. Since envp is a single item array with that single item being set to NULL, you can think of the envp arguments being set with C code like this:

EDX = envp = &argv[1];           

This is achieved by setting edx to esp while the argv array is only half constructed. Combining the code for the two assignments together you get this:

char *argv[2];
argv[1] = NULL;         // push eax, eax being zero
EDX = &argv[1];         // mov edx,esp
argv[0] = "//bin/sh";   // push ebx
ECX = argv;             // mov ecx,esp

It's a bit convoluted, but I hope that makes sense to you.

Update 2

All of the arguments to execve are passed as registers, but those registers are pointers to memory which needs to be allocated somewhere - in this case, on the stack. Since the stack builds downwards in memory, the chunks of memory need to be constructed in reverse order.

The memory for the three arguments looks like this:

char *filename:  2f 2f 62 69 | 6e 2f 73 68 | 00 00 00 00 
char *argv[]:    filename    | 00 00 00 00               
char *envp[]:    00 00 00 00   

The filename is constructed like this:

push eax        // '\0' terminator plus some extra
push 0x68732f6e // 'h','s','/','n'
push 0x69622f2f // 'i','b','/','/'

The argv argument like this:

push eax // NULL pointer
push ebx // filename

And the envp argument like this:

push eax // NULL pointer

But as I said, the original example decided to share memory between argv and evp, so there is no need for that last push eax.

I should also note that the reverse order of the characters in the two dwords used when constructing the string is because of the endianess of the machine, not the stack direction.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top