AK922 突破磁碟低階檢測實現檔案隱藏

2021-04-17 20:25:43 字數 3163 閱讀 3489

ak922: 突破磁碟低階檢測實現檔案隱藏

email: [email protected]

完成於:2007-08-08

目前,一些已公開的主流anti-rootkit檢測隱藏檔案主要有兩種方法:第一種是檔案系統層的檢測,屬於這一類的有icesword,darkspy,gmer等。第二種便是磁碟級別的低階檢測(disk low-level scanning),屬於這一類的ark也很多,典型代表為rootkit unhooker,filereg(is的外掛程式),rootkit revealer,blacklight等。當然,還有一些工具,它們在應用層上通過呼叫zwquerydirectoryfile來實施檢測。

驅動也好,應用也罷,說白了就是直接或間接傳送irp到下層驅動。第一類的傳送到fsd中(fastfat.sys/ntfs.sys),第二類被傳送到磁碟驅動(disk.sys),而後irp便會攜帶相應的檔案資訊返回,這時上層應用再根據返回資訊進行處理和判斷。但是由於disk級比fs級更底層,irp返回給我們的是更加接近資料原始組織方式的磁碟扇區資訊,所以在disk層上實施檔案檢測可以得到更令人信服的結果。但這並不等於說這類檢測不能被擊敗。本文就將介紹一種繞過該類檢測的實現方法,當然,這也是在ak922中使用的。

對於要實現檔案隱藏的rk,與其說是「繞過」,還不如說是「攔截」 -- 掛鉤某些核心函式呼叫,以便在返回上層之前我們有機會過濾掉待隱藏檔案的資訊。

ak922採用的方法是hook核心函式iofcompleterequest。這個函式很有意思,因為它不僅是乙個幾乎在任何驅動中都要呼叫的函式,而且引數中正好含有irp。有了irp,就有了一切。這些特性決定了它很適合做我們的「傀儡」。但更重要的是,一般在驅動中呼叫iofcompleterequest之時irp操作都已完畢,irp中相關域已經填充了內容,這就便於我們著手直接進行過濾而不用再做諸如傳送irp安裝完成例程之類的操作。

下面就著重說一下工作流程:

首先,判斷majorfunction是不是irp_mj_read以及io堆疊中的device是否是磁碟驅動的裝置物件,因為這才是我們要處理的核心irp,所有ark直接傳送到disk層的irp在這裡都可以被攔截到。

接下來的處理要特別注意,進入到這裡時irql是在apc_level以上的,因此我們不能碰任何irp中的使用者模式緩衝區,一碰極有可能藍,也就是說我們不能直接處理相關磁碟扇區資訊,而必須通過exqueueworkitem排隊乙個workitem的方法來處理。除此之外,由於disk層在裝置堆疊中處於*下的位置,大部分irp發到這裡時當前程序上下文早已不是原始irp發起者的程序上下文了,這裡的發起者應理解為ark程序。幸運的是在irp的tail.overlay.thread域中還儲存著原始ethread指標,為了操作使用者模式緩衝區,必須呼叫keattachprocess切到irp發起者的上下文環境中,而這個工作只能在處於passive_level級上的工作者執行緒中執行。在dispatch_level級上,做的事越少越好。

剛開始我還分兩種情況進行處理:因為並不是所有的irp都不處在原始上下文中,比如icesword發的irp到這裡還是處在icesword.exe程序中的,這時我認為可以不用排隊工作項,這樣就可以節省很多系統資源,提高過濾效率。於是我試圖在dispatch_level級上直接操作使用者緩衝區,但這根本行不通。驅動很不穩定,不一會就藍了。故索性老老實實地排隊去了,然後再分情況處理。**如下:

// 處理disk low-level scanning

if(irpsp->majorfunction == irp_mj_read && isdiskdrxdevice(irpsp->device) && irpsp->parameters.read.length != 0) }

}}來到工作者執行緒,到了passive_level級上,切換上下文之後,似乎安全多了。但是以防萬一,操作使用者模式緩衝區之前還是要呼叫probefor***函式先判斷一下。相關**如下:

void workerthread(pvoid context)

__except(exception_execute_handler)

kedetachprocess();    

}else

__except(exception_execute_handler){}}}

}準備工作終於算是做得差不多了,下面就開始真正塗改磁碟扇區內容了。這裡將涉及到fat32和ntfs磁碟檔案結構,我先把要用到的主要結構列出來,其餘的大家可以參考《ntfs documentation》。

typedef struct _index_headerindex_header, *pindex_header;

typedef struct _index_entryindex_entry, *pindex_entry;

讀取磁碟檔案資訊時每次都是以乙個扇區大小(512 bytes)的整數倍進行的,如果不了解相應卷的組織形式和資料結構,那麼感覺就是資料多而繁雜,搜尋效率也很低。但輔以上述結構便可快速定位待隱藏檔案並進行塗改。這裡不得不說一句,演算法的高效是很重要的,如果採用暴力搜尋的方式,那麼系統bsod的概率會大大增加。

在fat32卷上,當ak922搜尋到檔案ak922.sys的目錄項時,將其0x0偏移處的檔名的第乙個位元組置為"0xe5",即標記為刪除。這樣即可達到欺騙ark的目的。但為了更加隱蔽,不讓winhex察覺出來,最好把檔名全部清0。

處理ntfs卷稍微麻煩些,檔案記錄和索引項都要抹乾淨,具體實現見**,這裡不再贅述。

void handleakdiskhide(pvoid userbuf, ulong buflen)

userbuf = (pvoid)((ulong)userbuf + 0x20);

}} else if(bisntfsfile)

userbuf = (pvoid)((ulong)userbuf + filerecordsize);

}} else if(bisntfsindex)

preindxentry->size += currindxentry->size;

break;

}currposition += currindxentry->size;

preindxentry = currindxentry;

currindxentry = (pindex_entry)((ulong)currindxentry + currindxentry->size);}}

}