第一部分 背景知識簡介
幾乎所有編寫代碼的人都有這種體會:如今在計算機這個行業(yè)中,許多技術(shù)不是你不懂,而是你不知道。所以,在分析之前有些背景知識是必須要知道的。 一. 硬盤結(jié)構(gòu)簡介 1. 硬盤參數(shù)釋疑 到目前為止, 人們常說的硬盤參數(shù)還是古老的 CHS (Cylinder/Head/Sector)參數(shù). 那么為什么要使用這些參數(shù), 它們的意義是什么? 它們的取值范圍是什么? 很久以前, 硬盤的容量還非常小的時候, 人們采用與軟盤類似的結(jié)構(gòu)生產(chǎn)硬盤,也就是硬盤盤片的每一條磁道都具有相同的扇區(qū)數(shù),由此產(chǎn)生了所謂的3D參數(shù) (Disk Geometry)。既磁頭數(shù)(Heads), 柱面數(shù)(Cylinders), 扇區(qū)數(shù)(Sectors),以及相應(yīng)的尋址方式。 其中: 磁頭數(shù)(Heads) 表示硬盤總共有幾個磁頭,也就是有幾面盤片, 最大為 255 (用 8 個二進制位存儲); 柱面數(shù)(Cylinders) 表示硬盤每一面盤片上有幾條磁道, 最大為 1023(用 10 個二進制位存儲); 扇區(qū)數(shù)(Sectors) 表示每一條磁道上有幾個扇區(qū), 最大為 63 (用 6個二進制位存儲); 每個扇區(qū)一般是 512個字節(jié)(理論上講這不是必須的, 但好象都取此值)。 據(jù)此,磁盤最大容量為: 255 * 1023 * 63 * 512 / 1048576 = 8024 MB ( 1M = 1048576 Bytes ) 或硬盤廠商常用的單位: 255 * 1023 * 63 * 512 / 1000000 = 8414 MB ( 1M = 1000000 Bytes ) 在 CHS 尋址方式中, 磁頭, 柱面, 扇區(qū)的取值范圍分別為 0 到 Heads - 1,0 到 Cylinders - 1, 1 到 Sectors (注意是從 1 開始)。 2. 基本 Int 13H 調(diào)用簡介 BIOS Int 13H調(diào)用是 BIOS 提供的磁盤基本輸入輸出中斷調(diào)用, 它可以完成磁盤(包括硬盤和軟盤)的復位, 讀/寫, 校驗, 定位, 診斷, 格式化等功能。它使用的就是 CHS 尋址方式, 因此最大只能訪問 8 GB 左右的硬盤 ( 本文中如不作特殊說明, 均以 1M = 1048576 字節(jié)為單位). 而更不幸的是,標準的IDE接口容許256個扇區(qū)/磁道、65536個柱面及16個磁頭。它自己本身可以存取 137438953472(128 GB),但是加上BIOS方面63個扇區(qū)與1024個柱面的限制后,就只剩528482304(1024*16*63 = 504MB)可以定址得到,這就是所謂標準IDE硬盤只認前504MB問題。 3. 現(xiàn)代硬盤結(jié)構(gòu)簡介 在老式硬盤中, 由于每個磁道的扇區(qū)數(shù)相等 (與軟盤一樣), 所以外道的記錄密度要遠低于內(nèi)道, 因此會浪費很多磁盤空間。為了解決這一問題, 進一步提高硬盤容量, 人們改用等密度結(jié)構(gòu)生產(chǎn)硬盤, 也就是說, 外圈磁道的扇區(qū)比內(nèi)圈磁道多。采用這種結(jié)構(gòu)后, 硬盤不再具有實際的3D參數(shù), 尋址方式也改為線性尋址, 即以扇區(qū)為單位進行尋址。 為了與使用3D尋址的老軟件兼容 (如使用BIOS Int13H接口的軟件), 在硬盤控制器內(nèi)部安裝了一個地址翻譯器, 由它負責將老式3D參數(shù)翻譯成新的線性參數(shù)。這也是為什么現(xiàn)在硬盤的3D參數(shù)可以有多種選擇的原因 (不同的工作模式對應(yīng)不同的3D參數(shù), 如 LBA, LARGE, NORMAL)。 4. 擴展 Int 13H 簡介 雖然現(xiàn)代硬盤都已經(jīng)采用了線性尋址, 但是由于基本 Int 13H 的制約, 使用 BIOS Int 13H 接口的程序, 如 DOS 等還是只能訪問 8 G 以內(nèi)的硬盤空間。為了打破這一限制, Microsoft 等幾家公司制定了擴展 Int 13H 標準(Extended Int13H,詳見附錄A), 采用線性尋址方式存取硬盤,所以突破了 8 G 的限制,而且還加入了對可拆卸介質(zhì) (如活動硬盤) 的支持。 二. Boot Sector 結(jié)構(gòu)簡介 1. Boot Sector 的組成 Boot Sector 也就是硬盤的第一個扇區(qū), 它由 MBR (Master Boot Record),DPT (Disk Partition Table) 和 Boot Record ID(Magic Number) 三部分組成。 MBR 又稱作主引導記錄,占用 Boot Sector 的前 446 個字節(jié) ( 0 to 0x1BD ),包含了硬盤的一系列參數(shù)和一段系統(tǒng)主引導程序。引導程序主要是用來在系統(tǒng)硬件自檢完后負責從活動分區(qū)中裝載并運行系統(tǒng)引導程序(引導操作系統(tǒng))。它的最后一條執(zhí)行語句是一條JMP指令,跳到操作系統(tǒng)的引導程序去。這里往往是引導型病毒的注入點,也是各種多系統(tǒng)引導程序的注入點。但是由于引導程序本身完成的功能比較簡單,所以我們完全可以判斷該引導程序的合法性(比如看JMP指令的合法性),因而也易于修復。象命令fdisk/mbr可以修復MBR和 KV300這類軟件可以查殺任意類型的引導型病毒,就是這個道理。 DPT 即主分區(qū)表,占用 64 個字節(jié) (0x1BE to 0x1FD),記錄了磁盤的基本分區(qū)信息。主分區(qū)表分為四個分區(qū)項, 每項 16 字節(jié), 分別記錄了每個主分區(qū)的信息(因此最多可以有四個主分區(qū))。 Boot Record ID 即引導區(qū)標記,占用兩個字節(jié) (0x1FE and 0x1FF), 對于合法引導區(qū), 它等于 0xAA55, 這是判別引導區(qū)是否合法的標志. Boot Sector 的具體結(jié)構(gòu)如下圖所示: 2. 主分區(qū)表的結(jié)構(gòu) 主分區(qū)表由四個分區(qū)項構(gòu)成, 每一項的結(jié)構(gòu)如下: BYTE State : 分區(qū)狀態(tài), 0 = 未激活, 0x80 = 激活 (注意此項) BYTE StartHead : 分區(qū)起始磁頭號 WORD StartSC : 分區(qū)起始扇區(qū)和柱面號, 低字節(jié)的低6位為扇區(qū)號,高2位為柱面號的第 9,10 位, 高字節(jié) 為柱面號的低 8 位 BYTE Type : 分區(qū)類型, 如 0x0B = FAT32, 0x83 = Linux 等, 00 表示此項未用 BYTE EndHead : 分區(qū)結(jié)束磁頭號 WORD EndSC : 分區(qū)結(jié)束扇區(qū)和柱面號, 定義同前 DWORD Relative : 在線性尋址方式下的分區(qū)相對扇區(qū)地址 (對于基本分區(qū)即為絕對地址) DWORD Sectors : 分區(qū)大小 (總扇區(qū)數(shù)) 注意:在 DOS / Windows 系統(tǒng)下, 基本分區(qū)必須以柱面為單位劃分( Sectors * Heads 個扇區(qū)), 如對于 CHS 為 764/255/63 的硬盤, 分區(qū)的最小尺寸為 255 * 63 * 512 / 1048576 = 7.844 MB。 3. 擴展分區(qū)簡介 由于主分區(qū)表中只能分四個分區(qū), 有時無法滿足需求, 因此設(shè)計了一種擴展分區(qū)格式。 基本上說, 擴展分區(qū)的信息是以鏈表形式存放的, 但也有一些特別的地方。 首先,主分區(qū)表中要有一個基本擴展分區(qū)項, 所有擴展分區(qū)都隸屬于它,也就是說其他所有擴展分區(qū)的空間都必須包括在這個基本擴展分區(qū)中。 對于DOS / Windows 來說, 擴展分區(qū)的類型為 0x05。 除基本擴展分區(qū)以外的其他所有擴展分區(qū)則以鏈表的形式級聯(lián)存放, 后一個擴展分區(qū)的數(shù)據(jù)項記錄在前一個擴展分區(qū)的分區(qū)表中, 但兩個擴展分區(qū)的空間并不重疊。 擴展分區(qū)類似于一個完整的硬盤, 必須進一步分區(qū)才能使用。但每個擴展分區(qū)中只能存在一個其他分區(qū), 此分區(qū)在 DOS/Windows 環(huán)境中即為邏輯盤。因此每一個擴展分區(qū)的分區(qū)表 (同樣存儲在擴展分區(qū)的第一個扇區(qū)中)中最多只能有兩個分區(qū)數(shù)據(jù)項(包括下一個擴展分區(qū)的數(shù)據(jù)項)。 擴展分區(qū)和邏輯盤的示意圖如下: 三. 系統(tǒng)啟動過程簡介 系統(tǒng)啟動過程主要由一下幾步組成(以硬盤啟動為例): 1. 開機; 2. BIOS 加電或按reset鍵后都要進行系統(tǒng)復位,復位后指令地址為 0ffff:fff0,這個地方只有一條JMP指令, 跳轉(zhuǎn)到系統(tǒng)自檢 ( Power On Self Test -- POST )程序處; 3. 系統(tǒng)自檢完成后,將硬盤的第一個扇區(qū) (0頭0道1扇區(qū), 也就是Boot Sector)讀入內(nèi)存地址 0000:7c00 處; 4. 檢查 (WORD) 0000:7dfe 是否等于 0xaa55, 若不等于則轉(zhuǎn)去嘗試其他啟動介質(zhì), 如果沒有其他啟動介質(zhì) 則顯示 "No ROM BASIC" 然后死機; 5. 跳轉(zhuǎn)到 0000:7c00 處執(zhí)行 MBR 中的程序; 6. MBR程序 首先將自己復制到 0000:0600 處, 然后繼續(xù)執(zhí)行; 7. 在主分區(qū)表中搜索標志為活動的分區(qū),如果沒有發(fā)現(xiàn)活動分區(qū)或有不止一個活動分區(qū), 則轉(zhuǎn)停止; 8. 將活動分區(qū)的第一個扇區(qū)讀入內(nèi)存地址 0000:7c00 處; 9. 檢查 (WORD) 0000:7dfe 是否等于 0xaa55, 若不等于則 顯示 "Missing Operating System" 然后停止, 或嘗 試軟盤啟動或; 10. 跳轉(zhuǎn)到 0000:7c00 處繼續(xù)執(zhí)行特定系統(tǒng)的啟動程序; 11. 啟動系統(tǒng)... 以上步驟中 2,3,4,5 步是由 BIOS 的引導程序完成. 6,7,8,9,10步由MBR中的引導程序完成. 一般多系統(tǒng)引導程序 (如 SmartFDISK, BootStar, PQBoot 等)都是將標準主引導記錄替換成自己的引導程序, 在運行系統(tǒng)啟動程序之前讓用戶選擇要啟動的分區(qū)。 而某些系統(tǒng)自帶的多系統(tǒng)引導程序 (如 lilo, NT Loader 等)則可以將自己的引導程序放在系統(tǒng)所處分區(qū)的第一個扇區(qū)中, 在 Linux中即為 SuperBlock (其實 SuperBlock 是兩個扇區(qū))。 注:以上各步驟中使用的是標準 MBR, 其他多系統(tǒng)引導程序的引導過程可能與此不同。 下面簡要說明一下系統(tǒng)復位后的指令地址0ffff:fff0(物理地址0x0fffffff0): 在實地址模式下,內(nèi)存有兩個保留區(qū)域:系統(tǒng)初始化區(qū)和中斷向量表區(qū)。地址0x00000~0x003ff 是為中斷向量保留的,256個可能的中斷,每一個保留4字節(jié)的跳轉(zhuǎn)向量;地址0xfffffff0~0xffffffff是為系統(tǒng)初始化保留的,此處一般只有一條JMP指令,跳到系統(tǒng)初始引導程序。 系統(tǒng)復位后,cs = 0x0f000、eip = 0x0000fff0,而系統(tǒng)初始引導程序安排在 0x0ffff0000~0x0ffffffff, 一般為ROM固件,使初始引導程序工作于內(nèi)存實際地址空間以外的另一存儲段中。此區(qū)域的16~31位都應(yīng)為1,cs及eip的初值已保證地址線的16~19位為1,而20~31位,即地址線的高12位,則須由硬件強制置 1,這由一個標志觸發(fā)器在系統(tǒng)每次復位時置位實現(xiàn)觸發(fā)。而由于段間轉(zhuǎn)移指令要重新裝入cs寄存器,因此,每當執(zhí)行段間轉(zhuǎn)移指令時,此標志觸發(fā)器復位,以后,再次訪問時,不再向高12位地址線提供“1”信號,程序從此正常地工作于前1MB的地址空間。 第二部分 硬盤MBR主引導代碼分析 一.程序流程 ?。ㄒ龑葏^(qū)是指硬盤相應(yīng)分區(qū)的第一個扇區(qū),是和操作系統(tǒng)有關(guān)的,操作系統(tǒng)的引導是由它來完成的;而MBR主引導程序并不負責引導操作系統(tǒng),MBR是和操作系統(tǒng)無關(guān)的,他的任務(wù)是把控制權(quán)轉(zhuǎn)交給操作系統(tǒng)的引導程序.) 1 將程序代碼由0:7C00H移動到0:0600H(注,BIOS把MBR放在0:7C00H處) 2 搜索可引導分區(qū),即80H標志 成功:goto 3 失?。禾隦OM BASIC 無效分區(qū)表:goto 5 3 讀引導扇區(qū) 失敗:goto 5 成功:goto 4 4 驗證引導扇區(qū)最后是否為55AAH 失?。篻oto 5 成功:goto 6 5 打印錯誤進入無窮循環(huán) 6 跳到0:7C00H進行下一步啟動工作 二.代碼注釋 下面將用匯編語言寫出這一段代碼,并進行說明。 ;MBR.ASM ; MASM MBR ; LINK MBR ; EXE2BIN MBR .MODEL tiny .CODE ;設(shè)置寄存器及堆棧值 org 0 Head: Start: cli xor ax,ax mov ss,ax mov sp,7C00H ;ss:sp=0:7C00H mov si,sp push ax pop es push ax pop ds ;es=ds=0 sti ;將程序代碼由0:7C00H移動到0:0600H處 cld mov di,600H mov cx,100H ;100H Words=512 Bytes,即一個扇區(qū)大小 repne movsw db 0EAH ;這個是FAR JUMP的機器碼 dw offset Continue+600H, 0000H ;這個是跳轉(zhuǎn)目的地址,即0:061DH ;搜索可引導分區(qū) Continue: mov si,600H+1BEH ;si指向分區(qū)表 mov bl,4 ;四個分區(qū) FindBoot: cmp byte ptr[si],80H je SaveRec ;讀扇區(qū)位置 cmp byte ptr[si],0 jne Invaild ;無效分區(qū) add si,10H dec bl jnz FindBoot int 18H ;進入ROM BASIC ;讀取引導分區(qū)的扇區(qū),柱面號 SaveRec: mov dx,[si] mov cx,[si+2] mov bp,si ;檢查其余分區(qū)表 FindNext: add si,10H dec bl jz SetRead cmp byte ptr[si],0 ;是否存在非法分區(qū) je FindNext Invaild: mov si,offset ErrMsg1+600H ;字符串輸出子程序 PrintStr: lodsb cmp al,0 je DeadLock push si mov bx,7 mov ah,0EH ;輸出字符 int 10H pop si jmp short PrintStr ;下一字符 DeadLock: jmp short DeadLock ;無窮循環(huán),也可以寫成jmp $ ;讀引導扇區(qū) SetRead: mov di,5 ;讀取次數(shù) ReadBoot: mov bx,7C00H mov ax,201H push di int 13H ;cx,dx已經(jīng)在SaveRec處得到 pop di jnc GoBoot ;成功則啟動 xor ax,ax int 13H ;reset驅(qū)動器,然后再讀取 dec di jnz ReadBoot mov si,offset ErrMsg2+600H jmp short PrintStr 失敗輸出信息,并進入無窮循環(huán) ;檢查讀入的引導扇區(qū) GoBoot: mov si,offsetErrMsg3+600H mov di,7C00H+1FEH cmp word ptr[di],0AA55H jne PrintStr ;非AA55標志則輸出錯誤信息 mov si,bp ;si指向可啟動分區(qū) db 0EAH,0,7CH,0,0 ;跳轉(zhuǎn)至0:7C00H ErrMsg1 db 'Invaild partition table',0 ErrMsg2 db 'Error loading operating system',0 ErrMsg3 db 'Missing operating system',0 Tail: FillNum equ 1BEH-(Tail-Head) ;計算填0數(shù)目 db FillNum dup(0) ;四個分區(qū)表項數(shù)據(jù),跟分區(qū)情況有關(guān),詳細含義另解 PartTable db 80H,1,1,0,4,4,0D1H,2,11H,0,0,0,0FEH,0FFH,0,0 db 0,0,0C1H,3,5,4,0D1H,0FEH,0FFH,0FFH,0,0,0ACH,53H,0,0 db 20H dup(0) ID dw 0AA55H end start ;如果開始試用org 600H,那么訪問數(shù)據(jù)時就不必加上600H,如mov si,offset ErrMsg2+600H ;可寫為mov si,offset ErrMsg2,這時就不能用exe2bin得到數(shù)據(jù),必須試用debug ;debug mbr.exe ;-nmbr.bin ;-rcx 200 ;-wcs:600 ;-q 在硬盤的第一個扇區(qū)上保存著分區(qū)信息,即主分區(qū)表,共有四項,讀取分區(qū)表必須使用bios的int 13h,一般使用debug就可以了: debug -a xxxx:0100 mov ax,201 mov bx,200 mov cx,1 mov dx,80 ;如果是第二個硬盤則是81... int 13 int 20 xxxx:???? -g=100 這時xxxx:0200開始的512字節(jié)就是分區(qū)表所在的扇區(qū),前面一部分為MBR,在debug中用-d3be l40就可以看到64字節(jié)的分區(qū)表信息,16個字節(jié)為一項,用-e命令就可以修改,改完后可以重新寫回去,只要把前面代碼中的mov ax,201改為mov ax,301即可,或者直接把102處的2改成3,比如: -e 102 xxxx:0102 02.3 -g=100 這樣就寫回去了,不過修改硬盤的第一個扇區(qū)須非常謹慎。 下面說一下分區(qū)表項的具體意義,取其中一項舉個例子: 80 01 01 00 0B 3F FF 00 3F 00-00 00 81 4F 2F 00 1 (80)引導標志,80代表可引導,00代表不可引導,一般必須且只能有一個分區(qū)表項的引導標志為 80,除非你自己修改MBR 2 (01)分區(qū)開始磁頭 3,4 (01 00)=(0,1)分區(qū)開始柱面和扇區(qū)(后面后詳解) 5 (0B)分區(qū)類型(后面有詳解) 6 (3F)=(63)分區(qū)結(jié)束磁頭 7,8 (FF 00)=(768,63)分區(qū)結(jié)束柱面和扇區(qū)(同上) 9-12 (3F 00 00 00)=(63)此分區(qū)前扇區(qū)總數(shù),即相對扇區(qū)數(shù) 13-16 (81 4F 2F 00)=(002F4F81H=3100545)此分區(qū)扇區(qū)總數(shù) 柱面和扇區(qū)共用兩個字節(jié)表示,而柱面號為10位,最大1023,扇區(qū)號為6位,最大63,具體各位分布如下圖: 扇區(qū)號 _____|____ | | ( 7 6 5 4 3 2 1 0 ) ( 7 6 5 4 3 2 1 0 ) |__| |___________| |___________________| | 柱面號 關(guān)于分區(qū)類型,常見的有: 00 未用,Unused 01 DOS-12(FAT 12) 02 XENIX 04 DOS-16(FAT 16)(分區(qū)<32M的,應(yīng)該已沒有了) 05 EXTEND(DOS擴展分區(qū)) 06 BIGDOS(>32M)(這個才是現(xiàn)在常說的FAT 16) 07 HPFS(OS/2)(NTFS也是這個標記,好像是) 0B FAT 32 0F 這個一時不確定 50 DM 63 386/ix(unix) 64 NET286(Novell) 65 NET386(Novell) 82 Linux swap 83 Linux native FF BBT(UNIX Bad Block Table) 下面有幾個算式用來計算分區(qū)參數(shù): 1)第一分區(qū)參數(shù) 扇區(qū)總數(shù)=(結(jié)束柱面+1)*磁頭數(shù)*每柱面扇區(qū)數(shù)-相對扇區(qū)數(shù),例如:3100545=(768+1)*64*63-63 2)其它分區(qū)參數(shù) 扇區(qū)總數(shù)=(結(jié)束柱面-起始柱面+1)*磁頭數(shù)*每柱面扇區(qū)數(shù),如下例: 00 00 C1 01 05 3F FF FD C0 4F-2F 00 C0 90 0F 00 000F90C0H=1020096,(FF FD)=(1021,63),(C1 01)=(769,1),1020096=(1021-769+1)*64*63 3)第一分區(qū)相對扇區(qū)=每柱面扇區(qū)數(shù) 其它分區(qū)相對扇區(qū)=上一分區(qū)相對扇區(qū)+上一分區(qū)扇區(qū)總數(shù) 擴展分區(qū)信息是一個鏈狀結(jié)構(gòu),在刪除分區(qū)時,把前面的分區(qū)刪掉會導致后面的分區(qū)也找不到,原因就在于此,我們從主分區(qū)表中取出擴展分區(qū)項進行一下分析,如下: 00 00 01 C0 05 FE BF 6E C0 10-2F 00 EF A6 69 00 由此我們可以得到數(shù)據(jù): 開始磁頭:00 開始柱面扇區(qū):01 C0=(192,1) 用debug debug -a100 xxxx:0100 mov ax,201 mov bx,200 mov cx,c001 ;開始柱面扇區(qū)號 mov dx,80 ;dh中為開始磁頭號,這里為0 int 13 int 20 xxxx:???? -g=100 -d3be l10 讀出的扇區(qū)中有兩個16字節(jié)的分區(qū)表項和最后的一個55AA標志,這兩個分區(qū)表項為: 00 01 01 C0 06 FE 7F 97 3F 00-00 00 99 F2 34 00 00 00 41 98 05 FE BF 6E D8 F2-34 00 17 B4 34 00 第一個分區(qū)類型為6,其實這是第一個邏輯分區(qū),含義和主分區(qū)表項相同 第二個分區(qū)類型為5,這其實是指向下一個擴展分區(qū)表的 從這里我們可以得到: 開始磁頭:0 開始柱面扇區(qū):41 98=(408,1) 繼續(xù)用debug讀出(mov cx,9841)得到 00 01 41 98 06 FE BF 6E 3F 00-00 00 D8 B3 34 00 只有一個表項,是第二個邏輯盤,而且是邏輯盤鏈的最后一個。 可以看到,主分區(qū)表是非常重要的,所以除了小心操作外,還應(yīng)當進行備份,最安全的備份方式就是用筆抄下來,當然,每次重新進行分區(qū)后還應(yīng)當及時更新。從前面可以看出,分區(qū)表里最重要的還是柱面號,其它比如磁頭號都是0或者1或者最大值,扇區(qū)號都是1或63(最大值),扇區(qū)總數(shù)什么的也都能算出來,所以分區(qū)時最好把各分區(qū)的柱面號記下來,這樣一旦分區(qū)信息被破壞就可以進行恢復了。 如果主分區(qū)表不幸丟失或者邏輯分區(qū)鏈被破壞,那么只要從硬盤上找出還存在的分區(qū)信息,就有可能部分恢復分區(qū)信息,甚至全部可以恢復,不過這樣的麻煩大家還是應(yīng)盡量避免。 在Linux里有一種方法可以恢復主引導扇區(qū)(包括主分區(qū)表),用如下的命令: dd if=/boot/boot.NNNN of=/dev/hda bs=512 count=1 其中:boot.NNNN 是我們在安裝Linux之前整個主引導扇區(qū)的備份,NNNN是分區(qū)的主次設(shè)備號;bs(buffer size)是指重寫的字節(jié)數(shù)。如只是為了修復主引導記錄MBR(比如,想把LILO卸載掉),而不是恢復整個主引導扇區(qū),則用如下的命令: dd if=/boot/boot.NNNN of=/dev/hda bs=446 count=1 只把主引導扇區(qū)的備份文件boot.NNNN的前446個字節(jié)重寫入主引導扇區(qū)。 LILO 詳解 一臺電腦從加電到進入操作界面是經(jīng)過了一系列復雜的操作的?;镜墓ぷ魇怯葿IOS完成的。當POST(自檢)結(jié)束后,BIOS嘗試讀入 BIOS設(shè)定的第一個啟動設(shè)備的第一個扇區(qū),把它看作引導扇區(qū)(原先的BIOS總是先嘗試軟盤的),然后讀入里面的信息來引導系統(tǒng)。 我們先來看看DOS的系統(tǒng)引導區(qū): OFFSET 0x000 JMP xx ; 近距離跳轉(zhuǎn)到xx代碼段 0x003 ; 磁盤參數(shù) 0x03E ; 載入DOS系統(tǒng)核心的代碼段 0x1FE 0xAA55 ; 這是BIOS的幻數(shù) DOS的引導區(qū)總是從0開始,以BIOS的magic number 結(jié)束,總共512字節(jié)。從軟盤啟動比較簡單,因為只有一個引導扇區(qū):第一個扇區(qū)。而硬盤雖然有很多分區(qū),但是,BIOS根本不去查看分區(qū)信息,它象對待軟盤一樣對待硬盤,仍讀入第一個分區(qū):master boot record (MBR). 所以MBR也應(yīng)該從0開始,以BIOS的magic number 結(jié)束。在MBR的最后部分保存了分區(qū)表。每個分區(qū)信息占16字節(jié),定義了硬盤可以有4個Primary Partition。如果這些不夠用,可以設(shè)置所謂的擴展分區(qū)。擴展分區(qū)包含至少一個邏輯分區(qū)。擴展分區(qū)的第一個扇區(qū)結(jié)構(gòu)類似MBR,它的分區(qū)表的第一表項對應(yīng)第一個邏輯分區(qū)。如果存在第二個邏輯分區(qū),那么分區(qū)表的第二個表項就包含了一個指針。這個指針指向第一個邏輯分區(qū)后面的一個地址。這個地址包含一個分區(qū)表。該分區(qū)表的第一表項對應(yīng)第二個邏輯分區(qū)。這樣就組成一個鏈表,從而擴展分區(qū)可以有任意多的邏輯分區(qū)。 每一個主分區(qū)和擴展區(qū)都包含一個引導扇區(qū)。系統(tǒng)只能從這幾個地方之一啟動。BOOT標志決定哪個分區(qū)的引導扇區(qū)被引導。 MS-DOS的fdisk和大多數(shù)同類工具只能激活主分區(qū)。 MBR的代碼要作以下的操作: 1:確定活動分區(qū)(Active Partition) 2:使用BIOS,將活躍分區(qū)的啟動扇區(qū)讀入 3:跳到啟動扇區(qū)的0位置。 MBR的空間足夠容納一個引導程序來動態(tài)的決定活動分區(qū)。LILO就是這樣一個引導程序。 LILO(LInux LOader) LILO引導扇區(qū)包括一個分區(qū)表的空間,所以,LILO即可以安裝在MBR中,也可以安裝在某個分區(qū)的引導扇區(qū)。 1.LILO可以占據(jù)MBR,但是會將老的MBR沖去,出于安全起見,最好在在安裝LILO前,將老的MBR(包括分區(qū)表)做一個備份??梢酝ㄟ^鍵入 # dd if=/dev/hda of=/backup/MBR bs=512 count=1 來備份原來的MBR信息, 如果要將MBR寫回,可以鍵入: # dd if=/backup/MBR of=/dev/hda bs=446 count=1 這樣,原來的MBR就被寫回但不包括分區(qū)表。如果分區(qū)表也要恢復,那么設(shè)置bs=512。 2.通過MS-DOS MBR被引導 LILO就可以安裝在這些分區(qū)中的一個。當 LILO對應(yīng)分區(qū)被激活后,引導過程如下: BIOS 讀入 MBR MBR 讀入 活躍主分區(qū):LILO所在的分區(qū); LILO 引導Linux或另外的操作系統(tǒng)。 要引導其它OS且不用LILO很簡單,激活那個分區(qū)。Linux分區(qū)不會有任何變化。 3.LILO也可以被其他的系統(tǒng)引導程序(Boot Manager)引導 1. 假如boot manager可以引導擴展區(qū),Linux可以裝在擴展區(qū)上; 2. 假如 boot manager 可以引導第二硬盤分區(qū),linux可以裝在第二硬盤上; 3. 有些 boot manager 甚至可以引導邏輯分區(qū),那LILO就可以裝在邏輯分區(qū)上。 但是對于系統(tǒng)引導程序要特別注意的是:某些操作系統(tǒng)直接改寫MBR,這會將原來的boot manager破壞。 配置LILO 與LILO有關(guān),即有關(guān)系統(tǒng)引導的文件通常放在/boot/下,配置文件是/etc/lilo.conf下。合理的配置lilo. conf對于系統(tǒng)的正常高效運行有著非常重大的意義,可以通過man lilo.conf來查看配置的注意事項 下面是一些重要常用的選項: "boot=" 指明包含引導扇區(qū)的設(shè)備名(如:/dev/had),若此項忽略,則從當前的根分區(qū)中讀取引導扇區(qū)。 "root=" 告訴內(nèi)核啟動時以哪個設(shè)備作為根文件系統(tǒng)使用,其設(shè)定值為構(gòu)造內(nèi)核時根文件系統(tǒng)的設(shè)備名,可用的設(shè)備名有: (1)/dev/hdaN~/dev/hddN:ST-506兼容硬盤,a到d上的N個分區(qū) (2)/dev/sdaN~/dev/sdeN:SCSI兼容硬盤,a到e上的N個分區(qū) (3)/dev/xdaN~/dev/xdbN:XT兼容硬盤,a到b上的N個分區(qū) (4)/dev/fdN:軟盤,A:(N=0)或B:(N=1) (5)/dev/nfs:由網(wǎng)絡(luò)取得根文件系統(tǒng)的標志 "nfsroot=" 若需通過NFS提供根文件系統(tǒng)來引導無盤工作站,此參數(shù)為內(nèi)核指定了網(wǎng)絡(luò)根文件系統(tǒng)所在的機程序、目錄及NFS,其格式為:nfsroot=(〈server_ip〉:)〈root_dir〉(,nfs_options)) "nfsaddrs=" 設(shè)定網(wǎng)絡(luò)通訊所需的各種網(wǎng)絡(luò)界面地址,如無此參數(shù),則內(nèi)核會試圖用反向地址解析協(xié)定(RARP)或啟動協(xié)定(BOOTP)找出這些參數(shù),其格式為: nfsaddrs=〈客戶端IP〉:〈服務(wù)端IP〉:〈網(wǎng)關(guān)IP〉:〈子網(wǎng)屏蔽〉: 〈客戶端名稱〉:〈網(wǎng)絡(luò)設(shè)備名 〉:〈auto〉 "image=" 指定Linux的內(nèi)核文件。 "delay=" 以10毫秒為單位,設(shè)定引導第一個映像前的等待時間。 "disk=" 某一特殊的硬盤定義非標準參數(shù)。 "append=" 為內(nèi)核傳遞一個可選的參數(shù)行,其典型的應(yīng)用是為不能完全由系統(tǒng)自動識別的硬盤指定參數(shù),如:append = "hd=64,32,202",還有為一些無法自動識別大內(nèi)存的低版本內(nèi)核傳遞參數(shù),方法是append="mem=128M".mem后邊是數(shù)字+單位,這個單位可以是byte/M等等 "label=" 為每個映像指定一個名字,以供引導時選擇。 "read-only" 設(shè)定以只讀方式掛入根文件系統(tǒng),用于文件系統(tǒng)一致性檢查(fsck) "install=" 安裝一個指定文件作為新的引導扇區(qū),缺省為/boot/boot.b。 "loader=" 說明所使用的鏈加載程序(chain loader),缺省為/boot/chain.b,如果不是從首硬盤或軟盤啟動,那么,此選項必須說明。 "table=" 說明包含分區(qū)表的設(shè)備名,如果此參數(shù)忽略,引導加載程序?qū)⒉荒軅鬟f分區(qū)信息到已引導的操作系統(tǒng)。當此參數(shù)指向的分區(qū)表被修改時,必須重新運行/sbin/lilo。 "init=" 內(nèi)核初始化時執(zhí)行的程序,通常過程為init、getty、rc和sh,版本1.3.43以來的Linux內(nèi)核能夠執(zhí)行/sbin/init說明的命令行,若在引導過程中出現(xiàn)問題,則可設(shè)置init=/bin/sh直接跳到Shell。 "ramdisk_start=" 由于內(nèi)核不能放在壓縮的內(nèi)存文件系統(tǒng)映像內(nèi),為使內(nèi)核映像能夠和壓縮的內(nèi)存映像放在一張軟盤內(nèi),加入"ramdisk_start=〈offset〉",這樣內(nèi)核才開始執(zhí)行。 "vga=" 設(shè)置顯示模式,如80×50、132×44等。 "compact" 激活一種模式,在此模式下,LILO一次向BIOS請求讀入相鄰的幾個分區(qū)。這極大的縮短了裝載時間,特別是從軟盤啟動。 "Linear" 使LILO生成線性地址,而不使用通常的Sector/Head/Cylinder機制。Linux地址機制可以不依賴磁盤的物理結(jié)構(gòu)。 "install = boot sector" 使用指定的boot sector寫入引導扇區(qū),缺省用/boot/boot.b "map=" 說明映射文件的路徑。 "message=[File]" 指定一個文件,該文件的內(nèi)容將會在LILO引導是被顯示。假如沒有說明該文件,那么就只會出現(xiàn)"LILO"。 "verbose=[level]" 說明LILO的調(diào)試級別。從0(不顯示任何信息)到5(所有的狀態(tài)信息)。 "backup = [backup file]" 以前引導扇區(qū)內(nèi)容的備份文件。缺省使用/boot/boot.device number "force-backup=[backup file]" 和backup 相同,當時假如備份文件存在,被覆蓋。 "prompt" 指定要用戶通過鍵盤選擇要引導的內(nèi)核。不會缺省選擇。 "timeout=" 設(shè)置一個超時值,在此時間內(nèi)必須有鍵盤輸入,否則用第一個配置。類似,假如超時,就不能再輸入密碼。一般情況下,該取缺省值,無窮大。 "serial=port, bps parity bits" 設(shè)置串口參數(shù)。如果LILO會從該文件獲取串口參數(shù)的話。如果其中之一無效,那所有三個參數(shù)都無效。Port從四個標準串口選擇一個:0 對應(yīng)COM1 或者/dev/ttyS0.。支持的波特率范圍為:100-9600。所有校驗設(shè)置都支持(n:none,e:even,o:odd)bits為7或者 8。缺省為serial=0,2400n8. Ignore-table 讓LILO忽略被破壞的分區(qū)表。 fix-table 允許LILO將每個分區(qū)的(sector/head/cylinder)地址轉(zhuǎn)化為線性地址。通常,分區(qū)地址從cylinder boudary開始。某些操作系統(tǒng),會改變這一點。由于LILO只能將它的啟動扇區(qū)寫于兩種地址都一致的分區(qū)上,不正確的3D地址可以用fix- table來糾正。但是,這種糾正不能被保證是永遠的,所以重分區(qū)以保證對齊cylinder boudary 是最好的選擇。 "password=[password]" 為引導配置設(shè)置password restricted 放松對password的限制。只有用戶想傳附加的啟動參數(shù)給內(nèi)核時才需要password optional 允許配置的幾個內(nèi)核有錯誤的,或者不存在,如果不說明optional,LILO遇到這種情況就會打印一些錯誤信息然后退出。 LILO引導過程 每個從LILO引導的配置從image行開始。 image = kernel label = name Image包含要引導的內(nèi)核。Label是給用戶選擇用的。Image行通常指向一個設(shè)備,例如/dev/fd0,可以找到內(nèi)核的范圍用range來注明。 range = range range可以用start sector -end sector 或者 start sector + length 表示。例如: image = /dev/fd0 label = floppy range = 1+512 LILO 啟動信息 缺省設(shè)置的LILO啟動過程中在啟動過程中,LILO會顯示'LILO',如果LILO出錯退出, 可以根據(jù)顯示來判斷系統(tǒng)的出錯原因。 沒有信息:LILO根本就沒有被讀入,沒安裝LILO,或LILO駐留的分區(qū)沒被激活。 Lnumber : LILO的第一部分被讀入并開始執(zhí)行。但第二部分不能被讀入。后面的數(shù)字表明出錯原因。這可能是由于硬盤的物理錯誤或不正確的物理結(jié)構(gòu)信息 LI: LILO的第一部分可以讀入第二部分,第二部分執(zhí)行時出錯。這可能是不正確的物理結(jié)構(gòu)信息或重裝了boot.b而沒有運行LILO重新安裝。 LIL:LILO的第二部分啟動起來了,但是不能從map文件讀入descriptor tables.這說明不正確的物理結(jié)構(gòu)信息或物理錯誤。 LIL?: LILO的第二部分被讀到不正確的地址。原因同LI LIL-: descriptor tables有錯。這可能是不正確的物理結(jié)構(gòu)信息或重裝了map file而沒有運行LILO重新安裝。 LILO的卸載 LILO裝在MBR以后,它會保留一個MBR的備份在系統(tǒng)的/boot/boot.xxyy中,其中xyy是16進制的設(shè)備主/次號碼(major/minor numbers),利用命令"ls -l /dev/device"就可獲得硬盤或分區(qū)的主/次號碼。如果這些備份文件已經(jīng)存在,那么,當你重新安裝LILO時,它將不再生成此文件,這就保證了此備份文件是最原始的引導扇區(qū)。 若要卸載LILO,你只需恢復初始的引導扇區(qū)就可以了。例如:LILO安裝在/dev/had,對應(yīng)的備份文件為/boot/boot.0300,使用下面的命令即可: # dd if=/boot/boot.0300 of=/dev/had bs=446 count=1 LILO是現(xiàn)在Redhat Linux、TurboLinux等許多Linux distribution缺省的引導程序,正如上面所介紹的,擁有很強大的功能,更詳細的內(nèi)容可以在lilo安裝的README文件中發(fā)現(xiàn)。最重要的是在良好的備份意識指導下,多多實踐,這樣才能得到最佳的效果。 |
|
來自: zhuziay > 《linux啟動分析》