亚洲av成人无遮挡网站在线观看,少妇性bbb搡bbb爽爽爽,亚洲av日韩精品久久久久久,兔费看少妇性l交大片免费,无码少妇一区二区三区

  免費(fèi)注冊(cè) 查看新帖 |

Chinaunix

  平臺(tái) 論壇 博客 文庫(kù)
最近訪問(wèn)板塊 發(fā)新帖
查看: 1300 | 回復(fù): 5
打印 上一主題 下一主題

ways to find 2.6 kernel rootkits - [轉(zhuǎn)貼自CLF,作者:coolq] [復(fù)制鏈接]

論壇徽章:
0
跳轉(zhuǎn)到指定樓層
1 [收藏(0)] [報(bào)告]
發(fā)表于 2006-06-20 09:38 |只看該作者 |倒序?yàn)g覽
|=------------------=[ ways to find 2.6 kernel rootkits ]=------------------=|

|=--------------------------------------------------------------------------=|

|=-----------------=[ CoolQ <qufuping@ercist.iscas.ac.cn> ]=----------------=|

|=--------------------------------------------------------------------------=|



--[ 內(nèi)容



    0 - 前言



    1 - Kernel Rootkit的分類

        1.1 系統(tǒng)調(diào)用相關(guān)

        1.2 異常相關(guān)

        1.3 內(nèi)核靜態(tài)補(bǔ)丁

        1.4 處理指針相關(guān)



    2 - vmlinux/vmlinuz布局



    3 - 對(duì)策

        3.1 總述

        3.2 系統(tǒng)調(diào)用相關(guān)

        3.3 異常相關(guān)

        3.4 內(nèi)核靜態(tài)補(bǔ)丁

        3.5 處理指針相關(guān)



    4 - 需要注意的問(wèn)題

        4.1 SMP和CPU優(yōu)化帶來(lái)的麻煩

        4.2 2.4內(nèi)核的差異

        4.3 Fedora Core 2的4G補(bǔ)丁



    5 - 總結(jié)



    6 - 參考



    7 - 程序

        7.1 dump.c(kernel module)

        7.2 rkchecker.c(usermode app)



--[ 0 - 前言



內(nèi)核Rootkit由于隱蔽性好,逐漸成為了木馬的主流. 目前內(nèi)核木馬的檢測(cè)工具,有kstat,

chkrooktit, rkhunter 等等。這些工具或多或少都需要對(duì)System.map的支持,而且往往

只能對(duì)付某種類型的內(nèi)核木馬,能不能找一些比較通用的方法,對(duì)付大部分的內(nèi)核木馬,

并且盡量少的利用系統(tǒng)文件呢(例如不使用System.map)?

在現(xiàn)實(shí)的生活中,被入侵的主機(jī)往往沒(méi)有做太多的防衛(wèi)措施,因此,你或許沒(méi)有用St.

Michael確保內(nèi)核沒(méi)被修改,你也可能事先沒(méi)有將正常的系統(tǒng)調(diào)用表保存下來(lái),事后沒(méi)有

比較的標(biāo)準(zhǔn),這樣我們是不是就無(wú)能為力了呢?

本文試圖找到一種方法,利用磁盤上的內(nèi)核文件,對(duì)內(nèi)存中的內(nèi)核進(jìn)行驗(yàn)證,查找內(nèi)核

木馬的蛛絲馬跡。主要針對(duì)的是Linux 2.6內(nèi)核,實(shí)驗(yàn)環(huán)境是Redhat Fedora Core 2,

內(nèi)核為2.6.8.1/2.6.5-1.358(4G patch, redhat custom). 至于2.4內(nèi)核,有一定的差異,

但是思想還是不變的。

論壇徽章:
0
2 [報(bào)告]
發(fā)表于 2006-06-20 09:39 |只看該作者
--[ 1 - Kernel Rootkit的分類



首先了解一下內(nèi)核木馬的種類,大體上分為四種



--[ 1.1 系統(tǒng)調(diào)用相關(guān)

在2.2,2.4內(nèi)核,這種方法是最多的,2.6內(nèi)核,由于取消了對(duì)syscall_table符號(hào)的輸出,

這種方法的使用用了一定的限制,但是仍然可以通過(guò)[1]的方法獲得系統(tǒng)調(diào)用表的位置。

攻擊者可以從5個(gè)位置做手腳,后面還會(huì)詳細(xì)介紹。



--[ 1.2 異常相關(guān)

這種方法比較獨(dú)特,在[2]中提出,利用了Linux獨(dú)特的異常處理機(jī)制,修改了__ex_table

中的內(nèi)容,目前很少有工具對(duì)這種方法進(jìn)行檢查。



--[ 1.3 內(nèi)核靜態(tài)補(bǔ)丁

這種方法在[3]中由jbtzhm提出,主要的思想是將一個(gè)模塊靜態(tài)附著在啟動(dòng)文件的后面,然

后修改系統(tǒng)調(diào)用,使得程序有機(jī)會(huì)執(zhí)行,對(duì)付這種方法,主要是對(duì)文件進(jìn)行完整性檢測(cè),

前題是要有內(nèi)核文件的校驗(yàn)值。



--[ 1.4 處理指針相關(guān)

這種方法目標(biāo)廣泛,各種處理函數(shù)的指針都可能成為對(duì)象,例如binfmt的處理函數(shù)、vfs

的處理函數(shù),TCP/IP協(xié)議棧的處理函數(shù)……,攻擊者在修改這些函數(shù)時(shí),需要能夠得到

這些函數(shù)指針的符號(hào):要么是內(nèi)核導(dǎo)出的,要么需要借助System.map文件。對(duì)這種方法的

檢測(cè),往往也要借助System.map。



對(duì)于內(nèi)核木馬的介紹,GIAC上有一篇寫的非常好的Assignment[4],大家可以看看.



--[ 2 - vmlinux/vmlinuz布局



自己編譯過(guò)Linux內(nèi)核的人應(yīng)該都知道這兩個(gè)文件,[3]中分析了vmlinuz的結(jié)構(gòu),這里再

簡(jiǎn)單回顧一下。



vmlinux是ELF格式的內(nèi)核文件,主要用于調(diào)試,而vmlinuz是將vmlinux中Section為A的

內(nèi)容保存下來(lái),去除了ELF文件頭、Section Header、不必要的Section,并用Gzip壓縮,

在最前面附加了一個(gè)裝載和解壓的頭。



     vmlinus.lds.S              拷貝必須的節(jié),壓縮并加頭

*.o -----------------> vmlinux --------------------------->vmlinuz

vmlinuz: [bootsect][setup][[head][misc][compressed_kernel]]



下面再來(lái)看看vmlinux的ELF結(jié)構(gòu),我們先看一下生成vmlinux的連接腳本

13 SECTIONS

14 {

15   . = __PAGE_OFFSET + 0x100000;

16   /* read-only */

17   _text = .;                    /* Text and read-only data */

18   .text : {

19         *(.text)

20         SCHED_TEXT

21         LOCK_TEXT

22         *(.fixup)

23         *(.gnu.warning)

24         } = 0x9090

25

26   _etext = .;                   /* End of text section */

27

28   . = ALIGN(16);                /* Exception table */

29   __start___ex_table = .;

30   __ex_table : { *(__ex_table) }

31   __stop___ex_table = .;

32

33   RODATA

34

35   /* writeable */

36   .data : {                     /* Data */

37         *(.data)

38         CONSTRUCTORS

39         }

40

41   . = ALIGN(4096);



# readelf -S vmlinux (感謝Madsys提供)

Section Headers:

[Nr] Name              Type            Addr     Off    Size   ES Flg Lk Inf Al

[ 0]                   NULL            00000000 000000 000000 00      0   0  0

[ 1] .text             PROGBITS        c0100000 001000 31c1e9 00  AX  0   0 4096

[ 2] __ex_table        PROGBITS        c041c1f0 31d1f0 001188 00   A  0   0  4

[ 3] .rodata           PROGBITS        c041d380 31e380 03c6d9 00   A  0   0 32

[ 4] .pci_fixup        PROGBITS        c0459a5c 35aa5c 000398 00  WA  0   0  4

  ...

[10] __param           PROGBITS        c0469e2c 36ae2c 0005dc 00   A  0   0  4

[11] .data             PROGBITS        c046b000 36c000 08886c 00  WA  0   0 4096

  ...

[16] .init.text        PROGBITS        c04fb000 3fc000 01fd1a 00  AX  0   0 64

  ...

[23] .altinstr_replace PROGBITS        c05237eb 4247eb 00087f 00  AX  0   0  1

[24] .exit.text        PROGBITS        c0524080 425080 001595 00  AX  0   0 64

[25] .init.ramfs       PROGBITS        c0526000 427000 000086 00   A  0   0  1

[26] .bss              NOBITS          c0527000 428000 02f4dc 00  WA  0   0 4096

  ...



根據(jù)上邊的連接腳本和對(duì)vmlinux的格式分析,我們發(fā)現(xiàn),vmlinux中的.text是多個(gè).o

文件中.text、.sched.text、.lock.text、.fixup、.gnu.warning的綜合,接下來(lái)就是

__ex_table節(jié),這個(gè)節(jié)其實(shí)是一個(gè)表,表中的元素是多個(gè)異常指針對(duì)。每對(duì)指針中,第

一個(gè)指針是有可能發(fā)生異常的地址,第二個(gè)指針是發(fā)生異常時(shí),處理程序的地址。有關(guān)

__ex_table的分析,請(qǐng)參考[5]

至于其它的可執(zhí)行節(jié),例如.init.text、.exit.text,在系統(tǒng)啟動(dòng)后可能用作它用,一般

不會(huì)成為內(nèi)核木馬的目標(biāo),我們這里就不分析了。

論壇徽章:
0
3 [報(bào)告]
發(fā)表于 2006-06-20 09:41 |只看該作者
--[ 3 - 對(duì)策



--[ 3.1 總述



內(nèi)核木馬主要的目的,就是偷偷的執(zhí)行自己的程序,因此就需要在不同的地方hook正常的

系統(tǒng)執(zhí)行,將程序流導(dǎo)向自己。那么內(nèi)核木馬自己的程序會(huì)放在什么位置呢?如果內(nèi)核木

馬是以模塊形式裝載,那么程序應(yīng)該位于vmalloc的范圍,如果是jbtzhm的內(nèi)核靜態(tài)補(bǔ)丁,

程序會(huì)附加在.bss之后,可見,內(nèi)核木馬不太可能對(duì)vmlinz/vmlinux的.text進(jìn)行傷筋動(dòng)

骨的修改,充其量就是在.text程序的入口處跳轉(zhuǎn)出來(lái)而已,否則修改的代碼大小不好控

制,很容易破壞其它部分的代碼. 因此我們只要確定.text的起始范圍,并能保證.text

部分的代碼沒(méi)有受到破壞,調(diào)用.text的部分沒(méi)有修改,那么,內(nèi)核基本上就是安全的。



如果沒(méi)有System.map,我們?nèi)绾闻卸?text的范圍呢?(有的System.map,也沒(méi)有_text和

_etext符號(hào),例如Redhat FC2的System.map)。讓我們一步一步來(lái):



o 預(yù)處理

  Step1:打開內(nèi)核的啟動(dòng)文件,例如/boot/vmlinuz-2.6.8.1

  Step2:獲取該文件中Gzip Magic Number的起始位置

  Step3:從該起始位置開始,將剩余的內(nèi)容保存為kernel.gz

  Step4:用gzip -d解壓為kernel文件



o 利用模式匹配尋找_etext,__stop___ex_table

根據(jù)上邊的連接腳本,我們可以發(fā)現(xiàn),.text是純代碼,中間可能有個(gè)數(shù)不定的0x90,接下

來(lái)一個(gè)ALIGN(16)對(duì)齊之后,就是__ex_table,而__ex_table中全是指向.text的函數(shù)指針

,我們先來(lái)看一下__ex_table有什么規(guī)律:

# hexdump -C -s 0x31d1f0 -n 500 vmlinux-2.6.10

0031d1f0  c7 11 10 c0 ca 11 10 c0  b9 1a 10 c0 57 af 41 c0  |............W.A.|

0031d200  bc 1a 10 c0 60 af 41 c0  fa 1f 10 c0 69 af 41 c0  |....`.A.....i.A.|

0031d210  c2 27 10 c0 73 af 41 c0  d1 27 10 c0 7f af 41 c0  |.'..s.A..'....A.|

0031d220  dd 27 10 c0 8b af 41 c0  e3 27 10 c0 97 af 41 c0  |.'....A..'....A.|

0031d230  3e 28 10 c0 a3 af 41 c0  49 28 10 c0 ad af 41 c0  |>(....A.I(....A.|

0031d240  62 28 10 c0 b7 af 41 c0  6a 28 10 c0 c1 af 41 c0  |b(....A.j(....A.|

0031d250  d1 28 10 c0 cb af 41 c0  da 28 10 c0 d8 af 41 c0  |.(....A..(....A.|

0031d260  df 28 10 c0 e1 af 41 c0  e9 28 10 c0 ee af 41 c0  |.(....A..(....A.|

0031d270  ee 28 10 c0 f7 af 41 c0  fc 28 10 c0 04 b0 41 c0  |.(....A..(....A.|

0031d280  0a 29 10 c0 11 b0 41 c0  14 29 10 c0 1d b0 41 c0  |.)....A..)....A.|

0031d290  1e 29 10 c0 29 b0 41 c0  28 29 10 c0 35 b0 41 c0  |.)..).A.()..5.A.|

0031d2a0  32 29 10 c0 41 b0 41 c0  3b 29 10 c0 4d b0 41 c0  |2)..A.A.;)..M.A.|

0031d2b0  45 29 10 c0 59 b0 41 c0                           |E)..Y.A.|

0031d2b8

由于指針是指向_text到_etext之間的地址,而.text的大小一般都小于0x800000(8M),因此

指針的第一個(gè)字節(jié)總是等于0xc0(PAGE_OFFSET + 0x100000的第一個(gè)字節(jié)),根據(jù)這一特性

我們就能很容易的找到.text的結(jié)尾_etext。

那么__ex_table的結(jié)尾__stop___ex_table又該怎么找呢?

注意到.rodata的對(duì)齊32,以及.rodata的內(nèi)容

# hexdump -C -s 0x31e380 -n 50 vmlinux-2.6.10

0031e380  10 00 00 00 11 00 00 00  12 00 00 00 00 00 00 00  |................|

0031e390  08 00 00 00 07 00 00 00  09 00 00 00 06 00 00 00  |................|

0031e3a0  0a 00 00 00 05 00 00 00                           |........|

0031e3a8

我們只需要從_etext 16字節(jié)對(duì)齊后的地址,開始查找每一個(gè)整型,如果該整數(shù)的第一字

節(jié)不是PAGE_OFFSET + 0x100000的第一個(gè)字節(jié),該地址就是__stop___ex_table.

具體的步驟是:

  Step1:打開剛才生成的kernel文件

  Step2:從開頭按順序往后查找0xc0(標(biāo)準(zhǔn)內(nèi)核,0xc0代表(PAGE_OFFSET+0x100000)>>24)

        開頭的整數(shù),如果連續(xù)若干個(gè)(例如100個(gè))整數(shù)都滿足條件,那么第一個(gè)整數(shù)的

        地址就是_etext對(duì)齊后的結(jié)果(需要加上PAGE_OFFSET+0x100000, 即_text)

  Step3:繼續(xù)想后查找第一個(gè)字節(jié)不是0xc0的整數(shù),該整數(shù)的地址就是__stop___ex_table

        地址。對(duì)齊后就是.rodata的地址(需要加上PAGE_OFFSET+0x100000, 即_text)



既然已經(jīng)找到了_etext和__stop___ex_table,我們來(lái)分情況討論。



--[ 3.2 系統(tǒng)調(diào)用相關(guān)



前面說(shuō)到,基于系統(tǒng)調(diào)用的木馬,有5處可以做手腳,分別代表了系統(tǒng)調(diào)用執(zhí)行的每一個(gè)

階段,分別是:idtr, 0x80的中斷門system_call, system_call中調(diào)用的sys_call_table

地址,sys_call_table中每一個(gè)函數(shù)指針,每一個(gè)系統(tǒng)調(diào)用函數(shù)的內(nèi)部代碼。2.2/2.4的

內(nèi)核,最常見的目標(biāo)就是sys_call_table中的函數(shù)指針。為了躲避注入kstat的檢測(cè),攻

擊者有可打其它的四個(gè)地方的主意(例如將system_call中的sys_call_table指向別的位

置,并在該位置放置一份系統(tǒng)調(diào)用表的拷貝)。



采取的對(duì)策如下:

  Step 1: 確定_etext的值.

  Step 2: 將內(nèi)存中_text到_etext的內(nèi)容與vmlinuz解壓的kernel文件進(jìn)行逐字節(jié)的比較

          ,以確定內(nèi)存中的.text沒(méi)有發(fā)生改變,如有不同,說(shuō)明有內(nèi)核木馬。

  Step 3: 從idtr開始,利用[1]中的方法,獲得sys_call_table的指針列表

  Step 4: 對(duì)每一個(gè)指針,判斷該指針是        否指向_text至_etext之間,如果不是,說(shuō)

          明有內(nèi)核木馬



--[ 3.3 異常相關(guān)



這種木馬,實(shí)際上就是修改了__ex_table中的指針對(duì),我們只需要將磁盤上的__ex_table

與內(nèi)存中的__ex_table想比較就可以了:

  Step1: 確定_etext和__stop___ex_table的值

  Step2: 將內(nèi)存中_etext到__stop___ex_table的值進(jìn)行逐字節(jié)比較,如果有不同,說(shuō)明

         有內(nèi)核木馬

注意,在查找__stop___ex_table的時(shí)候,正常的__ex_table應(yīng)該是0xC0XXYYZZ,..,0,..,

T,....。其中0只是為了對(duì)齊而出現(xiàn)的,如果不滿足這個(gè)條件,十有八九是有此種類型的

木馬,而且還使用了靜態(tài)補(bǔ)丁(雖然目前還沒(méi)見到過(guò)這種情況)。



--[ 3.4 內(nèi)核靜態(tài)補(bǔ)丁



這種情況比較棘手,因?yàn)榇疟P上的vmlinuz就不可信,但即使使用這個(gè)不可信的文件,我

們也能找出一部分方法。jbtzhm將某些系統(tǒng)調(diào)用表的入口修改,使的一開始調(diào)用的是木馬

程序,我們只要將整個(gè)的.text反匯編,看是否有調(diào)用.text之外的情況(當(dāng)然這個(gè)范圍最

好越靠后越好, 如果是指向內(nèi)核bss之后,就屬于這種情況)。至于其它的代碼段,例如

.init.text,應(yīng)該不受影響,因?yàn)檫@些程序段不是顯式調(diào)用的。

當(dāng)然更好的方法是直接檢查vmlinuz的校驗(yàn)和。當(dāng)然如果你使用的是分發(fā)版的內(nèi)核,可靠

的vmlinuz文件還是很容易得到的。



--[ 3.5 處理指針相關(guān)



這種情況是最麻煩的,因?yàn)樾枰紤]的種類特別多,而且都是非常specific的,不過(guò)有

一點(diǎn),攻擊者如果想要修改某個(gè)處理函數(shù)指針,他必須能夠解析該符號(hào),一般是內(nèi)核導(dǎo)出

或者從System.map中查找。這樣我們可以有針對(duì)性的檢查某些特定的處理函數(shù),看這些函

數(shù)指針是不是指向_text到_etext。當(dāng)然,這個(gè)時(shí)候還得考慮模塊的.text,我們可以遍歷

模塊列表,獲得每個(gè)模塊的module_core和core_text_size。如果函數(shù)指針不屬于這些范

圍,那你就要小心了,可能有隱藏的模塊了。

[ 本帖最后由 leviathan.alan 于 2006-6-20 09:45 編輯 ]

論壇徽章:
0
4 [報(bào)告]
發(fā)表于 2006-06-20 09:42 |只看該作者
--[ 4 - 需要注意的問(wèn)題



--[ 4.1 SMP和CPU優(yōu)化帶來(lái)的麻煩



對(duì)于vmlinuz和內(nèi)存中的.text進(jìn)行逐字節(jié)比較,如果你的內(nèi)核有SMP,或者使用了CPU的某

些優(yōu)化(默認(rèn)情況下有很多),即使內(nèi)核是沒(méi)有問(wèn)題的,也會(huì)有內(nèi)容不相同的情況!



先來(lái)看對(duì)SMP的支持,注意以下這個(gè)宏

#define wmb() alternative("lock; addl $0,0(%%esp)", "sfence", X86_FEATURE_XMM)

經(jīng)測(cè)試,這一語(yǔ)句裝載到內(nèi)存中,內(nèi)容會(huì)發(fā)生改變,具體的原因還不得而知

0xf0 0x83 0x44 0x24 0x00 -> 0x0f 0xae (0xe8|0xf0) 0x8d 0x76

如果有誰(shuí)知道原因,請(qǐng)mail我。



另外,CPU優(yōu)化,也造成磁盤和內(nèi)存中的內(nèi)容不一致

一個(gè)例子就是list_for_each_entry調(diào)用的prefetch()

634 extern inline void prefetch(const void *x)

635 {

636         alternative_input(ASM_NOP4,

637                           "prefetchnta (%1)",

638                           X86_FEATURE_XMM,

639                           "r" (x));

640 }



#define GENERIC_NOP4        ".byte 0x8d,0x74,0x26,0x00\n"

#define K8_NOP4 ".byte 0x66,0x66,0x66,0x90\n"

#define K7_NOP4 ".byte 0x8d,0x44,0x20,0x00\n"



#ifdef CONFIG_MK8

#define ASM_NOP4 K8_NOP4

#elif defined(CONFIG_MK7)

#define ASM_NOP4 K7_NOP4

#else

#define ASM_NOP4 GENERIC_NOP4

出現(xiàn)不一致的情況就是上邊的幾種NOP4, 由于我對(duì)這一塊不熟悉,不知有誰(shuí)能指點(diǎn)一二?



--[ 4.2 2.4內(nèi)核的差異



2.4與2.6相比,__ex_table的位置靠后了

17   _etext = .;                   /* End of text section */

18

19   .rodata : { *(.rodata) *(.rodata.*) }

20   .kstrtab : { *(.kstrtab) }

21

22   . = ALIGN(16);                /* Exception table */

23   __start___ex_table = .;

24   __ex_table : { *(__ex_table) }

25   __stop___ex_table = .;

由于.rodata和.kstrtab都不會(huì)發(fā)生變化,因此,不影響本文的方法。



--[ 4.3 Fedora Core 2的4G補(bǔ)丁



Redhat的內(nèi)核改動(dòng)的地方很多,比較討厭,4G補(bǔ)丁就是其中之一,這里需要注意的是,

打了4G補(bǔ)丁的內(nèi)核,PAGE_OFFSET已經(jīng)不是0xc000000,而是0x02000000,內(nèi)核有自己?jiǎn)?br />
獨(dú)的4G空間了。

另外的一個(gè)影響是__ex_table中的異常處理指針,有一些發(fā)生異常的地方,指針是以

0xffff開頭的,估計(jì)4G在處理異常的時(shí)候,有些特別的地方.

00181000  60 41 10 02 63 41 10 02  30 48 10 02 40 f3 27 02  |`A..cA..0H..@.'.|

00181010  33 48 10 02 49 f3 27 02  35 55 10 02 52 f3 27 02  |3H..I.'.5U..R.'.|

00181020  41 55 10 02 5b f3 27 02  66 32 ff ff 64 f3 27 02  |AU..[.'.f2..d.'.|

                                   <--------->

00181030  67 32 ff ff 70 f3 27 02  6b 32 ff ff 7c f3 27 02  |g2..p.'.k2..|.'.|

          <--------->              <--------->

00181040  73 32 ff ff 8d f3 27 02  74 32 ff ff 99 f3 27 02  |s2....'.t2....'.|

          <--------->              <--------->

00181050  78 32 ff ff a5 f3 27 02  92 62 10 02 b6 f3 27 02  |x2....'..b....'.

          <--------->



--[ 5 - 總結(jié)



本文介紹的方法,對(duì)于檢查基于系統(tǒng)調(diào)用和異常表的木馬是非常有效的,對(duì)于內(nèi)核靜態(tài)補(bǔ)丁,

也是管用的. 對(duì)于處理函數(shù)指針的情況,思想適用,但是需要對(duì)每種情況寫一種擴(kuò)展(利用

符號(hào),判斷函數(shù)指針是否在正常的.text范圍內(nèi),包括內(nèi)核與模塊的.text)。

本文的方法,對(duì)于一種非常簡(jiǎn)單的靜態(tài)補(bǔ)丁,是無(wú)效的: 木馬將磁盤vmlinuz中的指令

修改,例如簡(jiǎn)單的將jz->jnz, jne->je。但如果系統(tǒng)使用的是發(fā)行版帶的標(biāo)準(zhǔn)內(nèi)核,我們

就能保證vmlinuz的完整性(很容易找到)。





--[ 6 - 參考



[1] Linux on-the-fly kernel patching without LKM

     <http://www.phrack.org/phrack/58/p58-0x07>

[2] Hijacking Linux Page Fault Handler

     <http://www.phrack.org/show.php?p=61&a=7>

[3] Static Kernel Patching

     <http://www.phrack.org/show.php?p=60&a=8>

[4] Linux kernel rootkits: protecting system's "Ring-zero"

     <http://www.giac.org/practical/GCUX/Raul_Siles_GCUX.pdf>

[5] 利用異常表處理 Linux 內(nèi)核態(tài)缺頁(yè)異常

     <http://www-900.ibm.com/developer ... /l-page/index.shtml>

[6] linux kernel source code

     <http://www.kernel.org>

[7] Intel用戶手冊(cè)

論壇徽章:
0
5 [報(bào)告]
發(fā)表于 2006-06-20 09:43 |只看該作者
--[ 7 - 程序



下面的程序只考慮的前面的兩種情況, 至于后面的兩種, 由于比較特殊, 需要根據(jù)自己的

需要,自己添加功能,當(dāng)然思想前面已經(jīng)陳述,很簡(jiǎn)單.


--[ 7.1 dump.c(kernel module)



  1. #include <linux/init.h>

  2. #include <linux/module.h>

  3. #include <linux/kernel.h>

  4. #include <linux/fs.h>

  5. #include <linux/file.h>

  6. #include <linux/moduleparam.h>

  7. #include <asm/page.h>

  8. #include <asm/uaccess.h>

  9. #include <asm/string.h>

  10. #include <asm/unistd.h>



  11. #define EOF             (-1)

  12. #define SEEK_SET        0

  13. #define SEEK_CUR        1

  14. #define SEEK_END        2



  15. struct {

  16.         unsigned short         limit;

  17.         unsigned int           base;

  18. } __attribute__ ((packed)) idtr;



  19. struct {

  20.         unsigned short         off1;

  21.         unsigned short         sel;

  22.         unsigned char          none,flags;

  23.         unsigned short         off2;

  24. } __attribute__ ((packed)) idt;



  25. static unsigned int len = 0x800000;

  26. module_param(len, uint, 0);

  27. static char buffer[256];



  28. struct file *klib_fopen(const char *filename, int flags, int mode);

  29. void klib_fclose(struct file *filp);

  30. int klib_fwrite(char *buf, int len, struct file *filp);

  31. void *memmem(void *start, unsigned int s_len, void *find, unsigned int f_len);



  32. struct file *klib_fopen(const char *filename, int flags, int mode)

  33. {

  34.         struct file *filp = filp_open(filename, flags, mode);

  35.         return (IS_ERR(filp)) ? NULL : filp;

  36. }



  37. void klib_fclose(struct file *filp)

  38. {

  39.         if (filp)

  40.                 fput(filp);

  41. }



  42. int klib_fwrite(char *buf, int len, struct file *filp)



  43. {



  44.         int writelen;

  45.         mm_segment_t oldfs;



  46.         if (filp == NULL)

  47.                 return -ENOENT;

  48.         if (filp->f_op->write == NULL)

  49.                 return -ENOSYS;

  50.         if (((filp->f_flags & O_ACCMODE) & (O_WRONLY | O_RDWR)) == 0)

  51.                 return -EACCES;

  52.         oldfs = get_fs();

  53.         set_fs(KERNEL_DS);

  54.         writelen = filp->f_op->write(filp, buf, len, &filp->f_pos);

  55.         set_fs(oldfs);



  56.         return writelen;



  57. }



  58. void *memmem(void *start, unsigned int s_len, void *find, unsigned int f_len)

  59. {

  60.         char                *p, *q;

  61.         unsigned int        len;

  62.         
  63.         p = start, q = find;

  64.         len = 0;

  65.         while((p - (char *)start + f_len) <= s_len){

  66.                 while(*p++ == *q++){

  67.                         len++;

  68.                         if(len == f_len)

  69.                                 return(p - f_len);

  70.                 };

  71.                 q = find;

  72.                 len = 0;

  73.         };

  74.         
  75.         return(NULL);

  76. }



  77. static int dump_init(void)

  78. {

  79.         unsigned int        addr_start = PAGE_OFFSET + 0x100000;

  80.         struct file         *filep;

  81.         unsigned int        sys_call_off, sct;

  82.         char                *p;



  83.         /* Step 1: dump kernel memory */

  84.         filep = klib_fopen("./kernel.dat", O_WRONLY | O_CREAT | O_TRUNC,

  85.                                 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);

  86.         if(filep == NULL){

  87.                 printk("Error create kernel.dat.\n");

  88.                 return 0;

  89.         }

  90.         
  91.         klib_fwrite((char*)addr_start, len, filep);

  92.         klib_fclose(filep);

  93.         printk("dump file to ./kernel.dat - OK.\n");



  94.         /* Step 2: Get syscall info */

  95.         filep = klib_fopen("./kernel.info", O_WRONLY | O_CREAT | O_TRUNC,

  96.                                 S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);

  97.         
  98.         if(filep == NULL){

  99.                 printk("Error create kernel.info.\n");

  100.                 return 0;

  101.         }

  102.         
  103.         
  104.         __asm__ ("sidt %0" : "=m" (idtr));

  105. //        printk("idtr base at 0x%X\n",(int)idtr.base);



  106.         memcpy(&idt,(void*)(idtr.base+8*0x80),sizeof(idt));

  107.         sys_call_off = (idt.off2 << 16) | idt.off1;



  108. //        printk("sys_call_off is at 0x%x\n", sys_call_off);

  109.         p = (char*)memmem ((void *)sys_call_off, 100, "\xff\x14\x85", 3);

  110.         
  111.         if(p){

  112.                 sct = *(unsigned*)(p+3);

  113. //                printk("syscall table at addr 0x%x, rel off 0x%x\n",

  114. //                        sct, sct - (unsigned int)addr_start);

  115.         }else

  116.                 ;

  117. //                printk("syscall table not find?\n");

  118.         
  119.         sprintf(buffer, ".text = 0x%x\n"

  120.                         "idtr = 0x%x\n"

  121.                         "sys_call_off = 0x%x\n"

  122.                         "sys_call_table = 0x%x\n"

  123.                         "sys_call_nr = %d\n",

  124.                         addr_start, idtr.base, sys_call_off,

  125.                         p ? sct : 0, NR_syscalls);

  126.         
  127.         klib_fwrite(buffer, strlen(buffer), filep);

  128.         klib_fclose(filep);



  129.         return 0;



  130. }





  131. static void dump_exit(void)

  132. {



  133.         return;

  134. }



  135. module_init(dump_init);

  136. module_exit(dump_exit);



  137. MODULE_LICENSE("GPL");
復(fù)制代碼

論壇徽章:
0
6 [報(bào)告]
發(fā)表于 2006-06-20 09:44 |只看該作者
--[ 7.2 rkchecker.c(usermode app)




  1. /*

  2. * Name: rkchecker.c

  3. * Author: CoolQ

  4. * License: GPL

  5. * Intro: try to find some kernel rootkits

  6. * Usage: # insmod dump.ko

  7. *        # cat kernel.info

  8. *        .text = 0xc0100000

  9. *        idtr = 0xaaaaaaaa

  10. *        sys_call_off = 0xbbbbbbbb

  11. *        sys_call_table = 0xcccccccc

  12. *        sys_call_nr = dd

  13. *        # ./rkchecker -m ./kernel.dat -d /boot/vmlinuz -s 0xcccccccc -n dd

  14. *        if you use 4G/4G patch, use

  15. *        # ./rkchecker -4 -m ./kernel.dat -d /boot/vmlinuz -s 0xcccccccc -n dd

  16. */





  17. #include <stdio.h>

  18. #include <stdlib.h>

  19. #include <unistd.h>

  20. #include <fcntl.h>

  21. #include <string.h>

  22. #include <getopt.h>

  23. #include <sys/mman.h>

  24. #include <sys/types.h>

  25. #include <sys/stat.h>



  26. #define KERNEL_DISC_FILE        "/boot/vmlinuz"

  27. #define KERNEL_TMP_GZ_FILE      "/tmp/kernel.gz"

  28. #define KERNEL_TMP_FILE         "/tmp/kernel"

  29. #define KERNEL_DUMP_FILE        "./kernel.dat"



  30. #define MAGIC_GZ                0x00088b1f

  31. #define TEXT_START              0xc0100000

  32. #define TEXT_START_4G           0x02100000

  33. #define THRESHOLD               100

  34. #define SYS_CALL_NR             240



  35. #define ERROR(str)                \

  36.         do{                       \

  37.                 perror(str);      \

  38.                 return -1;        \

  39.         }while(0)               



  40. int extract_file(const char *file);

  41. unsigned int find_text_end(const char *file);

  42. int check(const char *file_mem, const char *file_store, unsigned int offset);

  43. int check_text(void *start_mem, void *start_store, unsigned int len);

  44. int check_exceptiontbl(void *start_mem, void *start_store);

  45. int check_syscalltbl(void *start_mem, unsigned int sys_call_off,

  46.                      unsigned int nr);

  47. void usage(const char *prog);



  48. static char                *g_krnl_mem = KERNEL_DUMP_FILE;

  49. static char                *g_krnl_store = KERNEL_DISC_FILE;

  50. static int                 g_threshold = THRESHOLD;

  51. static unsigned int        g_text_start = TEXT_START;

  52. static unsigned int        g_sys_call_off;

  53. static unsigned int        g_sys_call_nr = SYS_CALL_NR;

  54. static unsigned int        g_text_end_off;



  55. int main(int argc, char *argv[])

  56. {

  57.         int                 ret;

  58.         char                *tmp;



  59.         if(argc < 4)

  60.                 usage(argv[0]);

  61.         
  62.         while((ret = getopt(argc, argv, "m:d:t:s:n:4")) != -1){

  63.                 switch(ret){

  64.                         case 'm':

  65.                                 g_krnl_mem = strdup(optarg);

  66.                                 break;

  67.                         case 'd':

  68.                                 g_krnl_store = strdup(optarg);

  69.                                 break;

  70.                         case 't':

  71.                                 g_threshold = atoi(optarg);

  72.                                 break;

  73.                         case 's':

  74.                                 g_sys_call_off = strtoul(optarg, &tmp, 16) - g_text_start;

  75.                                 break;

  76.                         case '4':

  77.                                 g_text_start = TEXT_START_4G;

  78.                                 break;

  79.                         case 'n':

  80.                                 g_sys_call_nr = atoi(optarg);

  81.                                 break;

  82.                         default:

  83.                                 usage(argv[0]);

  84.                                 break;

  85.                 }

  86.         };

  87.                
  88.         ret = extract_file(g_krnl_store);

  89.         if(ret == -1)

  90.                 exit(EXIT_FAILURE);

  91.         
  92.         unlink(KERNEL_TMP_FILE);

  93.         ret = system("gzip -d " KERNEL_TMP_GZ_FILE);

  94.         if(ret == -1)

  95.                 ERROR("ungzip error.\n");



  96.         g_text_end_off = find_text_end(KERNEL_TMP_FILE);

  97.         printf("[i] .text end at 0x%x\n", g_text_end_off);



  98.         ret = check(KERNEL_TMP_FILE, g_krnl_mem, g_text_end_off);

  99.         if(ret == -1){

  100.                 fprintf(stdout, "! your kernel maybe hacked.\n");

  101.                 return -1;

  102.         }

  103.         
  104.         unlink(KERNEL_TMP_FILE);

  105.         return 0;

  106. }

  107. int extract_file(const char *file)

  108. {

  109.         struct stat        st;

  110.         int                fd_read, fd_write;

  111.         int                mag = MAGIC_GZ;

  112.         int                len_gz;

  113.         char               *addr_read, *addr_write, *addr_gz;



  114.         if(stat(file, &st) == -1)

  115.                 ERROR("stat error.\n");

  116.         
  117.         fd_read = open(file, O_RDONLY);

  118.         fd_write = open(KERNEL_TMP_GZ_FILE, O_RDWR | O_TRUNC | O_CREAT,

  119.                         S_IRWXU | S_IRGRP | S_IROTH);

  120.         if(fd_read == -1 || fd_write == -1)

  121.                 ERROR("open error.\n");



  122.         addr_read = mmap(0, st.st_size, PROT_READ, MAP_SHARED, fd_read, 0);

  123.         if(addr_read == MAP_FAILED)

  124.                 ERROR("map failed.\n");

  125.         
  126.         addr_gz = memmem(addr_read, st.st_size, &mag, 4);

  127.         if(addr_gz == NULL)

  128.                 ERROR("not a bzImage\n");



  129.         len_gz = st.st_size - (int)(addr_gz - addr_read);

  130.         
  131.         if(lseek(fd_write, (off_t)(len_gz - 1), SEEK_SET) == (off_t)-1)

  132.                 ERROR("lseek error.\n");

  133.         write(fd_write, "a", 1);

  134.         
  135.         addr_write = mmap(0, len_gz, PROT_WRITE, MAP_SHARED, fd_write, 0);

  136.         if(addr_write == MAP_FAILED)

  137.                 ERROR("map failed.\n");



  138.         memcpy(addr_write, addr_gz, len_gz);

  139.         
  140.         munmap(addr_read, st.st_size);

  141.         munmap(addr_write, len_gz);

  142.         close(fd_read);

  143.         close(fd_write);

  144.         
  145.         return 0;

  146. }

  147. unsigned int find_text_end(const char *file)

  148. {

  149.         int                fd, count;

  150.         struct stat        st;

  151.         void               *addr;

  152.         unsigned int       *p, *tmp;

  153.         
  154.         stat(file, &st);

  155.         
  156.         fd = open(file, O_RDONLY);

  157.         if(fd == -1)

  158.                 ERROR("open error.\n");

  159.         
  160.         addr = mmap(0, st.st_size, PROT_READ, MAP_SHARED, fd, 0);

  161.         if(addr == MAP_FAILED)

  162.                 ERROR("map error.\n");



  163.         p = addr;

  164.         while((char *)p - (char *)addr < st.st_size){

  165.                 if((*p >> 24) == (g_text_start >> 24)){

  166.                         tmp = p;

  167.                         for(count = 0; count < g_threshold; count++, p++)

  168.                                 if((*p >> 24) != (g_text_start >> 24) &&

  169.                                    !((*p >> 16) == 0xffff &&

  170.                                      (g_text_start >> 24)==(TEXT_START_4G >>24)

  171.                                     )

  172.                                   )

  173.                                         break;

  174.                 }else

  175.                         p++;

  176.                 if(count == g_threshold){

  177.                         munmap(addr, st.st_size);

  178.                         close(fd);

  179.                         return((char *)tmp - (char *)addr);

  180.                 }

  181.         }

  182.         munmap(addr, st.st_size);

  183.         close(fd);

  184.         return 0;

  185. }

  186. int check(const char *file_mem, const char *file_store, unsigned int offset)

  187. {



  188.         int                ret, ret2, ret3;

  189.         int                fd_mem, fd_store;

  190.         void               *addr_mem, *addr_store;

  191.         struct stat        st_mem, st_store;



  192.         ret = 0;

  193.         
  194.         ret = stat(file_mem, &st_mem);

  195.         ret |= stat(file_store, &st_store);

  196.         if(ret)

  197.                 ERROR("stat error.\n");

  198.         
  199.         fd_mem = open(file_mem, O_RDONLY);

  200.         fd_store = open(file_store, O_RDONLY);

  201.         if(fd_mem == -1 || fd_store == -1)

  202.                 ERROR("open file error.\n");



  203.         addr_mem = mmap(0, st_mem.st_size, PROT_READ, MAP_SHARED, fd_mem, 0);

  204.         addr_store = mmap(0, st_store.st_size, PROT_READ, MAP_SHARED,

  205.                         fd_store, 0);

  206.         if(addr_mem == MAP_FAILED || addr_store == MAP_FAILED)

  207.                 ERROR("mmap error.\n");



  208.         ret = check_text(addr_mem, addr_store, offset);

  209.         if(!ret)

  210.                 fprintf(stdout, "   - .text check passed.\n");



  211.         ret2 = check_exceptiontbl(addr_mem + offset, addr_store + offset);

  212.         if(!ret2)

  213.                 fprintf(stdout, "   - exception table check passed.\n");



  214.         ret3 = check_syscalltbl(addr_mem, g_sys_call_off, g_sys_call_nr);

  215.         if(!ret3)

  216.                 fprintf(stdout, "   - sys_call_table check passed.\n");

  217.         
  218.         munmap(addr_mem, st_mem.st_size);

  219.         munmap(addr_store, st_store.st_size);

  220.         close(fd_mem);

  221.         close(fd_store);

  222.         
  223.         return(ret | ret2 | ret3);

  224. }

  225. int check_text(void *start_mem, void *start_store, unsigned int len)

  226. {

  227.         unsigned char      *p_mem, *p_store;

  228.         int                count, ret;

  229.         
  230.         fprintf(stdout, "[+] Start checking .text section.\n");

  231.         ret = 0;

  232.         
  233.         for(        p_mem = start_mem, p_store = start_store, count = 0;

  234.                 count < 10000 && ((char *)p_mem - (char *)start_mem) < len;

  235.                 p_mem++, p_store++

  236.         )

  237.                 if(*p_mem != *p_store){

  238.                         if(*p_mem == 0xf0 && *p_store == 0x0f){

  239.                                 if(        *(p_mem + 1) == 0x83 &&
  240.                                         *(p_store + 1) == 0xae &&

  241.                                         *(p_mem + 2) == 0x44 &&

  242.                                         (*(p_store + 2) == 0xe8 ||

  243.                                          *(p_store + 2) == 0xf0) &&

  244.                                         *(p_mem + 3) == 0x24 &&

  245.                                         *(p_store + 3) == 0x8d &&

  246.                                         *(p_mem + 4) == 0x00 &&

  247.                                         *(p_store + 4) == 0x76

  248.                                 ){

  249.                                         p_mem += 5;

  250.                                         p_store += 5;

  251.                                         continue;

  252.                                 }

  253.                         }else if(*p_mem == 0x8d && *p_store == 0x0f){

  254.                                 if(        (*(p_mem + 1) == 0x74 &&

  255.                                          *(p_store + 1) == 0x18 &&

  256.                                          *(p_mem + 2) == 0x26 &&

  257.                                          /* *(p_store + 2) == 0x01 && */

  258.                                          *(p_mem + 3) == 0x00 /* &&

  259.                                          *(p_store + 3) == 0x90*/) ||

  260.                                         (*(p_mem + 1) == 0x44 &&

  261.                                          /* *(p_store + 1) == 0x18 && */

  262.                                          *(p_mem + 2) == 0x20 &&

  263.                                          /* *(p_store + 2) == 0x08 && */

  264.                                          *(p_mem + 3) == 0x00 &&

  265.                                          *(p_store + 3) == 0x90)

  266.                                 ){

  267.                                         p_mem += 4;

  268.                                         p_store += 4;

  269.                                         continue;

  270.                                 }

  271.                         }else if(*p_mem == 0x66 /*&& *p_store == 0x0f*/){

  272.                                 if(        (*(p_mem + 1) == 0x66 &&

  273.                                          /**(p_store + 1) == 0x18 &&*/

  274.                                          *(p_mem + 2) == 0x66 &&

  275.                                          /**(p_store + 2) == 0x01 &&*/

  276.                                          *(p_mem + 3) == 0x90 /* &&

  277.                                          *(p_store + 3) == 0x90)*/ )

  278.                                 ){

  279.                                         p_mem += 4;

  280.                                         p_store += 4;

  281.                                         continue;

  282.                                 }

  283.                         }

  284.                         ret = -1;

  285.                         count++;

  286.                         fprintf(stdout, "mismatch no. %d at offset 0x%x",

  287.                                 count, (char *)p_mem - (char *)start_mem);

  288.                         fprintf(stdout, "\tstore = %02X, mem=%02X\n",

  289.                                 *p_mem, *p_store);

  290.                 }

  291.                
  292.         return ret;

  293. }

  294. int check_exceptiontbl(void *start_mem, void *start_store)

  295. {

  296.         unsigned int       *p_mem, *p_store;

  297.         int                ret;

  298.         
  299.         
  300.         ret = 0;



  301.         fprintf(stdout, "[+] Start checking exception table.\n");

  302.         if(((int)start_mem & 0x0000000f) != 0x0)

  303.                 fprintf(stdout, "   - the offset is weird, not aligned.\n");

  304.         
  305.         for(        p_mem = start_mem, p_store = start_mem;

  306.                         ((*p_store >> 24) == (g_text_start >> 24) ||

  307.                          ((*p_store >> 16) == 0xffff &&
  308.                           (g_text_start == TEXT_START_4G)

  309.                          ));

  310.                 p_mem++, p_store++

  311.            )

  312.                 if(*p_mem != *p_store){

  313.                         fprintf(stdout, "   - suspect except handler at 0x%x",

  314.                                         (unsigned int)p_mem);

  315.                         ret = -1;

  316.                 }

  317.         
  318.         if(((int)p_store & 0x0000000f) != 0x0)

  319.                 if(*p_store != 0){

  320.                         fprintf(stdout, "   - seems weired at 0x%x, "

  321.                                 "kernel file unreliable.\n", p_store);

  322.                         ret = -1;

  323.                 }



  324.         fprintf(stdout, "  [i] exception tabled end at __ex_table + 0x%x\n",

  325.                         (unsigned int)((char *)p_mem - (char *)start_mem));

  326.         return ret;

  327. }



  328. int check_syscalltbl(void *start_mem, unsigned int sys_call_off,

  329.                      unsigned int nr)

  330. {

  331.         unsigned int       *p;

  332.         int                i, ret;

  333.         
  334.         fprintf(stdout, "[+] Start checking sys_call_table.\n");

  335.         fprintf(stdout, "  [i] checknig %d items.\n", nr);

  336.         
  337.         ret = 0;

  338.         p = (int *)((char *)start_mem + sys_call_off);

  339.                         
  340.         for(i = 0; i < nr; i++, p++)

  341.                 if(*p < g_text_start || *p > g_text_start + g_text_end_off){

  342.                         fprintf(stdout, "   - sys_call no. %d suspicious."

  343.                                         "point to value %x\n", i, *p);

  344.                         ret = -1;

  345.                 }

  346.         
  347.         return ret;

  348. }



  349. void usage(const char *prog)

  350. {

  351.         fprintf(stderr, "Usage: %s [-4] [-t num] [-n num] -m file_1 -d file_2"

  352.                         "-s addr\n",

  353.                         prog);

  354.         fprintf(stderr, "Params:\n");

  355.         fprintf(stderr, "   -4: The kernel uses 4G/4G patch.\n");

  356.         fprintf(stderr, "   -t num: Set threshold to num.\n");

  357.         fprintf(stderr, "   -n num: Set sys_call_numbers to num.\n");

  358.         fprintf(stderr, "   -m file: Set memory dump file to file_1\n");

  359.         fprintf(stderr, "   -d file: Set disc kernel file to file_2\n");

  360.         fprintf(stderr, "   -s addr: Set the sys_call_table to addr\n");



  361.         exit(EXIT_FAILURE);

  362.         return;

  363. }


復(fù)制代碼
您需要登錄后才可以回帖 登錄 | 注冊(cè)

本版積分規(guī)則 發(fā)表回復(fù)

  

北京盛拓優(yōu)訊信息技術(shù)有限公司. 版權(quán)所有 京ICP備16024965號(hào)-6 北京市公安局海淀分局網(wǎng)監(jiān)中心備案編號(hào):11010802020122 niuxiaotong@pcpop.com 17352615567
未成年舉報(bào)專區(qū)
中國(guó)互聯(lián)網(wǎng)協(xié)會(huì)會(huì)員  聯(lián)系我們:huangweiwei@itpub.net
感謝所有關(guān)心和支持過(guò)ChinaUnix的朋友們 轉(zhuǎn)載本站內(nèi)容請(qǐng)注明原作者名及出處

清除 Cookies - ChinaUnix - Archiver - WAP - TOP