三年前面朝黄土背朝天的我,写了一篇如何在Windows 7
系统下枚举内核SSDT
表的文章《驱动开发:内核读取SSDT表基址》
三年过去了我还是个单身狗
,开个玩笑,微软的Windows 10
系统已经覆盖了大多数个人PC终端,以前的方法也该进行迭代更新了,或许在网上你能够找到类似的文章,但我可以百分百肯定都不能用,今天LyShark
将带大家一起分析Win10 x64
最新系统SSDT
表的枚举实现。
直接步入正题,首先SSDT
表中文为系统服务描述符表,SSDT表的作用
是把应用
层与内核
层联系起来
起到桥梁
的作用,枚举SSDT表
也是反内核
工具最基本的功能,通常在64位
系统中要想找到SSDT
表,需要先找到KeServiceDescriptorTable
这个函数,由于该函数没有被导出,所以只能动态的查找它的地址,庆幸的是我们可以通过查找msr(c0000082)
这个特殊的寄存器来替代查找KeServiceDescriptorTable
这一步,在新版系统中查找SSDT可以归纳为如下这几个步骤。
首先第一步通过rdmsr C0000082
MSR寄存器得到KiSystemCall64Shadow
的函数地址,计算KiSystemCall64Shadow
与KiSystemServiceUser
偏移量,如下图所示。
如上当我们找到了KiSystemServiceUser
的地址以后,在KiSystemServiceUser
向下搜索可找到KiSystemServiceRepeat
里面就是我们要找的SSDT
表基址。
得到ServiceTableBase
的地址后,就能得到每个服务函数的地址。但这个表存放的并不是SSDT
函数的完整地址,而是其相对于ServiceTableBase[Index]>>4
的数据,每个数据占四个字节,所以计算指定Index
函数完整地址的公式是;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
/
/
署名权
/
/
right to sign one's name on a piece of work
/
/
PowerBy: LyShark
typedef struct _SYSTEM_SERVICE_TABLE
{
PVOID ServiceTableBase;
PVOID ServiceCounterTableBase;
ULONGLONG NumberOfServices;
PVOID ParamTableBase;
} SYSTEM_SERVICE_TABLE,
*
PSYSTEM_SERVICE_TABLE;
ULONGLONG ssdt_base_aadress;
PSYSTEM_SERVICE_TABLE KeServiceDescriptorTable;
typedef UINT64(__fastcall
*
SCFN)(UINT64, UINT64);
SCFN scfn;
/
/
解密算法
VOID DecodeSSDT()
{
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"
;
/
*
48
:
8BC1
| mov rax,rcx | rcx
=
index
4C
:
8D12
| lea r10,qword ptr ds:[rdx] | rdx
=
ssdt
8BF8
| mov edi,eax |
C1EF
07
| shr edi,
7
|
83E7
20
|
and
edi,
20
|
4E
:
8B1417
| mov r10,qword ptr ds:[rdi
+
r10] |
4D
:
631C82
| movsxd r11,dword ptr ds:[r10
+
rax
*
4
] |
49
:
8BC3
| mov rax,r11 |
49
:C1FB
04
| sar r11,
4
|
4D
:
03D3
| add r10,r11 |
49
:
8BC2
| mov rax,r10 |
C3 | ret |
*
/
scfn
=
ExAllocatePool(NonPagedPool,
36
);
memcpy(scfn, strShellCode,
36
);
}
/
/
获取 KeServiceDescriptorTable 首地址
ULONGLONG GetKeServiceDescriptorTable()
{
/
/
设置起始位置
PUCHAR StartSearchAddress
=
(PUCHAR)__readmsr(
0xC0000082
)
-
0x1806FE
;
/
/
设置结束位置
PUCHAR EndSearchAddress
=
StartSearchAddress
+
0x8192
;
DbgPrint(
"扫描起始地址: %p --> 扫描结束地址: %p \n"
, StartSearchAddress, EndSearchAddress);
PUCHAR ByteCode
=
NULL;
UCHAR OpCodeA
=
0
, OpCodeB
=
0
, OpCodeC
=
0
;
ULONGLONG addr
=
0
;
ULONG templong
=
0
;
for
(ByteCode
=
StartSearchAddress; ByteCode < EndSearchAddress; ByteCode
+
+
)
{
/
/
使用MmIsAddressValid()函数检查地址是否有页面错误
if
(MmIsAddressValid(ByteCode) && MmIsAddressValid(ByteCode
+
1
) && MmIsAddressValid(ByteCode
+
2
))
{
OpCodeA
=
*
ByteCode;
OpCodeB
=
*
(ByteCode
+
1
);
OpCodeC
=
*
(ByteCode
+
2
);
/
/
对比特征值 寻找 nt!KeServiceDescriptorTable 函数地址
/
/
LyShark.com
/
/
4c
8d
15
e5
9e
3b
00
lea r10,[nt!KeServiceDescriptorTable (fffff802`
64da4880
)]
/
/
4c
8d
1d
de
20
3a
00
lea r11,[nt!KeServiceDescriptorTableShadow (fffff802`
64d8ca80
)]
if
(OpCodeA
=
=
0x4c
&& OpCodeB
=
=
0x8d
&& OpCodeC
=
=
0x15
)
{
/
/
获取高位地址fffff802
memcpy(&templong, ByteCode
+
3
,
4
);
/
/
与低位
64da4880
地址相加得到完整地址
addr
=
(ULONGLONG)templong
+
(ULONGLONG)ByteCode
+
7
;
return
addr;
}
}
}
return
0
;
}
/
/
得到函数相对偏移地址
ULONG GetOffsetAddress(ULONGLONG FuncAddr)
{
ULONG dwtmp
=
0
;
PULONG ServiceTableBase
=
NULL;
if
(KeServiceDescriptorTable
=
=
NULL)
{
KeServiceDescriptorTable
=
(PSYSTEM_SERVICE_TABLE)GetKeServiceDescriptorTable();
}
ServiceTableBase
=
(PULONG)KeServiceDescriptorTable
-
>ServiceTableBase;
dwtmp
=
(ULONG)(FuncAddr
-
(ULONGLONG)ServiceTableBase);
return
dwtmp <<
4
;
}
/
/
根据序号得到函数地址
ULONGLONG GetSSDTFunctionAddress(ULONGLONG NtApiIndex)
{
ULONGLONG ret
=
0
;
if
(ssdt_base_aadress
=
=
0
)
{
/
/
得到ssdt基地址
ssdt_base_aadress
=
GetKeServiceDescriptorTable();
}
if
(scfn
=
=
NULL)
{
DecodeSSDT();
}
ret
=
scfn(NtApiIndex, ssdt_base_aadress);
return
ret;
}
VOID UnDriver(PDRIVER_OBJECT driver)
{
DbgPrint((
"驱动程序卸载成功! \n"
));
}
NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath)
{
DbgPrint(
"hello lyshark.com \n"
);
ULONGLONG ssdt_address
=
GetKeServiceDescriptorTable();
DbgPrint(
"SSDT基地址 = %p \n"
, ssdt_address);
/
/
根据序号得到函数地址
ULONGLONG address
=
GetSSDTFunctionAddress(
51
);
DbgPrint(
"[LyShark] NtOpenFile地址 = %p \n"
, address);
/
/
得到相对SSDT的偏移量
DbgPrint(
"函数相对偏移地址 = %p \n"
, GetOffsetAddress(address));
DriverObject
-
>DriverUnload
=
UnDriver;
return
STATUS_SUCCESS;
}