作者:fallblood
--]概述
又是一個不眠的夜晚,其實這篇文檔是不應該發表的,因為保密的原則吧,但是我仔細
google了下,沒有類似的文章,而且發表的這部分文檔也不至於被認為是什麼絕密資料,
但是我還是隱藏了很多發現的內核級別可能存在的問題:)單純從匯編代碼的結構來闡述
下linux與freebsd到底那個更好玩一些.或者說那個運行速度會更快一些:)
我想大家看完這個文檔以後,或許會知道到底是Linux穩固?還是FreeBSD穩固?
在本文的最後部分,附加了shellcode的問題,但沒有專門的論述.
備注:本文觀點僅代表個人觀點,如有不對的地方,歡迎大家指正:)以提高本人的水平.
--]編譯調試
A:編譯選項
Linux :gcc -gdwarf-2 ***.c -o ***
FreeBSD: cc -gdwarf-2 ***.c -o ***
為了調試方便,我使用了上面的選項.
--------------------------------------
對於一般書寫shellcode的編譯選項一般為:
Linux :gcc -static -o *** ***.c
FreeBSD: cc -static -o *** ***.c
B:調試工具
Linux/Unix下面的調試工具為GDB,但是GDB基於內核的調試有些力不從心,因為GDB的調試是
基於用戶模式(User mode).
這裡我使用了其它的調試工具,所以下面大家看到的調試代碼比較特殊,在這裡事先聲明.
--]Linux的syscall跟蹤
寫過shellcode的人都知道syscall是寫shellcode的必需品:)當然這種概念只在Linux/Unix
的OS下才存在.最近這段時間因為一個"小小的問題"對Linux內核與FreeBSD的內核級別進行了
跟蹤和調試,然後發現一個蠻有意思的問題,自己感覺這個問題可能會與Linux下shellcode與
FreeBSD下shellcode的不同有關系,當然也和系統架構存在一些細微的關系.下面的內容是Linux
下面syscall的一些匯編代碼.
在Linux下面,Application調用syscall的代碼如下:
420D4330 55 PUSH EBP |
420D4331 89E5 MOV EBP,ESP |->堆棧框架
420D4333 83EC18 SUB ESP,00000018 |
420D4336 897DFC MOV dword ptr [EBP]-04,EDI |
420D4339 8B4D0C MOV ECX,dword ptr [EBP]+0c |
420D433C 8B7D08 MOV EDI,dword ptr [EBP]+08 |->syscall參數
420D433F 8975F8 MOV dword ptr [EBP]-08,ESI |
420D4342 8B5510 MOV EDX,dword ptr [EBP]+10 |
420D4345 895DF4 MOV dword ptr [EBP]-0c,EBX
420D4348 E81014F4FF CALL near32 ptr 4201575d
420D434D 81C3835F0500 ADD EBX,00055f83
420D4353 8D77FF LEA ESI,dword ptr [EDI]-01
420D4356 83FE02 CMP ESI,00000002
420D4359 8D75F0 LEA ESI,dword ptr [EBP]-10
420D435C 0F477514 CMOVA ESI,dword ptr [EBP]+14
420D4360 53 PUSH EBX
420D4361 89FB MOV EBX,EDI
420D4363 B81A000000 MOV EAX,0000001c //system call number value
420D4368 CD80 INT 80 //調用0x80
420D436A 5B POP EBX
420D436B 3D00F0FFFF CMP EAX,fffff000
420D4370 89C6 MOV ESI,EAX
420D4372 760E JBE short ptr 420d4382
420D4374 F7DE NEG ESI
420D4376 E8C912F4FF CALL near32 ptr 42015644
420D437B 8930 MOV dword ptr [EAX],ESI
420D437D BEFFFFFFFF MOV ESI,ffffffff
420D4382 85F6 TEST ESI,ESI
420D4384 782A JS short ptr 420d43b0
420D4386 85FF TEST EDI,EDI
420D4388 7426 JE short ptr 420d43b0
420D438A 83FF03 CMP EDI,00000003
420D438D 7721 JA short ptr 420d43b0
420D438F E8B012F4FF CALL near32 ptr 42015644
420D4394 C70000000000 MOV dword ptr [EAX],00000000
420D439A 8B45F0 MOV EAX,dword ptr [EBP]-10
420D439D 8B5DF4 MOV EBX,dword ptr [EBP]-0c
420D43A0 8B75F8 MOV ESI,dword ptr [EBP]-08
420D43A3 8B7DFC MOV EDI,dword ptr [EBP]-04
420D43A6 89EC MOV ESP,EBP
420D43A8 5D POP EBP
420D43A9 C3 RETN
---------------------------------------------------------------------
為了簡單分析,我們就看這裡的代碼:
420D4330 55 PUSH EBP |
420D4331 89E5 MOV EBP,ESP |->堆棧框架
420D4333 83EC18 SUB ESP,00000018 |
420D4336 897DFC MOV dword ptr [EBP]-04,EDI |
420D4339 8B4D0C MOV ECX,dword ptr [EBP]+0c |
420D433C 8B7D08 MOV EDI,dword ptr [EBP]+08 |->syscall參數
420D433F 8975F8 MOV dword ptr [EBP]-08,ESI |
420D4342 8B5510 MOV EDX,dword ptr [EBP]+10 |
420D4345 895DF4 MOV dword ptr [EBP]-0c,EBX
420D4348 E81014F4FF CALL near32 ptr 4201575d
420D434D 81C3835F0500 ADD EBX,00055f83
420D4353 8D77FF LEA ESI,dword ptr [EDI]-01
420D4356 83FE02 CMP ESI,00000002
420D4359 8D75F0 LEA ESI,dword ptr [EBP]-10
420D435C 0F477514 CMOVA ESI,dword ptr [EBP]+14
420D4360 53 PUSH EBX
420D4361 89FB MOV EBX,EDI
420D4363 B81A000000 MOV EAX,0000001c //system call number value
420D4368 CD80 INT 80 //調用0x80
----------------------------------------------------------------------
當然從上面的代碼,我們只能看到Linux在更深的一層調用syscall的一個匯編代碼過程,換句話
說,可能上面的這些代碼都是廢話:)OK,我們繼續看下面的內容.
--]FreeBSD的syscall
FreeBSD下面的syscall我進行了兩次跟進的操作才進入到內部,所以下面使用了兩個過程來演示
代碼,不過從下面的代碼來看FreeBSD的短了很多很多:)
trace into one step:
28080D98: 31C0 XOR EAX,EAX
28080D9A: 53 PUSH EBX
28080D9B: E800000000 CALL near32 ptr 28080da0
-------------------------------------------------------------------
trace into two step:
28080DA0: 5B POP EBX
28080DA1: 81C3AC980600 ADD EBX,000698ac
28080DA7: 8B934C0A0000 MOV EDX,dword ptr [EBX]+00000a4c
28080DAD: 8902 MOV dword ptr [EDX],EAX
28080DAF: 5B POP EBX
28080DB0: 8D051A000000 LEA EAX,dword ptr [0000001c]//system call number value
28080DB6: CD80 INT 80
28080DB8: 7201 JC short ptr 28080dbb
28080DBA: C3 RETN
--------------------------------------------------------------------
從上面的代碼來看,FreeBSD的syscall代碼比Linux的短了很多很多,但是僅僅是短還是不夠的,如果在看
這個文檔前你熟悉破解技術 or 溢出技術 or Intel匯編語言.我想可能大家有這樣的感覺,FreeBSD的調用
syscall的過程比Linux的要安全了很多很多,為什麼這麼說呢?請再返回仔細看上面的Linux/FreeBSD的匯
編代碼:)下面我們也會大概的論證下,但僅僅是猜測而已:)
--]FreeBSD比Linux安全?
學過破解技術的朋友,都知道通過一些跳轉指令來實現對於軟件的破解,當然使用跳轉指令可能僅僅對一些
簡單的軟件是有用處.突然發現我上面說的這句話是廢話,和本文沒有任何的關系,郁悶...看來腦袋裡面裝的
東西多也不是什麼好事情:(
言歸正傳,我們來大體的分析下為什麼說BSD比Linux要安全些!請看下面的代碼:
Linux的syscall調用:
420D4336 897DFC MOV dword ptr [EBP]-04,EDI |
420D4339 8B4D0C MOV ECX,dword ptr [EBP]+0c |
420D433C 8B7D08 MOV EDI,dword ptr [EBP]+08 |->syscall參數
420D433F 8975F8 MOV dword ptr [EBP]-08,ESI |
420D4342 8B5510 MOV EDX,dword ptr [EBP]+10 |
-----------------------------------------------------------------------------
420D435C 0F477514 CMOVA ESI,dword ptr [EBP]+14 |
420D4360 53 PUSH EBX |->syscall參數
420D4361 89FB MOV EBX,EDI |
420D4363 B81A000000 MOV EAX,0000001c //system call number value
420D4368 CD80 INT 80 //調用0x80
-----------------------------------------------------------------------------
從上面的代碼我們可以看到這樣一種情況,這裡我們假設調用系統函數write來寫輸出:)
write(filehandle, buf, buf_length)
其匯編代碼的函數調用,基本如下:
push buf_length
push buf
push filehandle
call write
然後進入到write函數後,我們就知道Linux的syscall的一個完整過程如下:
高級語言調用系統函數|
->jump syscall(即系統對系統函數的標識)|
->把syscall的參數賦給寄存器|
->mov eax,0x**(及上面write函數針對syscall的數值)|
->int 0x80|
->返回|
基本過程如上所示,那麼如果我們spoof(欺騙)這些傳遞參數的寄存器呢?假設spoof是成功的,
那麼很容易就會把一些壞變量值傳遞到syscall的系統調用,緊接著系統內核可能在接收到一些
壞信息的時候,處理不當,導致系統出現異常或者系統發生溢出.當然這些僅僅是猜測,本文的很
多內容都是在猜測,至於答案嘛,可能永遠都沒有...:)
\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
FreeBSD的syscall調用:
28080D98: 31C0 XOR EAX,EAX
28080D9A: 53 PUSH EBX
28080D9B: E800000000 CALL near32 ptr 28080da0
28080DA0: 5B POP EBX
28080DA1: 81C3AC980600 ADD EBX,000698ac
28080DA7: 8B934C0A0000 MOV EDX,dword ptr [EBX]+00000a4c
28080DAD: 8902 MOV dword ptr [EDX],EAX
28080DAF: 5B POP EBX
28080DB0: 8D051A000000 LEA EAX,dword ptr [0000001c]//system call number value
28080DB6: CD80 INT 80
28080DB8: 7201 JC short ptr 28080dbb
28080DBA: C3 RETN
從上面的代碼我們也可以看到這樣一種情況,這裡我們假設調用系統函數write來寫輸出:)
write(filehandle, buf, buf_length)
其匯編代碼的函數調用,基本如下:
push buf_length
push buf
push filehandle
call write
然後進入到write函數後,我們就知道Linux的syscall的一個完整過程如下:
高級語言調用系統函數|
->jump syscall(即系統對系統函數的標識)|
->mov eax,0x**(及上面write函數針對syscall的數值)|
->int 0x80|
->返回|
根據我的跟蹤分析,發現FreeBSD使用了程序裡面的參數變量,這樣的情況就是FreeBSD省去了一個寄存器調用
函數參數的過程,這樣就禁止了可能存在spoof寄存器的問題,從這點上來看,FreeBSD的確比Linux要安全很多.
------------------------------------------------------------------------------------------------
雖然Linux的這個syscall會調用寄存器保存參數值,可能有其好處(最起碼我感覺看代碼和分析一些內核的時,
舒服了很多:)). FreeBSD的就優良了很多,我不得不佩服FreeBSD的優點,開始的時候我也經常被FreeBSD這樣的調用方式搞的頭大
的厲害,但是就這麼看啊看的,反而習慣了.在之前的時候,一直是一段時間Linux,一段時間BSD;只有在最近交叉跟
蹤的時候,才發現上面這個自己感覺比較有意思的問題:)
--]FreeBSD的程序比Linux的運行速度快?
這個問題很難說,如果從上面的代碼來看的話,少了這麼多的匯編代碼,說FreeBSD比Linux慢估計誰都不會相信的.
當然我沒有針對FreeBSD的系統架構與Linux的系統架構進行更深入的對比分析,所以也不敢枉自下如此不清晰的結
論:)如果那位有興趣,能不能在相同的硬件平台下,對這倆OS做下測試?
再繼續羅嗦一個問題,雖然FreeBSD比Linux少了些匯編代碼,但是syscall的參數FreeBSD肯定也是獲取的,只不過
獲取的方式比Linux更直接了一些:)
--]FreeBSD與Linux的shellcode
先廢話一下,說到syscall如果不說些shellcode的故事,好像的確是少了那麼一點點事情...So,我們來看看FreeBSD
與Linux的shellcode.我書寫了一些簡單的shellcode,看到網上很多關於shellcode的中文教程都是拿GDB不斷調試出
來的,感覺好麻煩:(個人認為既然熟悉GDB調試技術,肯定熟悉匯編,也肯定熟悉syscall,不熟悉找下頭文件看看不就得
了...於是我一直用匯編來寫這些可愛的shellcode,剛學會幾天,不對的地方大家明示:)
到底是先說FreeBSD的shellcode,還是先說Linux的呢?我拿硬幣拋了下,至於為什麼拋硬幣...困了...找點刺激自己
神經的方法:)).好了,硬幣拋完了,先說FreeBSD下面的.
編譯:nasm -f elf ***.asm
ld -s -o *** ***.o
A: FreeBSD下面的shellcode(hello.asm):
section .text
global _start
_start:
xor eax,eax
cdq
push 0x0a216472
push 0x6f57206f
push 0x6c6c6548
mov ebx,esp
push byte 0xc
push ebx
push byte 0x1
push eax
mov al,0x4
int 0x80
xor eax,eax
push eax
mov al,0x1
int 0x80
------------------------------------------------------------------------------------------------
上面的的匯編代碼可以直接編譯來獲取shellcode,按照前面說的編譯辦法編譯,然後:
objdump -D hello > hello.txt
把獲得的機器碼copy出來就是一個freebsd下面的shellcode了.
B: Linux下面的shellcode(hello.asm):
global _start
_start:
xor eax,eax
jmp short string
code:
pop esi
push byte 15
push esi
push byte 1
push eax
int 0x80
xor eax,eax
push eax
push eax
mov al,1
int 0x80
string:
call code
db "Hello word!", 0x0a
------------------------------------------------------------------------------------------------
上面的的匯編代碼可以直接編譯來獲取shellcode,按照前面說的編譯辦法編譯,然後:
objdump -D hello > hello.txt
把獲得的機器碼copy出來就是一個linux下面的shellcode了.
C: 為什麼FreeBSD與Linux下面的shellcode不同?
這個問題,我想留給大家先思考下,然後再看我的下文.如果你看了我的下文還是不了解的話...那麼可能的情況
是你根本還不會匯編和Unix類型的編程...還有一個情況是,你太笨了:(
C-1: Linux的syscall的系統調用是如下的過程:
高級語言調用系統函數|
->jump syscall(即系統對系統函數的標識)|
->把syscall的參數賦給寄存器|
->mov eax,0x**(及上面write函數針對syscall的數值)|
->int 0x80|
->返回|
那麼,我們的shellcode在push參數的時候,就比較隨便一些了,因為在後面的系統級別的syscall又對參數進行了二
次的賦值,賦值給各個寄存器,然後才調用syscall.
C-2: FreeBSD的syscall系統調用是如下的過程:
高級語言調用系統函數|
->jump syscall(即系統對系統函數的標識)|
->mov eax,0x**(及上面write函數針對syscall的數值)|
->int 0x80|
看到沒有,或者說前面的內容記憶起來了吧?freebsd的syscall調用是在進入系統syscall前就push進來的,所以我們的
shellcode必須得把參數的值先push進來,而不是象linux那樣的隨意.
--]總結
其實,最後這部分關於shellcode的不同之處,真正要寫的話,估計還得整整的一篇內容.但是...人是鐵飯是鋼,一頓不吃
餓的慌.於是准備做下逃兵,先去添飽肚子,然後美美的睡一覺.順便做個美夢,在夢中,偶的"老大"又開始欺負偶了...