zoukankan      html  css  js  c++  java
  • 简单解释Windows如何使用FS段寄存器

    标 题: 简单解释Windows如何使用FS段寄存器
    作 者: rhettxie
    时 间: 2012-12-17,13:32:09
    链 接: http://bbs.pediy.com/showthread.php?t=159935

    昨天有人问我,为什么进程,线程的很多关键信息可以简单的通过FS寄存器来取到。是啊,为什么呢?于是便有了这篇文章。
      
       确实通过读取FS寄存器指定的内存可以获得很多系统关键信息, 主要是和进线程相关的很多信息,例如

    代码:
    lkd> u PsGetCurrentProcess
    nt!IoGetCurrentProcess:
    804f0700 64a124010000    mov     eax,dword ptr fs:[00000124h]
    804f0706 8b4044          mov     eax,dword ptr [eax+44h]
    
    代码:
    lkd> u PsGetCurrentThread
    nt!PsGetCurrentThread:
    8052c42a 64a124010000    mov     eax,dword ptr fs:[00000124h]
    

        可见,fs:[00000124h] 这里存放的是当前线程的KTHREAD,有了这个结构那么当前运行的进程,线程信息就都可以取到了。by the way,这种运行状态相关的信息必然也只能通过最简单的方式获取到,因为这是获取其它信息的源头。linux kernel 通过esp 向下取整到8K 就可以得到 thread_info信息,同样的简单。
        
        那么FS作为段寄存器到底指向的是什么呢? 我取了内核态和用户态FS的值,在内核态FS=0x30, 在用户态FS=0x3B。实际上如果你去看wrk中SwapContext 和 KiSystemServices的代码就会发现,FS 只会是前面提到的两个固定值。OK, 且看内核态FS 指向哪里:

    代码:
    kd> r gdtr
    gdtr=8003f000
    kd> dq 8003f000
    8003f000  00000000`00000000 00cf9a00`0000ffff
    8003f010  00cf9200`0000ffff 00cffa00`0000ffff
    8003f020  00cff200`0000ffff 80008b04`200020ab
    8003f030  ffc092df`f0000001 0040f300`00000fff
    8003f040  0000f200`0400ffff 00000000`00000000
    8003f050  80008954`a3000068 80008954`a3680068
    8003f060  00009202`2f30ffff 0000920b`80003fff
    8003f070  ff0092ff`700003ff 80009a40`0000ffff
    

      我打印了全局描述符GDTR指向的内存内容,FS 指向的描述符应该是其中一项(理论上也有可能指向LDTR,但后面会看到FS没有指向这里)。那么FS到底指的是那一项,这时候需要翻出来INTEL手册了



      

    代码:
    kd> .formats 0x30
    Evaluate expression:
      Hex:     00000030
      Decimal: 48
      Octal:   00000000060
      Binary:  00000000 00000000 00000000 00110000
      Chars:   ...0
      Time:    Thu Jan 01 08:00:48 1970
      Float:   low 6.72623e-044 high 0
      Double:  2.37152e-322
    

    和上面的图对照,0x30 解释的结果是
    RPL 0   TI  0   Index  6
    意思是从GDTR中取第6项,here we go 从前面打印的内存中取第6项,内容为
    ffc092df`f0000001。后面我们需要解释这个描述符项的含义。再次参照intel手册


    代码:
    kd> .formats ffc092df
      
      Binary:  11111111 11000000 10010010 11011111
      
    kd> .formats f0000001
    
      Binary:  11110000 00000000 00000000 00000001
    

      
    按手册中规则的形式,拼接出段的基地址
    11111111 11011111 11110000 00000000
    把这个数值转换成16进制为 0xFFDFF000 。 如果你熟悉windows内核的话现在应该WOW了。是的,这是关于运行态最重要的信息PCR的地址,而且这个地址永远固定在0xFFDFF000(单核,XP)。这里是一个KPCR结构,这个结构里有关于当前线程的所有信息。
        至此,我们搞清楚了在内核里面为什么可以通过FS方便的取得进程,线程信息,也解释前面列举的两个函数的原理。

      在用户态,走一遍我刚才介绍的流程一切也就了然了。过程不再赘述。得到的FS 指向的虚拟内存地址为7ffdd000。这个地址正好是线程的TEB的地址。实际上,KPCR里有字段直接指向了线程的TEB。
      
      

    代码:
    kd> dt -r _kpcr 0xFFDFF000
      nt!_KPCR
         +0x000 NtTib            : _NT_TIB
            +0x000 ExceptionList    : 0xf77c86d8 _EXCEPTION_REGISTRATION_RECORD
               +0x000 Next             : 0xf77c8ce4 _EXCEPTION_REGISTRATION_RECORD
               +0x004 Handler          : 0x80536230           _EXCEPTION_DISPOSITION  nt!_except_handler3+0
            +0x004 StackBase        : 0xf77c8df0 
            +0x008 StackLimit       : 0xf77c5000 
            +0x00c SubSystemTib     : (null) 
            +0x010 FiberData        : (null) 
            +0x010 Version          : 0
            +0x014 ArbitraryUserPointer : (null) 
            +0x018 Self             : 0x7ffdd000 _NT_TIB
               +0x000 ExceptionList    : 0x00d0ffdc _EXCEPTION_REGISTRATION_RECORD
               +0x004 StackBase        : 0x00d10000 
               +0x008 StackLimit       : 0x00d0d000 
               +0x00c SubSystemTib     : (null) 
               +0x010 FiberData        : 0x00001e00 
               +0x010 Version          : 0x1e00
               +0x014 ArbitraryUserPointer : (null) 
               +0x018 Self             : 0x7ffdd000 _NT_TIB
    

        最后我想说,亲自动手分析调试能让你更好的了解真相。行文匆忙,有错误请指正。*转载请注明来自看雪论坛@PEdiy.com


  • 相关阅读:
    第 425 期 Python 周刊
    第 423 期 Python 周刊
    第423期 Python 周刊
    Python Weekly 422
    第421期 Python 周刊
    第420期 Python 周刊
    LeetCode 3: 无重复字符的最长子串 Longest Substring Without Repeating Characters
    Python Weekly 419
    LeetCode 771: 宝石与石头 Jewels and Stones
    LeetCode 652: 寻找重复的子树 Find Duplicate Subtrees
  • 原文地址:https://www.cnblogs.com/kuangke/p/5488489.html
Copyright © 2011-2022 走看看