829
技術社區[雲棲]
關於SSDT
百度上比較好的解釋是: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.usingnamespace
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.typedefstruct
{
013. WORD offset:12;
014. WORD type:4;
015.} IMAGE_FIXUP_ENTRY, *PIMAGE_FIXUP_ENTRY;
016.
017.
018.typedefLONG
NTSTATUS;
019.
020.long( __stdcall *NtQuerySystemInformation )(
DWORD,PVOID,
DWORD,DWORD
);
021.
022.typedefstruct
_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.typedefstruct
{
035. DWORD dwNumberOfModules;
036. SYSTEM_MODULE_INFORMATION smi;
037.} MODULES, *PMODULES;
038.
039.#define SystemModuleInformation 11
040.
041.
042.
043.
044.DWORDGetHeaders(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. returnFALSE;
055.
056. *pfh=(PIMAGE_FILE_HEADER)&ibase[mzhead->e_lfanew];
057. if(((PIMAGE_NT_HEADERS)*pfh)->Signature!=IMAGE_NT_SIGNATURE)
058. returnFALSE;
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. returnFALSE;
064.
065. *psh=(PIMAGE_SECTION_HEADER)((PBYTE)*poh+sizeof(IMAGE_OPTIONAL_HEADER));
066. returnTRUE;
067.}
068.
069.
070.DWORDFindKiServiceTable(HMODULEhModule,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. returndwKiServiceTable;
113. }
114. }
115.
116. }
117. }
118. *(PDWORD)&pbr+=pbr->SizeOfBlock;
119. }
120. }
121.
122.
123.
124. return0;
125.}
126.
127.
128.intEnumSSDT()
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. return0;
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. return0;
163. }
164. GlobalFree(pModules);
165. if(!(dwKSDT=(DWORD)GetProcAddress(hKernel,"KeServiceDescriptorTable")))//在內核文件中查找KeServiceDescriptorTable地址
166. {
167. cout <<"Can't find KeServiceDescriptorTable\n";
168. return0;
169. }
170.
171. dwKSDT-=(DWORD)hKernel; //
獲取 KeServiceDescriptorTable RVA
172. if(!(dwKiServiceTable=FindKiServiceTable(hKernel,dwKSDT)))
// 獲取KiServiceTable地址
173. {
174. cout <<"Can't find KiServiceTable...\n";
175. return0;
176. }
177.
178. GetHeaders((char*)hKernel,&pfh,&poh,&psh);
179.
180. intdwIndex=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. return1;
189.}
190.
191.
192.
193.intmain()
194.{
195. EnumSSDT();
196.
197. system("pause");
198. return0;
199.}
最後更新:2017-04-03 15:21:51