VC++实现恢复SSDT
SSDT(System Services Descriptor Table),系统服务描述符表。这个表就是一个把ring3的Win32 API和ring0的内核API联系起来。SSDT并不仅仅只包含一个庞大的地址索引表,它还包含着一些其它有用的信息,诸如地址索引的基地址、服务函数个数等。
通过修改此表的函数地址可以对常用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"#endiftypedef enum _SYSTEM_INFORMATION_CLASS{SystemBasicInformation, // 0 SystemProcessorInformation, // 1 SystemPerformanceInformation, // 2SystemTimeOfDayInformation, // 3SystemNotImplemented1, // 4SystemProcessesAndThreadsInformation, // 5SystemCallCounts, // 6SystemConfigurationInformation, // 7SystemProcessorTimes, // 8SystemGlobalFlag, // 9SystemNotImplemented2, // 10SystemModuleInformation, // 11 系统模块SystemLockInformation, // 12SystemNotImplemented3, // 13SystemNotImplemented4, // 14SystemNotImplemented5, // 15SystemHandleInformation, // 16SystemObjectInformation, // 17SystemPagefileInformation, // 18SystemInstructionEmulationCounts, // 19SystemInvalidInfoClass1, // 20SystemCacheInformation, // 21SystemPoolTagInformation, // 22SystemProcessorStatistics, // 23SystemDpcInformation, // 24SystemNotImplemented6, // 25SystemLoadImage, // 26SystemUnloadImage, // 27SystemTimeAdjustment, // 28SystemNotImplemented7, // 29SystemNotImplemented8, // 30SystemNotImplemented9, // 31SystemCrashDumpInformation, // 32SystemExceptionInformation, // 33SystemCrashDumpStateInformation, // 34SystemKernelDebuggerInformation, // 35SystemContextSwitchInformation, // 36SystemRegistryQuotaInformation, // 37SystemLoadAndCallImage, // 38SystemPrioritySeparation, // 39SystemNotImplemented10, // 40SystemNotImplemented11, // 41SystemInvalidInfoClass2, // 42SystemInvalidInfoClass3, // 43SystemTimeZoneInformation, // 44SystemLookasideInformation, // 45SystemSetTimeSlipEvent, // 46SystemCreateSession, // 47SystemDeleteSession, // 48SystemInvalidInfoClass4, // 49SystemRangeStartInformation, // 50SystemVerifierInformation, // 51SystemAddVerifier, // 52SystemSessionProcessesInformation // 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 NTSTATUSZwQuerySystemInformation( 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表的RvaSsdtRva = (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;}//方式2ULONG 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;}//方式3ULONG GetSSDTShadowAddress3(){return 0;}//方式4ULONG 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表的RvaSsdtRva = 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;}