SSDTHook執行個體--編寫穩定的Hook過濾函數

來源:互聯網
上載者:User

標籤:ssdt hook   hook過濾函數   windows核心hook   ssdthook樣本   windows核心安全   

講解如何寫Hook過濾函數,比如NewZwOpenProcess。開啟進程。很多遊戲保護都會對這個函數進行Hook。由於我們沒有遊戲保護的代碼,無法得知遊戲公司是如何編寫這個過濾函數。

 

我看到很多奇形怪狀的Hook過濾函數的寫法。看得蛋痛無比。比如:

http://bbs.pediy.com/showthread.php?t=126802

http://bbs.pediy.com/showthread.php?t=126077

 

第一個bug:

調用這個函數

status = PsLookupProcessByProcessId(

          ClientId->UniqueProcess,

          &process

           );

這個函數我們要注意的地方。沒有看到清除調用引數ObDereferenceObject(process);

 

第二個bug:

參數 PCLIENT_ID ClientId

如果這個參數是NULL,那麼 ClientId-->UniqueProcess

就會產生藍屏即直接對一個NULL變數進行讀取。

 

http://bbs.pediy.com/showthread.php?t=105418

http://bbs.pediy.com/showthread.php?t=82548

http://bbs.pediy.com/showthread.php?t=82043

 

注:如果你用naked(裸函數)這種形式,就不應該有參數,如果你用__stdcall這種調用規則,就應該要有參數。

 

我覺得這個還算是標準(至少可讀性很高):

http://bbs.pediy.com/showthread.php?t=176477

 

 

要注重細節,這就是代碼穩定性的編寫過程。

 

隨便找一個之前的hook過濾函數的代碼,對照WRK,對使用的各種參數進行效驗,寫一個穩定的過濾函數。

 

穩定的SSDT Hook程式碼範例

SSDT.h 標頭檔的編碼:

#ifndef _SSDT_H_#define _SSDT_H_#include <ntifs.h>//核心匯出的SSDT表的結構typedef struct _SERVICE_DESCRIPTOR_TABLE {/** Table containing cServices elements of pointers to service handler* functions, indexed by service ID.*/PULONG   ServiceTable;/** Table that counts how many times each service is used. This table* is only updated in checked builds.*/PULONG  CounterTable;/** Number of services contained in this table.*/ULONG   TableSize;/** Table containing the number of bytes of parameters the handler* function takes.*/PUCHAR  ArgumentTable;} SERVICE_DESCRIPTOR_TABLE, *PSERVICE_DESCRIPTOR_TABLE;//全域變數PMDL  pmdl_system_call;PVOID *pdword_mapped_table;//******************** SSDT Hook宏(固定的) ****************************************************************//擷取Hook函數的Index#define SYSCALL_INDEX(_Function) *(PULONG)((PUCHAR)_Function+1)//實現SSDT表的Hook#define HOOK_SYSCALL(_Function, _Hook, _Orig )  _Orig = (PVOID) InterlockedExchange( (PLONG) &pdword_mapped_table[SYSCALL_INDEX(_Function)], (LONG) _Hook)//恢複SSDT表的Hook#define UNHOOK_SYSCALL(_Function, _Hook, _Orig )  InterlockedExchange( (PLONG) &pdword_mapped_table[SYSCALL_INDEX(_Function)], (LONG) _Hook)//聲明SSDT的匯出 extern PSERVICE_DESCRIPTOR_TABLE KeServiceDescriptorTable;#endif

SSDTHook.h 標頭檔的編碼:

#ifndef _SSDT_HOOK_H_#define _SSDT_HOOK_H_#include <ntifs.h>#include "SSDT.h"  //聲明沒有文檔化的函數PsGetProcessImageFileNameUCHAR* PsGetProcessImageFileName(__in PEPROCESS Process); //*************************************************************************************************************************//定義原函數的指標類型typedef NTSTATUS (__stdcall *REALZWOPENPROCESS)(OUT PHANDLE ProcessHandle,IN ACCESS_MASK DesiredAccess,IN POBJECT_ATTRIBUTES ObjectAttributes,IN PCLIENT_ID ClientId);//定義該函數指標REALZWOPENPROCESS RealZwOpenProcess;//儲存要Hook函數的真真實位址ULONG_PTR ul_ZwOpenProcess;//儲存要Hook函數的名稱UNICODE_STRING unicode_string;//Mdl方式的SSDT表的HookNTSTATUS MdlSSDTHook(ULONG_PTR ul_real_function, ULONG_PTR hook_function_addr ,ULONG_PTR *ul_save_real_function_addr);//移除Mdl方式的SSDT表的HookNTSTATUS MdlRemoveSSDTHook(ULONG_PTR ul_real_function, ULONG_PTR hook_function_addr, ULONG_PTR *ul_save_real_function_addr);#endif


SSDT.c 檔案的編寫

#include "SSDT.h"//******************************************************************************************//採用比較安全的方法修改ssdt表//因為SSDT的虛擬位址分頁屬性是唯讀,我們不能夠直接修改它,否則會產生藍屏//我們藉助Mdl分配一段虛擬位址映射到SSDT所在的物理地址,//同時因為我們映射的MDL記憶體屬性卻可以是可寫,所以就可以修改ssdt,這樣就替代了cr0方式。//******************************************************************************************//Mdl方式的SSDT表的HookNTSTATUS MdlSSDTHook(ULONG_PTR ul_real_function, ULONG_PTR hook_function_addr, ULONG_PTR *ul_save_real_function_addr){//構建記憶體描述符MDLpmdl_system_call = MmCreateMdl(NULL, KeServiceDescriptorTable->ServiceTable, KeServiceDescriptorTable->TableSize*sizeof(ULONG_PTR));if(!pmdl_system_call){return STATUS_UNSUCCESSFUL;}//根據MDL申請分配記憶體MmBuildMdlForNonPagedPool(pmdl_system_call);//設定MDL_MAPPED_TO_SYSTEM_VA標識,讓這塊記憶體變可寫pmdl_system_call->MdlFlags = pmdl_system_call->MdlFlags | MDL_MAPPED_TO_SYSTEM_VA;//鎖定記憶體pdword_mapped_table = MmMapLockedPages(pmdl_system_call, KernelMode);if (pdword_mapped_table){//SSDT表的HookHOOK_SYSCALL(ul_real_function, hook_function_addr, *ul_save_real_function_addr);}return STATUS_SUCCESS;}//移除Mdl方式的SSDT表的HookNTSTATUS MdlRemoveSSDTHook(ULONG_PTR ul_real_function, ULONG_PTR hook_function_addr, ULONG_PTR *ul_save_real_function_addr){//恢複SSDT表的HookUNHOOK_SYSCALL(ul_real_function, *ul_save_real_function_addr,hook_function_addr);if(pmdl_system_call){//解除記憶體鎖定MmUnmapLockedPages(pdword_mapped_table, pmdl_system_call);//釋放申請記憶體IoFreeMdl(pmdl_system_call);return STATUS_SUCCESS;}return STATUS_UNSUCCESSFUL;}


SSDTHook.c 檔案的編寫

#include "SSDTHook.h"//深度的字串效驗BOOLEAN ValidateUnicodeString(PUNICODE_STRING usStr){ULONG i;__try{//判斷字串的記憶體是否可訪問if (!MmIsAddressValid(usStr)){return FALSE;}//判斷是否為NULLif (usStr->Buffer == NULL || usStr->Length == 0){return FALSE;}//每一個位元組都要檢查for (i = 0; i < usStr->Length; i++){if (!MmIsAddressValid((PUCHAR)usStr->Buffer + i)){return FALSE;}}}__except(EXCEPTION_EXECUTE_HANDLER){//觸發異常          return FALSE;  }return TRUE;}//自訂的ZwOpenProcess函數(NewZwOpenProcess)NTSTATUS __stdcall NewZwOpenProcess(OUT PHANDLE ProcessHandle,IN ACCESS_MASK DesiredAccess,IN POBJECT_ATTRIBUTES ObjectAttributes,IN PCLIENT_ID ClientId){NTSTATUS status;ULONG PID;HANDLE handle_process_handle;PEPROCESS eprocess_process_object;KPROCESSOR_MODE PreMode;//擷取當前的系統模式MODEPreMode = ExGetPreviousMode();//*******************************如果非核心模式,就要開始檢查IN的這些參數都否可讀****************************//每Hook一個函數之前,你都要先對照WRK:if(PreMode != KernelMode){__try{//這裡用ProbeForRead來對參數ClientId進行測試,然後加try捕獲//檢查使用者模式地址的可讀性必須在ring0調用ProbeForRead(ClientId, sizeof(CLIENT_ID), sizeof(ULONG));}__except(EXCEPTION_EXECUTE_HANDLER){//返回異常代碼return GetExceptionCode();}}//執行到這裡說明改參數是可以訪問,那我們還要效驗ClientId是否為NULLif(ClientId != NULL && MmIsAddressValid(ClientId)){//更安全的訪問PID = (ULONG)ClientId->UniqueProcess;DbgPrint("OpenProcess %d by %s[0x%08X]\r\n", PID, PsGetProcessImageFileName(PsGetCurrentProcess()), PsGetCurrentProcess());}/*typedef struct _OBJECT_ATTRIBUTES {ULONG           Length;HANDLE          RootDirectory;PUNICODE_STRING ObjectName; //BufferULONG           Attributes;PVOID           SecurityDescriptor;PVOID           SecurityQualityOfService;}  OBJECT_ATTRIBUTES, *POBJECT_ATTRIBUTES;*/if (ObjectAttributes != NULL && MmIsAddressValid(ObjectAttributes)){//這個成員是一個指標 ObjectName。效驗指標是否為空白,接著是否可以訪問。這是第二層的效驗if (ObjectAttributes->ObjectName != NULL && MmIsAddressValid(ObjectAttributes->ObjectName)){//深度校正檢查if (ObjectAttributes->ObjectName->Buffer != NULL && ValidateUnicodeString(ObjectAttributes->ObjectName->Buffer)){//現在才可以安全不藍屏的訪問這個BufferDbgPrint("OpenObjectName %ws\r\n", ObjectAttributes->ObjectName->Buffer);}}}//如果我們要取ProcessHandle怎麼辦?status = RealZwOpenProcess(ProcessHandle, DesiredAccess, ObjectAttributes, ClientId);if (NT_SUCCESS(status)){//為什麼我們這裡不用效驗ProcessHandle?//因為函數調用成功了handle_process_handle = *ProcessHandle;//然後我們還可以通過handle,得到eprocess,即 handle->eprocess,還有一堆的轉換,比如eprocess->handle, handle->fileobjectstatus = ObReferenceObjectByHandle(handle_process_handle, GENERIC_READ,*PsProcessType, KernelMode, (PVOID*)&eprocess_process_object, 0); if(NT_SUCCESS(status)){DbgPrint("@@ OpenProcess %s by %s\r\n", PsGetProcessImageFileName(eprocess_process_object), PsGetProcessImageFileName(PsGetCurrentProcess()));//這裡很重要,消除引用計數ObDereferenceObject(eprocess_process_object);}//只要RealZwOpenProcess調用成功,無論如何一定要返回成功status = STATUS_SUCCESS;}return status;}//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//驅動卸載的常式函數VOID DriverUnload(IN PDRIVER_OBJECT DriverObject){//卸載Hookif (ul_ZwOpenProcess){//移除SSDT表的Hookif (MdlRemoveSSDTHook((ULONG_PTR)ul_ZwOpenProcess, NewZwOpenProcess, &RealZwOpenProcess) == STATUS_SUCCESS){DbgPrint("ZwOpenProcess Remove hook success\r\n");}}DbgPrint("DriverUnload\r\n");}//驅動入口常式函數NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject,PUNICODE_STRING RegistryPath){//設定驅動的卸載常式函數DriverObject->DriverUnload = DriverUnload;RtlInitUnicodeString(&unicode_string, L"ZwOpenProcess");//擷取要Hook函數的真實函數地址ul_ZwOpenProcess = (ULONG_PTR)MmGetSystemRoutineAddress(&unicode_string);if (ul_ZwOpenProcess){if (MdlSSDTHook((ULONG_PTR)ul_ZwOpenProcess, NewZwOpenProcess, &RealZwOpenProcess) == STATUS_SUCCESS){DbgPrint("ZwZwOpenProcess hook success\r\n");}}return STATUS_SUCCESS;}

makefile檔案的編寫:

## DO NOT EDIT THIS FILE!!!  Edit .\sources. if you want to add a new source# file to this component.  This file merely indirects to the real make file# that is shared by all the driver components of the Windows NT DDK#!INCLUDE $(NTMAKEENV)\makefile.def

sources檔案的編寫:

# $Id$TARGETNAME=SSDTHookTARGETPATH=objTARGETTYPE=DRIVER# Create browse info#BROWSER_INFO=1#BROWSERFILE=<some path># Additional defines for the C/C++ preprocessorC_DEFINES=$(C_DEFINES)SOURCES=SSDTHook.cSSDT.c



參考資料:

AGP講課資料的修改和整理。


著作權聲明:本文為博主原創文章,未經博主允許不得轉載。

SSDTHook執行個體--編寫穩定的Hook過濾函數

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.