如下示例**,摘錄自《深入理解計算機系統》:
#include
#include
size_t strlen(const char *s)
char *strcpy(char *dest, const char *src)
while (c);
return result; }
char *getline()
int main(int argc, char *argv)
標黃色的**是有問題的,如果讀入的字元大於buf[8],會導致緩衝區溢位。
gcc -o1 -m32 -o bufovf bufovf.c
編譯時,gcc
會發出警告:
/tmp/ccwrmuor.o: in function `getline':
bufovf.c:(.text+0x56):warning: the `gets' function is dangerous and should not be used.
objdump-d bufovf
disassembly of section .plt: ……
080484d4 :
80484d4: 55 push %ebp
80484d5: 89 e5 mov %esp,%ebp
80484d7: 83 ec 28 sub $0x28,%esp //esp = esp – 0x28
80484da: 89 5d f4 mov %ebx,0xfffffff4(%ebp) //
備份ebx
80484dd: 89 75 f8 mov %esi,0xfffffff8(%ebp) //
備份esi
80484e0: 89 7d fc mov %edi,0xfffffffc(%ebp) //
備份edi
80484e3: 8d 75 ec lea 0xffffffec(%ebp),%esi //esi = buf
80484e6: 89 34 24 mov %esi,(%esp) //
80484e9: e8 76 fe ff ff call 8048364 //
呼叫gets函式
80484ee: 89 f7 mov %esi,%edi //edi = esi
80484f0: fc cld //
清除df
標誌。
80484f1: b9 ff ff ff ff mov $0xffffffff,%ecx //ecx = -1
80484f6: b8 00 00 00 00 mov $0x0,%eax //eax = 0
80484fb: f2 ae repnz scas %es:(%edi),%al//
掃瞄buf
的內容,當尋找到
al的值(
0)時,掃瞄結束。
80484fd: f7 d1 not %ecx//ecx取反
80484ff: 83 e9 01 sub $0x1,%ecx //ecx = ecx -1
,得到buf
的長度。
8048502: 89 0c 24 mov %ecx,(%esp)//
把長度作為入參儲存到棧中
8048505: e8 8a fe ff ff call 8048394 //
呼叫malloc
804850a: 89 c3 mov %eax,%ebx//result = eax,
儲存malloc
分配的記憶體位址
804850c: 89 74 24 04 mov %esi,0x4(%esp) //esp+4 = buffer
,源記憶體位址
8048510: 89 04 24 mov %eax,(%esp) //esp = result
,目的記憶體位址
8048513: e8 9c ff ff ff call 80484b4 //
呼叫strcpy函式
8048518: 89 d8 mov %ebx,%eax //eax = result
,作為返回值
804851a: 8b 5d f4 mov 0xfffffff4(%ebp),%ebx
804851d: 8b 75 f8 mov 0xfffffff8(%ebp),%esi
8048520: 8b 7d fc mov 0xfffffffc(%ebp),%edi
8048523: 89 ec mov %ebp,%esp
8048525: 5d pop %ebp
8048526: c3 ret ……
df
(direction flag
)標誌位於
eflags
暫存器第
10bit
位,控制字串指令(
movs,cmps, scas, lods
和stos
)。設定
df標誌位,會引起字串指令自減(從高位元組到低位元組處理),清除
df標誌位,會引起字串指令自增(從低位元組到高位元組處理)。
std指令:用於設定
df標誌位。
cld指令:用於清除
df標誌位。
repnz
指令:當
ecx暫存器不是
0值時並且
zf標誌位是
0時迴圈。
scas
指令:掃瞄字串,與
repnz
聯合使用,每迴圈一次,
ecx減1。
es是段暫存器,儲存的是附加段(extra segment)的段號。
edi裝載的是
buf的位址偏移,通過
%es:(%edi)
,計算出
buf的虛擬記憶體位址(根據段號算出段起始位址,再加上edi儲存的位址偏移值),讀取buf的內容。
下圖是getline函式呼叫gets(buf);前的呼叫棧:
從圖中可以看出,如果gets函式寫buf超過8個位元組,就會導致緩衝區溢位,從而破壞棧上儲存的資料。
如果輸入的位元組小於等於23(加上字串結尾的0,小於等於24個位元組),破壞儲存包括ebp在內的幾個暫存器的儲存值,程式還能執行:
./bufovf
input>helloworld1234567890$$$
helloworld1234567890$$$
當輸入的位元組數達到24個(加上字串結尾的0,實際上是25個位元組),不僅破壞掉了舊ebp值,還破壞了函式的返回位址,程式崩潰:
./bufovf
input>helloworld1234567890$$$$
segmentation fault
32位組合語言學習筆記 4 移位操作
sal k,d d d k 左移。shl,與 sal相同。sar k,d d d k 算術右移。shr k,d d d l k 邏輯右移。算術右移是指左邊空出來的位填符號位。邏輯右移是指左邊空出來的位填0。示例 shift.c int shift left2 rightn int x,int n g...
32位組合語言學習筆記 6 設定條件碼
條件碼儲存在條件碼暫存器中,用於描述算術和最近邏輯操作的屬性。最常用的條件碼有 cf 進製標誌。zf 零標誌。sf 符號標誌。of 溢位標誌。算術和邏輯操作指令都會修改條件碼的值,但是 leal 指令不會修改條件碼的值。此外,cmp 指令和test 指令也會修改條件碼。cmp s2,s1 將s1 s...
組合語言學習筆記
學習參考資料 大灰狼 講彙編 資料匯流排,位址匯流排,控制匯流排。位址匯流排有多少條就決定了cpu最大的記憶體使用量。80386有32位位址匯流排,所以它的定址能力就是4g.暫存器 通用暫存器,段暫存器,ax暫存器 通用暫存器,存放資料。高位位元組ah,低位位元組al。實體地址表示方法 位址加法器,...