关于SSDT

简介: <p>百度上比较好的解释是:SSDT的全称是System Services Descriptor Table,系统服务描述符表。这个表就是一个把ring3的Win32 API和ring0的内核API联系起来。SSDT并不仅仅只包含一个庞大的地址索引表,它还包含着一些其它有用的信息,诸如地址索引的基地址、服务函数个数等。</p> <p>        说白了,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. }
 
相关文章
|
关系型数据库 Windows
驱动开发:内核读取SSDT表基址
在前面的章节`《X86驱动:挂接SSDT内核钩子》`我们通过代码的方式直接读取 `KeServiceDescriptorTable` 这个被导出的表结构从而可以直接读取到SSDT表的基址,而在Win64系统中 `KeServiceDescriptorTable` 这个表并没有被导出,所以我们必须手动搜索到它的地址。
236 0
驱动开发:内核读取SSDT表基址
|
定位技术 Windows
驱动开发:Win10内核枚举SSDT表基址
三年前面朝黄土背朝天的我,写了一篇如何在`Windows 7`系统下枚举内核`SSDT`表的文章`《驱动开发:内核读取SSDT表基址》`三年过去了我还是个`单身狗`,开个玩笑,微软的`Windows 10`系统已经覆盖了大多数个人PC终端,以前的方法也该进行迭代更新了,或许在网上你能够找到类似的文章,但我可以百分百肯定都不能用,今天`LyShark`将带大家一起分析`Win10 x64`最新系统`SSDT`表的枚举实现。
331 0
驱动开发:Win10内核枚举SSDT表基址
驱动开发:WinDBG 枚举SSDT以及SSSDT地址
在前面的博文`《驱动开发:内核读取SSDT表基址》`中已经教大家如何寻找`SSDT`表基地址了,今天给大家分享两个适用于`WinDBG`调试器上的脚本文件,该脚本文件可以很好的枚举出当前系统内的`SSDT`以及`SSSDT`表中的数据,可以方便后续文章的学习参考之用,当然脚本不是我写的,文章末尾我会给出参考原文链接。
304 0
驱动开发:WinDBG 枚举SSDT以及SSSDT地址
驱动开发:Win10枚举完整SSDT地址表
在前面的博文`《驱动开发:Win10内核枚举SSDT表基址》`中已经教大家如何寻找`SSDT`表基地址了,找到后我们可根据序号获取到指定`SSDT`函数的原始地址,而如果需要输出所有`SSDT`表信息,则可以定义字符串列表,以此循环调用`GetSSDTFunctionAddress()`函数得到,当然在此之间也可以调用系统提供的`MmGetSystemRoutineAddress()`函数顺便把当前地址拿到,并通过循环方式得到完整的SSDT列表。
336 0
驱动开发:Win10枚举完整SSDT地址表
|
监控 编译器 API
驱动开发:挂接SSDT内核钩子
SSDT 中文名称为系统服务描述符表,该表的作用是将Ring3应用层与Ring0内核层,两者的API函数连接起来,起到承上启下的作用,SSDT并不仅仅只包含一个庞大的地址索引表,它还包含着一些其它有用的信息,诸如地址索引的基址、服务函数个数等,SSDT 通过修改此表的函数地址可以对常用 Windows 函数进行内核级的Hook,从而实现对一些核心的系统动作进行过滤、监控的目的,接下来将演示如何通过编写简单的驱动程序,来实现搜索 SSDT 函数的地址,并能够实现简单的内核 Hook 挂钩。
319 0
|
Linux
自制操作系统Antz day02——进入保护模式 (上) jmp到保护模式
最近在看操作系统底层方面的东西,最开始的为什么是07c00h这个问题就让我对操作系统有了很大的兴趣。所以准备在看书之余顺便写一个操作系统(Anz)。至于为什么这个系统会被叫做Antz,可以参考Antz Uhl Kone, 日语为アインズ·ウール·ゴウン , 与之对应的还有接下来准备写的自制脚本语言A.
1452 0