77范文网 - 专业文章范例文档资料分享平台

恢复在WIN64上的SSDT钩子

来源:网络收集 时间:2020-08-23 下载这篇文档 手机版
说明:文章内容仅供预览,部分内容可能不全,需要完整文档或者需要复制内容,请下载word后使用。下载word有问题请添加微信号:或QQ: 处理(尽可能给您提供完整文档),感谢您的支持与谅解。点击这里给我发消息

恢复在WIN64上的SSDT钩子

在上一篇文章里我描述了如何在 Win64 系统上实现 SSDT HOOK,有 SSDT HOOK,自然也 有UNHOOK SSDT的方法,现在我就来讲一下如何实现UNHOOK SSDT。

要恢复 SSDT,首先要获得 SSDT 各个函数的原始地址,而 SSDT 各个函数的原始地址, 自然是存储在内核文件里的。于是,有了以下思路:

1.获得内核里KiServiceTable的地址(变量名称:KiServiceTable) 2.获得内核文件在内核里的加载地址(变量名称:NtosBase)

3.获得内核文件在PE32+结构体里的映像基址(变量名称:NtosImageBase) 4.在自身进程里加载内核文件并取得映射地址(变量名称:NtosInProcess) 5.计算出KiServiceTable和NtosBase之间的“距离”(变量名称:RVA)

6.获得指定INDEX 函数的地址(计算公式: *(PULONGLONG)(NtosInProcess + RVA + 8 * index) - NtosImageBase + NtosBase)

思路和 WIN32 下获得 SSDT 函数原始地址差异不大,接下来解释一下第六步的计算公式 是怎么得来的。首先看一张IDA的截图:

可见,从文件中的KiServiceTable 地址开始,每8 个字节,存储一个函数的“理想地

址”(之所以说是理想地址,是因为这个地址是基于『内核文件的映像基址NtosImageBase』 的,而不是基于『内核文件的加载基址 NtosBase』的)。因此,得到 8 * index。由于已经 获得了 KiServiceTable和 NtosBase之间的“距离”(RVA = KiServiceTable - NtosBase), 也已知内核文件在自身进程里的映射地址(NtosInProcess),所以就能算出文件中的 KiServiceTable 的地址(NtosInProcess + RVA)。所以,存储各个函数原始地址的文件地 址就是:NtosInProcess + RVA + 8 * index。把这个地址的值取出来(长度为8),就是: *(PULONGLONG)(NtosInProcess + RVA + 8 * index)。前面说了,由于得到的这个函数地

址是理想地址,因为它假设的加载基址是 PE32+结构体里的成员 ImageBase(映像基址)的 值。而实际上,内核文件的加载基址肯定不可能是这个值,所以还要减去内核文件的映像基

址(NtosImageBase)再加上内核文件的实际加载基址(NtosBase)。接下来,给出每一步的 具体实现过程的代码。

1.获得 KiServiceTable的地址

毫无疑问,这个必须在驱动里实现了。首先看一个结构体: typedef struct _System_Service_Table{ PVOID ServiceTableBase;

PVOID ServiceCounterTableBase; ULONG64 NumberOfServices; PVOID ParamTableBase;

} SYSTEM_SERVICE_TABLE, *PSYSTEM_SERVICE_TABLE;

这个结构体大家都很熟悉吧,只不过在 WIN64 下这个结构体胖了一倍,从 16 字节变成 了 32 字节。但很多性质都没变,获得 KeServiceDescriptorTable 的地址后,把

KeServiceDescriptorTable 的地址强制转化为此结构体的结构体指针,则此结构体的第一 项ServiceTableBase就是 KiServiceTable的地址。实际上写代码比描述得还简单,仅仅两 行(GetKeServiceDescriptorTable64 的代码已经在以前上解释过,这里不再赘 述):

ULONGLONG GetKeServiceDescriptorTable64() {

char KiSystemServiceStart_pattern[13] =

\ ULONGLONG CodeScanStart = (ULONGLONG)&_strnicmp;

ULONGLONG CodeScanEnd = (ULONGLONG)&KdDebuggerNotPresent; UNICODE_STRING Symbol; ULONGLONG i, tbl_address, b;

for (i = 0; i < CodeScanEnd - CodeScanStart; i++) {

if (!memcmp((char*)(ULONGLONG)CodeScanStart +i, (char*)KiSystemServiceStart_pattern,13)) {

for (b = 0; b < 50; b++) {

tbl_address = ((ULONGLONG)CodeScanStart+i+b);

if (*(USHORT*) ((ULONGLONG)tbl_address ) == (USHORT)0x8d4c) return ((LONGLONG)tbl_address +7) + *(LONG*)(tbl_address +3); }

} }

return 0; }

ULONG64 ssdt_base_aadress=GetKeServiceDescriptorTable64(); KiServiceTable=*(PULONGLONG)ssdt_base_aadress; 2.获得内核文件在内核里的加载地址

这个本质上属于枚举内核模块,使用 ZwQuerySystemInformation 的

SystemModuleInformation 功能号实现。由于第一个加载的总是内核文件,所以直接获得 0 号模块的基址即可。另外,还要获得内核文件的名称,因为根据CPU核心数目等硬件条件的 不同,内核文件的名称也是不尽相同的。

ULONGLONG GetNtosBaseAndPath(char *ModuleName) {

ULONG NeedSize, i, ModuleCount, BufferSize = 0x5000; PVOID pBuffer = NULL; ULONGLONG qwBase = 0; NTSTATUS Result;

PSYSTEM_MODULE_INFORMATION pSystemModuleInformation; do {

pBuffer = malloc( BufferSize ); if( pBuffer == NULL ) {

return FALSE; }

Result = ZwQuerySystemInformation( SystemModuleInformation, pBuffer, BufferSize, &NeedSize );

if( Result == STATUS_INFO_LENGTH_MISMATCH ) {

free( pBuffer ); BufferSize *= 2; }

else if( !NT_SUCCESS(Result) ) {

free( pBuffer ); return FALSE;

} }

while( Result == STATUS_INFO_LENGTH_MISMATCH );

pSystemModuleInformation = (PSYSTEM_MODULE_INFORMATION)pBuffer; if(ModuleName!=NULL)

strcpy(ModuleName,pSystemModuleInformation->Module[0].ImageName+pSystemM oduleInformation->Module[0].ModuleNameOffset);

qwBase=(ULONGLONG)pSystemModuleInformation->Module[0].Base; free(pBuffer); return qwBase; }

3.获得内核文件的映像基址

这个直接解析PE32+文件的结构即可,关于PE32+格式的详细内容,请见《初步探索PE32+ 格式文件》。 DWORD FileLen(char *filename) {

WIN32_FIND_DATAA fileInfo={0}; DWORD fileSize=0; HANDLE hFind;

hFind = FindFirstFileA(filename ,&fileInfo); if(hFind != INVALID_HANDLE_VALUE) {

fileSize = fileInfo.nFileSizeLow; FindClose(hFind); }

return fileSize; }

CHAR *LoadDllContext(char *filename) {

DWORD dwReadWrite, LenOfFile=FileLen(filename);

HANDLE hFile = CreateFileA(filename, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_EXISTING, 0, 0); if (hFile != INVALID_HANDLE_VALUE) {

PCHAR buffer=(PCHAR)malloc(LenOfFile); SetFilePointer(hFile, 0, 0, FILE_BEGIN);

ReadFile(hFile, buffer, LenOfFile, &dwReadWrite, 0); CloseHandle(hFile); return buffer; }

return NULL; }

VOID GetNtosImageBase() {

PIMAGE_NT_HEADERS64 pinths64; PIMAGE_DOS_HEADER pdih; char *NtosFileData=NULL;

NtosFileData=LoadDllContext(NtosName); pdih=(PIMAGE_DOS_HEADER)NtosFileData;

pinths64=(PIMAGE_NT_HEADERS64)(NtosFileData+pdih->e_lfanew); NtosImageBase=pinths64->OptionalHeader.ImageBase; printf(\}

4/5/6.获得SSDT 函数的原始地址

原理已经在前面解释过,这里直接给出代码。

ULONGLONG GetFunctionOriginalAddress(DWORD index) {

if ( NtosInProcess==0 )

NtosInProcess = (ULONGLONG)LoadLibraryExA(NtosName,0, DONT_RESOLVE_DLL_REFERENCES);

ULONGLONG RVA=KiServiceTable-NtosBase;

ULONGLONG temp=*(PULONGLONG)(NtosInProcess+RVA+8*(ULONGLONG)index); ULONGLONG RVA_index=temp-NtosImageBase; return RVA_index+NtosBase; }

接下来测试一下效果,在测试前,运行 SSDT HOOK NtTerminateProcess 的 DEMO(检测 出了 SSDT的异常项)。

百度搜索“77cn”或“免费范文网”即可找到本站免费阅读全部范文。收藏本站方便下次阅读,免费范文网,提供经典小说教育文库恢复在WIN64上的SSDT钩子在线全文阅读。

恢复在WIN64上的SSDT钩子.doc 将本文的Word文档下载到电脑,方便复制、编辑、收藏和打印 下载失败或者文档不完整,请联系客服人员解决!
本文链接:https://www.77cn.com.cn/wenku/jiaoyu/1144792.html(转载请注明文章来源)
Copyright © 2008-2022 免费范文网 版权所有
声明 :本网站尊重并保护知识产权,根据《信息网络传播权保护条例》,如果我们转载的作品侵犯了您的权利,请在一个月内通知我们,我们会及时删除。
客服QQ: 邮箱:tiandhx2@hotmail.com
苏ICP备16052595号-18
× 注册会员免费下载(下载后可以自由复制和排版)
注册会员下载
全站内容免费自由复制
注册会员下载
全站内容免费自由复制
注:下载文档有可能“只有目录或者内容不全”等情况,请下载之前注意辨别,如果您已付费且无法下载或内容有问题,请联系我们协助你处理。
微信: QQ: