殭屍程式

xiaokadba發表於2011-09-13

微軟系列的東西現在已經非常受人們的喜愛,尤其是他獨特人性化操作才讓大家愛不釋
手,但是他也以漏洞之王為稱,所以政府、企業等大型伺服器是絕對沒人敢用windows系
列產品的。相比之下Linux在安全方面就閒得非常強壯。 <wbr>而且照以後的發展趨勢來看Li
nux將在各各領域佔有絕對的優勢,這個年代要是不懂Linux很難立足。所以今天我就帶
大家步入Linux最基本的安全領域—"程式"。
<wbr> <wbr> <wbr> <wbr>大家都知道Linux跟Win2K一樣,都是多工的作業系統,也就是說,在同一個時間
內,可以有多個程式同時執行。如果大家對硬體體系有一定了解的話,就會知道,我們
使用的個人計算機(PC)的CPU是在一個時間片斷內只能執行一條指令,那麼Linux是如何
實現多程式同時執行的呢?這裡Linux使用了一種稱為"程式排程(process <wbr>scheduling
)"的武器,首先,為每個程式指派一定的執行時間,這個時間通常很短,短到以毫秒為
單位,然後依照某種規則,從眾多程式中挑選一個投入執行,其他的程式暫時等待,當
正在執行的那個程式時間耗盡,或執行完畢退出,或因某種原因暫停,Linux就會重新進
行排程,挑選下一個程式投入執行。因為每個程式佔用的時間片都很短,在我們使用者
的角度來看,就好像多個程式同時執行一樣了。我們瞭解了完了Linux多程式概念後,先
來看看什麼是程式?
一、程式概念:
<wbr> <wbr> <wbr> <wbr>當執行任何一個UNIX/Linux命令時,shell至少會建立一個程式來執行這個命令(這
個程式也叫做父程式),所以可以把任何在UNIX/Linux系統中執行的程式叫做程式;但
是程式並不是程式,程式是動態的,而程式是靜態的,並且多個程式(這多個程式裡除
了父程式,其他的就是子程式)可以併發的呼叫同一個程式。

<wbr> <wbr> <wbr> <wbr>系統中每一個程式都包含一個task_struct資料結構,所有指向這些資料結構的指標
組成一個程式向量陣列,系統預設的程式向量資料大小是512,表示系統中可同時容納5
12個程式。程式的task_struct資料結構包括了程式的狀態、排程資訊、程式識別符號等信
息。
<wbr> <wbr> <wbr> <wbr>由於UNIX系統是一個多程式的作業系統,所以每一個程式都是獨立的,都有自己的
許可權及任務,所以當某一程式失敗時並不會導致別的程式失敗。系統透過程式識別符號來
區分不同的程式,程式識別符號是一個非負正數,他在任何時刻都是唯一的,當某個程式
結束時,他的程式識別符號可以分配給另外一個新程式。系統將識別符號0分配給排程程式,
識別符號1分配給初始化程式。下面我來給大家演示一下程式由出生到死亡的一個流程圖。

程式一生流程圖:
出生:程式設計中的一句fork(),爸爸媽媽(父程式)讓小孩(子程式)出生了,並且繼
承裡父母所有的東西,我們也可以把他看成克隆人。
生活:然後隨著exec(),小孩長大(新程式)脫胎換骨,離家獨立,開始了為人民服
務的職業生涯。
死亡: <wbr>人有生老病死,程式也一樣,它可以是自然死亡,即執行到main函式的最後一個
"}",從容地離我們而去;也可以是自殺,自殺有2種方式,一種是呼叫exit函式, <wbr> <wbr>一
種是在main函式內使用return,無論哪一種方式,它都可以留下遺書,放在返回值裡保
留下來;它還甚至能可被謀殺,被其它程式透過另外一些方式結束他的生命(這裡跟人
有些不一樣,在程式裡,如果父程式死了,那麼他建立的所有子程式也一起跟著死去)

死後安葬方式:這一過程也是必有的,不能說人在哪死後就不管他,也不把屍體搬走吧
!:)程式死掉以後,會留下一具殭屍,wait()函式充當了殮屍工,把殭屍推去火化,使
其最終歸於無形。
這就是程式完整的一生。
<wbr> <wbr> <wbr> <wbr>程式在執行期間,會用到很多資源,包括最寶貴的CPU資源,當某一個程式佔用CPU
資源時,別的程式必須等待正在執行的程式空閒CPU後才能執行,由於存在很多程式在等
待,所以核心透過排程演算法來決定將CPU分配給哪個程式。概念清晰後我們接下來看看L
inux中,程式有哪幾種狀態。
二、Linux中的程式基本狀態:
<wbr> <wbr> <wbr> <wbr>1、執行(R)狀態:CPU正在執行,即程式正在佔用CPU。
<wbr> <wbr> <wbr> <wbr>2、就緒(W)狀態:程式已經具備的執行的一切條件,正在等待分配CPU的處理時間片

<wbr> <wbr> <wbr> <wbr>3、停止(S)狀態:程式不能使用CPU。
<wbr> <wbr> <wbr> <wbr>大家看到了在Linux中,正常來說程式有這麼3種狀態,但是在特殊情況下會多出一
種狀態,這就是我們要講的"殭屍程式(Zombie)"。下面我們會仔細的講解,接下來再
介紹一下程式的管理。
三、Linux中的程式管理
<wbr> <wbr> <wbr> <wbr> <wbr>管理分兩種,一個是如何啟動程式,另一個是如何排程程式。 <wbr>
<wbr> <wbr> <wbr> <wbr>1、啟動程式 <wbr>
<wbr> <wbr> <wbr> <wbr>鍵入需要執行的程式的程式名,執行一個程式,其實也就是啟動了一個程式。在Li
nux系統中每個程式都具有一個程式號(PID),用於系統識別和排程程式。啟動一個進
程有兩個主要途徑∶手工啟動和排程啟動,後者是事先進行設定,根據使用者要求自行啟
動。由使用者輸入命令,直接啟動一個程式便是手工啟動程式。但手工啟動程式又可以分
為很多種,根據啟動的程式型別不同、性質不同,實際結果也不一樣。 <wbr>
<wbr> <wbr> <wbr> <wbr>(1) <wbr>前臺啟動 <wbr>
<wbr> <wbr> <wbr> <wbr>前臺啟動是手工啟動一個程式的最常用的方式。一般來說使用者輸入一個命令"test"
,這就在前臺啟動了一個程式。這時候系統其實已經處於一個多程式狀態。有許多執行
在後臺的、系統啟動時就已經自動啟動的程式正在悄悄執行著。這時如果有使用者輸入"t
est"命令以後趕緊使用"ps <wbr>-x"來檢視,但是卻沒有發現這個程式,原因是因為這個程式
結束的太快,使用ps檢視時該程式已經執行結束了。所以如果大家想看到程式的話,得
輸入一個耗時的程式,我們下面會講到。
<wbr> <wbr> <wbr> <wbr>(2) <wbr>後臺啟動 <wbr>
<wbr> <wbr> <wbr> <wbr>直接從後臺手工啟動一個程式用得比較少一些,除非是該程式甚為耗時,且使用者也
不急著需要結果的時候。假設使用者要啟動一個需要長時間執行的格式化文字檔案的程式
。為了不使整個shell在格式化過程中都處於"癱瘓"狀態,從後臺啟動這個程式是明智的
選擇。 <wbr>
<wbr> <wbr> <wbr> <wbr>2、程式排程 <wbr>
<wbr> <wbr> <wbr> <wbr>當需要中斷一個前臺程式的時候,通常是使用Ctrl+c組合鍵;但是對於一個後臺程式
就不是一個組合鍵所能解決的了,這時就必須使用kill命令.該命令可以終止後臺程式.至
於終止後臺程式的原因很多,或許是該程式佔用的CPU時間過多;或許是該程式已經掛死
.這種情況是經常發生的。Kill命令的工作原理是:向Linux系統的核心傳送一個系統操
作訊號和某個程式的程式標識號,然後系統核心就可以對程式標識號指定的程式進行操
作。 <wbr>
<wbr> <wbr> <wbr> <wbr> <wbr>好了,程式的基本概念熟悉了以後大家會問那麼到底什麼是所謂的"殭屍程式"?,
什麼情況下會產生殭屍程式,如何殺掉殭屍程式?不用著急,我們先來熟悉一下有關Li
nux程式方面的程式設計。
<wbr> <wbr> <wbr>首先我先給大家介紹幾個非常重要的有關函式:
<wbr> <wbr> <wbr>
<wbr> <wbr> <wbr>fork(); <wbr> <wbr>功能:建立一個新的程式。(fork()<0[出錯]、fork()==0[子程式]、fork
()>0[父程式]
<wbr> <wbr> <wbr>wait(); <wbr> <wbr>功能:真正結束程式(收屍)。
<wbr> <wbr> <wbr>exec(); <wbr> <wbr>功能:執行外部程式。

<wbr> <wbr> <wbr> <wbr>好了,我現在讓大家就看看我們神秘殭屍程式是什麼樣子的?下面我來用c寫出父進
程建立子程式的程式碼:

#i <wbr>nclude <wbr>
#i <wbr>nclude <wbr>
main()
{
<wbr> <wbr> <wbr> <wbr>
<wbr> <wbr> <wbr> <wbr>fork(); <wbr>
<wbr> <wbr> <wbr> <wbr>if(fork()>0) <wbr>
<wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr>wait(NULL); <wbr> <wbr> <wbr> <wbr>
}
<wbr> <wbr> <wbr> <wbr>大家看完程式碼後,就會覺得這個程式碼正是我剛才講的程式一生是怎麼樣的,程式死
後,一定要為他收屍,否則他就會變成殭屍程式。下面就讓我們來看看未能把死去的進
程收屍會變成什麼樣子?

#i <wbr>nclude <wbr>
#i <wbr>nclude <wbr>
main()
{
<wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr>fork(); <wbr>
<wbr> <wbr> <wbr> <wbr>if(fork>0) <wbr>
<wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr>sleep(30); <wbr> <wbr> <wbr> <wbr>
<wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr>wait(NULL); <wbr> <wbr> <wbr> <wbr>
<wbr> <wbr> <wbr>
}


<wbr> <wbr> <wbr> <wbr>為了讓大家更清楚的看到殭屍程式我們把這個殭屍程式程式碼編譯,然後執行,
#gcc <wbr>-o <wbr>zombie <wbr>zombie.c
編譯成功後我們開始執行這個程式因為程式碼裡的sleep(30)是讓父程式睡眠30秒,如果我
們在前臺執行我們這個程式,那麼就不能執行其他shell命令了,所以這裡我們在執行的
命令後面加一個& <wbr>代表後臺執行的意思。
#./zomber <wbr>&
好了,我們在30秒內執行檢視程式命令來看看我們這個zombie程式是什麼樣的?
#ps <wbr>-aux <wbr>|grep <wbr>zombie
這個命令是顯示有關zombie的所有資訊。

<wbr> <wbr> <wbr> <wbr>看到這裡後,聰明的朋友會問,既然子程式是由父程式創造出來的,那麼如果一個
父程式執行完退出後,子程式不管是不是殭屍程式也直接就退出了,因為父程式死了嘛
。那麼這也不會造成多大危害啊?如果大家這麼認為那可就錯了,當我們剛才用ps命令
觀察程式的執行狀態時,看到某些程式的狀態列為defunct,這就是所謂的"殭屍"程式。
"殭屍"程式是一個早已死亡的程式,但在程式表(processs <wbr>table)中仍佔了一個位置
(slot)。由於程式表的容量是有限的,所以,defunct程式不僅佔用系統的記憶體資源,
影響系統的效能,而且如果其數目太多,還會導致系統癱瘓,具體請看下面的程式碼:

#i <wbr>nclude <wbr>
#i <wbr>nclude <wbr>
main()
{
<wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr>for <wbr>(;;) <wbr> <wbr>
<wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr>
<wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr> <wbr>fork(); <wbr>
}


懂C語言的朋友會知道for(;;)是一個死迴圈。那麼這僅有2行程式碼的程式就可以把你的l
inux瞬間當機,因為他的作用是無限制的在記憶體裡增加新的子程式,一個系統根據記憶體
的容量會分配程式的最大限制,一旦同時執行的程式數超符合,那麼你的機器必然會死
機。
<wbr> <wbr> <wbr>我這裡分別用了2個使用者進行測試過,一個是普通許可權的使用者,一個是Root使用者,測
試結果是"任何使用者只要執行這個程式都會讓機器死掉"。原因就是預設的Linux系統沒有
對普通使用者的使用最大程式進行限制。所以這樣對系統造成很大一個威脅,那麼我們如
何避免普通使用者非法執行過多資源或程式導致系統拖死,所以我們的給除了Root的使用者
做一下限制。

對普通使用者進行限制:
第1步:首先進到Linux終端用vi編輯/etc/security <wbr>/limits.conf檔案,在裡面加入:
<wbr>
  * <wbr>hard <wbr>core <wbr>0 <wbr>
  * <wbr>hard <wbr>rss <wbr>5000 <wbr>
  * <wbr>hard <wbr>nproc <wbr>20 <wbr>
<wbr> <wbr>
<wbr> <wbr>這裡的* <wbr>代表除了Root的所有使用者,(* <wbr>hard <wbr>core <wbr>0) <wbr>是禁止core <wbr>files"core <wbr>0",
(* <wbr>hard <wbr>rss <wbr>5000) <wbr>是限制記憶體使用為5MB"rss <wbr> <wbr>5000", <wbr>(* <wbr>hard <wbr>nproc <wbr>20 <wbr>)是限制進
程數為"nproc <wbr>50"。大家可以根據自己系統記憶體大小進行合理配置。
第2步:用vi編輯/etc/pam.d/login檔案,然後加上下面這行儲存退出就可以。 <wbr>
  session <wbr>required <wbr>/lib/security/pam_limits.so <wbr>
<wbr> <wbr> <wbr> <wbr>好了,現在我們已經對普通使用者限制了程式和記憶體使用極限,修改完配置以後大家
可以用Root和普通使用者分別進行測試,結果當然是普通使用者執行完我們剛才做的程式不
會當機了。
<wbr> <wbr> <wbr> <wbr>一個系統的安全性不取決與打不打補丁,雖然打補丁很重要,但是對系統做出相應
的配置也是相當重要的。

[@more@]

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/26274656/viewspace-1054999/,如需轉載,請註明出處,否則將追究法律責任。

相關文章