欢迎访问 生活随笔!

生活随笔

当前位置: 首页 > 编程资源 > 编程问答 >内容正文

编程问答

Win64 驱动内核编程-18.SSDT

发布时间:2025/6/17 编程问答 6 豆豆
生活随笔 收集整理的这篇文章主要介绍了 Win64 驱动内核编程-18.SSDT 小编觉得挺不错的,现在分享给大家,帮大家做个参考.

SSDT

 学习资料:http://blog.csdn.net/zfdyq0/article/details/26515019

 学习资料:WIN64内核编程基础 胡文亮

 

   SSDT(系统服务描述表),刚开始接触什么进程保护XXX啥的,都是看到在说SSDT(虽然说目前很多杀软都已经采用稳定简单的回调姿势了)。这次就弄清楚两个问题:

    如何在内核里动态获得 SSDT 的基址;

如何在内核里动态获得 SSDT 函数的地址;

    在 WIN32 下,第一个问题就根本不是问题,因为 KeServiceDescriptorTable 直接被导

出了。但是 WIN64 下 KeServiceDescriptorTable 没有被导出。所以必须搜索得到它的地址。

反汇编:uf KisystemCall64


    上面看到,貌似直接反汇编uf KiSystemServiceRepeat 试了下,一样可以找到SSDT基址,但是问题是,KiSystemServiceRepeat这个东西的地址找不到,而KiSystemCall64的地址直接可以直接读取指定的 msr 得出。

通过读取 C0000082 寄存器,能够得到 KiSystemCall64 的地址,然后从

KiSystemCall64 的地址开始,往下搜索 0x500 字节左右(特征码是 4c8d15),就能得到

KeServiceDescriptorTable 的地址了。同理,我们换一下特征码(4c8d1d),就能获得

KeServiceDescriptorTableShadow 的地址了。


然后是资料里面带的两个SSDT基址的函数:

    方法1(这个方法蓝屏了,我直接用的方法2)

ULONGLONG GetKeServiceDescriptorTable64() { char KiSystemServiceStart_pattern[13] = "\x8B\xF8\xC1\xEF\x07\x83\xE7\x20\x25\xFF\x0F\x00\x00"; 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; }方法2

ULONGLONG MyGetKeServiceDescriptorTable64() { PUCHAR StartSearchAddress = (PUCHAR)__readmsr(0xC0000082);PUCHAR EndSearchAddress = StartSearchAddress + 0x500; PUCHAR i = NULL; UCHAR b1=0,b2=0,b3=0; ULONG templong=0; ULONGLONG addr=0; for(i=StartSearchAddress;i<EndSearchAddress;i++) { if( MmIsAddressValid(i) && MmIsAddressValid(i+1) && MmIsAddressValid(i+2) ) { b1=*i; b2=*(i+1); b3=*(i+2); if( b1==0x4c && b2==0x8d && b3==0x15 ) //4c8d15 { memcpy(&templong,i+3,4); addr = (ULONGLONG)templong + (ULONGLONG)i + 7; return addr; } } } return 0; }

    接下来就是讲述 SSDT 函数地址了。在获得地址之前,需要知道 SSDT 函数的 INDEX。获得这个 INDEX 的方法很简单,直接在 RING3 读取 NTDLL 的内容即可。使用 WINDBG 的方法如下:随便创建一个进程,然后使用 WINDBG 附加:


    可以看到两次反汇编的结果几乎完全相同,唯一不同的地方是第二句。XXh 就是此函数的 index。知道 INDEX 之后,就可以计算地址了(资料上也是给了两个方法,建议使用方法2)。

方法1

VOID Initxxxx() { UCHAR strShellCode[36]="\x48\x8B\xC1\x4C\x8D\x12\x8B\xF8\xC1\xEF\x07\x83\xE7\x20\x4E\x8B\x14\x17\x4D\x63\x1C\x82\x49\x8B\xC3\x49\xC1\xFB\x04\x4D\x03\xD3\x49\x8B\xC2\xC3"; /* mov rax, rcx ;rcx=index lea r10,[rdx] ;rdx=ssdt mov edi,eax shr edi,7 and edi,20h mov r10, qword ptr [r10+rdi] movsxd r11,dword ptr [r10+rax*4] mov rax,r11 sar r11,4 add r10,r11 mov rax,r10 ret */ scfn=ExAllocatePool(NonPagedPool,36); memcpy(scfn,strShellCode,36); } ULONGLONG GetSSDTFunctionAddress64(ULONGLONG NtApiIndex) { ULONGLONG ret=0; ULONGLONG ssdt= MyGetKeServiceDescriptorTable64(); if(scfn==NULL) Initxxxx(); ret=scfn(NtApiIndex, ssdt); return ret; }
方法2

typedef struct _SYSTEM_SERVICE_TABLE{ PVOID ServiceTableBase; PVOID ServiceCounterTableBase; ULONGLONG NumberOfServices; PVOID ParamTableBase; } SYSTEM_SERVICE_TABLE, *PSYSTEM_SERVICE_TABLE;ULONGLONG GetSSDTFunctionAddress64_2(ULONGLONG Index) { LONG dwTemp=0; ULONGLONG qwTemp=0,stb=0,ret=0; PSYSTEM_SERVICE_TABLE ssdt=(PSYSTEM_SERVICE_TABLE)MyGetKeServiceDescriptorTable64(); stb=(ULONGLONG)(ssdt->ServiceTableBase); qwTemp = stb + 4 * Index; dwTemp = *(PLONG)qwTemp; dwTemp = dwTemp >> 4; ret = stb + (LONG64)dwTemp; return ret; }

    最后,总结一下 WIN32 和 WIN64 在 SSDT 方面的不同(我直接截图过来)。大家可以把 SSDT(其实 SHADOWSSDT 同理)想像成一排保险柜,每个柜子都有编号(从 开始),柜子的长度为四字节,每个柜子里都放了一个 LONG 数据。但不同的是,WIN32 的“柜子”里放的数据是某个函数的绝对地址,而 WIN64 的“柜子”里放的数据是某个函数的偏移地址。这个偏移地址要经过一定的计算才能变成绝对地址。


测试代码:

#include <ntddk.h> #include <windef.h> #include "MyDriver.h" #pragma intrinsic(__readmsr) typedef UINT64 (__fastcall *SCFN)(UINT64,UINT64); SCFN scfn;ULONGLONG MyGetKeServiceDescriptorTable64() { PUCHAR StartSearchAddress = (PUCHAR)__readmsr(0xC0000082);PUCHAR EndSearchAddress = StartSearchAddress + 0x500; PUCHAR i = NULL; UCHAR b1=0,b2=0,b3=0; ULONG templong=0; ULONGLONG addr=0; for(i=StartSearchAddress;i<EndSearchAddress;i++) { if( MmIsAddressValid(i) && MmIsAddressValid(i+1) && MmIsAddressValid(i+2) ) { b1=*i; b2=*(i+1); b3=*(i+2); if( b1==0x4c && b2==0x8d && b3==0x15 ) //4c8d15 { memcpy(&templong,i+3,4); addr = (ULONGLONG)templong + (ULONGLONG)i + 7; return addr; } } } return 0; }VOID Initxxxx() { UCHAR strShellCode[36]="\x48\x8B\xC1\x4C\x8D\x12\x8B\xF8\xC1\xEF\x07\x83\xE7\x20\x4E\x8B\x14\x17\x4D\x63\x1C\x82\x49\x8B\xC3\x49\xC1\xFB\x04\x4D\x03\xD3\x49\x8B\xC2\xC3"; /* mov rax, rcx ;rcx=index lea r10,[rdx] ;rdx=ssdt mov edi,eax shr edi,7 and edi,20h mov r10, qword ptr [r10+rdi] movsxd r11,dword ptr [r10+rax*4] mov rax,r11 sar r11,4 add r10,r11 mov rax,r10 ret */ scfn=ExAllocatePool(NonPagedPool,36); memcpy(scfn,strShellCode,36); }ULONGLONG GetSSDTFunctionAddress64(ULONGLONG NtApiIndex) { ULONGLONG ret=0; ULONGLONG ssdt= MyGetKeServiceDescriptorTable64(); if(scfn==NULL) Initxxxx(); ret=scfn(NtApiIndex, ssdt); return ret; }typedef struct _SYSTEM_SERVICE_TABLE{ PVOID ServiceTableBase; PVOID ServiceCounterTableBase; ULONGLONG NumberOfServices; PVOID ParamTableBase; } SYSTEM_SERVICE_TABLE, *PSYSTEM_SERVICE_TABLE;ULONGLONG GetSSDTFunctionAddress64_2(ULONGLONG Index) { LONG dwTemp=0; ULONGLONG qwTemp=0,stb=0,ret=0; PSYSTEM_SERVICE_TABLE ssdt=(PSYSTEM_SERVICE_TABLE)MyGetKeServiceDescriptorTable64(); stb=(ULONGLONG)(ssdt->ServiceTableBase); qwTemp = stb + 4 * Index; dwTemp = *(PLONG)qwTemp; dwTemp = dwTemp >> 4; ret = stb + (LONG64)dwTemp; return ret; }VOID DriverUnload(PDRIVER_OBJECT pDriverObj) { UNICODE_STRING strLink; RtlInitUnicodeString(&strLink, LINK_NAME); IoDeleteSymbolicLink(&strLink); IoDeleteDevice(pDriverObj->DeviceObject); }NTSTATUS DispatchCreate(PDEVICE_OBJECT pDevObj, PIRP pIrp) { pIrp->IoStatus.Status = STATUS_SUCCESS; pIrp->IoStatus.Information = 0; IoCompleteRequest(pIrp, IO_NO_INCREMENT); return STATUS_SUCCESS; }NTSTATUS DispatchClose(PDEVICE_OBJECT pDevObj, PIRP pIrp) { pIrp->IoStatus.Status = STATUS_SUCCESS; pIrp->IoStatus.Information = 0; IoCompleteRequest(pIrp, IO_NO_INCREMENT); return STATUS_SUCCESS; }NTSTATUS DispatchIoctl(PDEVICE_OBJECT pDevObj, PIRP pIrp) { NTSTATUS status = STATUS_INVALID_DEVICE_REQUEST; PIO_STACK_LOCATION pIrpStack; ULONG uIoControlCode; PVOID pIoBuffer; ULONG uInSize; ULONG uOutSize; pIrpStack = IoGetCurrentIrpStackLocation(pIrp); uIoControlCode = pIrpStack->Parameters.DeviceIoControl.IoControlCode; pIoBuffer = pIrp->AssociatedIrp.SystemBuffer; uInSize = pIrpStack->Parameters.DeviceIoControl.InputBufferLength; uOutSize = pIrpStack->Parameters.DeviceIoControl.OutputBufferLength; switch(uIoControlCode) { ; } if(status == STATUS_SUCCESS) pIrp->IoStatus.Information = uOutSize; else pIrp->IoStatus.Information = 0; pIrp->IoStatus.Status = status; IoCompleteRequest(pIrp, IO_NO_INCREMENT); return status; }NTSTATUS DriverEntry(PDRIVER_OBJECT pDriverObj, PUNICODE_STRING pRegistryString) { NTSTATUS status = STATUS_SUCCESS; UNICODE_STRING ustrLinkName; UNICODE_STRING ustrDevName; PDEVICE_OBJECT pDevObj; pDriverObj->MajorFunction[IRP_MJ_CREATE] = DispatchCreate; pDriverObj->MajorFunction[IRP_MJ_CLOSE] = DispatchClose; pDriverObj->MajorFunction[IRP_MJ_DEVICE_CONTROL] = DispatchIoctl; pDriverObj->DriverUnload = DriverUnload; RtlInitUnicodeString(&ustrDevName, DEVICE_NAME); status = IoCreateDevice(pDriverObj, 0, &ustrDevName, FILE_DEVICE_UNKNOWN, 0, FALSE, &pDevObj); if(!NT_SUCCESS(status)) return status; if(IoIsWdmVersionAvailable(1, 0x10)) RtlInitUnicodeString(&ustrLinkName, LINK_GLOBAL_NAME); else RtlInitUnicodeString(&ustrLinkName, LINK_NAME); status = IoCreateSymbolicLink(&ustrLinkName, &ustrDevName); if(!NT_SUCCESS(status)) { IoDeleteDevice(pDevObj); return status; } //test DbgPrint("[method 1]SSDT: %llx\n",MyGetKeServiceDescriptorTable64());DbgPrint("[method 1]NtOpenProcess: %llx\n",GetSSDTFunctionAddress64(0x23)); //WIN7X64 HARDCODE DbgPrint("[method 1]NtTerminateProcess: %llx\n",GetSSDTFunctionAddress64(0x29)); //WIN7X64 HARDCODEDbgPrint("[method 2]NtOpenProcess: %llx\n",GetSSDTFunctionAddress64_2(0x23)); //WIN7X64 HARDCODE DbgPrint("[method 2]NtTerminateProcess: %llx\n",GetSSDTFunctionAddress64_2(0x29));//WIN7X64 HARDCODE //test return STATUS_SUCCESS; }执行结果:


《新程序员》:云原生和全面数字化实践50位技术专家共同创作,文字、视频、音频交互阅读

总结

以上是生活随笔为你收集整理的Win64 驱动内核编程-18.SSDT的全部内容,希望文章能够帮你解决所遇到的问题。

如果觉得生活随笔网站内容还不错,欢迎将生活随笔推荐给好友。