該項目僅為實驗性項目,主要目的是想隱藏一個Telnet後門在主板的BIOS內,並讓其隨著計算機系統及操作系統成功的運行起來。運行後能反向Telnet連接到指定的計算機接受控制。
項目涉及的相關知識及技術目錄
1、 實驗環境,使用bochs調試工具。
2、 刷新BIOS技術問題。
3、 代碼植入BIOS問題。
4、 源代碼相關技術問題:
A、如何編寫BIOS模塊(如:PCI、 ISA)。
B、實模式關於HOOK磁盤中斷的問題。
C、磁盤中斷中選擇再次HOOK的問題。
D、NT保護模式下設置物理地址映射。
E、NT保護模式下線性地址尋址問題。
BIOS模塊調試實驗環境采用Bochs
Bochs虛擬機可以調試BIOS及操作系統,Bochs使用主要是配置它的配置文件,我們以實例配置文件簡單講解,Bochs實驗調試等網上有很多相關文章,這裡簡單講解。
我的配置實例:文件名xp.bxrc,修改後的及需要設置的內容如下:
######使用的系統BIOS模塊###### romimage: file=$BXSHARE/BIOS-bochs-latest ######使用的CPU 相關參數###### cpu: count=1, ips=10000000, reset_on_triple_fault=1 ######設置內存大小 ###### megs: 128 ######添加我們的BIOS模塊###### optromimage1: file=test.bin, address=0xd0000 ######使用的VGAROM模塊###### vgaromimage: file=$BXSHARE/VGABIOS-lgpl-latest ######設置虛擬機硬盤與光盤###### ata0-master: type=disk, path="c.img", mode=flat, cylinders=4161, heads=16, spt=63 #ata0-slave: type=cdrom, path="xp.iso", status=inserted ######設置引導設備 ###### boot: c #boot: cdrom, disk
Bochs調試加載配置文件方法:可以設置一個bat文件,如下內容:
set BXSHARE=d:\bochs
%BXSHARE%\bochsdbg.exe -q -f xp.bxrc
如何刷新各種BIOS問題
各種BIOS刷新相關工具早已在網上流傳,工具的使用這裡不作介紹,IcLord的作者已經給出很多編程方法實現。這裡簡單說下。
UniFlash開源項目我也詳細分析過,如果有必要我會給出UniFlash源代碼的詳解,該項目指出可以刷寫所有BIOS芯片,但是該項目刷新BIOS存在很多問題,絕大多數情況是無法刷新的我實驗過很多次,也嘗試修改他的代碼過很多次,沒找到原因。
Aword BIOS已經有通用的刷寫API調用,不管在NT下還是在實模式下,IcLord也作了講解。如果有時間我會給出實模式及NT下的刷寫源代碼及分析。
代碼植入BIOS問題
關於網上提及的,IcLord講到的我就不再做重復的分析。這裡主要講下我們的模塊可以植入哪些地方以方便隱藏。以前的教程講過的方法存的問題分析。
一、 ISA模塊形式植入:這種方式只適合於較早的計算機,因為目前的計算機系統BIOS是不會加載ISA模塊的。故只能做實驗調試用的方法。
二、 PCI模塊形式植入:該方法雖然系統BIOS都要加載PCI ROM,但是系統BIOS只加載實際存在的PCI卡的ROM模塊。而且通常BIOS設置中可以
關閉相應的ROM啟動。
三、 HOOK BootBlock或者說要啟動的模塊:該方法當然我認為是最有效的,但是又存在很多技術上的難題。檢驗和問題,不同BIOS的結構問題,過早的HOOK還存在再次獲取CPU運行機會問題等等。
本人實驗過以上提及的所有方法,我認為HOOK PCI、VGA及相關啟動模塊是比較可尋的辦法。為什麼?一般這類的ROM模塊是必須啟動的,而且調試發現一般它的ROM本身代碼用不完自身設置的大小,我們可以借助剩余大小隱藏我們的代碼。例如:集成顯卡會把顯卡ROM集成到系統BIOS模塊中,我們可以對該模塊進行HOOK,修改ROM頭部的跳轉指令,跳到我們的代碼開始處執行,我們的代碼執行完後跳轉到它的代碼開始處執行。
如何編寫BIOS模塊
BIOS是分模塊組合在一起的。這裡對PCI及ISA模塊作下簡單分析,VGA模塊跟PCI模塊幾乎一樣。模塊主要是頭部有個規范,該規范適合所有BIOS系統。具體可以參看《PCI系統結構》及其他書籍。
源代碼實例可以參看國外ROMOS開源項目,該開源項目的思想很值得學習。該項目講解了如何在BIOS中嵌入一個小型DOS,如:FreeDos。采用了把整個DOS系統盤鏡像植入BIOS中,跟早期的PXE引導DOS機制類似,然後HOOK磁盤中斷,模擬DOS系統盤鏡像出一個盤,源代碼編譯後只有900多字節。這種思想在早期還是很值得學習的。
實模式關於HOOK磁盤中斷問題
很早前就有業界內人士發貼問,為什麼在我的ROM模塊中HOOK磁盤中斷會失敗呢?關於這個問題現在目前網上已經有人作出過回答,國外的開源項目在2003年我都看到過。
由於我們的ROM模塊過早的運行,可能運行在磁盤服務前面了,這時如果HOOK Int 13h會因為BIOS加載磁盤服務時重寫Int 13h IVT值,故我們設法HOOK其他服務,這個服務要求較早被BIOS安裝且不會再次修改且加載操作系統前調用,最佳的這個服務選擇就是int 18h、int19h服務。可以參看
BIOS源代碼,也可以參看PXE SDK說明文檔略有講過。
我們的磁盤服務代碼建議放在實模式高端內存,通過BIOS數據區域可修改,內存40:13,即物理地址413h處的值。降低常規內存值,高端的內存就留給我們用。我們的保護模式下運行的代碼建議也放在這段內存,且要求放在以頁基址開始的內存中,以便後面代碼的頁映射我們的保護模式代碼物理頁。頁基址:內存物理頁地地址開始的低12位為零,參看《80386保護模式教程》。
若我們的代碼直接在內存的ROM映射區內,可能導致在NT下訪問不到我們的代碼,因為NT內核加載程序ntldr可能不會映射該段內存,甚至可能BIOS在使用後都會關閉ROM區域這段內存,而且ROM區域這段內存在初始化後被系統BIOS設置成只讀不能寫。當然我們可以采取用int 15h服務對ROM區域這段內存映射。
當然也可以在NT啟動過程中,在我們的磁盤服務中對想映射的內存都映射。由於代碼大小的限制,故有些沒必要的代碼。盡量不使用了。
磁盤中斷服務中再次HOOK問題
為了使我們的程序再次獲得CPU運行機會,我們不得不得再次設法。調試發現NTLDR進入保護模式後在加載NT內核文件時,會切換CPU到實模式調用Int 13H服務進行磁盤讀。
我們掛接磁盤服務就是為了截取NTLDR的讀操作,這裡我們可以HOOK 或者修改NTLDR另一部分OsLoader的代碼,跳轉到我們的代碼執行。當然也可以直接HOOK ntosknrl導出的服務,參看我在2008.4.1發布的“程序從DOS/BIOS駐留內存到WINNT下監視內存數據”。
注意,HOOK OsLoader的代碼時選擇HOOK指令問題,由於NTLDR切換到實模式讀取數據,讀完後會在保護模式下搬移數據到規劃位置,進行內核的安裝。故HOOK時選擇HOOK指令就選擇FFh/15h:使用CALL NEAR [OFS32]指令進行,該指令尋址采用絕對地址,類似指令也可以。
當然我們的代碼再次運行就會運行在OsLoader代碼被我們HOOK處,調用我我們的代碼執行,這時我們的代碼運行環境:DS = ES = 10h保護模式段,內存模式: FLAT。在這裡我們可以通過掃描_BlLoaderData數據結構,獲取NTOSKRNL鏡像基址。
可以通過PE搜索NTOSKRNL導出的API,可以參看網上相關教程。現在再次HOOK NTOSKRNL導出函數KeAddSystemServiceTable,HOOK該函數
可以截獲win32k.sys添加它自己的服務,以便我們再再次HOOk win32.sys導出函數NtUserRegisterClassExWOW。HOOK該函數可以截取所有應用層程序注冊窗口類,以便我們再再再次HOOK窗口類過程。這時我們的代碼就運行在NT的應用層模式下。
NT保護模式下設置物理地址映射
先看一個WinDbg實例關於在我們的磁盤服務中獲取CR3值修改頁映射的分析,以前我的分析內容:
NT內核被加載高端的2GB內存(80000000h~0ffffffffh)。參看NT內存安排.. a、win2k adv ser: WINDBG 看到 NT Kernel base = 0x80400000 也就是NTOSKRNL.exe加載位置 kd> r @cr3 ;斷點位置在NTOSKRNL.exe裡現在還沒有應用程序故低端內存還未使用 cr3=00030000 ;-> 頁目錄表所在物理頁(物理地址30000h) kd> d 80030000 80030800 ;看頁目錄發現現在低端2GB(0~80000000h)還未分配 80030000 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................ 80030010 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................ 80030020 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................ kd> d 80030800 ;看高端開始分配情況頁表(80000000h開始的分配情況) 80030800 63 21 03 00 63 41 03 00-63 51 03 00 63 31 03 00 c!..cA..cQ..c1.. 80030810 63 11 7c 00 63 21 7c 00-63 31 7c 00 63 41 7c 00 c.|.c!|.c1|.cA|. 80030820 63 51 7c 00 63 61 7c 00-63 71 7c 00 63 81 7c 00 cQ|.ca|.cq|.c.|. ;實例1:看80400000h(NT Kernel base),這個線性地址到物理地址映射情況. ;線性地址最高10位頁目錄項(每項占4Byte):80400000h最高10位=201h. ;在頁目表位