简体   繁体   English

重写一个小的execve shellcode

[英]Re-writing a small execve shellcode

Going through http://hackoftheday.securitytube.net/2013/04/demystifying-execve-shellcode-stack.html 浏览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. 我理解了调用execve的nasm程序,并试图重新编写它。

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 eg "/bin/sh" in this case), and edx will point to envp[] ( null in this case). 因此, eax = 11execve函数调用号), ebx应该指向char* filenameecx应该指向argv[] (这将与ebx相同,因为第一个参数是*filename本身,例如“/ bin / sh“在这种情况下”, edx将指向envp[] (在这种情况下为null )。

Original nasm code: 原始nasm代码:

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: 堆栈如下:

在此输入图像描述

Now i tried to optimize this by reducing a few instructions. 现在我尝试通过减少一些指令来优化它。 I agree that till mov ebx, esp the code will remain the same. 我同意,直到mov ebx, esp代码将保持不变。 However, since ecx will need to point to ebx , I can re-write the code as follows: 但是,由于ecx需要指向ebx ,我可以重新编写代码如下:

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: 我的堆栈如下: 在此输入图像描述

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. 我也运行了gdb,地址值是根据我的想法,但它不会运行。

In both cases ebx is pointing to the string "//bin/sh". 在这两种情况下,ebx都指向字符串“// bin / sh”。 The equivalent of C code like this: 相当于C代码,如下所示:

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

But in your first example, ecx is set to the address of a pointer to that string. 但是在第一个示例中,ecx被设置为指向该字符串的指针的地址。 The equivalent of C code like this: 相当于C代码,如下所示:

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. 在第二个示例中,ecx设置为与ebx相同的值。

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

The two examples are thus fundamentally different, with ecx have two completely different types and values. 这两个例子因此根本不同,ecx有两种完全不同的类型和价值。

Update: 更新:

I should add that technically ecx is an array of char pointers (the argv argument), not just a pointer to a char pointer. 我应该补充一点,技术上ecx是一个char指针数组( argv参数),而不仅仅是指向char指针的指针。 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. 只是那个数组的一半也是envp参数的两倍。 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: 由于envp是单个项目数组,并且该单个项目设置为NULL,因此可以考虑使用C代码设置的envp参数,如下所示:

EDX = envp = &argv[1];           

This is achieved by setting edx to esp while the argv array is only half constructed. 这是通过将edx设置为esp来实现的,而argv数组只构造了一半。 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 更新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. execve所有参数都作为寄存器传递,但这些寄存器是指向内存的指针,需要在某处分配 - 在这种情况下,在堆栈上。 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: 像这样的argv参数:

push eax // NULL pointer
push ebx // filename

And the envp argument like this: envp这样的论点是这样的:

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 . 但正如我所说,最初的例子决定在argv和evp之间共享内存,因此不需要最后一个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. 我还应该注意,构造字符串时使用的两个双字中字符的相反顺序是由于机器的字节顺序而不是堆栈方向。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM