通过修改此表的函数地址可以对常用windows函数及API进行hook,从而实现对一些关心的系统动作进行过滤、监控的目的。一些HIPS、防毒软件、系统监控、注册表监控软件往往会采用此接口来实现自己的监控模块,
目前极个别病毒确实会采用这种方法来保护自己或者破坏防毒软件,但在这种病毒进入系统前如果防毒软件能够识别并清除它将没有机会发作.
SSDT到底是什么呢?打一个比方,SSDT相当于系统内部API的指向标,作用就是告诉系统,需要调用的API在什么地方。
请看源码解析
/************************************************************************* * *ZwQuerySystemInformation函数常用结构 * **************************************************************************/ #ifndef _SPS_H_ #define _SPS_H_ 1 #include <ntddk.h> #include "table.h" #include "pe.h" #endif typedef enum _SYSTEM_INFORMATION_CLASS { SystemBasicInformation, // 0 SystemProcessorInformation, // 1 SystemPerformanceInformation, // 2 SystemTimeOfDayInformation, // 3 SystemNotImplemented1, // 4 SystemProcessesAndThreadsInformation, // 5 SystemCallCounts, // 6 SystemConfigurationInformation, // 7 SystemProcessorTimes, // 8 SystemGlobalFlag, // 9 SystemNotImplemented2, // 10 SystemModuleInformation, // 11 系统模块 SystemLockInformation, // 12 SystemNotImplemented3, // 13 SystemNotImplemented4, // 14 SystemNotImplemented5, // 15 SystemHandleInformation, // 16 SystemObjectInformation, // 17 SystemPagefileInformation, // 18 SystemInstructionEmulationCounts, // 19 SystemInvalidInfoClass1, // 20 SystemCacheInformation, // 21 SystemPoolTagInformation, // 22 SystemProcessorStatistics, // 23 SystemDpcInformation, // 24 SystemNotImplemented6, // 25 SystemLoadImage, // 26 SystemUnloadImage, // 27 SystemTimeAdjustment, // 28 SystemNotImplemented7, // 29 SystemNotImplemented8, // 30 SystemNotImplemented9, // 31 SystemCrashDumpInformation, // 32 SystemExceptionInformation, // 33 SystemCrashDumpStateInformation, // 34 SystemKernelDebuggerInformation, // 35 SystemContextSwitchInformation, // 36 SystemRegistryQuotaInformation, // 37 SystemLoadAndCallImage, // 38 SystemPrioritySeparation, // 39 SystemNotImplemented10, // 40 SystemNotImplemented11, // 41 SystemInvalidInfoClass2, // 42 SystemInvalidInfoClass3, // 43 SystemTimeZoneInformation, // 44 SystemLookasideInformation, // 45 SystemSetTimeSlipEvent, // 46 SystemCreateSession, // 47 SystemDeleteSession, // 48 SystemInvalidInfoClass4, // 49 SystemRangeStartInformation, // 50 SystemVerifierInformation, // 51 SystemAddVerifier, // 52 SystemSessionProcessesInformation // 53 }SYSTEM_INFORMATION_CLASS; //内核模块类型,我们要列举的是SystemProcessesAndThreadsInformation,进程和线程信 //线程信息 typedef struct _SYSTEM_THREAD_INFORMATION { LARGE_INTEGER KernelTime; LARGE_INTEGER UserTime; LARGE_INTEGER CreateTime; ULONG WaitTime; PVOID StartAddress; CLIENT_ID ClientId; KPRIORITY Priority; KPRIORITY BasePriority; ULONG ContextSwitchCount; LONG State; LONG WaitReason; } SYSTEM_THREAD_INFORMATION, *PSYSTEM_THREAD_INFORMATION; //线程结构 //进程信息 typedef struct _SYSTEM_PROCESS_INFORMATION { ULONG NextEntryDelta; //NextEntryOffset下一个进程结构的偏移量,每一个进程对应一个结构 //最后一个进程的NextEntryOffset=0 ULONG NumberOfThreads; //线程数目 LARGE_INTEGER Reserved[3]; LARGE_INTEGER CreateTime; //创建时间 LARGE_INTEGER UserTime; //用户模式(Ring 3)的CPU时间 LARGE_INTEGER KernelTime; //内核模式(Ring 0)的CPU时间 UNICODE_STRING ProcessName; //进程名 KPRIORITY BasePriority; //进程优先权 ULONG ProcessId; //进程标识符 ULONG InheritedFromProcessId; //父进程的标识符 ULONG HandleCount; //句柄数目 ULONG Reserved2[2]; ULONG PrivatePageCount; VM_COUNTERS VirtualMemoryCounters; //虚拟存储器的结构 IO_COUNTERS IoCounters; //IO计数结构 SYSTEM_THREAD_INFORMATION Threads[0]; //进程相关线程的结构数组 } SYSTEM_PROCESS_INFORMATION, *PSYSTEM_PROCESS_INFORMATION; //------------------------------------------------------------------------------ //模块信息 typedef struct _SYSTEM_MODULE_INFORMATION { ULONG Reserved[2]; PVOID Base; ULONG Size; ULONG Flags; USHORT Index; USHORT Unknown; USHORT LoadCount; USHORT ModuleNameOffset; CHAR ImageName[256]; } SYSTEM_MODULE_INFORMATION, *PSYSTEM_MODULE_INFORMATION; //模块列表 typedef struct _SYSMODULELIST{ ULONG ulCount; SYSTEM_MODULE_INFORMATION smi[1]; } SYSMODULELIST, *PSYSMODULELIST; //----------------------------------------------------------------------------------- //DRIVER_SECTION结构 typedef struct _LDR_DATA_TABLE_ENTRY { LIST_ENTRY InLoadOrderLinks; LIST_ENTRY InMemoryOrderLinks; LIST_ENTRY InInitializationOrderLinks; PVOID DllBase; PVOID EntryPoint; ULONG SizeOfImage; UNICODE_STRING FullDllName; UNICODE_STRING BaseDllName; ULONG Flags; USHORT LoadCount; USHORT TlsIndex; union { LIST_ENTRY HashLinks; struct { PVOID SectionPointer; ULONG CheckSum; }; }; union { struct { ULONG TimeDateStamp; }; struct { PVOID LoadedImports; }; }; struct _ACTIVATION_CONTEXT * EntryPointActivationContext; PVOID PatchInformation; }LDR_DATA_TABLE_ENTRY, *PLDR_DATA_TABLE_ENTRY; //=================================================================================== NTKERNELAPI NTSTATUS ZwQuerySystemInformation( IN SYSTEM_INFORMATION_CLASS SystemInformationClass, OUT PVOID SystemInformation, IN ULONG SystemInformationLength, OUT PULONG ReturnLength OPTIONAL ); //最终是通过遍历EPROCESS获取的 typedef NTSTATUS (*ZWQUERYSYSTEMINFORMATION)( IN SYSTEM_INFORMATION_CLASS SystemInformationClass, OUT PVOID SystemInformation, IN ULONG SystemInformationLength, OUT PULONG ReturnLength OPTIONAL ); //定义结构 NTSYSAPI BOOLEAN NTAPI KeAddSystemServiceTable( ULONG lpAddressTable, BOOLEAN bUnknown, ULONG dwNumEntries, ULONG lpParameterTable, ULONG dwTableID ); //****************************函数声明************************************* //根据地址查找模块 void FindModuleByAddress( ULONG Address, PVOID buffer); //根据RVA查找SSDT 文件偏移 ULONG FindFileOffsetByRva( ULONG ModuleAddress,ULONG Rva); //路径解析出子进程名 void GetModuleName( char *ProcessPath, char *ProcessName); //根据服务号得到当前的地址 ULONG FindOriAddress( ULONG index ); //得到SSDT Shadow表地址 ULONG GetSSDTShadowAddress2(); ULONG GetWin32Base2( PDRIVER_OBJECT driver); ULONG FindShadowOriAddress( ULONG index ); /***************************************************************************************** * *函数名:FindModuleByAddress *功能描述:根据函数地址查找所属模块 * ******************************************************************************************/ /***************************************************************************************** * * 原理: 利用ZwQuerySystemInformation传入SystemModuleInformation(11)得到系统模块列表 * 得到每个模块的起始和结束地址 * 比对地址,在那个范围就属于哪个模块 * 得到模块名 * ******************************************************************************************/ #include "refresh.h" void FindModuleByAddress( ULONG Address, PVOID buffer) { NTSTATUS status; ULONG size; ULONG i; ULONG minAddress; ULONG maxAddress; PSYSMODULELIST List; ZwQuerySystemInformation( SystemModuleInformation ,&size,0,&size); KdPrint(("[FindModuleByAddress] size:0x%x\n",size)); List=(PSYSMODULELIST)ExAllocatePool(NonPagedPool,size); if(List==NULL) { KdPrint(("[FindModuleByAddress] malloc memory failed\n")); return ; } status=ZwQuerySystemInformation(SystemModuleInformation,List,size,0); if(!NT_SUCCESS(status)) { KdPrint(("[FindModuleByAddress] query failed\n")); //打印错误 KdPrint(("[FindModuleByAddress] status: 0x%x\n",status)); ExFreePool( List ); return ; } //得到了模块链表 //判断模块名 for( i=0; i<List->ulCount; i++) { //得到模块的范围 minAddress = (ULONG)List->smi[i].Base; maxAddress = minAddress + List->smi[i].Size; //判断地址 if( Address >= minAddress && Address <= maxAddress ) { memcpy( buffer, List->smi[i].ImageName,sizeof(List->smi[i].ImageName)); KdPrint(("[FindModuleByAddress] modulename: %s\n",buffer)); //释放内存 ExFreePool(List); break; } } } /*************************************************************************************** * * 函数名:GetOriFunctionAddress * 功能描述:得到原始SSDT表中函数地址 * ****************************************************************************************/ /*************************************************************************************** * * 原理: 找到内核文件,获取基址BaseAddress * 根据内核文件查找SSDT表的文件偏移SSDTFileOffset = SSDTRVA-(节RVA-节Offset) * 读取函数的文件偏移FunctionFileOffset * VA=BaseAddress+FunctionFileOffset-00400000=800d8000 + FunctionFileOffset * *****************************************************************************************/ /**************************************************************************************** * * 根据RVA查找所在的文件偏移:FileOffset = Rva- (节Rva - 节Offset) * 找到区块表 *****************************************************************************************/ ULONG FindFileOffsetByRva( ULONG ModuleAddress,ULONG Rva) { PIMAGE_DOS_HEADER dos; PIMAGE_FILE_HEADER file; PIMAGE_SECTION_HEADER section; //区块数目 ULONG number; ULONG i; ULONG minAddress; ULONG maxAddress; ULONG SeFileOffset; ULONG FileOffset; dos = (PIMAGE_DOS_HEADER)ModuleAddress; file = (PIMAGE_FILE_HEADER)( ModuleAddress + dos->e_lfanew + 4 ); //得到区块数量 number = file->NumberOfSections; KdPrint(("[FindFileOffsetByRva] number :0x%x\n",number)); //得到第一个区块地址 section = (PIMAGE_SECTION_HEADER)(ModuleAddress + dos->e_lfanew + 4 + sizeof(IMAGE_FILE_HEADER) + file->SizeOfOptionalHeader); for( i=0;i<number;i++) { minAddress = section[i].VirtualAddress; maxAddress = minAddress + section[i].SizeOfRawData; SeFileOffset = section[i].PointerToRawData; if( Rva > minAddress && Rva < maxAddress) { KdPrint(("[FindFileOffsetByRva] minAddress :0x%x\n",minAddress)); KdPrint(("[FindFileOffsetByRva] SeFileOffset :0x%x\n",SeFileOffset)); FileOffset = Rva - ( minAddress - SeFileOffset); KdPrint(("[FindFileOffsetByRva] FileOffset :0x%x\n",FileOffset)); break ; } } return FileOffset; } //路径解析出子进程名 void GetModuleName( char *ProcessPath, char *ProcessName) { ULONG n = strlen( ProcessPath) - 1; ULONG i = n; KdPrint(("%d",n)); while( ProcessPath[i] != '\\') { i = i-1; } strncpy( ProcessName, ProcessPath+i+1,n-i); } /**************************************************************************************** * * 根据传入的服务号得到函数原始地址 * ****************************************************************************************/ ULONG FindOriAddress( ULONG index ) { //根据传入的index得到函数VA地址 //重定位函数地址 //BaseAddress - 0x00400000 + *(PULONG)(FileOffset+(index*4)) //ZwQuerySystemInformation得到内核文件基地址 //得到SSDT表的地址 //得到SSDT RVA 查找SSDT RVA所在的节 NTSTATUS status; ULONG size; ULONG BaseAddress; ULONG SsdtRva; ULONG FileOffset = 0; PSYSMODULELIST list; char Name[32]={0}; char PathName[256] = "\\SystemRoot\\system32\\"; ANSI_STRING name; UNICODE_STRING modulename; OBJECT_ATTRIBUTES object_attributes; IO_STATUS_BLOCK io_status = {0}; HANDLE hFile; //读取的位置 ULONG location; LARGE_INTEGER offset; ULONG address; //得到需要申请的内存大小 ZwQuerySystemInformation( SystemModuleInformation,&size,0,&size ); //申请内存 list = (PSYSMODULELIST) ExAllocatePool( NonPagedPool,size ); //验证是否申请成功 if( list == NULL) { //申请失败 KdPrint(("[FindOriAddress] malloc memory failed\n")); ExFreePool(list); return 0; } status = ZwQuerySystemInformation( SystemModuleInformation,list,size,0); if( !NT_SUCCESS( status )) { //获取信息失败 KdPrint(("[FindOriAddress] query failed\n")); KdPrint(("[FindOriAddress] status:0x%x\n",status)); ExFreePool(list); return 0; } //得到模块基址,第一个模块为内核文件 BaseAddress = (ULONG )list->smi[0].Base; KdPrint(("[FindOriAddress] BaseAddress:0x%x\n",BaseAddress)); //分离出内核文件名 GetModuleName(list->smi[0].ImageName,Name); KdPrint(("[FindOriAddress] processname:%s\n",Name)); strcat(PathName,Name); RtlInitAnsiString(&name,PathName); RtlAnsiStringToUnicodeString(&modulename,&name,TRUE); KdPrint(("[FindOriAddress] modulename: %wZ\n",&modulename)); ExFreePool(list); //经验证地址正确 //得到SSDT表的Rva SsdtRva = (ULONG)KeServiceDescriptorTable->ServiceTableBase - BaseAddress; //验证 KdPrint(("[FindOriAddress] SsdtRva:0x%x\n",SsdtRva)); //根据RVA查找文件偏移,//得到文件偏移了 FileOffset= FindFileOffsetByRva( BaseAddress,SsdtRva); KdPrint(("[FindOriAddress] FileOffset:0x%x\n",FileOffset)); //读取的位置 location = FileOffset + index * 4; offset.QuadPart =location; KdPrint(("[FindOriAddress] location:0x%x\n",location)); //利用ZwReadFile读取文件 //初始化OBJECT_ATTRIBUTES结构 InitializeObjectAttributes( &object_attributes, &modulename, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL); //打开文件 status = ZwCreateFile( &hFile, FILE_EXECUTE | SYNCHRONIZE, &object_attributes, &io_status, NULL, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ, FILE_OPEN, FILE_NON_DIRECTORY_FILE | FILE_RANDOM_ACCESS | FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0); if( !NT_SUCCESS( status )) { KdPrint(("[FindOriAddress] open error\n")); KdPrint(("[FindOriAddress] status = 0x%x\n", status)); ZwClose( hFile ); return 0; } status = ZwReadFile( hFile, NULL, NULL, NULL, NULL, &address, sizeof(ULONG), &offset, NULL); if( !NT_SUCCESS( status )) { KdPrint(("[FindOriAddress] read error\n")); KdPrint(("[FindOriAddress] status = 0x%x\n", status)); ZwClose( hFile ); return 0; } KdPrint(("[FindOriAddress] address:0x%x\n",address)); //重定位 address = BaseAddress - 0x00400000 + address; KdPrint(("[FindOriAddress] Oriaddress:0x%x\n",address)); //释放动态分配的内存 RtlFreeUnicodeString(&modulename); ZwClose( hFile ); return address; } /****************************************************************************************** * * 得到SSDT Shadow当前地址 * 1、KeServiceDescriptorTable - 0x40 + 0x10 * 2、搜索KeAddSystemServiceTable函数,特征码 * 3、Kthread->ServiceTable指向 * 4、MJ提出的搜索特定内存 * *******************************************************************************************/ //方式1,XP下-0x40; ULONG GetSSDTShadowAddress1() { ULONG address; ULONG ssdt; ssdt = (ULONG)KeServiceDescriptorTable; address = ssdt - 0x30; KdPrint(("[GetSSDTShadowAddress] ssdt:0x%x\n",ssdt)); KdPrint(("[GetSSDTShadowAddress] address:0x%x\n",address)); return address; } //方式2 ULONG GetSSDTShadowAddress2() { ULONG address; PUCHAR addr; PUCHAR p; addr = (PUCHAR)KeAddSystemServiceTable; for( p=addr; p<addr+PAGE_SIZE; p++) { if(*(PUSHORT)p == 0x888D) { address = *(PULONG)((ULONG)p+2); break; } } address = address + 0x10; KdPrint(("[GetSSDTShadowAddress] address:0x%x\n",address)); return address; } //方式3 ULONG GetSSDTShadowAddress3() { return 0; } //方式4 ULONG GetSSDTShadowAddress4() { return 0; } /********************************************************************************* * * 获得win32k.sys基址 * 1、ZwQuerySystemInformation * 2、遍历DriverSection链表 * **********************************************************************************/ ULONG GetWin32Base1() { NTSTATUS status; ULONG i; ULONG size; ULONG address; PSYSMODULELIST List; ZwQuerySystemInformation( SystemModuleInformation ,&size,0,&size); KdPrint(("[FindModuleByAddress] size:0x%x\n",size)); List=(PSYSMODULELIST)ExAllocatePool(NonPagedPool,size); if (List==NULL) { KdPrint(("[FindModuleByAddress] malloc memory failed\n")); ExFreePool( List ); return 0; } status=ZwQuerySystemInformation(SystemModuleInformation,List,size,0); if (!NT_SUCCESS(status)) { KdPrint(("[FindModuleByAddress] query failed\n")); //打印错误 KdPrint(("[FindModuleByAddress] status: 0x%x\n",status)); ExFreePool( List ); return 0; } for ( i=0; i < List->ulCount; i++ ) { if( strcmp(List->smi[i].ImageName,"\\SystemRoot\\System32\\win32k.sys") == 0) { KdPrint(("[GetWin32Base]name :%s\n",List->smi[i].ImageName)); address = (ULONG)List->smi[i].Base; KdPrint(("[GetWin32Base1] win32k.sys address:0x%x\n",address)); } } return address; } /********************************************************************************************* * * 驱动对象DRIVER_OBJECT中的DRIVER_SECTION * LDR_DATA_TABLE_ENTRY结构包含系统加载模块链表及基址 * * **********************************************************************************************/ ULONG GetWin32Base2( PDRIVER_OBJECT driver) { PLIST_ENTRY pList = NULL; PLDR_DATA_TABLE_ENTRY pLdr = NULL; ULONG BaseAddress = 0; pList = ( (PLIST_ENTRY)driver->DriverSection )->Flink; do { pLdr = CONTAINING_RECORD( pList, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks ); if( pLdr->EntryPoint != NULL && pLdr->FullDllName.Buffer!= NULL ) { if( !_wcsicmp( pLdr->FullDllName.Buffer, L"\\SystemRoot\\System32\\win32k.sys")) { BaseAddress = (ULONG )pLdr->DllBase; KdPrint(("[GetWin32Base2] win32k.sys address:0x%x\n",BaseAddress)); break ; } } pList = pList->Flink; }while( pList != ((PLIST_ENTRY)driver->DriverSection)->Flink ); return BaseAddress; } /**************************************************************************************** * * 根据传入的服务号得到Shadow 函数原始地址 * ****************************************************************************************/ ULONG FindShadowOriAddress( ULONG index ) { //内核文件win32k.sys基地址 //得到SSDT Shadow表的地址 //得到文件偏移 NTSTATUS status; ULONG size; ULONG BaseAddress; ULONG ShadowBase; ULONG ShadowAddress; ULONG SsdtRva; ULONG FileOffset = 0; UNICODE_STRING modulename; OBJECT_ATTRIBUTES object_attributes; IO_STATUS_BLOCK io_status = {0}; HANDLE hFile; //读取的位置 ULONG location; LARGE_INTEGER offset; ULONG address; BaseAddress = GetWin32Base1(); KdPrint(("[FindShadowOriAddress] BaseAddress:0x%x\n",BaseAddress)); //经验证地址正确 ShadowBase = GetSSDTShadowAddress2(); ShadowAddress = *(PULONG)ShadowBase; KdPrint(("[FindShadowOriAddress] ShadowAddress:0x%x\n",ShadowAddress)); //得到SSDT表的Rva SsdtRva = ShadowAddress - BaseAddress; //验证 KdPrint(("[FindOriAddress] SsdtRva:0x%x\n",SsdtRva)); //读取的位置 location = SsdtRva + index * 4; offset.QuadPart =location; KdPrint(("[FindOriAddress] location:0x%x\n",location)); //利用ZwReadFile读取文件 //初始化OBJECT_ATTRIBUTES结构 RtlInitUnicodeString(&modulename, L"\\SystemRoot\\system32\\win32k.sys"); InitializeObjectAttributes( &object_attributes, &modulename, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL); //打开文件 status = ZwCreateFile( &hFile, FILE_EXECUTE | SYNCHRONIZE, &object_attributes, &io_status, NULL, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ, FILE_OPEN, FILE_NON_DIRECTORY_FILE | FILE_RANDOM_ACCESS | FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0); if( !NT_SUCCESS( status )) { KdPrint(("[FindOriAddress] open error\n")); KdPrint(("[FindOriAddress] status = 0x%x\n", status)); ZwClose( hFile ); return 0; } status = ZwReadFile( hFile, NULL, NULL, NULL, NULL, &address, sizeof(ULONG), &offset, NULL); if( !NT_SUCCESS( status )) { KdPrint(("[FindOriAddress] read error\n")); KdPrint(("[FindOriAddress] status = 0x%x\n", status)); ZwClose( hFile ); return 0; } KdPrint(("[FindOriAddress] address:0x%x\n",address)); address = address; KdPrint(("[FindOriAddress] Oriaddress:0x%x\n",address)); ZwClose( hFile ); return address; }