簡體   English   中英

重寫一個小的execve shellcode

[英]Re-writing a small execve shellcode

瀏覽http://hackoftheday.securitytube.net/2013/04/demystifying-execve-shellcode-stack.html

我理解了調用execve的nasm程序,並試圖重新編寫它。

一些背景資料:

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

因此, eax = 11execve函數調用號), ebx應該指向char* filenameecx應該指向argv[] (這將與ebx相同,因為第一個參數是*filename本身,例如“/ bin / sh“在這種情況下”, edx將指向envp[] (在這種情況下為null )。

原始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

堆棧如下:

在此輸入圖像描述

現在我嘗試通過減少一些指令來優化它。 我同意,直到mov ebx, esp代碼將保持不變。 但是,由於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

但是,當我運行重新編寫的代碼時,我遇到了分段錯誤。

我的堆棧如下: 在此輸入圖像描述

任何想法為什么重寫代碼不起作用? 我也運行了gdb,地址值是根據我的想法,但它不會運行。

在這兩種情況下,ebx都指向字符串“// bin / sh”。 相當於C代碼,如下所示:

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

但是在第一個示例中,ecx被設置為指向該字符串的指針的地址。 相當於C代碼,如下所示:

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

在第二個示例中,ecx設置為與ebx相同的值。

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

這兩個例子因此根本不同,ecx有兩種完全不同的類型和價值。

更新:

我應該補充一點,技術上ecx是一個char指針數組( argv參數),而不僅僅是指向char指針的指針。 你實際上是在堆棧上構建一個兩項數組。

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

只是那個數組的一半也是envp參數的兩倍。 由於envp是單個項目數組,並且該單個項目設置為NULL,因此可以考慮使用C代碼設置的envp參數,如下所示:

EDX = envp = &argv[1];           

這是通過將edx設置為esp來實現的,而argv數組只構造了一半。 將兩個賦值的代碼組合在一起就可以得到:

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

這有點令人費解,但我希望這對你有意義。

更新2

execve所有參數都作為寄存器傳遞,但這些寄存器是指向內存的指針,需要在某處分配 - 在這種情況下,在堆棧上。 由於堆棧在內存中向下構建,因此需要以相反的順序構造內存塊。

三個參數的內存如下所示:

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   

文件名的構造如下:

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

像這樣的argv參數:

push eax // NULL pointer
push ebx // filename

envp這樣的論點是這樣的:

push eax // NULL pointer

但正如我所說,最初的例子決定在argv和evp之間共享內存,因此不需要最后一個push eax

我還應該注意,構造字符串時使用的兩個雙字中字符的相反順序是由於機器的字節順序而不是堆棧方向。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM