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