整个结构会很复杂,比如处理IRP部分:
模型中我们最需要关注这三个概念:
DRIVER_OBJECT
包含许多驱动程序标准例程的入口点的存储。同样重要的是要注意这一点:当 I/O 管理器处理 IRP
时,它会将当前驱动程序的DRIVER_OBJECT
内存地址提供给名为 DriverEntry
的主函数。更详细的描述参考链接1。
了解一些重要的结构能帮助我们快速构建需要的payload
。
它是 Input/Output Request Packet
的简称,在WDM.H
定义了标准的NT结构。如下:
我们重点关注两个元素:
该结构体有上面提到的 CurrentStackLocation
指定,其结构可以从这查看https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/wdm/ns-wdm-_io_stack_location
。
我们需要关注的两个结构体是:
该结构体位于 IO_STACK_LOCATION结构中,标识驱动程序处理 I/O 请求的逻辑、虚拟或物理设备。
把上面的结构体组好到一起,就是DRIVER_OBJECT
每个驱动程序都包含主要功能代码(major function codes),这些代码告诉驱动程序应执行哪些操作来满足 I/O 请求。所有驱动程序必须至少支持:
下面将给一个实际的例子,直接上demo。
核心功能将被放置在vikingdrv2DeviceControl
例程中,该例程有两个参数:
首先把IO_STACK_LOCATION
指针存储到栈上,该结构用来接受用户发来的信息:
大致结构如下:
然后我们定义名为 DriverEntry
的主函数。如前所述,此函数获取指向DRIVER_OBJECT
结构的指针。为了知道在提供IRP_MJ
代码时必须执行哪个函数,驱动程序必须定义调度例程(dispatch routine)。这里最重要的是使其能够处理IRP_MJ_DEVICE_CONTROL
消息:让它指向 vikingdrv2DeviceControl
函数。
这就是一个简单基础的驱动实例~,确实很基础,但是能用。
参考自https://leanpub.com/windowskernelprogramming
,写一个简单的驱动程序,需要完成三个功能:
驱动程序客户端和驱动程序本身必须具有“通用”说话方式。DeviceIoControl
函数将控制代码直接发送到指定的设备驱动程序,使设备执行相应的操作。这个函数有三个重要的部分:
创建入口点:
DriverEntry(_In_ PDRIVER_OBJECT DriverObject, _In_ PUNICODE_STRING RegistryPath)
设置调度例程来处理IRP_MJ_DEVICE_CONTROL
/驱动程序对象:我们将函数命名为vikingdrv2DeviceControl
。
DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = vikingdrv2DeviceControl;
提供device name
和symlink name
名称,然后创建设备对象,以便客户端可以访问驱动程序并打开文件系统句柄。
现在我们有一个指向设备对象的指针,通过提供符号链接使用户模式调用方可以访问它。
前面是准备处理请求部分,下面是如何处理它。
首先,我们必须找到我们的堆栈位置(从驱动程序的角度来看),并确认我们的客户端/用户给了我们一个我们能够处理的 IOCTL。
然后我们处理缓冲区以检索客户端准备的 ThreadData
结构
auto data = (ThreadData*)stack->Parameters.DeviceIoControl.Type3InputBuffer;
最终,我们会处理客户提供的数据。这里我们修改进程的线程优先级:
在内核部分:驱动程序正在等待请求。现在客户端代码呢?
首先,让我们创建一个处理用户提供的参数的 main 函数。
然后使用符号链接打开设备的句柄。
现在,调用 DeviceIoControl 并在之后关闭设备句柄。
编译此驱动程序会生成一个文件.sys该文件可以作为服务安装:
sc create viking_drv2 type= kernel binpath= C:\viking_driver2.sys
然后禁用签名验证,如果驱动程序已签名,则启用测试签名模式并禁用完整性检查。
重启并启动服务。
这个例子参考自Windows Kernel Programming
。肯定会运行的,但是问题是目的是提权,而不是修改线程优先级。
寻找线程内存环境:
当 PsLookupProcessByProcessId
API 结束时,名为 process
和 system_process
的 PEPROCESS
结构可用,并且包含获取有关请求的 PID(以及系统 pid 编号 4)的信息所需的所有内容。
获取进程 token:
上面所有操作完成之后,提权需要重新写一个客户端,先中止进程:
FindAndReplaceMember((PDWORD_PTR)process, (DWORD_PTR)targetToken, (DWORD_PTR)systemToken, MaxExpectedEprocessSize);
但是不用再启用vs,直接使用ps代替调用:
看看效果
typedef struct _IRP {
CSHORT
Type
;
USHORT Size;
PMDL MdlAddress;
ULONG Flags;
union {
struct _IRP
*
MasterIrp;
__volatile
LONG
IrpCount;
PVOID SystemBuffer;
} AssociatedIrp;
LIST_ENTRY ThreadListEntry;
IO_STATUS_BLOCK IoStatus;
KPROCESSOR_MODE RequestorMode;
BOOLEAN PendingReturned;
CHAR StackCount;
CHAR CurrentLocation;
BOOLEAN Cancel;
KIRQL CancelIrql;
CCHAR ApcEnvironment;
UCHAR AllocationFlags;
union {
PIO_STATUS_BLOCK UserIosb;
PVOID IoRingContext;
};
PKEVENT UserEvent;
union {
struct {
union {
PIO_APC_ROUTINE UserApcRoutine;
PVOID IssuingProcess;
};
union {
PVOID UserApcContext;
_IORING_OBJECT
*
IoRing;
struct _IORING_OBJECT
*
IoRing;
};
} AsynchronousParameters;
LARGE_INTEGER AllocationSize;
} Overlay;
__volatile PDRIVER_CANCEL CancelRoutine;
PVOID UserBuffer;
union {
struct {
union {
KDEVICE_QUEUE_ENTRY DeviceQueueEntry;
struct {
PVOID DriverContext[
4
];
};
};
PETHREAD Thread;
PCHAR AuxiliaryBuffer;
struct {
LIST_ENTRY ListEntry;
union {
struct _IO_STACK_LOCATION
*
CurrentStackLocation;
ULONG PacketType;
};
};
PFILE_OBJECT OriginalFileObject;
} Overlay;
KAPC Apc;
PVOID CompletionKey;
} Tail;
} IRP;
typedef struct _IRP {
CSHORT
Type
;
USHORT Size;
PMDL MdlAddress;
ULONG Flags;
union {
struct _IRP
*
MasterIrp;
__volatile
LONG
IrpCount;
PVOID SystemBuffer;
} AssociatedIrp;
LIST_ENTRY ThreadListEntry;
IO_STATUS_BLOCK IoStatus;
KPROCESSOR_MODE RequestorMode;
BOOLEAN PendingReturned;
CHAR StackCount;
CHAR CurrentLocation;
BOOLEAN Cancel;
KIRQL CancelIrql;
CCHAR ApcEnvironment;
UCHAR AllocationFlags;
union {
PIO_STATUS_BLOCK UserIosb;
PVOID IoRingContext;
};
PKEVENT UserEvent;
union {
struct {
union {
PIO_APC_ROUTINE UserApcRoutine;
PVOID IssuingProcess;
};
union {
PVOID UserApcContext;
_IORING_OBJECT
*
IoRing;
struct _IORING_OBJECT
*
IoRing;
};
} AsynchronousParameters;
LARGE_INTEGER AllocationSize;
} Overlay;
__volatile PDRIVER_CANCEL CancelRoutine;
PVOID UserBuffer;
union {
struct {
union {
KDEVICE_QUEUE_ENTRY DeviceQueueEntry;
struct {
PVOID DriverContext[
4
];
};
};
PETHREAD Thread;
PCHAR AuxiliaryBuffer;
struct {
LIST_ENTRY ListEntry;
union {
struct _IO_STACK_LOCATION
*
CurrentStackLocation;
ULONG PacketType;
};
};
PFILE_OBJECT OriginalFileObject;
} Overlay;
KAPC Apc;
PVOID CompletionKey;
} Tail;
} IRP;
typedef struct _DRIVER_OBJECT {
CSHORT
Type
;
CSHORT Size;
PDEVICE_OBJECT DeviceObject;
ULONG Flags;
PVOID DriverStart;
ULONG DriverSize;
PVOID DriverSection;
PDRIVER_EXTENSION DriverExtension;
UNICODE_STRING DriverName;
PUNICODE_STRING HardwareDatabase;
PFAST_IO_DISPATCH FastIoDispatch;
PDRIVER_INITIALIZE DriverInit;
PDRIVER_STARTIO DriverStartIo;
PDRIVER_UNLOAD DriverUnload;
PDRIVER_DISPATCH MajorFunction[IRP_MJ_MAXIMUM_FUNCTION
+
1
];
} DRIVER_OBJECT,
*
PDRIVER_OBJECT;
typedef struct _DRIVER_OBJECT {
CSHORT
Type
;
CSHORT Size;
PDEVICE_OBJECT DeviceObject;
ULONG Flags;
PVOID DriverStart;
ULONG DriverSize;
PVOID DriverSection;
PDRIVER_EXTENSION DriverExtension;
UNICODE_STRING DriverName;
PUNICODE_STRING HardwareDatabase;
PFAST_IO_DISPATCH FastIoDispatch;
PDRIVER_INITIALIZE DriverInit;
PDRIVER_STARTIO DriverStartIo;
PDRIVER_UNLOAD DriverUnload;
PDRIVER_DISPATCH MajorFunction[IRP_MJ_MAXIMUM_FUNCTION
+
1
];
} DRIVER_OBJECT,
*
PDRIVER_OBJECT;
NTSTATUS vikingdrv2DeviceControl(PDEVICE_OBJECT, PIRP Irp) {
auto stack
=
IoGetCurrentIrpStackLocation(Irp);
switch (stack
-
>Parameters.DeviceIoControl.IoControlCode) {
case IOCTL_number1: {
auto data
=
(ThreadData
*
)stack
-
>Parameters.DeviceIoControl.Type3InputBuffer;
}
...
}
}
NTSTATUS vikingdrv2DeviceControl(PDEVICE_OBJECT, PIRP Irp) {
auto stack
=
IoGetCurrentIrpStackLocation(Irp);
switch (stack
-
>Parameters.DeviceIoControl.IoControlCode) {
case IOCTL_number1: {
auto data
=
(ThreadData
*
)stack
-
>Parameters.DeviceIoControl.Type3InputBuffer;
}
...
}
}
NTSTATUS DriverEntry(_In_ PDRIVER_OBJECT DriverObject, _In_ PUNICODE_STRING RegistryPath) {
/
/
调度例程 dispatch routine
DriverObject
-
>MajorFunction[IRP_MJ_CREATE]
=
vikingdrv2CreateClose;
DriverObject
-
>MajorFunction[IRP_MJ_CLOSE]
=
vikingdrv2CreateClose;
DriverObject
-
>MajorFunction[IRP_MJ_DEVICE_CONTROL]
=
vikingdrv2DeviceControl;
}
NTSTATUS DriverEntry(_In_ PDRIVER_OBJECT DriverObject, _In_ PUNICODE_STRING RegistryPath) {
/
/
调度例程 dispatch routine
DriverObject
-
>MajorFunction[IRP_MJ_CREATE]
=
vikingdrv2CreateClose;
DriverObject
-
>MajorFunction[IRP_MJ_CLOSE]
=
vikingdrv2CreateClose;
DriverObject
-
>MajorFunction[IRP_MJ_DEVICE_CONTROL]
=
vikingdrv2DeviceControl;
}
0x800
, METHOD_NEITHER, FILE_ANY_ACCESS)
struct ThreadData {
ULONG ThreadId;
int
Priority;
};
0x800
, METHOD_NEITHER, FILE_ANY_ACCESS)
struct ThreadData {
ULONG ThreadId;
int
Priority;
};
UNICODE_STRING devName
=
RTL_CONSTANT_STRING(L
"\\Device\\vikingdrv2"
);
/
/
驱动名
UNICODE_STRING symLink
=
RTL_CONSTANT_STRING(L
"\\??\\vikingdrv2"
);
/
/
symlink
PDEVICE_OBJECT DeviceObject;
NTSTATUS status
=
IoCreateDevice(
DriverObject,
/
/
自定义的驱动对象
0
,
& devName,
/
/
device name,
FILE_DEVICE_UNKNOWN,
/
/
device
type
,
0
,
/
/
characteristics flags,
FALSE,
& DeviceObject
/
/
输出指针位置
);
if
(!NT_SUCCESS(status)) {
KdPrint((
"Failed to create device object (0x%08X)\n"
, status));
return
status;
}
UNICODE_STRING devName
=
RTL_CONSTANT_STRING(L
"\\Device\\vikingdrv2"
);
/
/
驱动名
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)