Meltdown&Spectre补丁
毫无疑问,这个补丁是微软用于修复Intel的CPU漏洞的补丁。
安装了这个补丁之后,最明显的变化可以看到msr地址0xC0000082所指向的函数不再是KiSystemCall64了,而是一个影子函数。
这给搜索ShadowSSDT(或SSDT)带来了困难,如果继续使用读取msr得到的地址作为搜索的起始位置,那么将无法搜索到ShadowSSDT(或SSDT)所在的位置。
幸运的是,其实我们并不需要做太多的修改,还是可以正常拿到ShadowSSDT(或SSDT)的地址的呢。
代码实现
咱们先来看代码吧:
ULONG64 GetKiSystemServiceUser()
{
PUCHAR EndSearchAddress;
//0xc0000082 现在变成了 KiSystemCall64Shadow
ULONGLONG KiSystemServiceUser = 0;
ULONGLONG templong = 0xffffffffffffffff;
PUCHAR i;
PUCHAR pKiSystemCall64 = (PUCHAR)__readmsr(0xc0000082);
EndSearchAddress = pKiSystemCall64 + 0x500;
for (i = pKiSystemCall64; i < EndSearchAddress + 0xff; i++)
{
if (MmIsAddressValid(i) && MmIsAddressValid(i + 5))
{
if (*(PUCHAR)i == 0xe9 && *(PUCHAR)(i + 5) == 0xc3)
{
//fffff803`23733383 e9631ae9ff jmp nt!KiSystemServiceUser(fffff803`235c4deb)
//fffff803`23733388 c3 ret
RtlCopyMemory(&templong, (PUCHAR)(i + 1), 4);
KiSystemServiceUser = templong + 5 + (ULONGLONG)i; // KiSystemServiceUser
return KiSystemServiceUser;
}
}
}
return 0;
}
ULONG64 g_shadowSSDT = NULL;
ULONG64 GetKeServiceDescriptorTableShadow64()
{
if (g_shadowSSDT != NULL)
return g_shadowSSDT;
PUCHAR StartSearchAddress = (PUCHAR)__readmsr(0xC0000082);
PUCHAR EndSearchAddress = StartSearchAddress + 0x500;
PUCHAR i = NULL;
UCHAR b1 = 0, b2 = 0, b3 = 0;
ULONG templong = 0;
ULONG64 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 == 0x1d) //4c8d1d
{
memcpy(&templong, i + 3, 4);
addr = (ULONG64)templong + (ULONG64)i + 7;
g_shadowSSDT = addr;
return addr;
}
}
}
// 没搜到, 此时一定可以确定是因为安装了CPU漏洞补丁, KiSystemCall64变成了Shadow
// 这时候需要从KiSystemServiceUser开始继续搜
StartSearchAddress = (PUCHAR)GetKiSystemServiceUser();
if (StartSearchAddress == 0)
{
return 0;
}
EndSearchAddress = StartSearchAddress + 0x500;
i = NULL;
b1 = 0, b2 = 0, b3 = 0;
templong = 0;
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 == 0x1d) //4c8d1d
{
memcpy(&templong, i + 3, 4);
addr = (ULONG64)templong + (ULONG64)i + 7;
g_shadowSSDT = addr;
return addr;
}
}
}
return 0;
}
原理说明
其实这个代码非常好理解,我们先用常规的代码搜索一遍ShadowSSDT。如果没有搜到,那么可以说明系统安装了CPU漏洞补丁。
这个时候我们从0xc0000082的位置搜索KiSystemServiceUser函数,之后从KiSystemServiceUser函数的地址开始搜ShadowSSDT,就可以拿到ShadowSSDT的地址了。
其实原理也很好理解的呢……
首先,搜索ShadowSSDT或SSDT,因为保存这个地址的汇编代码总是在KiSystemServiceUser函数的下方,因此,其实本身就是可以从KiSystemServiceUser开始搜索的。
但是由于直接拿0xc0000082这个msr,可以拿到KiSystemCall64函数的地址,而且KiSystemCall64函数就在KiSystemServiceUser的上方,因此直接拿到0xc0000082的msr所指向的地址,并作为起始开始搜索ShadowSSDT(或SSDT),操作起来更为容易且简单。
但是现在msr不再指向KiSystemCall64,因此之前的方法不好用了。不过我们可以稍加变通:从这个位置开始搜索KiSystemServiceUser函数的所在位置,然后再从KiSystemServiceUser开始搜索,不就实现了和之前一样的效果了嘛……?
于是就这么简单啦w
暂无评论