在这个驱动随便什么人都可以写的时代里。
DeviceIoControl通信肯定是被人用烂了的。
用hook 通信么,又不支持x64系统。
Callback通信又多写很多代码。
WMI通信代码写起来很烦人,Flt通信代码也很冗长。
于是猜测是不是可以用CREATEFILE来通信呢?


观察ZwCreateFile的参数,发现有一个EA参数,这个东西是一个可以自己改变大小的结构体。
NTSTATUS ZwCreateFile(
_Out_ PHANDLE FileHandle,
_In_ ACCESS_MASK DesiredAccess,
_In_ POBJECT_ATTRIBUTES ObjectAttributes,
_Out_ PIO_STATUS_BLOCK IoStatusBlock,
_In_opt_ PLARGE_INTEGER AllocationSize,
_In_ ULONG FileAttributes,
_In_ ULONG ShareAccess,
_In_ ULONG CreateDisposition,
_In_ ULONG CreateOptions,
_In_opt_ PVOID EaBuffer,
_In_ ULONG EaLength
);
EA的基础结构是
typedef struct _FILE_FULL_EA_INFORMATION {
ULONG NextEntryOffset;
UCHAR Flags;
UCHAR EaNameLength;
USHORT EaValueLength;
CHAR EaName[1];
} FILE_FULL_EA_INFORMATION, *PFILE_FULL_EA_INFORMATION;
于是可以写出一个IRP_MJ_CREATE处理根据EA来进行处理,这样通信代码就很简单了。
驱动的代码写起来很简单了。
NTSTATUS
DrvCreate(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
{
PIO_STACK_LOCATION IoStack = IoGetCurrentIrpStackLocation(Irp);
NTSTATUS ntStatus = STATUS_SUCCESS;
PFILE_FULL_EA_INFORMATION StartEA, ea;
StartEA = (PFILE_FULL_EA_INFORMATION)Irp->AssociatedIrp.SystemBuffer;
if ( StartEA != NULL )
ntStatus = ProcessEA(StartEA);
Irp -> IoStatus.Status = ntStatus;
Irp -> IoStatus.Information = 0;
IoCompleteRequest ( Irp, IO_NO_INCREMENT );
return ntStatus;
}
应用层填充起来也很容易:
CHAR Buffer[sizeof(FILE_FULL_EA_INFORMATION) + CMD_LENGTH + sizeof(CMD_STRING)] = {0};
PFILE_FULL_EA_INFORMATION Ea = (PFILE_FULL_EA_INFORMATION)&Buffer;
PCMD_CONTEXT cmd;
Ea->NextEntryOffset = 0;
Ea->Flags = 0;
Ea->EaNameLength = CMD_LENGTH;
RtlCopyMemory(Ea->EaName, CMD_STRING, CMD_LENGTH);
Ea->EaValueLength = sizeof(CMD_CONTEXT);
cmd = (PCMD_CONTEXT)&Ea->EaName[Ea->EaNameLength+1];
cmd->dwKey = dwCmd;
剩下的东西很简单了,无非就是用ZwCreateFile通信了~
具体完整事例代码见附件了。
CreateEADemo.zip抛弃DeviceIoControl之后是不是世界很清凉呢?
[培训]科锐逆向工程师培训第53期2025年7月8日开班!