日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

简单说说SSDT

發(fā)布時間:2025/3/20 编程问答 25 豆豆
生活随笔 收集整理的這篇文章主要介紹了 简单说说SSDT 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
論技術(shù),我還差得遠(yuǎn),而且網(wǎng)上關(guān)于SSDT的文章也多不勝數(shù)。但是還是想自己寫一下,因為我想試試我能不能用最簡單的語言來描述SSDT——這個對一般來 人來說比較神秘的屬于內(nèi)核的地帶。引用EVA說的一句話,“以為寫個驅(qū)動就是內(nèi)核,還遠(yuǎn)著了”——大概是這么個意思,記得不是很清楚。

關(guān)于SSDT,描述得最清楚的應(yīng)該算《SSDT Hook的妙用-對抗ring0 inline hook》一文了,作者是墮落天才。這里引用一下他寫的開頭部分,略有個別字符的修改:

內(nèi)核中有兩個系統(tǒng)服務(wù)描述符表,一個是KeServiceDescriptorTable,由ntoskrnl.exe導(dǎo)出,一個是 KeServieDescriptorTableShadow,沒有導(dǎo)出。這兩者都是一個結(jié)構(gòu)體,結(jié)構(gòu)下面會給出。他們的區(qū)別 是,KeServiceDescriptorTable僅有 ntoskrnel一項,而KeServieDescriptorTableShadow則包含了ntoskrnel和win32k。一般的Native API的服務(wù)地址由KeServiceDescriptorTable分派,而gdi.dll和
user.dll的內(nèi)核API調(diào)用服務(wù)地址,由 KeServieDescriptorTableShadow分派。還有要清楚一點的是win32k.sys只有在GUI線程中才加載,一般情況下是不加 載的。

他們的結(jié)構(gòu)如下:

typedef?struct?_SYSTEM_SERVICE_TABLE
{
????PVOID?ServiceTableBase;????
//這個指向系統(tǒng)服務(wù)函數(shù)地址表
????PULONG?ServiceCounterTableBase;
????ULONG?NumberOfService;?????
//服務(wù)函數(shù)的個數(shù),NumberOfService*4?就是整個地址表的大小
????ULONG?ParamTableBase;
}SYSTEM_SERVICE_TABLE,
*PSYSTEM_SERVICE_TABLE;

typedef?
struct?_SERVICE_DESCRIPTOR_TABLE
{
????SYSTEM_SERVICE_TABLE?ntoskrnel;????
//ntoskrnl.exe的服務(wù)函數(shù)
????SYSTEM_SERVICE_TABLE?win32k;????//win32k.sys的服務(wù)函數(shù),(gdi.dll/user.dll的內(nèi)核支持)
????SYSTEM_SERVICE_TABLE?NotUsed1;
????SYSTEM_SERVICE_TABLE?NotUsed2;
}SYSTEM_DESCRIPTOR_TABLE,
*PSYSTEM_DESCRIPTOR_TABLE;?

當(dāng)系統(tǒng)需要使用一個本機API的時候,就會去查找SYSTEM_DESCRIPTOR_TABLE這個表,也就是由ntoskrnl.exe導(dǎo)出的 KeServiceDescriptorTable:

nt!RtlpBreakWithStatusInstruction:
80527fc8?cc??????????????
int?????3
kd
>?dd?KeServiceDescriptorTable
80553380??805021fc?00000000?0000011c?80502670
80553390??00000000?00000000?00000000?00000000
805533a0??
00000000?00000000?00000000?00000000
805533b0??
00000000?00000000?00000000?00000000
805533c0??
00002710?bf80c227?00000000?00000000
805533d0??f9e6da80?f963a9e0?816850f0?806e0f40
805533e0??
00000000?00000000?00000000?00000000
805533f0??97c5ac40?01c7abf5?
00000000?00000000?

可以看到,KeServiceDescriptorTable的地址是80553380。現(xiàn)在看看這個地址保存的是什么,因為這個地址的值就是 SYSTEM_SERVICE_TABLE的起始地址。好了,我們看到這個地址保存的是805021fc,那么也就是說,系統(tǒng)服務(wù)的地址表起始地址為 805021fc了。看看這個表是些什么鬼東西:

kd>?dd?805021fc
805021fc??
80599746?805e6914?805ea15a?805e6946
8050220c??805ea194?805e697c?805ea1d8?805ea21c
8050221c??8060b880?8060c5d2?805e1cac?805e1904
8050222c??805ca928?805ca8d8?8060bea6?805ab334
8050223c??8060b4be?8059dbbc?805a5786?805cc406
8050224c??804ffed0?8060c5c4?8056be64?805353f2
8050225c??80604b90?805b19c0?805ea694?80619a56
8050226c??805eeb86?80599e34?80619caa?805996e6?
這個過程是這樣的,最開始是SYSTEM_DESCRIPTOR_TABLE(80553380)保存了SYSTEM_SERVICE_TABLE的地址 (805021fc),SYSTEM_SERVICE_TABLE的地址(805021fc)又保存了很多地址,這個地址就是系統(tǒng)服務(wù)的地址了,類似 NtOpenProcess這樣的ring0的函數(shù)地址。這樣,系統(tǒng)就可以方便的找到每一個ring0函數(shù)去調(diào)用。

我們先看看第一個地址80599746是個什么函數(shù),反匯編一下:

kd>?u?80599746
nt
!NtAcceptConnectPort:
80599746?689c000000??????push????9Ch
8059974b?6820a14d80??????push????offset?nt
!_real+0x128?(804da120)
80599750?e8abebf9ff??????call????nt!_SEH_prolog?(80538300)
80599755?64a124010000????mov?????eax,dword?ptr?fs:[00000124h]
8059975b?8a8040010000????mov?????al,
byte?ptr?[eax+140h]
80599761?884590??????????mov?????byte?ptr?[ebp-70h],al
80599764?84c0????????????test????al,al
80599766?0f84b9010000????je??????nt!NtAcceptConnectPort+0x1df?(80599925)?

原來是NtAcceptConnectPort函數(shù),第二個805e6914呢?我們也看一下,

kd>?u?805e6914
nt
!NtAccessCheck:
805e6914?8bff????????????mov?????edi,edi
805e6916?
55??????????????push????ebp
805e6917?8bec????????????mov?????ebp,esp
805e6919?33c0????????????xor?????eax,eax
805e691b?
50??????????????push????eax
805e691c?ff7524??????????push????dword?ptr?[ebp
+24h]
805e691f?ff7520??????????push????dword?ptr?[ebp+20h]
805e6922?ff751c??????????push????dword?ptr?[ebp
+1Ch]?原來是NtAccessCheck函數(shù)。

這樣我們可以清楚的看到,在這個起始地址為0x805021fc的表中,保存了各個ring0函數(shù)的地址。下面我來做個簡單的比喻。

從前有一個很大的幫派,名字叫做Windows,功能很多并且很強大。因為這些各方面的能力由各個專人負(fù)責(zé),他們一個人做一件事情。隨著人員增 多,幫主發(fā)現(xiàn)聯(lián)系起來越來越困了。有一天幫主要找竟然NtOpenProcess來調(diào)查一下他的一個手下是不是別的幫派派來的間諜,但是他發(fā)現(xiàn) NtOpenProcess跑不見了。

于是軍師就想出了一個好辦法來解決這個問題:先建立一個封閉的密室,這個密室只有八袋長老以上的人才能進去。密室中間有一張紙條,上面寫著一個地 址——溫家堡,還有這個地址放著多少人的聯(lián)系信息等內(nèi)容。這個密室就是Ntdll.dll,這個紙條就是 SYSTEM_DESCRIPTOR_TABLE,上寫的地址就是SYSTEM_SERVICE_TABLE,也就是溫家堡了。這個溫家堡是一個有很多大 房間的地方,每個房子有個房間號
,房間里面又放著一張紙條,上面寫著各個手下的住所。比如說編號為7A的房間,里面放的是NtOpenProcess的家庭住址。

這樣一來,幫主要找人就容易了。先去密室找到紙條,看看上面寫的是溫家堡還是白云城,那個地方有多少個人的聯(lián)系信息等。如果是溫家堡就跑到那里 去,看看要找誰,找NtOpenProcess就去7A房間。在這個房間里一看,啊,里面寫著NtOpenProcess現(xiàn)在就住在密室的旁邊……搞定。

這里就有一個新的問題,幫主假設(shè)這個里面寫的東西都是正確的,沒有被人改過。于是就有了別派的間諜發(fā)現(xiàn)了,偷偷溜進密室,然后根據(jù)紙條的內(nèi)容,又 跑到溫家堡。進到7A房間,神不知鬼不覺的把里面記錄的NtOpenProcess的地址改成了自己的家。于是,幫主再找人,發(fā)現(xiàn)找到對頭家里去了。這個 就是傳說中的SSDT Hook了。

攻擊者進入ring0之后,找到KeServiceDescriptorTable地址的值,即SYSTEM_SERVICE_TABLE的地址 (進入密室,找到紙條寫的地址——溫家堡)。然后改寫SYSTEM_SERVICE_TABLE中一個特定函數(shù)的地址為自己定義的函數(shù)入口處,截獲了系統(tǒng) 調(diào)用(來到溫家堡,改掉7A房間里面寫的住所,改成自己家)。一次HOOK就完成了。

下面我給一段簡單的代碼,演示怎么樣讓一個特定的PID不會被殺死。這段代碼基本和《SSDT Hook的妙用-對抗ring0 inline hook》一文一樣,我只是注釋了一下而已,另外在MyNtOpenProcess處加了個判斷是不是某個特定PID的功能。

代碼
/*
演示HOOK系統(tǒng)服務(wù)調(diào)用表中的NtOpenProcess函數(shù),保護需要保護的進程被,防止被殺掉
*/

#include
<ntddk.h>

/*
KeServiceDescriptorTable僅有ntoskrnel一項,沒有包含win32k,而且后面的兩個字段都沒有使用,所

以為了簡便直接把SystemServiceDescriptorTable定義成SYSTEM_SERVICE_TABLE,免得訪問多個結(jié)構(gòu)體的

字段,麻煩。這里明白就行了。
*/
typedef?
struct?_SystemServiceDescriptorTable
{
????PVOID????ServiceTableBase;
????PULONG????ServiceCounterTableBase;
????ULONG????NumberOfService;
????ULONG????ParamTableBase;
}SystemServiceDescriptorTable,
*PSystemServiceDescriptorTable;

//?KeServiceDescriptorTable為ntoskrnl.exe導(dǎo)出
extern????PSystemServiceDescriptorTable????KeServiceDescriptorTable;

//?定義一下NtOpenProcess的原型,下面如果用匯編調(diào)用就不用定義了,但是我想盡量不用匯編
typedef????NTSTATUS????(__stdcall?*NTOPENPROCESS)(?OUT?PHANDLE?ProcessHandle,
????????????????????????????????????????????????

IN?ACCESS_MASK?AccessMask,
????????????????????????????????????????????????

IN?POBJECT_ATTRIBUTES?ObjectAttributes,
????????????????????????????????????????????????

IN?PCLIENT_ID?ClientId
????????????????????????????????????????????????

);

NTOPENPROCESS????RealNtOpenProcess;

//?定義函數(shù)原型
VOID?Hook();
VOID?Unhook();
VOID?OnUnload(IN?PDRIVER_OBJECT?DriverObject);

//?真實的函數(shù)地址,我們會在自定義的函數(shù)中調(diào)用
ULONG????RealServiceAddress;

//?需要被驅(qū)動保護的進程ID
HANDLE????MyPID;

//?自定義的NtOpenProcess函數(shù)
NTSTATUS?__stdcall?MyNtOpenProcess(?OUT????PHANDLE?ProcessHandle,
????????????????????IN????ACCESS_MASK?DesiredAccess,
????????????????????IN????POBJECT_ATTRIBUTES?ObjectAttributes,
????????????????????IN????PCLIENT_ID?ClientId?)
{
????NTSTATUS????rc;
????ULONG????????PID;
????
????
//DbgPrint(?"NtOpenProcess()?called.\n"?);
????
????rc?
=?(NTSTATUS)(NTOPENPROCESS)RealNtOpenProcess(?ProcessHandle,?DesiredAccess,

ObjectAttributes,?ClientId?);
????
????
if(?(ClientId?!=?NULL)?)
????{
????????PID?
=?(ULONG)ClientId->UniqueProcess;
????????
//DbgPrint(?"%d?was?opened,Handle?is?%d.\n",?PID,?(ULONG)ProcessHandle?);
????????
????????
//?如果進程PID是1520,直接返回權(quán)限不足,并將句柄設(shè)置為空
????????if(?PID?==?1520?)
????????{
????????????DbgPrint(?
"Some?want?to?open?pid?1520!\n"?);
????????????
????????????ProcessHandle?
=?NULL;
????????????????????????
????????????rc?
=?STATUS_ACCESS_DENIED;
????????}
????}
????
????
return?rc;
}

//?驅(qū)動入口
NTSTATUS?DriverEntry(?IN?PDRIVER_OBJECT?DriverObject,?PUNICODE_STRING?RegistryPath?)
{
????DriverObject
->DriverUnload?=?OnUnload;

????Hook();
????
????
return?STATUS_SUCCESS;
}

//?驅(qū)動卸載
VOID?OnUnload(IN?PDRIVER_OBJECT?DriverObject)
{
????Unhook(?);
}

//??此處修改SSDT中的NtOpenProcess服務(wù)地址
VOID?Hook()
{
????ULONG????????????Address;
????
????
//?0x7A為Winxp+SP2下NtOpenProcess服務(wù)ID號
????
//?Adress是個地址A,這個地址的數(shù)據(jù)還是一個地址B,這個地址B就是NtOpenProcess的地址了
????
//?(ULONG)KeServiceDescriptorTable->ServiceTableBase就是溫家堡的第一個房間
????
//?Address是第7A個房間。
????Address?=?(ULONG)KeServiceDescriptorTable->ServiceTableBase?+?0x7A?*?4;

????
//?取得地址A的值,也就是NtOpenProcess服務(wù)的地址了,保存原來NtOpenProcess的地址以后恢

復(fù)用
????RealServiceAddress?
=?*(ULONG*)Address;
????
????RealNtOpenProcess?
=?(NTOPENPROCESS)RealServiceAddress;
????
????DbgPrint(?
"Address?of?Real?NtOpenProcess:?0x%08X\n",?RealServiceAddress?);

????DbgPrint(
"?Address?of?MyNtOpenProcess:?0x%08X\n",?MyNtOpenProcess?);

????
//?去掉內(nèi)存保護
????__asm
????{
????????cli
????????mov????eax,?cr0
????????and????eax,?not?10000h
????????mov????cr0,?eax
????}
????
????
//?修改SSDT中NtOpenProcess服務(wù)的地址
???*((ULONG*)Address)?=?(ULONG)MyNtOpenProcess;

????
//?恢復(fù)內(nèi)存保護
????__asm
????{
????????mov????eax,?cr0
????????or????eax,?10000h
????????mov????cr0,?eax
????????sti
????}
}

//
VOID?Unhook()
{
???ULONG???Address;
???Address?
=?(ULONG)KeServiceDescriptorTable->ServiceTableBase?+?0x7A?*?4;

????__asm
????{
????????cli
????????mov????eax,?cr0
????????and????eax,?not?10000h
????????mov????cr0,?eax
????}

????
//?還原SSDT
????*((ULONG*)Address)?=?(ULONG)RealServiceAddress;
????
????__asm
????{
????????mov????eax,?cr0
????????or????eax,?10000h
????????mov????cr0,?eax
????????sti
????}

????DbgPrint(
"Unhook");
}?


?轉(zhuǎn)載自:http://icylife.net/yunshu/show.php?id=435

?

?

?

?

?


?

?

總結(jié)

以上是生活随笔為你收集整理的简单说说SSDT的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。