Author: PolyMeta
Email: PolyMeta@whitecell.org
Homepage:http://www.whitecell.org
Date: 2006-05-27
殼作為一種主要的軟件保護(hù)手段大概可以分為壓縮殼和加密殼兩類,
驅(qū)動殼編寫總結(jié)
。而現(xiàn)在流行的加殼程序無論是壓縮的還是加密的幾乎都是針對應(yīng)用層程序的,對于驅(qū)動
程序的保護(hù)殼則幾乎是空白。筆者只在一些國外加密狗的驅(qū)動中見過類似應(yīng)用層
的保護(hù)殼。本篇文章主要介紹驅(qū)動加殼程序與應(yīng)用層加殼程序在編寫上的區(qū)別以
及一些注意事項。
1.校驗(yàn)和的計算
驅(qū)動程序被加殼后必須重新進(jìn)行校驗(yàn)和的計算,否則加殼后的驅(qū)動加載會
失敗
;*****************計算pe文件校驗(yàn)和*********************
CalcPECheckSum PROC lpBaseAddr:DWORD,dwFileSize:DWORD
LOCAL CheckSum:DWORD
pushad
mov ecx,dwFileSize
inc ecx
shr ecx,1
xor eax,eax
clc
mov esi,lpBaseAddr
cal_checksum:
adc ax,word ptr [esi]
inc esi
inc esi
loop cal_checksum
mov ebx,dwFileSize
add eax,ebx
mov CheckSum,eax
popad
mov eax,CheckSum
ret
CalcPECheckSum endp
;*******************************************************
2.原始IAT的處理
由于原驅(qū)動程序被加上了我們的外殼,所以原驅(qū)動程序的IAT表的填寫工作
要由我們的外殼程序來完成。應(yīng)用層殼一般通過GetModuleHandle和GetProcAdd
ress兩個API來完成這個工作,或者自己實(shí)現(xiàn)這兩個API的功能。而驅(qū)動殼是要
隨驅(qū)動程序一起被加載到內(nèi)核當(dāng)中去的,但內(nèi)核里沒有這兩個函數(shù),需要我們
自己對這兩個函數(shù)做內(nèi)核的實(shí)現(xiàn)。當(dāng)然也可以用MmGetSystemRoutineAddress函
數(shù),不過它只能得到ntoskrnl.exe和hal.dll兩個模塊的函數(shù),對于其它模塊則
無能為力了,影響殼的通用性。
殼的GetModuleHandle函數(shù)可以通過遍歷PsLoadedModuleList鏈表來實(shí)現(xiàn),
關(guān)于遍歷這個鏈表的方法可以參照Futo的代碼,通過DRIVEROBJECT的DriverSec
tion成員來完成,而驅(qū)動對象可以從堆棧當(dāng)中找到。
殼的GetProcAddress函數(shù)的實(shí)現(xiàn)就很簡單了,內(nèi)核模塊本身也是PE文件,
直接遍歷一下PE的導(dǎo)出表就ok了。
還有一點(diǎn)需要注意的就是UNICODE的轉(zhuǎn)換,PE文件里面的字符串是以ASCII
方式存儲的,而內(nèi)核里的字符串多半是用UNICODE方式存放的,這點(diǎn)需要注意。
3.節(jié)表的處理
在給程序加殼的時候一般都要添加新節(jié),用于存放殼的代碼,應(yīng)用層程序
的節(jié)表的最后一項和第一個節(jié)之間一般是有一個很大的空間可以用來添加新的
節(jié)表項的,但一般情況下驅(qū)動程序節(jié)表的最后一項后面緊接著就是第一個節(jié),
根本沒有足夠的0x28大小的空間存放新的節(jié)表項,
電腦資料
《驅(qū)動殼編寫總結(jié)》(http://www.ishadingyu.com)。解決的方法有兩種,第一種將所有的節(jié)向后移動,而第二種方法則是將PE頭整體向前移動覆蓋掉部分無用
的dos頭,留出足夠的空間存放新的節(jié)表項。
另外一點(diǎn)需要注意的是,加殼后的驅(qū)動程序的每一個節(jié)表項必須滿足如下
兩個公式,才能被系統(tǒng)正常加載
1) VirtualAddress == PointerToRawData
2) SizeOfRawData >= VirtualSize
至于為什么,筆者也沒搞清楚,這只是筆者通過分析驅(qū)動加載代碼及實(shí)驗(yàn)
的結(jié)果,哪位仁兄知道還請賜教:)
4.重定位表的處理
由于驅(qū)動程序是要被加載到內(nèi)核空間中,所以外殼必須實(shí)現(xiàn)原來由系統(tǒng)完
成的原驅(qū)動程序的重定位工作。原驅(qū)動程序的重定位表的處理方法跟應(yīng)用層 D
LL 文件的處理方法完全一樣,代碼如下:
mov eax,dword ptr [ebp+OriginalRelocateAddr]
add eax,dword ptr [ebp+ModuleHandle]
mov ecx,dword ptr [ebp+OriginalRelocateSize]
mov ebx,eax
mov esi,dword ptr [ebp+ModuleHandle]
sub esi,dword ptr [ebp+OriginalBaseAddr] ;esi=diff
NextRelocateBlock:
.if ecx == 0
jmp FixAllRelocate
.endif
assume ebx : ptr IMAGE_BASE_RELOCATION
push ecx
mov ecx,dword ptr [ebx].SizeOfBlock
sub ecx,sizeof IMAGE_BASE_RELOCATION
shr ecx,1
mov eax,ebx
add eax,sizeof IMAGE_BASE_RELOCATION
NextRelocateEntry:
xor edi,edi
mov di,word ptr [eax]
shr edi,12
.if edi == IMAGE_REL_BASED_HIGHLOW
movzx edi,word ptr [eax]
and edi,0fffh
add edi,dword ptr [ebx].VirtualAddress
add edi,dword ptr [ebp+ModuleHandle]
add dword ptr [edi],esi
.endif
add eax,2
loop NextRelocateEntry
pop ecx
sub ecx,dword ptr [ebx].SizeOfBlock
add ebx,dword ptr [ebx].SizeOfBlock
jmp NextRelocateBlock
FixAllRelocate:
需要注意的一點(diǎn):驅(qū)動程序被加殼后必須要有重定位表,否則驅(qū)動加載會失
敗,解決的方法需要自己構(gòu)造一個假的重定位表來替換原始的重定位表。
另外,由于驅(qū)動殼的特殊性,shell的編寫和驅(qū)動程序的編寫沒什么區(qū)別,
稍有錯誤就會藍(lán)屏。
寫這篇文章的主要目的是對筆者在編寫驅(qū)動加殼程序的過程中所遇到的一些
問題及其解決方法的總結(jié),避免以后忘了,同時也給想寫驅(qū)動殼的兄弟們一點(diǎn)我
的心得,少走一些彎路。
WSS(Whitecell Security Systems),一個非營利性民間技術(shù)組織,致力于各種系統(tǒng)安全技術(shù)的研究。堅持傳統(tǒng)的hacker精神,追求技術(shù)的精純。