from:http://www.debugman.com/read.php?tid=646
現(xiàn)在RK(rootkit)和ARK(anti-
rootkit)的斗爭(zhēng)已經(jīng)進(jìn)行了很久,在印象中最早出來的ARK工具是冰刃(IceSword),從冰刃開始出來到現(xiàn)在RK和ARK的斗爭(zhēng)一直在繼續(xù),
目前冰刃還是在流行當(dāng)中,自己感覺也正是冰刃的出來才帶動(dòng)了當(dāng)前流行的RK和ARK的斗爭(zhēng)
呵呵,現(xiàn)在很多病毒木馬已經(jīng)廣泛的帶有驅(qū)動(dòng),使用一些RK的技術(shù)和方法使自己更底層些更強(qiáng)大些,當(dāng)前流行的ARK工具主要包括:隱藏進(jìn)程檢測(cè),內(nèi)核驅(qū)動(dòng)檢
測(cè),SSDT檢測(cè),代碼HOOK檢測(cè),注冊(cè)表隱藏的檢測(cè),隱藏文件的檢測(cè)等一些功能的,下面談?wù)勛约簩?duì)一些功能的簡(jiǎn)單愚見 嘻嘻。
關(guān)于進(jìn)程檢測(cè):其實(shí)最早在R3下隱藏進(jìn)程的方法已經(jīng)很早開始流行起來被用到各種軟件上來,在R0下如斷ActiveProcessLinks鏈,擦掉句柄表等等,一步步的發(fā)展?jié)u漸的更強(qiáng)大起來一些技巧和方法開始出來和流行起來,如FUTO,phide_ex等。。。。。。
檢
測(cè)隱藏進(jìn)程的方法可以把一些現(xiàn)在流行的方法組合起來用,首先可以通過進(jìn)程的EPROCESS結(jié)構(gòu)中的進(jìn)程活動(dòng)鏈表ActiveProcessLinks來
進(jìn)行掃描一邊,可以通過進(jìn)程句柄表的枚舉通過EPROCESS的HANDLE_TABLE,HANDLE_TABLE結(jié)構(gòu)中的
HandleTableLis鏈表來掃描一邊來獲得一些EPROCESS,可以通過定位PsLookupProcessByProcessId代碼中的
PspCidTable鏈表掃描一邊獲得一些EPROCESS,PspCidTable在各系統(tǒng)中枚舉是不太一樣的,也可以通過先找出
KiWaitInListHead,KiWaitOutListHead和KiDispatcherReadyListHead這些鏈表然后對(duì)這些鏈表掃
描獲得一些EPROCESS,以上具體的實(shí)現(xiàn)代碼可以GOOGLE之網(wǎng)上實(shí)現(xiàn)的代碼已經(jīng)很多了,再者也可以找到內(nèi)核中的線程切換SwapContext函
數(shù)進(jìn)行HOOK下的,在自己實(shí)現(xiàn)的SwapContext函數(shù)根據(jù)線程的偏移量找出進(jìn)程的EPROCESS結(jié)構(gòu),把上面獲得的所有EPROCESS匯集起
來還需要判斷下當(dāng)前進(jìn)程是否是真正的活著的:)可以通過EPROCESS里的標(biāo)志位Flags(如XP
下0x248)一些標(biāo)志判斷下的,還要注意下對(duì)上面這些鏈表匯集起來是會(huì)有重復(fù)的進(jìn)程的,在你自己的匯集函數(shù)中根據(jù)EPROCESS判斷下的
廢話了,感覺實(shí)現(xiàn)了上面的一些方法對(duì)付一般的隱藏進(jìn)程已經(jīng)足夠了的,但厲害的RK還是有的,現(xiàn)在存在可以逃過這些方法的RK的,在進(jìn)程EPROCESS的
結(jié)構(gòu)里偏移0x1f8(XP SP2下)有個(gè)struct? MMSUPPORT Vm結(jié)構(gòu):
struct _MMSUPPORT
{
/* off 0x00000000 */? ? union LARGE_INTEGER? ? LastTrimTime;
/* off 0x00000008 */? ? struct? MMSUPPORT_FLAGS? ? Flags;
/* off 0x0000000C */? ? unsigned long? ? PageFaultCount;
/* off 0x00000010 */? ? unsigned long? ? PeakWorkingSetSize;
/* off 0x00000014 */? ? unsigned long? ? WorkingSetSize;
/* off 0x00000018 */? ? unsigned long? ? MinimumWorkingSetSize;
/* off 0x0000001C */? ? unsigned long? ? MaximumWorkingSetSize;
/* off 0x00000020 */? ? struct _MMWSL*? ? VmWorkingSetList;
/* off 0x00000024 */? ? struct LIST_ENTRY? ? WorkingSetExpansionLinks;
/* off 0x0000002C */? ? unsigned long? ? Claim;
/* off 0x00000030 */? ? unsigned long? ? NextEstimationSlot;
/* off 0x00000034 */? ? unsigned long? ? NextAgingSlot;
/* off 0x00000038 */? ? unsigned long? ? EstimatedAvailable;
/* off 0x0000003C */? ? unsigned long? ? GrowthSinceLastEstimate;
};
在這個(gè)結(jié)構(gòu)里+0x24有個(gè)? ? WorkingSetExpansionLinks他也是個(gè)LIST_ENTRY鏈表的,遍例下他可以獲得進(jìn)程的EPROCESS的,如
PEPROCESS eprocess, eprocess2
eprocess =PsGetCurrentProcess();
lp=(PLIST_ENTRY)(*(PVOID )((PUCHAR)eprocess+0x1f8+0x24+4));
cur =lp->Flink;
for(;cur!=lp;cur=cur->Flink)
{
eprocess2=(PEPROCESS)((ULONG)cur-0x1f8-0x24);
PVOID session= (PVOID)(*(PULONG)((PCHAR) eprocess2+ 0x170));
if(MmIsAddressValid(session)){
AddProcess(eprocess2);
}
}
再
者在進(jìn)程EPROCESS的結(jié)構(gòu)里偏移0x0b4(XP SP2下)存在個(gè)struct _LIST_ENTRY? ?
SessionProcessLinks結(jié)構(gòu),他也是個(gè)鏈表的 :)通過遍例他也可以的獲得一些EPROCESS。還有個(gè)地方可以的 呵呵
在每個(gè)線程對(duì)象里(ETHREAD)偏移0x34里有個(gè)struct _KAPC_STATE ApcState
結(jié)構(gòu)的在_KAPC_STATE結(jié)構(gòu)里偏移0x10,再者也可以通過遍例內(nèi)存來查找隱藏進(jìn)程,從內(nèi)存MmSystemRangeStart開始到
System進(jìn)程的EPROCESS地址就可以了主要是判斷這個(gè)地址是否是個(gè)有效的進(jìn)程,方法挺多的如判斷下是否是進(jìn)程對(duì)象這個(gè)地址如果是
EPROCESS看看PID,ThreadListHead,ReadyListHead是否正確有效的等等,很多方法的應(yīng)該組合起來判斷下保證肯定是進(jìn)
程就可以了,還可以通過HOOK一些函數(shù)的如KeUpdateRunTime,KeDispatchInterrupt等來檢測(cè)隱藏進(jìn)程,還可以設(shè)置下
PsSetCreateProcessNotifyRoutine在每次進(jìn)程創(chuàng)建的時(shí)候?qū)€程插入個(gè)APC的來進(jìn)行統(tǒng)計(jì)檢測(cè)的,其實(shí)我覺得對(duì)于檢測(cè)隱藏進(jìn)
程的方法技巧還有很多,偉大的WINDOWS還需要我們挖掘呀。進(jìn)程的結(jié)束可以通過調(diào)用ZwTerminateProcess或者調(diào)用未公開的
PspTerminateProcess函數(shù)的,關(guān)于這個(gè)函數(shù)在網(wǎng)上已經(jīng)很廣泛了,可以通過遍例進(jìn)程的每個(gè)線程調(diào)用
PspTerminateThreadByPointer的結(jié)束每個(gè)線程的,這些未公開的函數(shù)都需要事先的查找和定位的,還可以使用RKU
(RkUnhooker)的內(nèi)存清零大法的切換到該進(jìn)程然后對(duì)該進(jìn)程內(nèi)存清零RtlZeroMemory,再者也可以對(duì)該進(jìn)程的每個(gè)線程插入APC來結(jié)束
進(jìn)程的,最后如果你有時(shí)間你也可以通過觀看2K的代碼自己來實(shí)現(xiàn)進(jìn)程的結(jié)束。
內(nèi)核驅(qū)動(dòng)檢測(cè)首先你可以通過
ZwQuerySystemInformation的SystemModuleInformation功能號(hào)來枚舉內(nèi)核驅(qū)動(dòng)的,然后可以通過打開目錄對(duì)
象,進(jìn)行枚舉代碼就略了GOOGLE之吧,也可以通過枚舉IoDriverObjectType和IoDeviceObjectType對(duì)象類型進(jìn)行查找
枚舉順便把他們的DeviceObject和AttachedDevice等也枚舉下吧,接著可以通過查找PsLoadedModuleList對(duì)該鏈進(jìn)
行下枚舉的,可以對(duì)這個(gè)目錄對(duì)象再搜索一邊的”\\Driver”。通過對(duì)上面這些方法的枚舉可以查找到很多驅(qū)動(dòng)對(duì)象了,相信現(xiàn)在你的驅(qū)動(dòng)對(duì)象鏈表已經(jīng)夠
多了
嘿嘿,夠累吧,接下來,你可以對(duì)上面你已經(jīng)查找到的驅(qū)動(dòng)對(duì)象的0x38偏移MajorFunction查找一邊看看他的地址是否在已知的驅(qū)動(dòng)地址范圍內(nèi),
如不在你知道該怎么辦的,再對(duì)MajorFunction里的每個(gè)例程地址找一邊的從0到28也看看他們的地址是否在已知的驅(qū)動(dòng)地址范圍內(nèi),最后再說一種
的方法的,也可以像進(jìn)程那樣內(nèi)存枚舉的,像進(jìn)程那樣從MmSystemRangeStart開始枚舉吧,判斷下是否是PE文件有沒有那幾個(gè)關(guān)鍵PE特征
的,如MZ,PE等,看看是否存在PE文件頭是否有效,看看這個(gè)地址是否已經(jīng)是你檢測(cè)出來的驅(qū)動(dòng)地址的,避免重復(fù)的,看看你所檢測(cè)出來的所有驅(qū)動(dòng)對(duì)象的
MajorFunction[X]和DriverStartIo是否有在這個(gè)地址,如果有并且這個(gè)地址你先前沒有檢測(cè)出來沒有重復(fù)的他很有可能是個(gè)未知的
驅(qū)動(dòng)的,其實(shí)和進(jìn)程內(nèi)存查找一樣的,關(guān)鍵是判斷的,需要判斷對(duì)的,肯定他是某個(gè)對(duì)象的然后你就可以把他加如到你自己的某個(gè)鏈表里。最后也可以通過對(duì)一些關(guān)
鍵函數(shù)的HOOK
如ExAllocatePool,ExAllocatePoolWithTag等在自己實(shí)現(xiàn)這些函數(shù)里記錄下esp+0x24地址的,對(duì)這些地址進(jìn)行判斷
的來看看這些地址是否包含在某些內(nèi)核模塊當(dāng)中當(dāng)然還需要判斷下他是否就是個(gè)PE驅(qū)動(dòng)文件,這種方法就是RKU用到的方法的。驅(qū)動(dòng)就說這些吧。
前面說得太多了,后面說少點(diǎn)吧 嘿嘿。
關(guān)于SSDT HOOK的檢測(cè),通過定位ntoskrnl.exe磁盤文件里KeServiceDescriptorTable與內(nèi)存中的KeServiceDescriptorTable對(duì)各個(gè)服務(wù)函數(shù)進(jìn)行比較就可以的。代碼網(wǎng)上很多的。
關(guān)
于代碼HOOK檢測(cè),我也不想說什么的,可以對(duì)內(nèi)存中ntoskrnl.exe
的導(dǎo)入函數(shù)和導(dǎo)出函數(shù)與磁盤文件中的地址進(jìn)行比較,也可以通過對(duì)ntoskrnl.exe
PE文件里的某些節(jié)(section)進(jìn)行掃描的,再加上對(duì)一些關(guān)鍵文件的導(dǎo)入函數(shù)和導(dǎo)出函數(shù)進(jìn)行掃描,加上對(duì)某些關(guān)鍵驅(qū)動(dòng)(如文件系統(tǒng)驅(qū)動(dòng))的
MajorFunction里的每個(gè)例程進(jìn)行掃描,再者對(duì)IDT,GDT掃描下的。
關(guān)于注冊(cè)表隱藏的檢測(cè),首先可以用到把一些注冊(cè)表相關(guān)
的函數(shù)INLINE HOOK的SSDT HOOK的都恢復(fù)下再使用的其實(shí)所謂的不相關(guān)的也需要UNHOOK下的,如badrkdemo
他就HOOK了ObOpenObjectByName函數(shù)組織對(duì)注冊(cè)表的訪問的 具體的看情況來吧
哈哈,也可以通過對(duì)一些未公開的函數(shù)進(jìn)行使用的CM系列函數(shù)的,再者可以通過分析HIVE文件的來顯示注冊(cè)表各個(gè)項(xiàng)的,通過分析HIVE文件其實(shí)也不是很
難的,了解了HIVE文件結(jié)構(gòu)和HIVE文件的組織的,就可以讀他了,這些資料網(wǎng)上可以找到的,通過讀HIVE文件來給用戶顯示當(dāng)前注冊(cè)表各個(gè)項(xiàng)的可以的
但我并不推薦自己改寫系統(tǒng)的HIVE文件的,如提供DELETE
MODIFE等功能的我覺得如改的不好,或結(jié)構(gòu)沒有完全清楚的,寫到HIVE文件里是錯(cuò)誤的,那么當(dāng)再次啟動(dòng)時(shí)系統(tǒng)讀HIVE文件時(shí)就不好過了,自己一點(diǎn)
愚見,如果你夠強(qiáng)大當(dāng)然是沒有問題的。
關(guān)于隱藏文件的檢測(cè),現(xiàn)在流行的隱藏文件的RK很多的,如Unreal.A,AK922等,自己可
以通過在驅(qū)動(dòng)中自己構(gòu)建IRP包自己發(fā)送給文件驅(qū)動(dòng)的方法的,還有就是先恢復(fù)些關(guān)鍵函數(shù)的,像注冊(cè)表那樣的,恢復(fù)INLINE HOOK SSDT
HOOK,文件驅(qū)動(dòng)關(guān)鍵例程HOOK的,現(xiàn)在流行HOOK內(nèi)核的完成例程的,HOOK是防不勝防的,還要注意下附加在文件系統(tǒng)上的一些過濾驅(qū)動(dòng)的,還有就
是通過使用DeviceIoControl發(fā)送一些特殊的IoControlCode控制代碼給文件系統(tǒng)的,這需要對(duì)文件系統(tǒng)的熟悉的,還有就是自己分析
磁盤文件的對(duì)FAT32,NTFS等格式文件系統(tǒng)自己分析來查找文件的,關(guān)于自己分析磁盤文件的,網(wǎng)上的信息和資料也是很多的,首先判斷下屬于哪個(gè)文件系
統(tǒng),然后根據(jù)特定的文件系統(tǒng)格式自己分析的就可以的,其實(shí)這些方法的關(guān)鍵是怎么讀和寫的,讀和寫做到最底層,把讀和寫做好我想他檢測(cè)文件功能是強(qiáng)大的。
夠
了,一些ARK的功能說到這就可以了,我希望各位搞RK的和ARK的人看了之后又會(huì)作出很多厲害,強(qiáng)大的東西來,希望看了之后會(huì)對(duì)各位有一點(diǎn)幫助的,希望
可以在當(dāng)前流行的RK和ARK中會(huì)有更新更強(qiáng)大的東西出現(xiàn)的,來激勵(lì)我們學(xué)習(xí)和前進(jìn)的,引用一位好友的話“現(xiàn)在感覺大部分木馬病毒什么的都是用的老一套東
西的什么SSDT HOOK的。。。。。。,希望可以有些新的技術(shù)出現(xiàn)的”,其實(shí)現(xiàn)在有些RK是很牛的,其實(shí)都是一個(gè)目標(biāo)的
希望技術(shù)和知識(shí)可以不斷進(jìn)步的 嘿嘿。一個(gè)沒有未來的人:)談?wù)勱P(guān)于RK和ARK未來的發(fā)展 RK
更底層,ARK也更底層,攻和防,RK和ARK的斗爭(zhēng)會(huì)繼續(xù)的,RK會(huì)出現(xiàn)固化在某個(gè)文件里,會(huì)在重裝系統(tǒng)后還會(huì)存在,會(huì)寫到硬件中。。。。。。,ARK
勢(shì)必也需要對(duì)這些問題關(guān)注的。
謝謝各位看完文章的,本人一介小菜知識(shí)有限,以上是自己的一點(diǎn)愚見,如有什么錯(cuò)誤和不足之處,請(qǐng)各位指教。
本文之中的有些知識(shí)是朋友和一些牛人給予幫助,謝謝他們的幫助。
作者:single
2007-10-19