0x01 程序及其編譯環境
程序如下,功能:我們必須輸入正確的密碼1234567才能得到密碼驗證的確認,跳出循環。否則程序提示密碼錯誤再次輸入。
#include <stdio.h>#define PASSWORD "1234567"int verify_password(char* password)
{int authenticated;authenticated = strcmp(password, PASSWORD);return authenticated;
}int main(void)
{int valid_flag = 0;char password[1024];while (1){printf("please input password: ");scanf("%s", password);valid_flag = verify_password(password);if (valid_flag){printf("incorrect password!\n\n");}else{printf("Congratulation! You have passed the verification!\n");break;}}
}
程序編譯環境:
操作系統:win xp
編譯器:VC++6.0
build版本:release版本
對于產生release版本,我們可以在編譯時,選擇下圖內容
如果沒上面的界面,我們可以右鍵空白區域,然后選擇組建,就可以出現上面的界面。
程序的運行結果效果圖如下:
0x02 分析程序
找到工程的文件夾,我們使用release編譯時,會生成一個Release文件夾,在這個文件夾中,我們找到.exe文件
將exe文件直接拖到IDA中,IDA就會把二進制文件翻譯成質量上乘的反匯編代碼。默認情況下,IDA會自動識別main函數。
按F12會自動繪制出更加專業和詳細的函數流程圖。
用鼠標選擇程序分支點,按空格鍵切換到匯編代碼
這條指令就是我們要找的if分支,內存地址VA:40106E.
用OD打開文件,Ctrl+G,跳轉到這個地址。
OD默認情況下將程序中斷在PE裝載器開始處,而不是main函數的開始。
我們在這個地址打上斷點
密碼驗證函數的返回值存放在EAX中,if語句通過以下兩條指令實現。
test eax,eax
JE XXXX
現在我們將je改成jne,現在當我們輸入正確密碼就會提示錯誤,輸入錯誤密碼就會正確
改過之后,原本JE對應的機器指令為74,改成jnz之后變為75,運行程序,單步執行就可以看到執行了正確密碼才應該得到的指令。
0x03 破解程序
方法1
右鍵----復制到可執行文件-----所有修改
選擇全部復制
右鍵----保存文件,就可以了
運行程序,當我們輸入1234567,會讓我們繼續輸入,輸入其他會立即退出
方法2
這里我們要認識幾個名詞:
- 文本偏移地址(File Offset):數據在PE文件中的地址叫文件偏移地址,這是文件在磁盤上存放時相對于文件開頭的偏移。
- 裝入基址(Image Base):PE裝入內存時的基地址。默認情況下,EXE文件在內存中的基地址是0x00400000,DLL文件時0x10000000.
- 虛擬內存地址(VA):PE文件中的指令被裝入內存后的地址
- 相對虛擬地址:內存地址相對于映射基址的偏移量
- 節偏移:存儲單位差異引起的節基址差
文件偏移地址=VA-裝入基址-節偏移
節偏移=.text段的虛擬內存地址-文件偏移地址
文件數據在磁盤和內存中的存放:
- 磁盤:以0x200字節為基本單位進行存放。當一個數據節不足0x200字節時,不足的地方將被0x00填充;當一個數據節超過0x200,下一個0x200將分配給這個節使用。
- 內存:以0x1000字節為基本單位進行組織。類似的,不足將被補全,如果超出將分配下一個節為其所用。
節偏移就是這些基本單位造成的,也就是0x00填充的地方
用LordPE打開exe文件
我們可以看到.text的虛擬內存地址(Voffset)=0x1000,文件偏移地址(Roffset)也是這個。所以節偏移=0
40106E.這個地址的指令在PE文件中的文件偏移地址=40106E-400000-節偏移=0x106E
用編譯器打開exe文件,這里我使用010Editor,Ctrl+G,輸入0x106E直接跳轉到JE指令的機器代碼處,將74改成75
保存后執行,結果和方法1一樣。