目的
在Win7 64位系统上编写驱动利用ExRegisterAttributeInformationCallback
注册回调进行通信
操作步骤
1.利用MmGetSystemRoutineAddress
获取ExRegisterAttributeInformationCallback中ExpDisSetAttributeInformation、ExpDisQueryAttributeInformation全局变量位置,并将其置为0,以实现执行到注册的目标回调函数
2.三环部分利用NtQueryInformationFile
进行通信,最后一项的FileInformationClass
成员置为0x34以实现调用到0环注册的回调函数
3.在卸载驱动时将其原先保存的ExpDisQueryAttributeInformation、ExpDisSetAttributeInformation进行恢复,否则将蓝屏
逆向分析
箭头所标记位置进行判断全局变量ExpDisSetAttributeInformation、ExpDisQueryAttributeInformation是否为空,如果不为空就不进行注册,所以需要在操作步骤一中将其进行置0
对ExpDisQueryAttributeInformation进行交叉引用发现其最终会通过NtQueryInformationFile进行调用
NtQueryInformationFile中会判断成员FileInformationClass是否为0x34,如果不为0x34则不进行调用ExQueryAttributeInformation
实现代码
Win7_Comm.h(通信头文件)
#pragma once
#include<ntifs.h>
typedef struct _CommPackage
{
ULONG64 Id;
ULONG64 cmd;
ULONG64 Data;
ULONG64 Size;
ULONG64 retStatus;
}CommPackage, * PCommPackage;
typedef NTSTATUS(*CommCallbackProc)(PCommPackage package);
typedef NTSTATUS(*FileCallBack)(HANDLE FileHandle, PVOID info);
typedef struct _RegisterCallback
{
FileCallBack QueryFileCallback;
FileCallBack SetFileCallBack;
}RegisterCallback, * PRegisterCallback;
typedef NTSTATUS(*ExRegisterAttributeInformationCallbackProc)(PRegisterCallback callbacks);
NTSTATUS CommWin7(CommCallbackProc callback);
VOID UnRegisterCommWin7();
VOID UnRegisterCommWin10();
VOID UnRegisterComm();
NTSTATUS SetFileCallBack(HANDLE FileHandle, PVOID info);
NTSTATUS QueryFileCallBack(HANDLE FileHandle, PVOID info);
Win7_Comm.c (通信实现代码)
#include"Win7_comm.h"
FileCallBack oldExpDisQueryAttributeInformationFunc = 0;
FileCallBack oldExpDisSetAttributeInformationFunc = 0;
CommCallbackProc gCommCallback = NULL;
PULONG64 gWin7CallbackVar = 0;
NTSTATUS QueryFileCallBack(HANDLE FileHandle, PVOID info)
{
KdPrintEx((77, 0, "QueryFileCallBack\r\n"));
if (MmIsAddressValid(info))
{
PCommPackage package = (PCommPackage)info;
if (package->Id == 0x12345678)
{
package->retStatus = gCommCallback(package);
}
else
{
if (oldExpDisQueryAttributeInformationFunc)
{
return oldExpDisQueryAttributeInformationFunc(FileHandle, info);
}
}
}
return STATUS_SUCCESS;
}
NTSTATUS SetFileCallBack(HANDLE FileHandle, PVOID info)
{
KdPrintEx((77, 0, "SetFileCallBack\r\n"));
if (MmIsAddressValid(info))
{
PCommPackage package = (PCommPackage)info;
if (package->Id == 0x12345678)
{
package->retStatus = gCommCallback(package);
}
else
{
if (oldExpDisSetAttributeInformationFunc)
{
return oldExpDisSetAttributeInformationFunc(FileHandle, info);
}
}
}
return STATUS_SUCCESS;
}
NTSTATUS CommWin7(CommCallbackProc callback)
{
UNICODE_STRING unName = { 0 };
RtlInitUnicodeString(&unName, L"ExRegisterAttributeInformationCallback");
ExRegisterAttributeInformationCallbackProc pFunc = MmGetSystemRoutineAddress(&unName);
DbgBreakPoint();
//寻找系统初始化的ExpDisQueryAttributeInformation与ExpDisSetAttributeInformation
ULONG64 offset = *(PULONG)((ULONG64)pFunc + 0xD + 3);
PULONG64 ExpDisQueryAttributeInformation = (offset + 0x14 + (ULONG64)pFunc);
oldExpDisQueryAttributeInformationFunc = (FileCallBack)ExpDisQueryAttributeInformation[0];
oldExpDisSetAttributeInformationFunc = (FileCallBack)ExpDisQueryAttributeInformation[1];
ExpDisQueryAttributeInformation[0] = 0;
ExpDisQueryAttributeInformation[1] = 0;
RegisterCallback rcb = { 0 };
rcb.SetFileCallBack = SetFileCallBack;
rcb.QueryFileCallback = QueryFileCallBack;
NTSTATUS state = pFunc(&rcb);
if (NT_SUCCESS(state))
{
gWin7CallbackVar = ExpDisQueryAttributeInformation;
gCommCallback = callback;
}
return state;
}
VOID UnRegisterCommWin7()
{
if (gWin7CallbackVar)
{
gWin7CallbackVar[0] = oldExpDisQueryAttributeInformationFunc;
gWin7CallbackVar[1] = oldExpDisSetAttributeInformationFunc;
}
}
VOID UnRegisterComm()
{
RTL_OSVERSIONINFOEXW version = { 0 };
RtlGetVersion(&version);
if (version.dwBuildNumber == 7600 || version.dwBuildNumber == 7601)
{
UnRegisterCommWin7();
return;
}
}
DriverMain.c (驱动主函数)
#include<ntifs.h>
#include"Win7_comm.h"
VOID DriverUnload(_In_ struct _DRIVER_OBJECT* DriverObject)
{
DbgPrint("--------------DRIVER_UNLOAD-----------------");
UnRegisterComm();
}
NTSTATUS NTAPI DispatchComm(PCommPackage package)
{
DbgPrintEx(77, 0, "[db]:%llx,%llx\r\n", package->Id, package->cmd);
}
NTSTATUS DriverEntry(IN PDRIVER_OBJECT pDriverObject, IN PUNICODE_STRING pRegistryPath)
{
NTSTATUS state = CommWin7(DispatchComm);
pDriverObject->DriverUnload = DriverUnload;
return STATUS_SUCCESS;
}
通信三环程序.cpp (三环通信程序)
#include <stdio.h>
#include<windows.h>
typedef struct _IO_STATUS_BLOCK {
union {
ULONG Status;
PVOID Pointer;
};
ULONG_PTR Information;
} IO_STATUS_BLOCK, * PIO_STATUS_BLOCK;
typedef struct _CommPackage
{
ULONG64 Id;
ULONG64 cmd;
ULONG64 Data;
ULONG64 Size;
ULONG64 retStatus;
}CommPackage, * PCommPackage;
typedef ULONG(WINAPI* NtQueryInformationFileProc)(
__in HANDLE FileHandle,
__out PIO_STATUS_BLOCK IoStatusBlock,
__out_bcount(Length) PVOID FileInformation,
__in ULONG Length,
__in ULONG FileInformationClass);
int main()
{
char a[] = "123";
PUCHAR b = (PUCHAR)a;
NtQueryInformationFileProc NtQueryInformationFile = (NtQueryInformationFileProc)GetProcAddress(GetModuleHandleA("ntdll"),"NtQueryInformationFile");
if (NtQueryInformationFile == NULL)
{
printf("NtQueryInformationFile获取失败!\n");
system("pause");
return 0;
}
IO_STATUS_BLOCK is = { 0 };
char buf[0xFF] = { 0 };
PCommPackage package = (PCommPackage)buf;
package->Id = 0x12345678;
package->cmd = 1;
HANDLE handle = CreateFileA("C:\\1.txt", FILE_ALL_ACCESS, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
system("pause");
NtQueryInformationFile(handle, &is, buf, sizeof(buf), 0x34);
CloseHandle(handle);
system("pause");
}
参考文献
某超级注入程序的驱动逆向
火哥内核视频