要注意gdt的第一项是0,不能使用。
然后看gdt中那一项的p位没有置位,再添加一个调用门描述符。描述符的offset指向需要被ring3程序调用的ring0函数地址。DPL为3。当然selector权限也需要是3。描述符中的selector应是0x8,说明是ring0下code段。驱动通过DeviceIoControl传递给ring3程序调用门的selector,当然也可以通过文件注册表之类的。不过这里我有点不解,使用了调用门之后,system("pause");就不起作用了。。有知道的请说一声。由于调用门是段间转移,所以用ret返回是错误的,会蓝屏。得用retf。至于怎么使编译器产生retf,我也不大清楚,所以就直接__declspec(naked)内嵌汇编了。有知道的拜托也说声,谢谢啦。还有,真的,写代码真得小心,我因为&和|的笔误调试了好久。
ring0:
#include <ntddk.h>
/*#pragma pack(1)
typedef struct _CALLGATE
{
USHORT OffsetLow;
USHORT selector;
UCHAR ParamCount :4;
UCHAR SomeBits :4;
UCHAR tyep :4;
UCHAR AppSystem :1;
UCHAR dpl :2;
UCHAR present :1;
USHORT OffsetHigh;
}CALLGATE, *PCALLGATE;
#pragma pack()*/
#pragma pack(1)
typedef struct _CALLGATE
{
USHORT OffsetLow;
USHORT selector;
UCHAR DCount;
UCHAR GType;
USHORT OffsetHigh;
}CALLGATE, *PCALLGATE;
typedef struct _GDT_ENTRY
{
USHORT limit;
ULONG base;
}GDT_ENTRY, *PGDT_ENTRY;
#pragma pack()
#define IOCTL_SELECTOR CTL_CODE(FILE_DEVICE_UNKNOWN,0x800,METHOD_BUFFERED,FILE_READ_DATA|FILE_WRITE_DATA)
CALLGATE OrigCallGate = {0};
PCALLGATE pOrigCallGate = NULL;
USHORT selector = 0;
NTSTATUS DispatchGeneral(PDEVICE_OBJECT pDeviceObject,PIRP pIrp);
NTSTATUS DispatchDeviceControl(PDEVICE_OBJECT pDeviceObject,PIRP pIrp);
VOID DriverUnload(PDRIVER_OBJECT pDriverObject);
VOID AddCallGate(VOID);
MyFunc(VOID);
VOID Ring0Func(VOID);
NTSTATUS DriverEntry(PDRIVER_OBJECT pDriverObject,PUNICODE_STRING pRegistryPath)
{
UNICODE_STRING usDriverName = {0};
UNICODE_STRING usDosDeviceName = {0};
WCHAR wDriverName[] = L"\Device\CallGate";
WCHAR wDosDeviceName[] = L"\DosDevices\CallGate";
PDEVICE_OBJECT pDeviceObject = NULL;
ULONG i = 0;
NTSTATUS NtStatus = STATUS_SUCCESS;
KdPrint(("DriverEntry"));
RtlInitUnicodeString(&usDriverName,wDriverName);
RtlInitUnicodeString(&usDosDeviceName,wDosDeviceName);
NtStatus = IoCreateDevice(pDriverObject,0,&usDriverName,FILE_DEVICE_UNKNOWN,0,FALSE,&pDeviceObject);
if(NT_SUCCESS(NtStatus))
{
for(i = 0;i < IRP_MJ_MAXIMUM_FUNCTION;i++)
{
pDriverObject->MajorFunction[i] = DispatchGeneral;
}
pDriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = DispatchDeviceControl;
pDriverObject->DriverUnload = DriverUnload;
NtStatus = IoCreateSymbolicLink(&usDosDeviceName,&usDriverName);
if(!NT_SUCCESS(NtStatus))
{
IoDeleteDevice(pDeviceObject);
return NtStatus;
}
}
AddCallGate();
return NtStatus;
}
NTSTATUS DispatchGeneral(PDEVICE_OBJECT pDeviceObject,PIRP pIrp)
{
pIrp->IoStatus.Status = STATUS_SUCCESS;
pIrp->IoStatus.Information = 0;
IoCompleteRequest(pIrp,IO_NO_INCREMENT);
return STATUS_SUCCESS;
}
NTSTATUS DispatchDeviceControl(PDEVICE_OBJECT pDeviceObject,PIRP pIrp)
{
PIO_STACK_LOCATION irpsp = NULL;
PUSHORT pOutputBuffer = NULL;
NTSTATUS NtStatus = STATUS_UNSUCCESSFUL;
irpsp = IoGetCurrentIrpStackLocation(pIrp);
switch(irpsp->Parameters.DeviceIoControl.IoControlCode)
{
case IOCTL_SELECTOR:
{
pOutputBuffer = pIrp->AssociatedIrp.SystemBuffer;
if(pOutputBuffer)
{
if(irpsp->Parameters.DeviceIoControl.OutputBufferLength >= 2)
{
pOutputBuffer[0] = selector;
pIrp->IoStatus.Status = STATUS_SUCCESS;
pIrp->IoStatus.Information = 2;
NtStatus = STATUS_SUCCESS;
}
else
{
pIrp->IoStatus.Status = STATUS_BUFFER_TOO_SMALL;
pIrp->IoStatus.Information = 0;
NtStatus = STATUS_BUFFER_TOO_SMALL;
}
}
else
{
pIrp->IoStatus.Status = STATUS_INVALID_PARAMETER;
pIrp->IoStatus.Information = 0;
NtStatus = STATUS_INVALID_PARAMETER;
}
break;
}
}
IoCompleteRequest(pIrp,IO_NO_INCREMENT);
return NtStatus;
}
VOID DriverUnload(PDRIVER_OBJECT pDriverObject)
{
UNICODE_STRING usDosDeviceName = {0};
WCHAR wDosDeviceName[] = L"\DosDevices\CallGate";
KdPrint(("Driver Unload"));
pOrigCallGate->OffsetLow = OrigCallGate.OffsetLow;
pOrigCallGate->selector = OrigCallGate.selector;
pOrigCallGate->DCount = OrigCallGate.DCount;
pOrigCallGate->GType = OrigCallGate.GType;
pOrigCallGate->OffsetHigh = OrigCallGate.OffsetHigh;
RtlInitUnicodeString(&usDosDeviceName,wDosDeviceName);
IoDeleteSymbolicLink(&usDosDeviceName);
IoDeleteDevice(pDriverObject->DeviceObject);
}
VOID AddCallGate(VOID)
{
//PVOID pGdtBase = NULL;
GDT_ENTRY gdtr = {0};
PCALLGATE pCallGate = NULL;
ULONG i = 0;
/*__asm
{
push eax
sgdt [esp-2]
pop eax
mov pGdtBase, eax
}*/
KdPrint(("Add Call Gate"));
__asm sgdt gdtr
for(i = 1;i < gdtr.limit;i++)
{
pCallGate = (PCALLGATE)(gdtr.base + i*8);
if(!(pCallGate->GType & 0x80))
{
KdPrint(("%d",i));
pOrigCallGate = pCallGate;
OrigCallGate.OffsetLow = pCallGate->OffsetLow;
OrigCallGate.selector = pCallGate->selector;
OrigCallGate.DCount = pCallGate->DCount;
OrigCallGate.GType = pCallGate->GType;
OrigCallGate.OffsetHigh = pCallGate->OffsetHigh;
pCallGate->OffsetLow = (USHORT)MyFunc;
pCallGate->selector = 0x8;
pCallGate->DCount = 0;
pCallGate->GType = 0xEC;
pCallGate->OffsetHigh = (USHORT)((ULONG)MyFunc>>16);
selector = (USHORT)((i * 8) | 3);
break;
}
}
}
__declspec(naked) MyFunc(VOID)
{
__asm
{
pushad
pushfd
call Ring0Func
popfd
popad
retf
}
}
VOID Ring0Func(VOID)
{
DbgPrint("call gate");
}
ring3:
#include <windows.h>
#include <winioctl.h>
#include <stdio.h>
#define IOCTL_SELECTOR CTL_CODE(FILE_DEVICE_UNKNOWN,0x800,METHOD_BUFFERED,FILE_READ_DATA|FILE_WRITE_DATA)
int main()
{
HANDLE hFile;
WORD farcall[3];
DWORD dwReturn;
farcall[0] = 0x0;
farcall[1] = 0x0;
farcall[2] = 0x0;
hFile = CreateFile("\\.\CallGate",GENERIC_READ|GENERIC_WRITE,0,NULL,OPEN_EXISTING,0,NULL);
if(hFile != INVALID_HANDLE_VALUE)
{
DeviceIoControl(hFile,IOCTL_SELECTOR,NULL,0,&farcall[2],2,&dwReturn,NULL);
if(farcall[2])
{
__asm call fword ptr [farcall]
}
else
{
printf("unable to get selector");
}
}
else
{
printf("unable to open device
");
}
system("pause");
return 1;
}