前一段時間遇到了一個非常有意思的問題,在控件的頁面上顯示了非法的字符串
接下來大家就一步步根據上次的定位思路來看下這個問題。
首先,找到這塊控件的代碼
class CItem
{
****
std::string input;
****
}
發現這個控件裏有一個默認構造的string對象,由此可以大膽猜測,有沒有可能是string的靜態變量地址被篡改了。
然後,我們運行core來看下string的字符串地址。
(gdb) thread apply all bt
發現線程裏沒有頁面的信息,所有隻能從別的地方入手。由標準庫的string實現我們知道,默認構造生成的字符串地址,均指向同一個全局靜態變量。Cpage頁面繼承自Citem,而Citem中有一個string的成員,所有我們查找包含page頁面的線程。查看Cpage的string成員地址即可找到Citem類的string成員地址
class CPage : public CItem
{
***
std::string m_title;
***
}
上面有一個string成員,分別打印他們的值
並且查看符號表可知,m_title是默認構造生成的string
pm_title
{static npos = <optimized out>, _M_dataplus = {<std::allocator<char>> = {<__gnu_cxx::new_allocator<char>> = {<No data fields>}, <No data fields>},
_M_p = 0x3ddc9b8 <_ZNSs4_Rep20_S_empty_rep_storageE@@GLIBCXX_3.4+24> "*******}}
(gdb) info symbol _ZNSs4_Rep20_S_empty_rep_storageE
std::string::_Rep::_S_empty_rep_storage in section .bss of /usr/lib64/libstdc++.so.6
所以我們知道肯定是string的靜態變量內容被覆蓋了。現在有2個思路,一個是靜態變量地址越界,還有一種是靜態變量的內容被其他默認構造生成的字符串篡改。
先看第一種思路
(gdb) x /32xg 0x3ddc9b8 - 8*16
0x3ddc938: 0x0000000000000000 0x0000000000000000
0x3ddc948 0x00000030144ee1b0 0x00000030142bd4e0
0x3ddc958: 0x00000030142bd500 0x00000030142bd430
0x3ddc968: 0x00000030142bd830 0x00000030142bd210
0x3ddc978: 0x00000030142bd840 0x00000030142bd440
0x3ddc988: 0x0000000000000000 0x0000000000000000
0x3ddc998: 0x0000000000000000 0x0000000000000000
0x3ddc9a8 : 0x0000000000000000 0x0000000000000000
0x3ddc9b8 : ******** *********
0x3ddc9c8 : 0x00000030142c8352 0x0000000000000000
0x3ddc9d8: 0x0000000000000000 0x0000000000000058
0x3ddc9e8 : 0x0000000000000000 0x00000030144ec5e0
0x3ddc9f8 : 0x0000003014299d50 0x000000301429a9d0
0x3ddca08 : 0xffffffffffffffa8 0xffffffffffffffa8
0x3ddca18: 0x00000030144ec5e0 0x0000003014299d40
0x3ddca28: 0x000000301429a9c0 0x0000000000000000
(gdb)
從內存地址看,之前的內存地址都是0,不太像是被內存越界改掉的。
再來看第二種思路,用上面非法的字符串搜索代碼中出現的字符串位置,在代碼中檢索出一段代碼,往靜態變量地址寫數據的地方
之後在測試的時候,使用gdb watch這個地址,發現問題就是出在這裏。
如果在代碼中沒有檢索到dav關鍵字,可以在服務器上輸入如下命令,看哪些第三方庫使用到。
[root]$ find .|xargs grep -ri "string" -l