源代碼在前面例子的基礎上做一下修改:
1、buffer大小改爲4字節(節省空間)
2、讀取文件內容放棄fscanf( )函數,使用fread( )代替
代碼如下:
#include <stdio.h>
#include <Windows.h>
#define PASSWORD "123456"
int verify_password(char * password)
{
int authenticated;
char buffer[4];
authenticated=strcmp(password,PASSWORD);
strcpy(buffer,password);
return authenticated;
}
int main()
{
int valid_flag=0;
int size=0;
char password[1024];
LoadLibraryA("user32.dll");
FILE * fp=NULL;
if( !(fp=fopen("D:\\password.txt","rb")) )
{
printf("open file fail!\n");
exit(0);
}
// fscanf函數讀取文件全部內容有弊端
fseek(fp, 0, SEEK_END);
size=ftell(fp);
fseek(fp, 0, SEEK_SET);
fread(password,1,size,fp);
fclose(fp);
fp=NULL;
valid_flag=verify_password(password);
if(valid_flag)
printf("incorrect password!\n");
else
printf("Congratulation! You have passed the verification!\n");
system("pause");
return 0;
}
找到2處地址:
1、進程空間固有指令jmp esp的地址
在user32.dll庫中搜索,運氣好找到了,0x77D29353
在od中確認,該地址下確實有指令jmp esp
2、ExitProcess函數地址:0x7C81D20A
password.txt文件內容修改如下:
1、前12字節0x90用來覆蓋buffer[4]、authenticated、上一個棧的ebp值
2、0x77D29353用來覆蓋返回地址的值(即jmp esp指令地址)
3、0x77D507EA是MessageBoxA函數地址
4、0x7C81D20A是ExitProcess函數地址
一、編譯程序生成pe文件
二、od調試:
1、strcpy執行前棧內容
2、strcpy執行後棧內容
3、ret返回到系統中固有的jmp esp指令
4、執行jmp esp指令,注意esp值
5、跳轉到指定代碼處
關於使用fread函數替換fscanf函數,看下面2張圖對比:
1、數據中間出現0x0A,內容沒有被全部讀取
2、0x0A修改成0xAA,內容全部被讀取
結合fscanf(fp,"%s",password)代碼中的%s,大概明白了吧!