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?同理)想像成一排保險柜,每個柜子都有編號(從?0?開始),柜子的長度為四字節,每個柜子里都放了一個?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的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。