SystemServiceTable

文章详细阐述了在Windows操作系统中,从用户模式进入内核模式后,如何通过系统服务描述符表(SSDT)找到并调用内核函数的过程。具体包括根据系统服务号在_KTHREAD结构体中的ServiceTable找到对应的函数地址,以及如何从堆栈传递参数。同时提到了SSDT的组成和如何通过WinDbg工具进行分析。此外,还讨论了驱动程序访问SSDT的方式以及存在的SSDTShadow表。
摘要由CSDN通过智能技术生成

进0环后,3环的各种寄存器的值都会保留到_Trap_Frame结构体中,接下来我将会讲解:如何根据系统服务号(eax中存储)找到要执行的内核函数?调用时参数是存储到3环的堆栈,如何传递给内核函数?

SystemServiceTable,即系统服务表,它不是SSDT
表由4部分组成,ServiceTable指向的是函数地址数组,每个成员四个字节;Count表示调用次数,没啥意义;ServiceLimit表示这张表有几个函数;ArgumentTable指向对应函数有几个字节参数,每个成员一个字节

从图中可以看出,Windows提供了两张表:上面的表是用来处理一般内核函数的,下面这张表是用来处理与GUI相关的内核函数
在这里插入图片描述
我们根据服务表的索引12这个位可以判断是哪张服务表,既然找到了哪张服务表,后12位就是在服务表的索引。通过这个索引,找到函数地址,有几个参数,我们就可以调用它了。这个系统服务表的地址 : _KTHREAD + 0xe0

   kd> dt _KTHREAD
nt!_KTHREAD
   +0x000 Header           : _DISPATCHER_HEADER
   +0x010 MutantListHead   : _LIST_ENTRY
   +0x018 InitialStack     : Ptr32 Void
   +0x01c StackLimit       : Ptr32 Void
   +0x020 Teb              : Ptr32 Void
   +0x024 TlsArray         : Ptr32 Void
   +0x028 KernelStack      : Ptr32 Void
   +0x02c DebugActive      : UChar
   +0x02d State            : UChar
   +0x02e Alerted          : [2] UChar
   +0x030 Iopl             : UChar
   +0x031 NpxState         : UChar
   +0x032 Saturation       : Char
   +0x033 Priority         : Char
   +0x034 ApcState         : _KAPC_STATE
   +0x04c ContextSwitches  : Uint4B
   +0x050 IdleSwapBlock    : UChar
   +0x051 Spare0           : [3] UChar
   +0x054 WaitStatus       : Int4B
   +0x058 WaitIrql         : UChar
   +0x059 WaitMode         : Char
   +0x05a WaitNext         : UChar
   +0x05b WaitReason       : UChar
   +0x05c WaitBlockList    : Ptr32 _KWAIT_BLOCK
   +0x060 WaitListEntry    : _LIST_ENTRY
   +0x060 SwapListEntry    : _SINGLE_LIST_ENTRY
   +0x068 WaitTime         : Uint4B
   +0x06c BasePriority     : Char
   +0x06d DecrementCount   : UChar
   +0x06e PriorityDecrement : Char
   +0x06f Quantum          : Char
   +0x070 WaitBlock        : [4] _KWAIT_BLOCK
   +0x0d0 LegoData         : Ptr32 Void
   +0x0d4 KernelApcDisable : Uint4B
   +0x0d8 UserAffinity     : Uint4B
   +0x0dc SystemAffinityActive : UChar
   +0x0dd PowerState       : UChar
   +0x0de NpxIrql          : UChar
   +0x0df InitialNode      : UChar
   +0x0e0 ServiceTable     : Ptr32 Void
   +0x0e4 Queue            : Ptr32 _KQUEUE
   +0x0e8 ApcQueueLock     : Uint4B
   +0x0f0 Timer            : _KTIMER
   +0x118 QueueListEntry   : _LIST_ENTRY
   +0x120 SoftAffinity     : Uint4B
   +0x124 Affinity         : Uint4B
   +0x128 Preempted        : UChar
   +0x129 ProcessReadyQueue : UChar
   +0x12a KernelStackResident : UChar
   +0x12b NextProcessor    : UChar
   +0x12c CallbackStack    : Ptr32 Void
   +0x130 Win32Thread      : Ptr32 Void
   +0x134 TrapFrame        : Ptr32 _KTRAP_FRAME
   +0x138 ApcStatePointer  : [2] Ptr32 _KAPC_STATE
   +0x140 PreviousMode     : Char
   +0x141 EnableStackSwap  : UChar
   +0x142 LargeStack       : UChar
   +0x143 ResourceIndex    : UChar
   +0x144 KernelTime       : Uint4B
   +0x148 UserTime         : Uint4B
   +0x14c SavedApcState    : _KAPC_STATE
   +0x164 Alertable        : UChar
   +0x165 ApcStateIndex    : UChar
   +0x166 ApcQueueable     : UChar
   +0x167 AutoAlignment    : UChar
   +0x168 StackBase        : Ptr32 Void
   +0x16c SuspendApc       : _KAPC
   +0x19c SuspendSemaphore : _KSEMAPHORE
   +0x1b0 ThreadListEntry  : _LIST_ENTRY
   +0x1b8 FreezeCount      : Char
   +0x1b9 SuspendCount     : Char
   +0x1ba IdealProcessor   : UChar
   +0x1bb DisableBoost     : UChar

有一个变量是导出的:dd KeServiceDescriptorTable ,可以通过其访问SSDT
SSDT的全称是System Services Descriptor Table,意为系统服务描述符表
SSDT有四个成员,每个成员都是一张系统服务表
第一个是函数地址表
第二个是调用次数
第三个是函数个数
第四个是一个字节的参数个数表
在这里插入图片描述

ReadProcessMemory的SSDT

kd> dd KeServiceDescriptorTable
8055b220  804e36a8 00000000 0000011c 80511088
8055b230  00000000 00000000 00000000 00000000
8055b240  00000000 00000000 00000000 00000000
8055b250  00000000 00000000 00000000 00000000
8055b260  00002730 bf80c0b6 00000000 00000000
8055b270  f7944a80 ba6bbb60 899a8670 f743c8e8
8055b280  00000000 00000000 47f32278 0000000b
8055b290  67c35b38 01d97eff 00000000 00000000

//找函数地址
kd> dd 804e36a8 + ba * 4
804e3990  8057f2ce 8058fd8c 8056747b 80588efe
804e39a0  80567fa9 8065c2a2 8064f79e 806500fa
804e39b0  8057dcda 8056c82e 8056c346 806242c6
804e39c0  8062d0d7 805de5f4 80577ce6 8062ced0
804e39d0  8059fb88 8053cbfa 8064fc91 8063091c
804e39e0  8058fcb2 8064fd92 8064fe7d 8064ffaa
804e39f0  805904de 8064a047 8064a047 8062ecdf

//找参数个数
kd> db 80511088 + ba
80511142  14 04 08 0c 14 08 08 0c-08 10 14 08 04 08 0c 04  ................
80511152  08 0c 0c 04 08 08 0c 0c-24 08 08 08 0c 04 08 04  ........$.......
80511162  10 08 04 04 04 14 14 10-10 10 10 10 10 08 14 18  ................
80511172  04 04 10 0c 08 14 0c 0c-08 08 1c 0c 04 18 14 04  ................

驱动程序访问SSDT

#include <ntddk.h>

// extern PKSERVICE_TABLE_DESCRIPTOR KeServiceDescriptorTable;
extern ULONG KeServiceDescriptorTable;    //只是为了访问地址,就不写那个结构体了

NTSTATUS UnloadDriver(PDRIVER_OBJECT DriverObject)
{
    DbgPrint("卸载成功!!!");
}

NTSTATUS DriverEntry(PDRIVER_OBJECT DriverObject, PUNICODE_STRING RegistryPath)
{

    DriverObject->DriverUnload = UnloadDriver;

    DbgPrint("SSDT 的地址:%X", KeServiceDescriptorTable);
    return STATUS_SUCCESS;
}

SSDTShadow

SSDTShadow和SSDT不一样的是它并没有从内核文件导出。不过我们还是可以从WinDbg找到它:dd KeServiceDescriptorTableShadow

它的结构和SSDT是一模一样的,只不过它多了一张表,就是少的那个与GUI相关的服务表。那么我们能不能直接用驱动访问这张表呢?答案是不行

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值