CSDN博客

img sssa2000

学习心得----seh(4)

发表于2004/7/8 17:05:00  894人阅读

解读cih进入ring0的秘密

  看了大家对前面几篇的评论,觉得有点怪异,看来大家对技术的追求还不是那么强烈,声明以下,我写的这些东西或许永远也不会对你的实际应用有帮助,这只是黑客们对技术的研究,如果你的愿望只是一般的编程,这篇文章不适合你。

  这几天开始编一个游戏,以前没有接触过游戏编程,觉得很有意思,还有directX的编程,真得很爽,我估计也就几天的热情吧,呵呵。

  还有,我知道我的老婆每天都来看我的文章,这里问个好:亲爱的tina,你好啊!

  正题。

  我们今天研究的代码主要是进入ring0的实现。首先我们要有几个问题,不知道你们有没有这样的问题,反正我在研究cih的时候是有。

  1、什么是ring0?

  2、为什么要进入ring0?

  3、怎么样才算进入ring0

  现在解答一下。

  什么是ring0呢?windows分4层保护结构,最核心的ring0,最外面的是ring3,ring0层的应用程序可以直接和硬件打交道,其他层的就必须通过hal.dll来调用相应的api来和硬件打交道,所以如果想突破限制,搞些破坏就要进入ring0.

怎么才算进入ring0? 当cs=28,ds=30时就可以认为进入了ring0.

  进入的方法还有很多种,比如什么中断门,陷阱门,调用门,具体请察看微机原理相应的知识。

  怎么通过seh进入呢?记得上一章我们说的lpcontext么?就是靠它了!

  现在说一下流程:

1、设置seh链表

2、触发断点异常int3

3、清除自己触发的异常

4、通过lpcontext修改cs=28,ds=30

这就是主要的了,是不是很简单亚。其实到昨天我还是想不通为什么要通过seh才能修改,今天终于灵光一现,想通了,其实就是看我自己写的第3篇的那段关于lpcontext的话才想到的,呵呵。

 

下面是我学习cih的代码,我也加入了一些注释,你们看吧:

;;;;;;;;;;;;;;;;;;;;;;;;;;我估计这段代码使tasm编译的,和masm有些不一样

include "../inc/win32n.inc"

 

extern    _ExitProcess@4

extern    _GetTickCount@0

extern    _GetStdHandle@4

extern    _MessageBeep@4

extern    _WriteConsoleA@20

 

global _mainCRTStartup

 

SEGMENT .text USE32 class=code

 

_mainCRTStartup

    push    dword STD_OUTPUT_HANDLE                ;

    call    _GetStdHandle@4                        ;获取输出控制屏的句柄

    mov    [stdout],eax                            ;保存句柄

 

    ;******************************************

    ;* 以下这一段是按照SEH必要的方式形成链表

    ;******************************************

    xor    ebx,ebx        ;先清0

    push    dword eh      ;压入自己ExceptHandle指针,即 eh 处

    push    dword [fs:ebx]                        ;压入当前[FS:0] ,想想为什么不直接fs:0?

    mov    [fs:ebx],esp                            ;形成链表形式

 

 

    pushfd                                        ;入栈保存当前EFlags标志寄存器的内容

    mov    eax,esp                                    ;保存当前堆栈指针到 eax

 

    ;******************************************

    ;* 这里将产生断点中断,从而进入异常处理程序

    ;******************************************

    int3

 

    ;******************************************

    ;* 这里是从异常处理程序中返回后来到的地址

    ;******************************************

    mov    ebx,cr3                                    ;以后将会显示ebx的内容,即显示 cr3 的内容

 

    ;**************************************************************************************

    ;* 以下是一种特殊方式的跳转。由于使用 push/iretd 来进行跳转,注意不是 push/retn。

    ;* 所以,在堆栈中要把各个寄存器的内容入栈,这是因为当中断发生时,系统会自动把

    ;* 这些寄存器的内容入栈,而在 iretd 返回时自动出栈。这就是 iretd 和 retn 的区别。

    ;* 另外,由于在异常处理程序中进行了以下修改。所以刚返回时:ECX=CS,CS=28,EDX=SS,SS=30,

    ;* 所以,此时我们看到各寄存器的内容与此相同。这主要是一种演示,或者说是一种简单的应用。

    ;这一段我也不懂,不懂为什么可以达到目的,我和figozhu讨论过,也没有答案,这个我先欠大家的 **************************************************************************************

    push    dword edx        ; GS

    push    dword edx        ; FS

    push    dword edx        ; ES

    push    dword edx        ; DS

    push    dword edx        ; SS

    push    eax                ; ESP

    push    dword [eax]        ; EFLAGS

    push    dword ecx        ; CS

    push    dword .wow        ; EIP

    iretd

.wow

    ;******************************************

    ;* 显示 ebx 的内容

    ;******************************************

    popfd

    call    printaddress

 

    ;******************************************

    ;* 这一段将在SEH链表中清除自己的异常处理

    ;******************************************

    pop    dword [fs:0]                            ;通过出栈的方式修改[FS:0]的内容

    add    esp,4

 

    push    dword MB_ICONASTERISK

    call    _MessageBeep@4                        ;鸣声提示

 

    push    dword 0

    call    _ExitProcess@4                        ;退出程序

;    retn

 

;******************************************

;* 这里是自己的异常处理程序开始

;******************************************

eh

    push    ebp   ;保存ebp,当前指针

    mov    ebp,esp

    push    ebx                                    ;入栈保存

    push    ecx                                    ;入栈保存

 

    ;******************************************

    ;* 这一段为判断异常标志(ExceptionFlags)是否

    ;* 为UNWIND_STACK。

    ;******************************************

    mov    eax,[ebp+8]                                ;[EBP+8]=EXCEPTION_RECORD_ptr,即EAX为EXCEPTION_RECORD的指针 。

    test    dword [eax+4],6                        ;[EAX+4]=EXCEPTION_RECORD_ptr->ExceptionFlags,

                                                ;即判断ExceptionFlags是否为UNWIND_STACK,此在SEH.inc中有定义

    jz    .cont                                    ;是,则跳转

 

    ;******************************************

    ;* 显示 oi

    ;******************************************

    push    dword 0    ;保存现场后调用函数显示

    push    dword written

    push    dword 2

    push    dword oi

    push    dword [stdout]

    call    _WriteConsoleA@20

    mov    eax,1

    jmp    .e

 

.cont

    ;*********************************************************

    ;* 判断异常代码(ExceptionCode)是否为EXCEPTION_BREAKPOINT ,也就是int3

    ;*********************************************************

    mov    ebx,[ebp+8]                                ;[EBP+8]=EXCEPTION_RECORD_ptr,即EAX为EXCEPTION_RECORD的指针           

    mov    eax,1

    cmp    dword [ebx],0x80000003                    ;[EBX]=EXCEPTION_RECORD_ptr->ExceptionCode, int3的异常特征码是0x80000003

                                                ;即判断ExceptionCode是否为EXCEPTION_BREAKPOINT(断点标志)

    jne    .e                                        ;不是,则跳转,返回值EAX为1

 

    ;**********************************************************

    ;* 修改xFrame_RECORD_ptr->cx_Ecx=xFrame_RECORD_ptr->cxSegCs

    ;主要利用context来修改**********************************************************

    mov    eax,[ebp+0x10]                            ;[EBP+10]=xFrame_RECORD_ptr,即EAX为xFrame_RECORD的指针

    movzx    ecx,word [eax+CONTEXT.cx_SegCs]

    mov    [eax+CONTEXT.cx_Ecx],ecx                ;xFrame_RECORD_ptr->cx_Ecx=xFrame_RECORD_ptr->cxSegCs

 

    ;**********************************************************

    ;* 修改xFrame_RECORD_ptr->cx_SegCs=0x28

    ;**********************************************************

    mov    dword [eax+CONTEXT.cx_SegCs],0x28 ;修改cs=28

 

    ;**********************************************************

    ;* 修改xFrame_RECORD_ptr->cx_Edx=xFrame_RECORD_ptr->cxSegSs

    ;**********************************************************

    movzx    ecx, word [eax+CONTEXT.cx_SegSs]

    mov    [eax+CONTEXT.cx_Edx],ecx

 

    ;**********************************************************

    ;* 修改xFrame_RECORD_ptr->cx_SegSs=0x30

    ;**********************************************************

    mov    dword [eax+CONTEXT.cx_SegSs],0x30

;ss=30

    ;**********************************************************

    ;* 修改xFrame_RECORD_ptr->cx_EFlags=0x0200

    ;**********************************************************

    or    dword [eax+CONTEXT.cx_EFlags],0x0200    ;设置EFlags中的IF标志(中断允许标志)为1,即 CLI

 

    ;*********************************************************

    ;* 在控制屏上显示 ebx 的内容

    ;*********************************************************

    mov    ebx,0x12345678

    call    printaddress

 

    ;*********************************************************

    ;* EAX=0,即通知Kernel将继续执行

    ;*********************************************************

    mov    eax,0

 

.e

    pop    ecx                   ;恢复现场                     ;出栈恢复

    pop    ebx                                        ;出栈恢复

    mov    esp,ebp

    pop    ebp

    retn                                        ;返回

;******************************************

;* 这里是自己的异常处理程序结束处 到这里进入ring0也结束了

;******************************************

 

;******************************************

;* 转换ebx的内容为字符形式,并在屏幕上显示

;* ebx为入口参数,代表一个地址

;******************************************

printaddress

    push    ecx            ; just a lame routine to print out

    push    edx            ; a hex address, no explanations ;-)

 

    xor    ecx,ecx

.n

    rol    ebx,4

    mov    dl,bl

    and    dl,0x0F

    cmp    dl,0x9

    ja    .abcdef

    add    dl,'0'

    jmp    .a

.abcdef

    add    dl,'A'-0xA

.a

    mov    [ecx+address],dl

    inc    cl

    cmp    cl,8

    jne    .n

 

    push    dword 0

    push    dword written

    push    dword 9

    push    dword address

    push    dword [stdout]

    call    _WriteConsoleA@20

 

    pop    edx

    pop    ecx

    retn

 

SEGMENT .data USE32 class=data

 

stdout    dd 0

onedot    db '.'

oi    db '!',0x0A

written    dd 0

address    db 0,1,2,3,4,5,6,7,0x0A

;**********************************end********

 

好了,该说得都说了,代码也贴出来了,是不是觉得有点拨云见日的感觉?我是有这种感觉的,以前听他们说怎么怎么难,其实也不过如此,所以没有亲身体会过的人是没有资格评论什么难易的。

 

要随时准备学习新的技术,这是我的心得。接下来准备写点apihook的文章,自己学习也希望和朋友们分享,如果有时间我想每天写一篇文章,比玩游戏好。

0 0

相关博文

我的热门文章

img
取 消
img