To be the apostrophe which changed 「Impossible」 into 「I'm possible」 —— failwest
沒有星星的夜裡,我用知識吸引你
上節課沒有操練滴東西,不少蠢蠢欲動的同學肯定已經坐不住了。悟空,不要猴急,下面的兩堂課都是實踐課,用來在實踐中深入體會上節課中的知識,並且很有趣味性哦
信息安全技術是一個對技術性要求極高的領域,除了紮實的計算機理論基礎外、更重要的是優秀的動手實踐能力。在我看來,不懂二進位就無從談起安全技術。
緩衝區溢出的概念我若干年前已經瞭然於胸,不就是淹個返回地址把 CPU 指到緩衝區的 shellcode 去麼。然而當我開始動手實踐的時候,才發現實際中的情況遠遠比原理複雜。
國內近年來對網絡安全的重視程度正在逐漸增加,許多高校相繼成立了「信息安全學院」或者設立「網絡安全專業」。科班出身的學生往往具有紮實的理論基礎,他們通曉密碼學知識、知道 PKI 體系架構,但要談到如何真刀實槍的分析病毒樣本、如何拿掉 PE 上複雜的保護殼、如何在二進位文件中定位漏洞、如何對軟體實施有效的攻擊測試……能夠做到的人並不多。
雖然每年有大量的網絡安全技術人才從高校湧入人力市場,真正能夠滿足用人單位需求的卻聊聊無幾。捧著書本去做應急響應和風險評估是濫竽充數的作法,社會需要的是能夠為客戶切實解決安全風險的技術精英,而不是滿腹教條的闊論者。
我所知道的很多資深安全專家都並非科班出身,他們有的學醫、有的學文、有的根本沒有學歷和文憑,但他們卻技術精湛,充滿自信。
這個行業屬於有興趣、夠執著的人,屬於為了夢想能夠不懈努力的意志堅定者。如果你是這樣的人,請跟著我把這個系列的所有實驗全部完成,之後你會發現眼中的軟體,程序,語言,計算機都與以前看到的有所不同——因為以前使用肉眼來看問題,我會教你用心和調試器以及手指來重新體驗它們。
首先簡單複習上節課的內容:
高級語言經過編譯後,最終函數調用通過為其開闢棧幀來實現
開闢棧幀的動作是編譯器加進去的,高級語言程式設計師不用在意
函數棧幀中首先是函數的局部變量,局部變量後面存放著函數返回地址
當前被調用的子函數返回時,會從它的棧幀底部取出返回地址,並跳轉到那個位置(母函數中)繼續執行母函數
我們這節課的思路是,讓溢出數組的數據躍過 authenticated,一直淹沒到返回地址,把這個地址從 main 函數中分支判斷的地方直接改到密碼驗證通過的分支!
這樣當 verify_password 函數返回時,就會返回到錯誤的指令區去執行(密碼驗證通過的地方)
由於用鍵盤輸入字符的ASCII表示範圍有限,很多值如0x11,0x12等符號無法直接用鍵盤輸入,所以我們把用於實驗的代碼在第二講的基礎上稍加改動,將程序的輸入由鍵盤改為從文件中讀取字符串。
#include <stdio.h>
#define PASSWORD "1234567"
int verify_password (char *password)
{
int authenticated;
char buffer[8];
authenticated=strcmp(password,PASSWORD);
strcpy(buffer,password);//over flowed here!
return authenticated;
}
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("incorrect password!\n");
}
else
{
printf("Congratulation! You have passed the verification!\n");
}
fclose(fp);
}
程序的基本邏輯和第二講中的代碼大體相同,只是現在將從同目錄下的password.txt 文件中讀取字符串而不是用鍵盤輸入。我們可以用十六進位的編輯器把我們想寫入的但不能直接鍵入的 ASCII 字符寫進這個 password.txt 文件。
用 VC6.0 將上述代碼編譯連結。我這裡使用默認編譯選項,BUILD 成 debug 版本。鑑於有些同學反映自己的用的是 VS2003 和 VS2005,我好人做到底,把我 build 出來的 PE 一併在附件中雙手奉上——沒話說了吧!不許不學,不許學不會,不許說難,不許不做實驗!呵呵。
要 PE 的點擊左下角閱讀原文查看、下載。
在與 PE 文件同目錄下建立 password.txt 並寫入測試用的密碼之後,就可以用OllyDbg 加載調試了。
停~~~啥是OllyDbg,開玩笑,在這裡問啥是 Ollydbg 分明是不給看雪老大的面子麼!如果沒有這個調試器的話,去工具版找吧,帖子附件要掛出個 OD 的話會給被人鄙視的。
在開始動手之前,我們先理理思路,看看要達到實驗目的我們都需要做哪些工作。
要摸清楚棧中的狀況,如函數地址距離緩衝區的偏移量,到底第幾個字節能淹到返回地址等。這雖然可以通過分析代碼得到,但我還是推薦從動態調試中獲得這些信息。
要得到程序中密碼驗證通過的指令地址,以便程序直接跳去這個分支執行
要在 password.txt 文件的相應偏移處填上這個地址
這樣 verify_password 函數返回後就會直接跳轉到驗證通過的正確分支去執行了。
首先用 OllyDbg 加載得到的可執行 PE 文件如圖: