關於__stack_chk_guard_ptr的理解

過年前幾天公司無事,開始做些無關的事情,比如玩玩遊戲,但是我作爲程序員,玩遊戲的總是想找一些捷徑。比如破解下加密方式,發現一些遊戲漏洞等等。

如此,便是反編譯了遊戲的加密SO。用到的工具是IDA 和 Hopper 這倆都行。因爲Mac的IDA 不能變成C。 所以用了下Hopper 還挺好用的。

好了,開始說我遇到的問題:

在靜態反彙編一個SO的過程中,開頭得到這樣一段彙編代碼:
.text:00002770                 EXPORT Java_com_happyhour_android_xt_getKey
.text:00002770
.text:00002770 var_2D8         = -0x2D8
.text:00002770 var_2D4         = -0x2D4
.text:00002770 var_2D0         = -0x2D0
.text:00002770 var_2CC         = -0x2CC
.text:00002770 var_2C8         = -0x2C8
.text:00002770 var_2C4         = -0x2C4
.text:00002770 var_2C0         = -0x2C0
.text:00002770 var_2BC         = -0x2BC
.text:00002770 var_2B8         = -0x2B8
.text:00002770 var_2B4         = -0x2B4
.text:00002770 var_2B0         = -0x2B0
.text:00002770 var_2AC         = -0x2AC
.text:00002770 var_2A4         = -0x2A4
.text:00002770 var_294         = -0x294
.text:00002770 var_274         = -0x274
.text:00002770 dest            = -0x21C
.text:00002770 var_218         = -0x218
.text:00002770 s               = -0x214
.text:00002770 var_1C          = -0x1C
.text:00002770
.text:00002770                 PUSH    {R4-R7,LR}
.text:00002772                 MOVS    R6, R3
.text:00002774                 LDR     R3, =(__stack_chk_guard_ptr - 0x277E)
.text:00002776                 LDR     R4, =0xFFFFFD3C
.text:00002778                 MOVS    R5, R0
.text:0000277A                 ADD     R3, PC ; __stack_chk_guard_ptr
.text:0000277C                 LDR     R3, [R3] ; __stack_chk_guard
.text:0000277E                 ADD     SP, R4
.text:00002780                 LDR     R1, [R3]
.text:00002782                 STR     R3, [SP,#0x2D8+var_2AC]
.text:00002784                 STR     R1, [SP,#0x2D8+var_1C]
.text:00002786                 CMP     R6, #0
.text:00002788                 BNE     loc_278C
.text:0000278A                 B       loc_2A64

前面都好理解啊,就是到哪個__stack_chk_guard_ptr 很難理解是什麼意思。那這個地址放的是什麼吶,在Hopper裏面看到地址放的是0。

那下面那幾條語句很難理解啊,把0存入了一個內存,然後把地址爲0的內容放入了內存中。 這時候我懷疑這個地址是在Java 加載SO的時候動態放進去的。

查了下,果然。這是個堆棧保護區。在程序開始的時候把它的值存起來,然後在程序結束的時候,再去看一下里面的值和保存起來的值是不是一致,如果一致的話。說明該程序沒有被溢出攻擊,如果不一致,拋出段錯誤,也就是segment deafult 。


爲了印證這個想法,去看下程序最後怎麼做的:

.text:00002A66                 LDR     R1, [SP,#0x2D8+var_2AC]
.text:00002A68                 LDR     R2, [SP,#0x2D8+var_1C]
.text:00002A6A                 MOVS    R0, R6
.text:00002A6C                 LDR     R3, [R1]
.text:00002A6E                 CMP     R2, R3
.text:00002A70                 BEQ     loc_2A76
.text:00002A72                 BLX     __stack_chk_fail

看到沒,果然進行了一次比較。 呵呵。挺有意思的。 那意思是我如果再進行堆棧溢出的時候 更改玩EIP之後。一定要把這個值還原。

===================華麗的分割線==============================

這幾天下載了一些堆棧溢出的資料分析,補充一下

這個值常見的有幾種方式:

1、0x000aff0d

2、隨機值 

如果是第一種方式的話,即使可以精準預測保護區的位置,也會對攻擊造成麻煩,因爲如果是strcpy攻擊的話,遇見/0會終止。 如果gets的話,遇見\n會終止。

隨機值就不可能預測啊,除非你要知道隨機值如何生成的。

那就不能進行攻擊了麼,參考了下 http://staff.ustc.edu.cn/~bjhua/courses/security/2014/readings/stackguard-bypass.pdf

這篇文章,發現其實還是可以攻擊的。就是要根據一些特殊情況,他舉了例子,

這種代碼可能是這樣的:

int func(char *msg) {

    char buf[80];

    strcpy(buf,msg);

    // toupper(buf);        // just to give func() "some" sense

    strcpy(msg,buf);

}

int main(int argv, char** argc) {

        func(argc[1]);

}

其實這種代碼挺常見的, 我剛學習C的時候經常寫,想修改msg的信息,然後直接不好修改。通過複製過來,然後修改完再複製過去。

這種就會有攻擊的漏洞,這樣通過msg填寫buff溢出把msg的地址給改了。這時候有人會說這樣也會修改了 canary 字段。別慌。這個判斷是在程序最後纔會執行。

下一個語句,把buf的內容複製到msg指向的地址空間。哈哈。這樣如果把msg指向GOT的表。很容易修改了exit()函數的函數指針,比如修改成注入的shellcode。

這樣函數執行完判斷髮現 canary修改了,執行退出函數,然後就執行了exit();然後然後然後.... 就沒有然後了。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章