Click here to Skip to main content
15,443,778 members
Articles / Programming Languages / C++
Posted 21 Jun 2008

Tagged as


57 bookmarked

Entering Ring 0 using minimalistic approach

Rate me:
Please Sign up or sign in to vote.
4.97/5 (15 votes)
21 Jun 2008CPOL2 min read
Kernel adventures of brave developer and other scary tales

What this article is not

This article is meant for people who need easer way of Ring 0 (developing debugging profiling, performance monitoring tools, etc.) and therefore already know what Ring 0 is. Considering how many great tutorials about Protected Mode are already out there. Like Intel 80386 Reference Programmer's Manual or Protected mode programming tutorial it would be like bringing wood to forest. But greatest source are of course Intel and Amd cpu manufacturer manuals themselves.


I recently started development of program called SysMon. It is utility simmilar to RegMon or FileMon but it will monitor systemcalls instead. It requires reading some registers (MSRs etc) that are unfortunately accessible only in mysterious ring 0 land. yet thanks to great idea sharing sites like CodeProject I found interesting way how tho get this data without all that inhuman kernel driver debugging galore just to read one register. Plus printf is printf ;)


I was inspired by many great articles for example here on CodeProject those from old Kernel Adventurer Anton Bassov. Unfortunately many of those were relaying on some offsets which as we know change all the time. Since that code was not working on my version of windows I started windows version independent offset free approach plus I am minimalist so I decimated and decimated and this is the last extract of that mysterious kernel manna. I didn't tested it on vista.

The code

If you remember Msdos days you will some day realize that Windows itself is just another oversized protected mode Application. If you look at any protected mode manual you will find that Intel did build 3 ways of switching between ring levels. Interrupts syscalls or Call Gates ( don't bother, he never picks up )... Anyway Call Gate is exactly what this code does since it's simplest. We read Global Descriptor Table and write back address of our function on first free spot + desired ring level. So when we call this function it begins running at desired ring 0 but returns to previous ring 3 level. As an example I read cr0 register and return some text. So Enjoy it. And I am open to any further ideas how to make this code even simpler.

Word of Advice

Use Windows XP images and VirtualPC from here or similar software to test any changes. As is true with any Device Driver Development. This is Ring 0. Any slightest mistake usually means immediate Reset or Frozen computer.

VirtualPc 2007 have Bug thou. it don't have implemented sgdt in ring 3 so you need to replace this instruction with fixed value while testing.

Following values are valid For XP SP2:

// __asm sgdt gdtr
gdtr.base = 0x8003f000;
gdtr.limit = 0x03ff;

#include    <span class="code-keyword"><windows.h></span>
#include    <span class="code-keyword"><stdio.h></span>

#pragma pack(1)

struct  CALL_GATE { WORD addrlo; WORD seg; BYTE arg:5; BYTE u:3; BYTE typ:5; BYTE dpl:2; BYTE pres:1; WORD addrhi; } ;

#define Virtual(a,b,c,d) { struct VIRTUAL{void* A;void* B;DWORD C;}; VIRTUAL v={(void*)(a),b,c}; hr=NtSystemDebugControl(d,&v,sizeof(v),0,0,0); }

void Ring0( DWORD cs, char*& text ) {
    text = "Hello World from Ring 0 \n";        
    __asm mov eax,cr0
    __asm leave
    __asm retf 4

int main() {

    LONG (NTAPI *NtSystemDebugControl)     (int,void*,DWORD,void*,DWORD,DWORD*);
    *(DWORD*)   &NtSystemDebugControl    =(DWORD)GetProcAddress(LoadLibrary("ntdll"),"NtSystemDebugControl");

    TOKEN_PRIVILEGES pv={1},po; pv.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED ; HANDLE t; int hr; DWORD no;
    // This will enable NtSystemDebugControl usage
    hr = LookupPrivilegeValue(  0, SE_DEBUG_NAME, &pv.Privileges[0].Luid );
    hr = OpenProcessToken(      GetCurrentProcess(), TOKEN_ALL_ACCESS,&t);
    hr = AdjustTokenPrivileges( t,0,&pv,sizeof(po),&po, &no);
    // This ensures that on multi cpu/core systems we patch the right GDT for right cpu
    hr = SetThreadAffinityMask (GetCurrentThread(),1); Sleep(100);

    // We read GDT table
    LDT_ENTRY gdt[1000]={0}; struct {WORD limit;DWORD base;} gdtr; __asm sgdt gdtr
    // Find free spot
    Virtual(gdtr.base, &gdt,gdtr.limit,8);    for(int gate=1;gate<100;gate++)    { if(!gdt[gate].HighWord.Bits.Pres) break; }    
    // Construct Call Gate pointing to Ring0 proc and write it there
    DWORD addr=(DWORD)Ring0; CALL_GATE g={addr&0xffff,8,1,0,12,3,1,addr>>16}; Virtual(gdtr.base+gate*8, &g,8,9); 
    // Quite ugly way to do far call 
    WORD farcall[3]={0,0,(gate<<3)}; char* param=0,**p=&param; long result=0; 

    // Switch from Ring 3 to Ring 0 is just normal call ;)
    __asm push p
    __asm call fword ptr [farcall]
    __asm mov  result, eax

    // Cleanup Call Gate from GDT
    __int64 c=0; Virtual(gdtr.base+gate*8, &c,8,9); 

    printf("\n %s\n  CR0 = %X ",param,result); getchar();    

    return 0;

Locations of visitors

Locations of visitors to this page


This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Written By
Software Developer (Senior)
Slovakia Slovakia
Past Projects:
[]Mobile network software: HLR-Inovation for (Corba)
Medical software: CorRea module for CT scanner
[]Computer Games:XboxLive/net code for Conan, Knights of the temple II, GeneTroopers, CivilWar, Soldier of fortune II
[]Computer Games:XboxLive/net code for Elveon game based on Unreal Engine 3
ESET Reasearch.
Looking for job

Comments and Discussions

QuestionAwesome article, but ... Pin
Khundalini12-Mar-19 8:21
MemberKhundalini12-Mar-19 8:21 
GeneralMy vote of 5 Pin
gndnet5-Jan-11 22:36
Membergndnet5-Jan-11 22:36 
GeneralGreat Article Pin
ShaneMcDonald11-Nov-10 13:05
MemberShaneMcDonald11-Nov-10 13:05 
QuestionHow to go into ring0 Pin
redvc28-May-10 16:10
Memberredvc28-May-10 16:10 
GeneralAwesome! Pin
Bartosz Wójcik11-Jan-10 16:02
MemberBartosz Wójcik11-Jan-10 16:02 
GeneralMore arguments Pin
unix_soul31-Jul-09 1:31
Memberunix_soul31-Jul-09 1:31 
QuestionHelp Please? Pin
Turion18-Jul-09 19:09
MemberTurion18-Jul-09 19:09 
Generalproblem occured beacuse of "__asm call fword ptr [farcall]" Pin
wyybaba28-Mar-09 19:03
Memberwyybaba28-Mar-09 19:03 
GeneralVista/Windows Server 2003 SP1 Pin
french_rt1525-Nov-08 5:46
Memberfrench_rt1525-Nov-08 5:46 
GeneralRe: Vista/Windows Server 2003 SP1 Pin
maddinthegreat5-Jul-11 1:23
Membermaddinthegreat5-Jul-11 1:23 
Generalx64... [modified] Pin
Michael Chourdakis23-Jul-08 22:50
MemberMichael Chourdakis23-Jul-08 22:50 
GeneralRe: x64... Pin
maddinthegreat5-Jul-11 1:28
Membermaddinthegreat5-Jul-11 1:28 
General[Message Deleted] Pin
Saccopharynx29-Jun-08 20:25
MemberSaccopharynx29-Jun-08 20:25 
GeneralRe: It works but not entire at all. Pin
Ladislav Nevery30-Jun-08 4:18
MemberLadislav Nevery30-Jun-08 4:18 
General[Message Deleted] Pin
Saccopharynx1-Jul-08 20:00
MemberSaccopharynx1-Jul-08 20:00 
GeneralRe: It works but not entire at all. [modified] Pin
Ladislav Nevery2-Jul-08 1:36
MemberLadislav Nevery2-Jul-08 1:36 
Questionxp sp2/sp3 Pin
the Same [aaaaaa]24-Jun-08 10:34
Memberthe Same [aaaaaa]24-Jun-08 10:34 
AnswerRe: xp sp2/sp3 Pin
Ladislav Nevery25-Jun-08 2:49
MemberLadislav Nevery25-Jun-08 2:49 
GeneralJobs at Frontier Pin
Kochise23-Jun-08 21:43
MemberKochise23-Jun-08 21:43 
GeneralRe: Jobs at Frontier Pin
Ladislav Nevery25-Jun-08 2:43
MemberLadislav Nevery25-Jun-08 2:43 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.