第一次發文,不知道會不會觸犯版規,如有錯誤歡迎告知,謝謝。
OS:XP SP3
編譯器: DEV C++ 4.9.9.2
工具:
OD (ollydbg)
IDA
CFF Explorer
猜密碼程式: 正確密碼1234567 猜到對為止
#include <stdio.h>
#define PASSWORD "1234567"
int verify_password (char *password)
{
int authenticated;
authenticated=strcmp(password,PASSWORD);
return authenticated;
}
main()
{
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;
}
}
}
1.定位關鍵跳轉,並且爆破
2.爆破後修改PE檔
(IDA可以還原出代碼跟流程圖,但是有時候代碼會跟其他反組譯工具不一樣,但邏輯是差不多的)
可以看見 cmp 比較完,然後跳轉指令 jz,接下去有兩條分支
一條跳轉到 401332,接下去會congratulation....
另一條直接走向 incorrect password....
可以發現 cmp 比較完,然後跳轉指令 je 這就是剛剛說的兩個指令不一樣。(但邏輯是一樣的)
1.假設 cmp 123,123 (左)-(右) /// 123-123 = 0 當結果是0的時候 , ZF標誌位=1
2.JZ,JE
這兩個指令是一個意思,通過ZF標誌位是否跳轉,當執行到JZ或者JE指令時,如果ZF=1則跳轉,如果ZF=0,不跳轉
好玩的來了
正確輸入會是 cmp 1234567,1234567 /// 1234567-1234567=0 當結果是0的時候 , ZF標誌位=1
JNE,JNZ
這兩條語句同一個意思,只是叫法不同,當執行到這兩條語句時,如果標誌位ZF=0,則跳轉
也就是說我們輸入778899
當 cmp 1234567,778899 /// 1234567-778899 不會是 0 ,所以ZF會被設0
所以 jne 或是 jnz 就會跳瞜!!!
正常的 JE 的指令對應 opcode 是 74 0E
修改後 JNZ 的指令對應 opcode 是 75 0E
只需要修改 1 byte
這次我們先用難度較高的手動修該 PE檔 了解一下PE結構
(關於PE 不深入討論 網路上有很多文章)
exe檔 其實是 pe 格式。
PE 格式的結構,定義了一隻程式在虛擬內存中的結構
(因為Windows是虛擬一個4GB的內存給每一個進程 可能實際上你的主機只有512MB 蓋茲牛逼!)
所以在小小的PE結構中,定義了如何放大並映射到4GB虛擬內存。
所以了解PE結構 很重要!!!
imageBase 00400000 就是虛擬的基地址
也就是說PE結構,現在從虛擬地址00400000開始
接下來我們只關注 .text的 Section 這是存放代碼的地方
Raw address 0x400 代表 PE文件中的代碼段(.text)在相對PE文件 0x400的位置
Virtual Address 0x1000 代表 PE代碼段(.text) 映射到 虛擬的基地址(0x00400000)+ 0x1000 = 0x00401000
imageBase:0x00400000
虛擬的 .text Virtual Address 在 imageBase + 0x1000 位置上
PE的 .text真實位置是在距離 PE 文件 0x400的位置上
1.那很簡單,先算出第一個代碼(00401000) 跟 00401322的距離:
00401322- (00400000+00001000) = 322
2.真實的 PE.text 在 0x400
0x400 + 0x322 = 0x722
成功了。
如果喜歡這方面的知識也歡迎交流。