日韩无码专区无码一级三级片|91人人爱网站中日韩无码电影|厨房大战丰满熟妇|AV高清无码在线免费观看|另类AV日韩少妇熟女|中文日本大黄一级黄色片|色情在线视频免费|亚洲成人特黄a片|黄片wwwav色图欧美|欧亚乱色一区二区三区

RELATEED CONSULTING
相關咨詢
選擇下列產(chǎn)品馬上在線溝通
服務時間:8:30-17:00
你可能遇到了下面的問題
關閉右側工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營銷解決方案
黑客與宕機

造成系統(tǒng)異常宕機(無響應、異常重啟)的原因有很多種,最常見的是操作系統(tǒng)內(nèi)部缺陷和設備驅動缺陷。本文作者將和大家分享內(nèi)存轉儲分析的底層邏輯和方法論,并通過一個線上真實案例來展示從分析到得出結論的整個過程,希望對同學們處理此類問題和對系統(tǒng)的理解上有所幫助。

創(chuàng)新互聯(lián)建站專注于企業(yè)成都全網(wǎng)營銷、網(wǎng)站重做改版、五家渠網(wǎng)站定制設計、自適應品牌網(wǎng)站建設、H5建站、商城網(wǎng)站制作、集團公司官網(wǎng)建設、成都外貿(mào)網(wǎng)站建設公司、高端網(wǎng)站制作、響應式網(wǎng)頁設計等建站業(yè)務,價格優(yōu)惠性價比高,為五家渠等各大城市提供網(wǎng)站開發(fā)制作服務。

相信凡是與計算機高頻親密接觸的人,都遇到過系統(tǒng)無響應,或突然重啟的情況。這樣的情況如果發(fā)生在客戶端設備,如手機,或者筆記本電腦上,且不是頻繁出現(xiàn),基本上我們的解法就是鴕鳥算法,即默默重啟設備,然后繼續(xù)使用,當作什么都沒發(fā)生過。

但是,如果這樣的問題發(fā)生在服務端,比如運行微信、微博后臺程序的虛擬機或者物理機上,那往往會產(chǎn)生相當嚴重的影響。輕則導致業(yè)務中斷,重則導致業(yè)務長時間無法工作。

大家都知道,驅動這些計算機的是運行在其上的操作系統(tǒng),如 Windows 或者 Linux 等。系統(tǒng)異常宕機(無響應、異常重啟)的原因有很多種,但總體來看,操作系統(tǒng)內(nèi)部缺陷,或者設備驅動缺陷是最常見的兩類原因。

從根本上解決這類問題“唯一正確”的方法,是操作系統(tǒng)內(nèi)存轉儲分析(Memory Dump Analysis)。內(nèi)存轉儲分析屬于高階的軟件調(diào)試能力,需要工程師有豐富且全面的系統(tǒng)級別理論知識和大量的疑案破解似的上手實踐經(jīng)驗。

內(nèi)存轉儲分析的方法論

內(nèi)存轉儲分析是對專業(yè)能力要求極高的一個工作,也是非常不容易的一件事情。在以往案例分享后,得到比較有趣的反饋,如“耳邊想起了柯南的配音”,或者“真黑貓警長!做的是 IT 工程師,卻整天搞刑偵工作”。

內(nèi)存轉儲分析需要用到的基礎能力,包括但不限于反匯編、匯編分析、各種語言的代碼分析,系統(tǒng)層面各種結構的理解,如堆,棧,虛表等,甚至深入到 bit 級別。

試想,一個系統(tǒng)運行了很長一段時間。在這段時間里,系統(tǒng)積累了大量正常、甚至不正常的狀態(tài)。這時如果系統(tǒng)突然出現(xiàn)了一個問題,那這個問題十有八九跟長時間積累下來的狀態(tài)有關系。

分析內(nèi)存轉儲,就是分析發(fā)生問題時,系統(tǒng)產(chǎn)生的“快照”。實際上需要工程師以這個快照為出發(fā)點,追溯歷史,找出問題發(fā)生源頭。這有點像是從案發(fā)現(xiàn)場,推理案發(fā)經(jīng)過一樣。

死鎖分析方法

內(nèi)存轉儲分析方法,可以從所要解決問題的角度,簡單分成兩類,分別是死鎖分析方法,和異常分析方法。這兩種方法的區(qū)別在于,死鎖分析方法以系統(tǒng)全局為出發(fā)點,而異常分析則從具體異常點開始。

死鎖問題表現(xiàn)出來,就是系統(tǒng)不響應問題。死鎖分析方法著眼于全局。這里的全局,就是整個操作系統(tǒng),包括所有進程在內(nèi)的系統(tǒng)全貌。我們從教科書里學到的知識,一個運行中的程序,包括了代碼段,數(shù)據(jù)段和堆棧段。用這個方法去看一個系統(tǒng)也同樣適合。系統(tǒng)的全貌,其實就包括正在被執(zhí)行的代碼(線程),和保存狀態(tài)的數(shù)據(jù)(數(shù)據(jù)、堆棧)。

死鎖的本質,是系統(tǒng)中部分或者全部線程,進入了互相等待且互相依賴的狀態(tài),使得進程所承載的任務無法被繼續(xù)執(zhí)行了。所以我們分析這類問題的中心思想,就是分析系統(tǒng)中所有的線程的狀態(tài)和它們之間的依賴關系,正如如圖 1 所示。

圖 1

線程的狀態(tài)相對來說是比較確定的信息。我們可以通過讀取內(nèi)存轉儲中線程的狀態(tài)標志位,來獲取這類的信息。而依賴關系分析則需要很多的技巧和實踐經(jīng)驗。最常用分析方法有對象的持有等待關系分析,時序分析等。

異常分析方法

相對死鎖分析,異常分析方法的核心是異常。我們經(jīng)常遇到的異常有除零操作,非法指令執(zhí)行,錯誤地址訪問,甚至包括軟件層面自定義的非法操作等。這些異常反應到操作系統(tǒng)層面,就是異常重啟類宕機問題。

異常問題歸根結底是處理器執(zhí)行了具體的指令而觸發(fā)的。換句話說,我們看到的現(xiàn)象,肯定是處理器踩到了異常點。所以分析異常類問題,我們需要從異常點出發(fā),逐步地推導出代碼執(zhí)行到這一點的完整邏輯。

以經(jīng)驗來看,懂得做內(nèi)存轉儲異常分析的工程師不多,而理解以上一點的人更是少之又少。很多工程師分析異常重啟問題,基本上只停留在異常本身,根本沒有推導出問題背后的整個邏輯。

相比死鎖分析方法,異常分析的方法沒有那么多固定的章法,甚至很多時候,因為問題邏輯復雜,我們沒有辦法找出根本原因。

總體看來,異常分析的底層邏輯,是不斷地對比預期和非預期的狀況,然后找出背后的原因。比如處理其執(zhí)行了錯誤指令而觸發(fā)的異常,那我們需要從回答正常被執(zhí)行的指令應該是什么,為什么處理器拿到了這個錯誤指令這兩個問題開始,不斷深入,追根究底。

用死鎖分析方法處理異常問題,用異常分析方法處理死鎖問題

以上兩種內(nèi)存轉儲分析方法,是基于問題分析的起點和一般性分析手段來分類的。在實際問題處理過程中,我們經(jīng)常需要從系統(tǒng)全局狀態(tài)中,找到進一步處理異常問題的思路,也會用具體細節(jié)分析手段,來給全局類問題最后一擊。

黑客與宕機

問題背景

宕機問題有一種比較少見的問題模式,就是看起來完全不相關的機器同時出現(xiàn)宕機。處理這個模式的問題,我們需要找到在這些機器上能同時觸發(fā)問題的條件。

通常,這些機器要么幾乎在同一時間點出現(xiàn)問題,要么從某一個時間點開始,相繼出現(xiàn)問題。對于前一種情況,比較常見的情形是,物理設備故障導致運行在其上的所有虛擬機宕機,或者一個遠程管理軟件同時殺死了多個系統(tǒng)的關鍵進程;對于后一種情況,可能的一個原因是,用戶在所有實例上部署了同一個有問題的模塊(軟件、驅動)。

而實例被大范圍地攻擊,則是另一個常見的原因。比如在 WannaCry 勒索病毒肆虐的時候,經(jīng)常出現(xiàn)一些公司,或者一些部門的機器全部藍屏的情形。

在這個案例中,用戶安裝了阿里云的云監(jiān)控產(chǎn)品之后,出現(xiàn)了大范圍云服務器連續(xù)宕機的情況。為了自證清白,我們耗費了不少體力腦力來深入分析這個問題。通過此案例分享,希望能給讀者以啟發(fā)。

壞掉的內(nèi)核棧

我們處理操作系統(tǒng)宕機類問題的唯一正確方法是內(nèi)存轉儲。不管是 Linux 或 Windows,在系統(tǒng)宕機之后,都能夠通過自動,或者人工的方式,產(chǎn)生內(nèi)存轉儲。

分析 Linux 內(nèi)存轉儲的第一步,我們使用 crash 工具打開內(nèi)存轉儲,并用 sys 命令觀察系統(tǒng)的基本信息和宕機的直接原因。對于這個問題來說,宕機的直接原因是"Kernel panic - not syncing: stack-protector: Kernel stack is corrupted in: ffffxxxxxxxx87eb",如圖 2 所示。

圖2

關于這條信息,我們必須逐字解讀。"Kernel panic - not syncing:" 這部分內(nèi)容在內(nèi)核函數(shù)panic 里輸出,凡是調(diào)用到 panic 函數(shù),必然會有這一部分輸出,所以這一部分內(nèi)容和問題沒有直接關系。而"stack-protector: Kernel stack is corrupted in:" 這部分內(nèi)容,在內(nèi)核函數(shù)__stack_chk_fail,這個函數(shù)是一個堆棧檢查函數(shù),它會檢查堆棧,同時在發(fā)現(xiàn)問題的時候調(diào)用panic 函數(shù)產(chǎn)生內(nèi)存轉儲報告問題。

而它報告的問題是堆棧損壞。關于這個函數(shù),后續(xù)我們會進一步分析。

而 ffffxxxxxxxx87eb 這個地址,是函數(shù) __builtin_return_address(0) 的返回值。當這個函數(shù)的參數(shù)是 0 的時候,這個函數(shù)的輸出值是調(diào)用它的函數(shù)的返回地址。這句話現(xiàn)在有點繞,但是后續(xù)分析完調(diào)用棧,問題就會變得很清楚。

函數(shù)調(diào)用棧

分析宕機問題的核心,就是分析 panic 的調(diào)用棧。圖 3 中的調(diào)用棧,乍看起來是system_call_fastpath 調(diào)用了 __stack_chk_fail,然后 __stack_chk_fail 調(diào)用了 panic,報告了堆棧損壞的問題。但是稍微和類似的堆棧作一點比較的話,就會發(fā)現(xiàn),事實并非這么簡單。

圖3

圖 4 是一個類似的,以 system_call_fastpath 函數(shù)開始的調(diào)用棧。不知道大家有沒有看出來這個調(diào)用棧和上邊調(diào)用棧的不同。實際上,以 system_call_fastpath 函數(shù)開始的調(diào)用棧,表示這是一次系統(tǒng)調(diào)用(system call)的內(nèi)核調(diào)用棧。

圖4

圖 4 的調(diào)用棧,表示用戶模式的進程,有一次 epoll 的系統(tǒng)調(diào)用,然后這個調(diào)用進入了內(nèi)核模式。而圖 3 中的調(diào)用棧顯然是有問題的,因為我們就算查遍所有的文檔,也不會找到一個系統(tǒng)調(diào)用,會對應于內(nèi)核 __stack_chk_fail 函數(shù)。

這里需要提醒的是,這邊引出另外一個,在分析內(nèi)存轉儲的時候需要注意的問題,就是用 bt 打印出來的調(diào)用棧有的時候是錯誤的。

所謂的調(diào)用棧,其實不是一種數(shù)據(jù)結構。用 bt 打印出來的調(diào)用棧,其實是從真正的數(shù)據(jù)結構,線程內(nèi)核堆棧中,根據(jù)一定的算法重構出來的。而這個重構過程,其實是函數(shù)調(diào)用過程的一個逆向工程。

相信大家都知道堆棧的特性,即先進后出。關于函數(shù)調(diào)用,以及堆棧的使用,可以參考圖 5??梢钥吹?,每個函數(shù)調(diào)用,都會在堆棧上分配到一定的空間。而 CPU 執(zhí)行每個函數(shù)調(diào)用指令 call,都會順便把這條 call 指令的下一條指令壓棧。這些“下一條指令”,就是所謂的函數(shù)返回地址。

圖5

這個時候,我們再回頭看 Panic 的直接原因那一部分,即函數(shù) __builtin_return_address(0) 的返回值。

這個返回值,其實就是調(diào)用 __stack_chk_fail 的 call 指令的下一條指令,這條指令屬于調(diào)用者函數(shù)。這條指令地址被記錄為 ffffxxxxxxxx87eb。

如圖 6 所示,我們用 sym 命令查看這個地址臨近的函數(shù)名,顯然這個地址不屬于函數(shù)system_call_fastpath,也不屬于內(nèi)核任何函數(shù)。這也再次驗證了,panic 調(diào)用棧是錯誤的這個結論。

圖6

關于 raw stack,如圖7所示,我們可以用 bt -r 命令來查看。因為 raw stack 往往有幾個頁面,這里只截圖和 __stack_chk_fail 相關的這一部分內(nèi)容。

圖7

這部分內(nèi)容,有三個重點數(shù)據(jù)需要注意,panic 調(diào)用 __crash_kexec 函數(shù)的返回值,這個值是panic 函數(shù)的一條指令的地址;__stack_chk_fail 調(diào)用 panic 函數(shù)的返回值,同樣的,它是__stack_chk_fail 函數(shù)的一條指令的地址;ffffxxxxxxxx87eb 這個指令地址,屬于另外一個未知函數(shù),這個函數(shù)調(diào)用了 __stack_chk_fail。

Syscall number 和 Syscall table

因為帶有 system_call_fastpath 函數(shù)的調(diào)用棧,對應著一次系統(tǒng)調(diào)用,而 panic 的調(diào)用棧是壞的,所以這個時候我們自然而然會疑問,到底這個調(diào)用棧對應的是什么系統(tǒng)調(diào)用。

在 linux 操作系統(tǒng)實現(xiàn)中,系統(tǒng)調(diào)用被實現(xiàn)為異常。而操作系統(tǒng)通過這次異常,把系統(tǒng)調(diào)用相關的參數(shù),通過寄存器傳遞到內(nèi)核。在我們使用 bt 命令打印出調(diào)用棧的時候,我們同時會輸出,發(fā)生在這個調(diào)用棧上的異常上下文,也就是保存下來的,異常發(fā)生的時候,寄存器的值。

對于系統(tǒng)調(diào)用(異常),關鍵的寄存器是 RAX,如圖 8 所示。它保存的是系統(tǒng)調(diào)用號。我們先找一個正常的調(diào)用棧驗證一下這個結論。0xe8 是十進制的 232。

圖8

使用 crash 工具,sys -c 命令可以查看內(nèi)核系統(tǒng)調(diào)用表。我們可以看到,232 對應的系統(tǒng)調(diào)用號,就是 epoll,如圖 9 所示。

圖9

這個時候我們再回頭看“函數(shù)調(diào)用棧”這節(jié)的圖 3,我們會發(fā)現(xiàn)異常上下文中 RAX 是 0。正常情況下這個系統(tǒng)調(diào)用號對應 read 函數(shù),如圖 10 所示。

圖10

從圖 11 中,我們可以看出,有問題的系統(tǒng)調(diào)用表顯然是被修改過的。修改系統(tǒng)調(diào)用表(system call table)這種事情,常見的有兩種代碼會做,這個相當辯證。一種是殺毒軟件,而另外一種是病毒或木馬程序。當然還有另外一種情況,就是某個蹩腳的內(nèi)核驅動,無意識地改寫了系統(tǒng)調(diào)用表。

另外我們可以看到,被改寫過的函數(shù)的地址,顯然和最初被 __stack_chk_fail 函數(shù)報出來的地址,是非常鄰近的。這也可以證明,系統(tǒng)調(diào)用確實是走進了錯誤的 read 函數(shù),最終踩到了__stack_chk_fail 函數(shù)。

圖11

Raw data

基于上邊的數(shù)據(jù),來完全說服客戶,總歸還是有點經(jīng)驗主義。更何況,我們甚至不能區(qū)分,問題是由殺毒軟件導致的,還是木馬導致的。這個時候我們花費了比較多的時間,嘗試從內(nèi)存轉儲里挖掘出 ffffxxxxxxxx87eb 這個地址更多的信息。

有一些最基本的嘗試,比如嘗試找出這個地址對應的內(nèi)核模塊等等,但是都無功而返。這個地址既不屬于任何內(nèi)核模塊,也不被已知的內(nèi)核函數(shù)所引用。這個時候,我們做了一件事情,就是把這個地址前后連續(xù)的,所有已經(jīng)落實(到物理頁面)的頁面,用 rd 命令打印出來,然后看看有沒有什么奇怪的字符串可以用來作為 signature 定位問題。

就這樣,我們在鄰近地址發(fā)現(xiàn)了下邊這些字符串,如圖 12 所示。很明顯這些字符串應該是函數(shù)名。我們可以看到 hack_open 和 hack_read 這兩個函數(shù),對應被 hacked 的 0 和 2 號系統(tǒng)調(diào)用。還有函數(shù)像 disable_write_protection 等等。這些函數(shù)名,顯然說明這是一段“不平凡”的代碼。

圖12

后記

宕機問題的內(nèi)存轉儲分析,需要我們足夠的耐心。我個人的一條經(jīng)驗是:every bit matters,就是不要放過任何一個 bit 的信息。內(nèi)存轉儲因為機制本身的原因,和生成過程中一些隨機的因素,必然會有數(shù)據(jù)不一致的情況,所以很多時候,一個小的結論,需要從不同的角度去驗證。


當前題目:黑客與宕機
標題URL:http://m.5511xx.com/article/dpsgged.html