当前位置: 首页 > news >正文

windows内核研究(系统调用 二)

WindowsApi函数调用过程(3环进0环)


由于我系统是64位的,在调用32位函数时,会把原本的32位api转为64位内核函数来调用
在这里插入图片描述
_KUSER_SHARED_DATA结构体

  1. 在User层和Kernel层分别定义了一个_KUSER_SHARED_DATA结构区域,用于User层和Kernel层共享某些数据
  2. 它们使用固定的地址值来映射,_KUSER_SHARED_DATA结构区域在User和Kernel层地址分别为:
    • User层地址为:0x7FFE0000
    • Kernel层地址为:0x7FFDF0000

注:虽然指向的是同一个物理页,但在User层是只读的,在Kernel层是可写的

我们来查看一个这个 _KUSER_SHARED_DATA 结构体

1: kd> dt _KUSER_SHARED_DATA
ntdll!_KUSER_SHARED_DATA+0x000 TickCountLowDeprecated : Uint4B+0x004 TickCountMultiplier : Uint4B+0x008 InterruptTime    : _KSYSTEM_TIME+0x014 SystemTime       : _KSYSTEM_TIME+0x020 TimeZoneBias     : _KSYSTEM_TIME+0x02c ImageNumberLow   : Uint2B+0x02e ImageNumberHigh  : Uint2B+0x030 NtSystemRoot     : [260] Wchar+0x238 MaxStackTraceDepth : Uint4B+0x23c CryptoExponent   : Uint4B+0x240 TimeZoneId       : Uint4B+0x244 LargePageMinimum : Uint4B+0x248 AitSamplingValue : Uint4B+0x24c AppCompatFlag    : Uint4B+0x250 RNGSeedVersion   : Uint8B+0x258 GlobalValidationRunlevel : Uint4B+0x25c TimeZoneBiasStamp : Int4B+0x260 NtBuildNumber    : Uint4B+0x264 NtProductType    : _NT_PRODUCT_TYPE+0x268 ProductTypeIsValid : UChar+0x269 Reserved0        : [1] UChar+0x26a NativeProcessorArchitecture : Uint2B+0x26c NtMajorVersion   : Uint4B+0x270 NtMinorVersion   : Uint4B+0x274 ProcessorFeatures : [64] UChar+0x2b4 Reserved1        : Uint4B+0x2b8 Reserved3        : Uint4B+0x2bc TimeSlip         : Uint4B+0x2c0 AlternativeArchitecture : _ALTERNATIVE_ARCHITECTURE_TYPE+0x2c4 BootId           : Uint4B+0x2c8 SystemExpirationDate : _LARGE_INTEGER+0x2d0 SuiteMask        : Uint4B+0x2d4 KdDebuggerEnabled : UChar+0x2d5 MitigationPolicies : UChar+0x2d5 NXSupportPolicy  : Pos 0, 2 Bits+0x2d5 SEHValidationPolicy : Pos 2, 2 Bits+0x2d5 CurDirDevicesSkippedForDlls : Pos 4, 2 Bits+0x2d5 Reserved         : Pos 6, 2 Bits+0x2d6 CyclesPerYield   : Uint2B+0x2d8 ActiveConsoleId  : Uint4B+0x2dc DismountCount    : Uint4B+0x2e0 ComPlusPackage   : Uint4B+0x2e4 LastSystemRITEventTickCount : Uint4B+0x2e8 NumberOfPhysicalPages : Uint4B+0x2ec SafeBootMode     : UChar+0x2ed VirtualizationFlags : UChar+0x2ee Reserved12       : [2] UChar+0x2f0 SharedDataFlags  : Uint4B+0x2f0 DbgErrorPortPresent : Pos 0, 1 Bit+0x2f0 DbgElevationEnabled : Pos 1, 1 Bit+0x2f0 DbgVirtEnabled   : Pos 2, 1 Bit+0x2f0 DbgInstallerDetectEnabled : Pos 3, 1 Bit+0x2f0 DbgLkgEnabled    : Pos 4, 1 Bit+0x2f0 DbgDynProcessorEnabled : Pos 5, 1 Bit+0x2f0 DbgConsoleBrokerEnabled : Pos 6, 1 Bit+0x2f0 DbgSecureBootEnabled : Pos 7, 1 Bit+0x2f0 DbgMultiSessionSku : Pos 8, 1 Bit+0x2f0 DbgMultiUsersInSessionSku : Pos 9, 1 Bit+0x2f0 DbgStateSeparationEnabled : Pos 10, 1 Bit+0x2f0 SpareBits        : Pos 11, 21 Bits+0x2f4 DataFlagsPad     : [1] Uint4B+0x2f8 TestRetInstruction : Uint8B+0x300 QpcFrequency     : Int8B+0x308 SystemCall       : Uint4B	//这个位置对应的就是系统调用,刚好和我上面获取到的函数地址的偏移一致+0x30c SystemCallPad0   : Uint4B+0x310 SystemCallPad    : [2] Uint8B+0x320 TickCount        : _KSYSTEM_TIME+0x320 TickCountQuad    : Uint8B+0x320 ReservedTickCountOverlay : [3] Uint4B+0x32c TickCountPad     : [1] Uint4B+0x330 Cookie           : Uint4B+0x334 CookiePad        : [1] Uint4B+0x338 ConsoleSessionForegroundProcessId : Int8B+0x340 TimeUpdateLock   : Uint8B+0x348 BaselineSystemTimeQpc : Uint8B+0x350 BaselineInterruptTimeQpc : Uint8B+0x358 QpcSystemTimeIncrement : Uint8B+0x360 QpcInterruptTimeIncrement : Uint8B+0x368 QpcSystemTimeIncrementShift : UChar+0x369 QpcInterruptTimeIncrementShift : UChar+0x36a UnparkedProcessorCount : Uint2B+0x36c EnclaveFeatureMask : [4] Uint4B+0x37c TelemetryCoverageRound : Uint4B+0x380 UserModeGlobalLogger : [16] Uint2B+0x3a0 ImageFileExecutionOptions : Uint4B+0x3a4 LangGenerationCount : Uint4B+0x3a8 Reserved4        : Uint8B+0x3b0 InterruptTimeBias : Uint8B+0x3b8 QpcBias          : Uint8B+0x3c0 ActiveProcessorCount : Uint4B+0x3c4 ActiveGroupCount : UChar+0x3c5 Reserved9        : UChar+0x3c6 QpcData          : Uint2B+0x3c6 QpcBypassEnabled : UChar+0x3c7 QpcShift         : UChar+0x3c8 TimeZoneBiasEffectiveStart : _LARGE_INTEGER+0x3d0 TimeZoneBiasEffectiveEnd : _LARGE_INTEGER+0x3d8 XState           : _XSTATE_CONFIGURATION

查看CPU是否支持快速调用

通过eax=1来执行CPUID指令,处理器的特征信息被放在ecx和edx当中,其中edx包含了一个SEP位(11位) 该位指明了当前处理器是否支持sysenter/sysexit指令

支持:ntdll.dll!KiFastSystemCall()(64位下为SYSCALL)
不支持:ntdll.dll!KilntSystemCall()(64位下为SYSCALL)

cpuid 指令 // 可以查询cpu的很多信息,需要参数,通过eax来传递

在这里插入图片描述
执行完后rcx和rdx的值

在这里插入图片描述

  • rcx:0xFED8320B
  • rdx:0x178BFBFF–>0001 0111 1000 1011 1111 1011 1111 1111

看rdx中的第11位为1,说明我当前cpu是支持的

在操作系统启动时,就会通过cpuid指令查看看是否支持sysenter/sysexit指令,如果支持就会把KiFastSystemCall()写入到7FFE0308这个地址否则为KilntSystemCall()这个函数

3环进0环需要改哪些寄存器?

  1. CS寄存器:CS的权限由3变为0,意味着需要新的CS
  2. SS寄存器:SS与CS的权限永远一致,需要新的SS
  3. ESP寄存器:权限发生切换的时候,堆栈也一定会切换,需要新的ESP
  4. EIP寄存器:进0环后代码的位置也会改变,需要新的EIP

x86
不支持时,使用int 2Eh这种中断门来实现3环到0环的跳转
在这里插入图片描述
支持时直接使用sysenter来进行跳转
在这里插入图片描述

为什么sysenter叫快速调用?

那是因为中断门进0环,需要的CS,EIP在IDT表中,需要查内存(SS与ESP由TSS提供),如果CPU支持sysenter指令,操作系统会提前让CS,SS,ESP,EIP的值存在MSR寄存器中,sysenter指令执行时,CPU会将MSR寄存器中的值直接写入相关寄存器,没有读内存的过程,所以叫快速调用(本质上是一样的)

INT 0x2E进0环

查看idt表2e的位置

在这里插入图片描述
在这里插入图片描述

拆分:8277(地址高)ee(说明是中断门 1110 1110 )00 0008(CS) 8fb1(地址低)

地址(要执行的代码EIP):82778fb1

u 指令 // 对一个地址进行反汇编

在这里插入图片描述

这里就是我们进到内核后执行代码的地方

sysenter进0环

在执行sysenter指令之前,操作系统必须指定0环的CS段,SS段,EIP以及ESP(详情参考inter手册第二卷 sysenter指令)

MSR寄存器地址
IA32_SYSENTER_CS174H
IA32_SYSENTER_ESP175H
IA32_SYSENTER_EIP176H
SS(MSR中并没有存储SS)IA32_SYSENTER_CS+8

可以通过RDMSR/WRMST来进行读写(操作系统使用WRMST写该寄存器)

在这里插入图片描述
反汇编地址:82779280

在这里插入图片描述
可以看到如果使用的是sysenter那么这个方法正是我们上面说的KiFastCallEntry

总结:

  1. API通过中断门进0环:
    • 固定中断号为0x2E
    • CS/EIP由门描述符提供 ESP/SS由TSS提供
    • 进入0环后执行的内核函数:NT!KiSystemService
  2. API通过sysenter指令进0环
    • CS/ESP/EIP由MSR寄存器提供(SS通过CS+8算出来)
    • 进入0环后执行的内核函数:NT!KiFastCallEntry
http://www.dtcms.com/a/274749.html

相关文章:

  • vue使用printJS实现批量打印及单个打印 避免空白页
  • Kubernetes 高级调度
  • SSM与SpringBoot面试题
  • Gin 中常见参数解析方法
  • 解锁48V USB-C供电潜力,慧能泰重磅推出PD3.2 DRP芯片HUSB253
  • 使用 SSH 连接 GitHub
  • UC浏览器PC版自2016年后未再更新不支持vue3
  • Grok-4 发布会图文总结
  • 【常见分布及其特征(1)】引言
  • 异步复习(线程)
  • CS144 lab2 tcp_receiver
  • Linux入门篇学习——Linux 编写第一个自己的命令,make 工具和 makefile 文件
  • C语言实现Linux命令行工具:VI和CAT
  • 飞算JavaAI进阶:重塑Java开发范式的AI革命
  • LGA核心板贴装指南:关键细节决定产品成败
  • MD2Doc转换器(基于Python)
  • Java 中的锁分类
  • 网页嵌入与接入功能说明
  • LeetCode经典题解:128、最长连续序列
  • Vue3 postcss-px-to-viewport-8-plugin
  • 力扣-21.合并两个有序链表
  • 【三维重建工具】NeRFStudio、3D GaussianSplatting、Colmap安装与使用指南
  • (7)机器学习小白入门 YOLOv:机器学习模型训练详解
  • 「GRPO训练参数详解:理解Batch构成与生成数量的关系」
  • 如何使用数字化动态水印对教育视频进行加密?
  • 学习日记-spring-day46-7.11
  • 【Linux-云原生-笔记】系统引导修复(grub、bios、内核、系统初始化等)
  • USB数据丢包真相:为什么log打印会导致高频USB数据丢包?
  • 数据库系统的基础知识(三)
  • Logback.xml配置详解与实战指南