在之前的文章中LyShark
一直都在教大家如何讓驅動程式與應用層進行正向通信
,而在某些時候我們不僅僅只需要正向通信,也需要反向通信,例如殺毒軟體如果驅動程式攔截到惡意操作則必須將這個請求動態的轉發到應用層以此來通知用戶,而這種通信方式的實作有多種,通常可以使用創建Socket套接字的方式實作,亦或者使用本章所介紹的通過事件同步
的方法實作反向通信,
基于事件同步方式實作的通信需要用的最重要函式IoCreateNotificationEvent()
這是微軟定為開發者提供的,
IoCreateNotificationEvent 例程創建或打開一個命名通知事件,用于通知一個或多個執行執行緒已發生事件,
PKEVENT IoCreateNotificationEvent(
[in] PUNICODE_STRING EventName,
[out] PHANDLE EventHandle
);
其中的第二個引數EventHandle
指向回傳事件物件的內核句柄的位置的指標,此處為了能更好的接收和管理指標與行程之間的關系我們最好定義一個DEVICE_EXTEN
結構體,
// 自定義設備擴展
typedef struct
{
HANDLE hProcess; // HANDLE
PKEVENT pkProcessEvent; // 事件物件
HANDLE hProcessId; // PID
HANDLE hpParProcessId; // PPID
BOOLEAN bIsCreateMark; // Flag
}DEVICE_EXTEN, *PDEVICE_EXTEN;
驅動入口處PsSetCreateProcessNotifyRoutine
則用于創建一個行程回呼,該回呼函式被指定為pMyCreateProcessThreadRoutine
當回呼函式被創建后,一旦有新行程創建則會執行函式內部的具體流程,
如代碼所示,在pMyCreateProcessThreadRoutine
函式內首先通過(PDEVICE_EXTEN)GlobalDevObj->DeviceExtension
得到了自定義設備擴展指標,接著將當前行程的PID,PPID,isCreate
等屬性賦予到擴展指標中,當一切準備就緒后,通過呼叫KeSetEvent
將當前行程事件設定為有信號狀態,設定后重置為默認值,
// 自定義回呼函式
VOID pMyCreateProcessThreadRoutine(IN HANDLE pParentId, HANDLE hProcessId, BOOLEAN bisCreate)
{
PDEVICE_EXTEN pDeviceExten = (PDEVICE_EXTEN)GlobalDevObj->DeviceExtension;
// 將進行資訊依次復制到結構體中
pDeviceExten->hProcessId = hProcessId;
pDeviceExten->hpParProcessId = pParentId;
pDeviceExten->bIsCreateMark = bisCreate;
// 設定為有信號
KeSetEvent(pDeviceExten->pkProcessEvent, 0, FALSE);
// 重置狀態信號
KeResetEvent(pDeviceExten->pkProcessEvent);
}
此時由于客戶端中通過OpenEventW(SYNCHRONIZE, FALSE, EVENT_NAME)
打開了內核物件,并通過WaitForSingleObject(hProcessEvent, INFINITE)
一直在等待事件,一旦內核驅動KeSetEvent(pDeviceExten->pkProcessEvent, 0, FALSE)
設定為有信號狀態,則應用層會通過DeviceIoControl
向內核層發送IOCTL
控制信號并等待接收資料,
此時主派遣函式DisPatchIoControl
被觸發執行,通過(PPROCESS_PTR)pUserOutPutBuffer
獲取到應用層緩沖區設備指標,并依次通過pBuffer->
的方式設定引數,最后回傳狀態碼,此時應用層PROCESS_PTR
中也就得到了行程創建的相關資訊,
pBuffer = (PPROCESS_PTR)pUserOutPutBuffer;
uIoControl = pIrpStack->Parameters.DeviceIoControl.IoControlCode;
uReadLen = pIrpStack->Parameters.DeviceIoControl.InputBufferLength;
uWriteLen = pIrpStack->Parameters.DeviceIoControl.OutputBufferLength;
switch (uIoControl)
{
case IOCTL:
pDeviceExten = (PDEVICE_EXTEN)GlobalDevObj->DeviceExtension;
pBuffer->hProcessId = pDeviceExten->hProcessId;
pBuffer->hpParProcessId = pDeviceExten->hpParProcessId;
pBuffer->bIsCreateMark = pDeviceExten->bIsCreateMark;
break;
default:
ntStatus = STATUS_INVALID_PARAMETER;
uWriteLen = 0;
break;
}
如上就是內核層與應用層的部分代碼功能分析,接下來我將完整代碼分享出來,大家可以自行測驗效果,
驅動程式WinDDK.sys完整代碼;
// 署名權
// right to sign one's name on a piece of work
// PowerBy: LyShark
// Email: [email protected]
#include <ntifs.h>
#include <ntstrsafe.h>
#define IOCTL CTL_CODE(FILE_DEVICE_UNKNOWN,0x801,METHOD_BUFFERED,FILE_ANY_ACCESS)
UNICODE_STRING GlobalSym = { 0 };
PDEVICE_OBJECT GlobalDevObj;
// 自定義設備擴展
typedef struct
{
HANDLE hProcess; // HANDLE
PKEVENT pkProcessEvent; // 事件物件
HANDLE hProcessId; // PID
HANDLE hpParProcessId; // PPID
BOOLEAN bIsCreateMark; // Flag
}DEVICE_EXTEN, *PDEVICE_EXTEN;
// 自定義結構體(臨時)
typedef struct
{
HANDLE hProcessId;
HANDLE hpParProcessId;
BOOLEAN bIsCreateMark;
}PROCESS_PTR, *PPROCESS_PTR;
// 自定義回呼函式
VOID pMyCreateProcessThreadRoutine(IN HANDLE pParentId, HANDLE hProcessId, BOOLEAN bisCreate)
{
PDEVICE_EXTEN pDeviceExten = (PDEVICE_EXTEN)GlobalDevObj->DeviceExtension;
// 將進行資訊依次復制到結構體中
pDeviceExten->hProcessId = hProcessId;
pDeviceExten->hpParProcessId = pParentId;
pDeviceExten->bIsCreateMark = bisCreate;
// 設定為有信號
KeSetEvent(pDeviceExten->pkProcessEvent, 0, FALSE);
// 重置狀態信號
KeResetEvent(pDeviceExten->pkProcessEvent);
}
// 默認派遣函式
NTSTATUS DisPatchComd(PDEVICE_OBJECT pDeviceObject, PIRP pIrp)
{
pIrp->IoStatus.Information = 0;
pIrp->IoStatus.Status = STATUS_SUCCESS;
IoCompleteRequest(pIrp, IO_NO_INCREMENT);
return pIrp->IoStatus.Status;
}
// 主派遣函式
NTSTATUS DisPatchIoControl(PDEVICE_OBJECT pDeviceObject, PIRP pIrp)
{
NTSTATUS ntStatus;
PIO_STACK_LOCATION pIrpStack;
PVOID pUserOutPutBuffer;
PPROCESS_PTR pBuffer;
ULONG uIoControl = 0;
ULONG uReadLen;
ULONG uWriteLen;
PDEVICE_EXTEN pDeviceExten;
pIrpStack = IoGetCurrentIrpStackLocation(pIrp);
pUserOutPutBuffer = pIrp->AssociatedIrp.SystemBuffer;
pBuffer = (PPROCESS_PTR)pUserOutPutBuffer;
uIoControl = pIrpStack->Parameters.DeviceIoControl.IoControlCode;
uReadLen = pIrpStack->Parameters.DeviceIoControl.InputBufferLength;
uWriteLen = pIrpStack->Parameters.DeviceIoControl.OutputBufferLength;
switch (uIoControl)
{
case IOCTL:
pDeviceExten = (PDEVICE_EXTEN)GlobalDevObj->DeviceExtension;
pBuffer->hProcessId = pDeviceExten->hProcessId;
pBuffer->hpParProcessId = pDeviceExten->hpParProcessId;
pBuffer->bIsCreateMark = pDeviceExten->bIsCreateMark;
break;
default:
ntStatus = STATUS_INVALID_PARAMETER;
uWriteLen = 0;
break;
}
pIrp->IoStatus.Information = uWriteLen;
pIrp->IoStatus.Status = ntStatus;
IoCompleteRequest(pIrp, IO_NO_INCREMENT);
return ntStatus;
}
// 卸載驅動
VOID DriverUnLoad(PDRIVER_OBJECT pDriverObject)
{
NTSTATUS ntStatus;
UNICODE_STRING SymboLicLinkStr = { 0 };
// 洗掉符號鏈接
ntStatus = RtlUnicodeStringInit(&SymboLicLinkStr, L"\\DosDevices\\Symboliclnk");
ntStatus = IoDeleteSymbolicLink(&SymboLicLinkStr);
// 注銷行程訊息回呼
PsSetCreateProcessNotifyRoutine(pMyCreateProcessThreadRoutine, TRUE);
IoDeleteDevice(pDriverObject->DeviceObject);
}
// 入口函式
NTSTATUS DriverEntry(PDRIVER_OBJECT pDriver, PUNICODE_STRING RegistryPath)
{
NTSTATUS ntStatus = NULL;
PDEVICE_OBJECT pDeviceObject = NULL;
UNICODE_STRING uDeviceName = { 0 };
UNICODE_STRING uEventName = { 0 };
// 初始化字串
ntStatus = RtlUnicodeStringInit(&uDeviceName, L"\\Device\\ProcLook");
ntStatus = RtlUnicodeStringInit(&GlobalSym, L"\\DosDevices\\Symboliclnk");
ntStatus = RtlUnicodeStringInit(&uEventName, L"\\BaseNamedObjects\\ProcLook");
DbgPrint("hello lyshark.com");
if (!NT_SUCCESS(ntStatus))
{
return ntStatus;
}
// 創建設備
ntStatus = IoCreateDevice(pDriver,sizeof(DEVICE_EXTEN),&uDeviceName,FILE_DEVICE_UNKNOWN,FILE_DEVICE_SECURE_OPEN,FALSE,&pDeviceObject);
DbgPrint("[LyShark] 創建設備物件");
if (!NT_SUCCESS(ntStatus))
{
IoDeleteDevice(pDeviceObject);
return ntStatus;
}
pDriver->Flags |= DO_BUFFERED_IO;
GlobalDevObj = pDeviceObject;
// 獲取設備擴展指標,并IoCreateNotificationEvent創建一個R3到R0的事件
PDEVICE_EXTEN pDeviceExten = (PDEVICE_EXTEN)pDeviceObject->DeviceExtension;
pDeviceExten->pkProcessEvent = IoCreateNotificationEvent(&uEventName, &pDeviceExten->hProcess);
KeClearEvent(pDeviceExten->pkProcessEvent);
DbgPrint("[LyShark] 創建事件回呼");
// 創建符號鏈接
ntStatus = IoCreateSymbolicLink(&GlobalSym, &uDeviceName);
if (!NT_SUCCESS(ntStatus))
{
IoDeleteDevice(pDeviceObject);
return ntStatus;
}
// 注冊行程創建回呼
ntStatus = PsSetCreateProcessNotifyRoutine(pMyCreateProcessThreadRoutine, FALSE);
DbgPrint("[LyShark] 創建行程回呼");
if (!NT_SUCCESS(ntStatus))
{
IoDeleteDevice(pDeviceObject);
return ntStatus;
}
// 初始化派遣函式
for (ULONG i = 0; i < IRP_MJ_MAXIMUM_FUNCTION; i++)
{
pDriver->MajorFunction[i] = DisPatchComd;
}
pDriver->MajorFunction[IRP_MJ_DEVICE_CONTROL] = DisPatchIoControl;
// 關閉驅動
pDriver->DriverUnload = DriverUnLoad;
return ntStatus;
}
應用層客戶端程式lyshark.exe
完整代碼;
// 署名權
// right to sign one's name on a piece of work
// PowerBy: LyShark
// Email: [email protected]
#include <iostream>
#include <Windows.h>
#define EVENT_NAME L"Global\\ProcLook"
#define IOCTL CTL_CODE(FILE_DEVICE_UNKNOWN,0x801,METHOD_BUFFERED,FILE_ANY_ACCESS)
typedef struct
{
HANDLE hProcessId;
HANDLE hpParProcessId;
BOOLEAN bIsCreateMark;
}PROCESS_PTR, *PPROCESS_PTR;
int main(int argc, char* argv[])
{
PROCESS_PTR Master = { 0 };
PROCESS_PTR Slave = { 0 };
DWORD dwRet = 0;
BOOL bRet = FALSE;
// 打開驅動設備物件
HANDLE hDriver = CreateFile(L"\\\\.\\Symboliclnk",GENERIC_READ | GENERIC_WRITE,NULL,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);
if (hDriver == INVALID_HANDLE_VALUE)
{
return 0;
}
// 打開內核事件物件
HANDLE hProcessEvent = OpenEventW(SYNCHRONIZE, FALSE, EVENT_NAME);
if (NULL == hProcessEvent)
{
return 0;
}
while (TRUE)
{
// 等待事件
WaitForSingleObject(hProcessEvent, INFINITE);
// 發送控制信號
bRet = DeviceIoControl(hDriver,IOCTL,NULL,0,&Master,sizeof(Master),&dwRet,NULL);
if (!bRet)
{
return 0;
}
if (bRet)
{
if (Master.hpParProcessId != Slave.hpParProcessId || Master.hProcessId != Slave.hProcessId || Master.bIsCreateMark != Slave.bIsCreateMark)
{
if (Master.bIsCreateMark)
{
printf("[LyShark] 父行程: %d | 行程PID: %d | 狀態: 創建行程 \n", Master.hpParProcessId, Master.hProcessId);
}
else
{
printf("[LyShark] 父行程: %d | 行程PID: %d | 狀態: 退出行程 \n", Master.hpParProcessId, Master.hProcessId);
}
Slave = Master;
}
}
else
{
break;
}
}
CloseHandle(hDriver);
return 0;
}
手動編譯這兩個程式,將驅動簽名后以管理員身份運行lyshark.exe
客戶端,此時螢屏中即可看到滾動輸出效果,如此一來就實作了回圈傳遞引數的目的,
文章出處:https://www.cnblogs.com/LyShark/p/17137118.html
本博客所有文章除特別宣告外,均采用 BY-NC-SA 許可協議,轉載請注明出處!
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/555640.html
標籤:C
下一篇:返回列表