百度上比较好的解释是:SSDT的全称是System Services Descriptor Table,系统服务描述符表。这个表就是一个把ring3的Win32 API和ring0的内核API联系起来。SSDT并不仅仅只包含一个庞大的地址索引表,它还包含着一些其它有用的信息,诸如地址索引的基地址、服务函数个数等。
说白了,SSDT就是把系统两个不同级别的函数给关联起来,因为为了安全需要,我们平常所使用的API函数基本都是在ring3下的函数,ring3的级别比较低,但是有些涉及到系统底层的函数怎么办呢?Windows就给出一个SSDT表,把ring3和ring0的函数给关联起来,这样,我们就通过使用ring3的函数就可以直接做一些底层操作了。
好吧,既然有这个东西,谁最关心呢?当然是杀毒软件最关心了,因为为了阻止某些病毒不让他破坏系统的底层,杀毒软件会把SSDT中的地址给修改并转向,这样,当病毒或程序调用这些函数的时候,就无法找到真正的对应函数,从而调用失败。
不过这玩意已经没有什么神秘的了,道高一尺魔高一丈,现在的病毒已经可以绕过SSDT去直接调用底层函数了,或者说可以找出底层函数的真实地址了,这里,我们就简单利用KeServiceDescriptorTable这个函数来读取系统的SSDT表吧。
完整代码如下:
001.#include "stdafx.h" 002.#include <windows.h> 003.#include <iostream> 004.using namespace std; 005. 006.#define RVATOVA(base,offset) ((PVOID)((DWORD)(base)+(DWORD)(offset))) 007.#define ibaseDD *(PDWORD)&ibase 008.#define STATUS_INFO_LENGTH_MISMATCH ((NTSTATUS)0xC0000004L) 009.#define NT_SUCCESS(Status) ((NTSTATUS)(Status) >= 0) 010. 011. 012.typedef struct { 013. WORD offset:12; 014. WORD type:4; 015.} IMAGE_FIXUP_ENTRY, *PIMAGE_FIXUP_ENTRY; 016. 017. 018.typedef LONG NTSTATUS; 019. 020.long ( __stdcall *NtQuerySystemInformation )( DWORD, PVOID, DWORD, DWORD ); 021. 022.typedef struct _SYSTEM_MODULE_INFORMATION {//Information Class 11 023. ULONG Reserved[2]; 024. PVOID Base; 025. ULONG Size; 026. ULONG Flags; 027. USHORT Index; 028. USHORT Unknown; 029. USHORT LoadCount; 030. USHORT ModuleNameOffset; 031. CHAR ImageName[256]; 032.}SYSTEM_MODULE_INFORMATION,*PSYSTEM_MODULE_INFORMATION; 033. 034.typedef struct { 035. DWORD dwNumberOfModules; 036. SYSTEM_MODULE_INFORMATION smi; 037.} MODULES, *PMODULES; 038. 039.#define SystemModuleInformation 11 040. 041. 042. 043. 044.DWORD GetHeaders(PCHAR ibase, 045. PIMAGE_FILE_HEADER *pfh, 046. PIMAGE_OPTIONAL_HEADER *poh, 047. PIMAGE_SECTION_HEADER *psh) 048. 049.{ 050. PIMAGE_DOS_HEADER mzhead=(PIMAGE_DOS_HEADER)ibase; 051. 052. if ((mzhead->e_magic!=IMAGE_DOS_SIGNATURE) || 053. (ibaseDD[mzhead->e_lfanew]!=IMAGE_NT_SIGNATURE)) 054. return FALSE; 055. 056. *pfh=(PIMAGE_FILE_HEADER)&ibase[mzhead->e_lfanew]; 057. if (((PIMAGE_NT_HEADERS)*pfh)->Signature!=IMAGE_NT_SIGNATURE) 058. return FALSE; 059. *pfh=(PIMAGE_FILE_HEADER)((PBYTE)*pfh+sizeof(IMAGE_NT_SIGNATURE)); 060. 061. *poh=(PIMAGE_OPTIONAL_HEADER)((PBYTE)*pfh+sizeof(IMAGE_FILE_HEADER)); 062. if ((*poh)->Magic!=IMAGE_NT_OPTIONAL_HDR32_MAGIC) 063. return FALSE; 064. 065. *psh=(PIMAGE_SECTION_HEADER)((PBYTE)*poh+sizeof(IMAGE_OPTIONAL_HEADER)); 066. return TRUE; 067.} 068. 069. 070.DWORD FindKiServiceTable(HMODULE hModule,DWORD dwKSDT) 071.{ 072. PIMAGE_FILE_HEADER pfh; 073. PIMAGE_OPTIONAL_HEADER poh; 074. PIMAGE_SECTION_HEADER psh; 075. PIMAGE_BASE_RELOCATION pbr; 076. PIMAGE_FIXUP_ENTRY pfe; 077. 078. DWORD dwFixups=0,i,dwPointerRva,dwPointsToRva,dwKiServiceTable; 079. BOOL bFirstChunk; 080. 081. GetHeaders((char *)hModule,&pfh,&poh,&psh); 082. 083. // loop thru relocs to speed up the search 084. if ((poh->DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress) && 085. (!((pfh->Characteristics)&IMAGE_FILE_RELOCS_STRIPPED))) { 086. 087. pbr=(PIMAGE_BASE_RELOCATION)RVATOVA(poh->DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress,hModule); 088. 089. bFirstChunk=TRUE; 090. // 1st IMAGE_BASE_RELOCATION.VirtualAddress of ntoskrnl is 0 091. while (bFirstChunk || pbr->VirtualAddress) { 092. bFirstChunk=FALSE; 093. 094. pfe=(PIMAGE_FIXUP_ENTRY)((DWORD)pbr+sizeof(IMAGE_BASE_RELOCATION)); 095. 096. for (i=0;i<(pbr->SizeOfBlock-sizeof(IMAGE_BASE_RELOCATION))>>1;i++,pfe++) { 097. if (pfe->type==IMAGE_REL_BASED_HIGHLOW) { 098. dwFixups++; 099. dwPointerRva=pbr->VirtualAddress+pfe->offset; 100. // DONT_RESOLVE_DLL_REFERENCES flag means relocs aren't fixed 101. dwPointsToRva=*(PDWORD)((DWORD)hModule+dwPointerRva)-(DWORD)poh->ImageBase; 102. 103. // does this reloc point to KeServiceDescriptorTable.Base? 104. if (dwPointsToRva==dwKSDT) { 105. // check for mov [mem32],imm32. we are trying to find 106. // "mov ds:_KeServiceDescriptorTable.Base, offset _KiServiceTable" 107. // from the KiInitSystem. 108. if (*(PWORD)((DWORD)hModule+dwPointerRva-2)==0x05c7) { 109. // should check for a reloc presence on KiServiceTable here 110. // but forget it 111. dwKiServiceTable=*(PDWORD)((DWORD)hModule+dwPointerRva+4)-poh->ImageBase; 112. return dwKiServiceTable; 113. } 114. } 115. 116. } 117. } 118. *(PDWORD)&pbr+=pbr->SizeOfBlock; 119. } 120. } 121. 122. 123. 124. return 0; 125.} 126. 127. 128.int EnumSSDT() 129.{ 130. HMODULE hKernel; 131. DWORD dwKSDT; // rva of KeServiceDescriptorTable 132. DWORD dwKiServiceTable; // rva of KiServiceTable 133. PMODULES pModules=(PMODULES)&pModules; 134. DWORD dwNeededSize,rc; 135. DWORD dwKernelBase,dwServices=0; 136. PCHAR pKernelName; 137. PDWORD pService; 138. PIMAGE_FILE_HEADER pfh; 139. PIMAGE_OPTIONAL_HEADER poh; 140. PIMAGE_SECTION_HEADER psh; 141. NtQuerySystemInformation = (long(__stdcall*)(DWORD,PVOID,DWORD,DWORD))GetProcAddress( GetModuleHandle( "ntdll.dll" ),"NtQuerySystemInformation" ); 142. //通过NtQuerySystemInformation取得系统内核文件,判断为是ntoskrnl.exe ntkrnlmp.exe ntkrnlpa.exe 143. rc=NtQuerySystemInformation(SystemModuleInformation,pModules,4,(ULONG)&dwNeededSize); 144. if (rc==STATUS_INFO_LENGTH_MISMATCH) //如果内存不够 145. { 146. pModules=(PMODULES)GlobalAlloc(GPTR,dwNeededSize) ; //重新分配内存 147. rc=NtQuerySystemInformation(SystemModuleInformation,pModules,dwNeededSize,NULL); //系统内核文件是总是在第一个,枚举1次 148. } 149. 150. if (!NT_SUCCESS(rc)) 151. { 152. cout << "NtQuerySystemInformation() Failed !\n"; //NtQuerySystemInformation执行失败,检查当前进程权限 153. return 0; 154. } 155. 156. dwKernelBase=(DWORD)pModules->smi.Base; // imagebase 157. pKernelName=pModules->smi.ModuleNameOffset+pModules->smi.ImageName; 158. hKernel=LoadLibraryEx(pKernelName,0,DONT_RESOLVE_DLL_REFERENCES); // 映射ntoskrnl //高 159. if (!hKernel) 160. { 161. cout << "Failed to load \n"; 162. return 0; 163. } 164. GlobalFree(pModules); 165. if (!(dwKSDT=(DWORD)GetProcAddress(hKernel,"KeServiceDescriptorTable"))) //在内核文件中查找KeServiceDescriptorTable地址 166. { 167. cout << "Can't find KeServiceDescriptorTable\n"; 168. return 0; 169. } 170. 171. dwKSDT-=(DWORD)hKernel; // 获取 KeServiceDescriptorTable RVA 172. if (!(dwKiServiceTable=FindKiServiceTable(hKernel,dwKSDT))) // 获取KiServiceTable地址 173. { 174. cout << "Can't find KiServiceTable...\n"; 175. return 0; 176. } 177. 178. GetHeaders((char *)hKernel,&pfh,&poh,&psh); 179. 180. int dwIndex=0; 181. for (pService=(PDWORD)((DWORD)hKernel+dwKiServiceTable); 182. *pService-poh->ImageBase<poh->SizeOfImage; 183. pService++,dwServices++,dwIndex++) 184. { 185. printf("0x%03X-0x%08X\n",dwIndex,*pService-poh->ImageBase+dwKernelBase); //SSDT索引和地址 186. } 187. FreeLibrary(hKernel); 188. return 1; 189.} 190. 191. 192. 193.int main() 194.{ 195. EnumSSDT(); 196. 197. system("pause"); 198. return 0; 199.}
浙公网安备 33010602011771号