Code: Select all
#Include "windows.bi"
Dim Shared NtSystemDebugControl As Function(As Integer, As Any Ptr, As Dword, As Any Ptr, As Dword, As Dword Ptr) As Long
Type CALL_GATE Field = 1
addrlo As Word
Seg As Word
arg:5 As Byte
u:3 As Byte
typ:5 As Byte
dpl:2 As Byte
pres:1 As Byte
addrhi As Word
End Type
Type gdtrStruct Field = 1
limit As Word
base As Dword
End Type
Type VIRTUAL1 Field = 1
A As Any Ptr
B As Any Ptr
C As Dword
End Type
#Define Virtual(_a_, _b_, _c_, _d_) Scope: Var v = Type<VIRTUAL1>((_a_), (_b_), (_c_)): NtSystemDebugControl((_d_), @v, SizeOf(v), 0, 0, 0): End Scope
' This sub will be executed in kernel mode!
Sub Ring0(cs As Dword, text As ZString Ptr)
*text = !"Hello World from Ring 0 \n"
' Store value of control register 0 in eax (which is normally not allowed) in order to prove we are in Ring 0!
Asm mov eax, cr0
' Return to Ring 3
Asm
leave
.byte 0xCA ' retf 4
.word 4
End Asm
End Sub
Function Main() As Integer
NtSystemDebugControl = GetProcAddress(LoadLibrary("ntdll"), "NtSystemDebugControl")
Dim As TOKEN_PRIVILEGES pv, po
pv.PrivilegeCount = 1
pv.Privileges(0).Attributes = SE_PRIVILEGE_ENABLED
Dim As HANDLE t
Dim As Dword no
' This will enable NtSystemDebugControl usage
LookupPrivilegeValue(0, SE_DEBUG_NAME, @pv.Privileges(0).Luid)
OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS, @t)
AdjustTokenPrivileges(t, 0, @pv, SizeOf(po), @po, @no)
' This ensures that on multi cpu/core systems we patch the right GDT for right cpu
SetThreadAffinityMask(GetCurrentThread(), 1)
SleepEx(100, FALSE)
' We read GDT table
Dim As LDT_ENTRY gdt(1000)
Dim As gdtrStruct gdtr
Asm sgdt [gdtr]
' Find free spot
Virtual(gdtr.base, @gdt(0), gdtr.limit, 8)
Dim As Integer gate
For i As Integer = 1 To 99
If gdt(i).HighWord.Bits.Pres = 0 Then
gate = i
Exit For
EndIf
Next
' Construct Call Gate pointing to Ring0 proc and write it there
Var addr = CUInt(@Ring0)
Dim As CALL_GATE g = Type(addr And &hFFFF, 8, 1, 0, 12, 3, 1, addr Shr 16)
Virtual(gdtr.base + gate * 8, @g, 8, 9)
' Quite ugly way to do far call
Dim As Word farcall(3) = {0, 0, gate Shl 3}
Dim As ZString Ptr param = CAllocate(100)
Dim As Long result
' Switch from Ring 3 to Ring 0 is just normal call ;)
Asm
push [param]
call fword Ptr [farcall]
mov [result], eax
End Asm
' Cleanup Call Gate from GDT
Dim As LongInt c = 0
Virtual(gdtr.base + gate * 8, @c, 8, 9)
Print !"\n" & *param & !"\nCR0 = " & Hex(result, 8)
Sleep
DeAllocate(param)
Return 0
End Function
End(Main())
greetings, Cherry