[英]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 = 11
( execve
函數調用號), ebx
應該指向char* filename
, ecx
應該指向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.