首页
社区
课程
招聘
[分享] X86系统调用_上(Ring3)
2020-6-3 21:20 4980

[分享] X86系统调用_上(Ring3)

2020-6-3 21:20
4980

1). 在操作系统调用Windows API时,无论是 Kernel32.dll 还是 User32.dll 或者是 GDI.dll 最终调用的都是 Ntdll.dll 中的函数进入R0(不调用R0的函数除外)

2). 我们以 WriteProcessMemory 函数为例子,其在 Kernel32.dll 中,我们查看其的代码实现,如下:发现其最终调用的是位于 Ntdll.dll 中的 NtWriteVirtualMemory 函数, 我们进入 Ntdll.dll 查询

3). 发现其并没有做任何处理,而是 Call  0x7FFE0300 函数, eax 的值是系统服务号(SSDT表的索引)

在这里我们需要了解R0和R3的共享内存块,也就是一个共享的结构体 _KUSER_SHARED_DATA, 其结构如下(微软目前公布的结构体成员如下):

ntdll!_KUSER_SHARED_DATA
   +0x000 TickCountLow     : 0xb3c
   +0x004 TickCountMultiplier : 0xfa00000
   +0x008 InterruptTime    : _KSYSTEM_TIME
   +0x014 SystemTime       : _KSYSTEM_TIME
   +0x020 TimeZoneBias     : _KSYSTEM_TIME
   +0x02c ImageNumberLow   : 0x14c
   +0x02e ImageNumberHigh  : 0x14c
   +0x030 NtSystemRoot     : [260] 0x43
   +0x238 MaxStackTraceDepth : 0
   +0x23c CryptoExponent   : 0
   +0x240 TimeZoneId       : 0
   +0x244 Reserved2        : [8] 0
   +0x264 NtProductType    : 1 ( NtProductWinNt )
   +0x268 ProductTypeIsValid : 0x1 ''
   +0x26c NtMajorVersion   : 5
   +0x270 NtMinorVersion   : 1
   +0x274 ProcessorFeatures : [64]  ""
   +0x2b4 Reserved1        : 0x7ffeffff
   +0x2b8 Reserved3        : 0x80000000
   +0x2bc TimeSlip         : 0
   +0x2c0 AlternativeArchitecture : 0 ( StandardDesign )
   +0x2c8 SystemExpirationDate : _LARGE_INTEGER 0x0
   +0x2d0 SuiteMask        : 0x110
   +0x2d4 KdDebuggerEnabled : 0x3 ''
   +0x2d5 NXSupportPolicy  : 0x2 ''
   +0x2d8 ActiveConsoleId  : 0
   +0x2dc DismountCount    : 0
   +0x2e0 ComPlusPackage   : 0xffffffff
   +0x2e4 LastSystemRITEventTickCount : 0
   +0x2e8 NumberOfPhysicalPages : 0x1ff6c
   +0x2ec SafeBootMode     : 0 ''
   +0x2f0 TraceLogging     : 0
   +0x2f8 TestRetInstruction : 0xc3
   +0x300 SystemCall       : 0x7c92e4f0
   +0x304 SystemCallReturn : 0x7c92e4f4
   +0x308 SystemCallPad    : [3] 0
   +0x320 TickCount        : _KSYSTEM_TIME
   +0x320 TickCountQuad    : 0
   +0x330 Cookie           : 0x59d47d1

所谓共享内存块指的是任何一个R3的进程中都有一个线性地址和R0的一个线性地址指向了同一块物理页

User层(3环)地址为:0x7FFE0000
Kernnel层(0环)地址为:0xFFDF0000
虽然指向同一块物理页,但是3环只是可读,而0环却是可读可写

在回到之前 Call  0x7FFE0300函数,我们通过上面可以知道是 _KUSER_SJARED_DATA 结构体成员的

+0x300 SystemCall       : 0x7c92e4f0(如果不支持 sysenter 指令,则会替换为中断门函数 KiIntSystemCall 地址)

用 WinDbg 查看对应函数

kd> u 0x7c92e4f0
ntdll!KiFastSystemCall

用 IDA 查看函数流程, edx 指向了 R3 的ESP

发现只是调用了一个汇编指令 sysenter

在这里我们要明白,在08年前,操作系统进入0环,都是通过 INT 0x2E 进入对应的0环的分发函数, 之后用 sysenter 指令替代了调用门,因为 sysenter 指令更加的高效

通过 sysenter 进入0环,系统默认会去 MSR 寄存器中获取对应的 CS(MSRAddr: 174H)、EIP(MSRAddr: 176H)、ESP(MSRAddr: 175H)(参考INTEL白皮书)

我们用WinDbg查看对应的数据, EIP对应的0环跳转函数如下:

但是任何提权都需要改变  CS、EIP、ESP、SS 四个寄存器的值,为何这里没有 SS 寄存器?

其实在08年后,操作系统规定在 CS 代码段描述符后就是 SS 数据段描述符, 例如: 在 GDT表 0x8 段选子后 + 0x8字节的位置就是 SS 数据段描述符描述符 0x10 段选子

所以可以认为 CS段描述符后 + 0x8 == SS段描述符后:

4).所以(支持sysenter模式下)R3进入0环流程如上

但是如果不支持 sysenter 指令(操作系统通过 CPUID 指令来判断是否支持 sysenter 指令), 则会调用 KiIntSystemCall 函数, 其函数流程如下:

通过 INT 0x2E 进入 0环,我们可以查看对应的0环函数, edx 指向R3的函数参数


[培训]内核驱动高级班,冲击BAT一流互联网大厂工 作,每周日13:00-18:00直播授课

收藏
点赞2
打赏
分享
最新回复 (3)
雪    币: 1473
活跃值: (9290)
能力值: ( LV13,RANK:385 )
在线值:
发帖
回帖
粉丝
TkBinary 5 2020-6-4 09:05
2
2
总结一下: 之前通过int 2E 进入. 后面 出了两个快速调用. sysenter 以及 sysexit  当xp后面cpu支持快速调用的时候.会为其分配三个函数. KiIntSystemCall KiFastSystemCall KiFastSystemCallRet  利用CPUID来判断是否支持快速调用. 如果不支持.则调用KiInitSystemCall 其实内部就是封装的Int 2E 如果支持则调用KiFastSystemCall 内部就是Sysenter  参考毛德操老师的 内核系统调用.
雪    币: 1290
活跃值: (2332)
能力值: ( LV4,RANK:40 )
在线值:
发帖
回帖
粉丝
灵幻空间 2020-6-4 17:55
3
0
感谢
雪    币: 259
活跃值: (283)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
ZwCopyAll 2020-6-4 18:00
4
0
666
游客
登录 | 注册 方可回帖
返回