• 标 题:怎样利用SEH技巧进入Ring0级 (8千字)
  • 作 者:ljtt
  • 时 间:2001-4-7 21:17:57
  • 链 接:http://bbs.pediy.com

欢迎各位有空光临小站。http://st0ne.go.163.com

『技术研习』  『以前更新』 

--------------------------------------------------------------------------------


怎样利用SEH技巧进入Ring0级

【前言】
这份源码我学习到现在有一段时间了。其中的一些注释是我自己加上的。现在就作一份资料和大家交流吧。
注意几点情况:1、这种方法只能在Windows95/98下使用,如果在NT/2000下使用是不成功的。
______________2、当段选择符CS=28、DS=30时,在Windows98下即为Ring0级时的选择符。
______________3、CR3的内容和内存定址有关,只有在Ring0级才可以读出其内容,否则非法。所以这里通过读CR3的内容来验证是否进入了Ring0级。
______________4、完整的源码我已经上传到主页的"源码学习"下。这里来"下载"。

; 分析日期:2000-10-24
; 此程序主要为SEH技术的一种应用,这里将详细的注释说明。这是我今天分析的第二个相关源程序

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
    push    dword eh                            ;压入自己Except Handle指针,即 eh 处
    push    dword [fs:ebx]                        ;压入当前[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,
    ;* 所以,此时我们看到各寄存器的内容与此相同。这主要是一种演示,或者说是一种简单的应用。
    ;**************************************************************************************
    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
    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
    ;*********************************************************
    mov    ebx,[ebp+8]                                ;[EBP+8]=EXCEPTION_RECORD_ptr,即EAX为EXCEPTION_RECORD的指针           
    mov    eax,1
    cmp    dword [ebx],0x80000003                    ;[EBX]=EXCEPTION_RECORD_ptr->ExceptionCode,
                                                ;即判断ExceptionCode是否为EXCEPTION_BREAKPOINT(断点标志)
    jne    .e                                        ;不是,则跳转,返回值EAX为1

    ;**********************************************************
    ;* 修改xFrame_RECORD_ptr->cx_Ecx=xFrame_RECORD_ptr->cxSegCs
    ;**********************************************************
    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

    ;**********************************************************
    ;* 修改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

    ;**********************************************************
    ;* 修改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                                        ;返回
;******************************************
;* 这里是自己的异常处理程序结束处
;******************************************

;******************************************
;* 转换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

 

--------------------------------------------------------------------------------

《加密及解密技术交流站》由 ljtt 制作 版权所有
©2000 -2001 All Rights Reserved
 
转载本站所有文章请注明出处,尊重作者的劳动也是尊重你自己。让我们一同撑起绿色的天空!