2013-02-12 92 views
3

我正在學習作業,我完全難住。教授和助教都沒有幫助,因爲他們提供給每個學生的每個答案都是「繼續尋找,答案就在那裏」的一些變化。我想透過這個代碼外殼:內嵌程序集啓動外殼

#include <stdio.h> 
#include <stdlib.h> 

const char code[] = 
"\x31\xc0" 
"\x50" 
"\x68""//sh" 
"\x68""/bin" 
"\x89\xe3" 
"\x50" 
"\x53" 
"\x89\xe1" 
"\x99" 
"\xb0\x0b" 
"\xcd\x80" 
; 

int main(int argc, char **argv) 
{ 
printf("running...\n"); 

char buf[sizeof(code)]; 
strcpy(buf, code); 
((void(*)())buf)(); 
} 

我試圖與在網上找到其他一些例子(包括本網站)以及來自教授提供額外的PDF的例子來代替code[]。這些都沒有用。我用gdb反彙編,試圖構建我自己的code[],那也失敗了。對於它的價值,我可以說在一個普通用戶中,我的應用程序在((void(*)())buf)();行上出現段錯誤,並且在同一行上的root用戶退出(無段錯誤通知)。

我不知道還有什麼地方需要這個任務,我不能在任何後來的緩衝區溢出任務上工作,直到我能理解這個簡單的第一步。任何幫助將大大讚賞。

編輯:我忘了提及,我已經在OSX 10.8.2和Ubuntu VM上通過VirtualBox嘗試了這一點。我假設它不適用於OSX,但我絕望。哈對於Ubuntu的,我們被要求做:

須藤#sysctl -w kernel.randomize_va_space = 0

命令和apt-get安裝的zsh CD/bin中 須藤RM SH 須藤LN -s /斌/ zsh/bin/sh

這些命令應該禁用地址空間隨機化,安裝zsh並將其鏈接到/ bin/sh。我完成了所有的VM的任務,沒有任何錯誤

+0

您的系統可能會將您的堆棧所在的頁面標記爲不可執行。在一個調試器中,你會看到'call'指令時的分段錯誤,其地址爲'buf'作爲參數。你的任務是否涉及繞過這種保護? – 2013-02-12 08:09:12

+0

@MichaelFoukarakis我曾打算補充一點,但已經晚了!我現在已經編輯了這個問題,提供了更多的信息來回答我相信的這個問題。 – 2013-02-12 20:14:28

+0

那麼,你面臨的問題與有問題的代碼無關。也許你想發佈你的任務的目標? – 2013-02-12 20:17:52

回答

10

您的代碼拆開來是這樣的:

00000000 31C0    xor eax,eax 
00000002 50    push eax 
00000003 682F2F7368  push dword 0x68732f2f 
00000008 682F62696E  push dword 0x6e69622f 
0000000D 89E3    mov ebx,esp 
0000000F 50    push eax 
00000010 53    push ebx 
00000011 89E1    mov ecx,esp 
00000013 99    cdq 
00000014 B00B    mov al,0xb 
00000016 CD80    int 0x80 

禮貌的ndisasm。讓我們一步一步地完成這些指令並分析堆棧幀。

xor eax,eaxeax寄存器清零,因爲操作數與其自身的XOR操作總是會產生零結果。然後push eax將值壓入堆棧。因此,堆棧目前看起來或多或少像這樣(相對於在代碼的開始的的esp值示出偏移量,esp意味着esp目前指向堆棧小區):

 +----------+ 
    0 | 00000000 | 
esp -4 | xxxxxxxx | 
     +----------+ 

接下來,我們2個push dword指令,這推動了一些直接的價值堆棧,其中 - 它們執行後 - 看起來是這樣的:

 +----------+ 
    0 | 00000000 | 
    -4 | 68732f2f | 
    -8 | 6e69622f | 
esp -12| xxxxxxxx | 
     +----------+ 

esp當前指向那個被推到堆棧中的第二立即值的最後一個字節。讓我們嘗試將推送的值解釋爲ASCII,按照從當前值esp開始按順序從堆棧中讀取的順序進行解釋。我們得到2f62696e2f2f7368的字節序列,其ASCII碼等於/bin//sh。另外,序列以0結尾,所以它是一個有效的C字符串。

這就是爲什麼當前值esp被保存到寄存器ebx中的主要原因。它包含將要運行的可執行文件的路徑。雙斜槓對操作系統來說不是問題,因爲POSIX只是忽略了多次出現的斜槓並將它們視爲一個斜線。

接下來,我們將當前值eaxebx推入堆棧。我們知道eax包含零,並且ebx包含指向C字符串"/bin//sh"的指針。堆棧目前看起來是這樣的:

  +----------+ 
     0 | 00000000 | 
     -4 | 68732f2f | 
     -8 | 6e69622f | 
    ebx -12| 00000000 | 
     -16| (ebxVal) | 
ecx esp -20| xxxxxxxx | 
      +----------+ 

推寄存器的值到堆棧後,當前指針esp保存在ecx

cdqcdq是一種在這種情況下執行非常整潔的技巧的指令:它將eax的當前值簽名擴展到edx:eax寄存器對中。因此,在這種情況下,由於零的符號擴展爲零,因此它會將值edx中的值清零。當然,我們可以通過xor edx, edx清除edx中的值,但該指令使用兩個字節編碼 - 而cdq只佔用一個。

下一條指令將值0xb(11)放入eax的低字節寄存器中。與前一種情況類似,我們可以僅執行mov eax, 0xb,但這會導致5字節指令,因爲立即數必須編碼爲完整的32位值。

int 0x80在Linux上調用系統調用調用程序。該公司預計的系統調用在eax額外的參數在ebxecxedxesiediebp數目(現在等於0xb,所以sys_execve函數將被調用),和。

現在,讓我們來看看原型該系統調用:

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

因此,filename說法被放置在ebx - 它指向/bin//shargv,置於ecx中,是要執行的可執行文件的參數數組,必須以NULL值終止。在Intel架構上,NULL等於0,而ecx指向的是:指向/bin//sh的指針,然後是NULL的值。 envp(即NULL)指向一組環境值,其值必須表示爲char*key=value

execve的成功執行導致當前過程映像替換爲指向可執行文件的映像,並使用所提供的參數執行該映像。在這種情況下,/bin/sh將被執行(如果存在),參數爲/bin//sh

邁克爾可能是正確的,爲什麼這不起作用:最近的Linux內核將數據頁標記爲不可執行,並試圖執行它們將導致分段錯誤。

+0

這是很有價值的知識,我相信很快會在這裏派上用場。我感謝你的時間! – 2013-02-12 23:34:15