微软技术分享
+ -

使用管道PIPE在内核与应用层通讯

2023-11-24 0 0
原文转自:https://lyshark.blog.csdn.net/article/details/127131339

csdn《微软技术分享》原文转载分享:https://lyshark.blog.csdn.net/

什么是PIPE管道?

在Windows编程中,数据重定向需要用到管道PIPE,管道是一种用于在进程间共享数据的机制,通常由两端组成,数据从一端流入则必须从令一端流出,也就是一读一写,利用这种机制即可实现进程间直接通信。管道的本质其实是一段共享内存区域,多数情况下管道是用于应用层之间的数据交换的,其实驱动中依然可以使用命名管道实现应用层与内核层的直接通信。

那么如何在内核中创建一个管道?请看以下代码片段,以及MSDN针对函数的解析。

  • InitializeObjectAttributes:初始化一个OBJECT_ATTRIBUTES结构,它设置将被打开的对象句柄的属性。然后调用方可以将一个指向该结构的指针传递给实际打开句柄的例程。
  • ZwCreateFile:该函数的作用时创建或打开一个已经存在的文件,在这里其实是打开objAttr这个文件。
  • KeInitializeEvent:将事件对象初始化为同步 (单个服务) 或通知类型事件,并将其设置为已发出信号或未发出信号的状态。
HANDLE g_hClient;
IO_STATUS_BLOCK g_ioStatusBlock;
KEVENT g_event;

VOID NdisMSleep(IN ULONG  MicrosecondsToSleep);

// 初始化管道
void init()
{
    UNICODE_STRING uniName;
    OBJECT_ATTRIBUTES objAttr;

    RtlInitUnicodeString(&uniName, L"\\DosDevices\\Pipe\\LySharkPipeConn");
    InitializeObjectAttributes(&objAttr, &uniName, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL);

    ZwCreateFile(&g_hClient, GENERIC_READ | GENERIC_WRITE, &objAttr, &g_ioStatusBlock, NULL, FILE_ATTRIBUTE_NORMAL, 0, FILE_OPEN, FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0);
    if (!g_hClient)
    {
        return;
    }
    KeInitializeEvent(&g_event, SynchronizationEvent, TRUE);
}

原理就是打开\DosDevices\Pipe\LySharkPipeConn文件,然后将事件对象初始化为同步状态。

接下来就是如何将数据发送给应用层的问题,发送问题可以调用ZwWriteFile这个内核函数,如下我们实现的效果是将一个char类型的字符串传输给应用层。

// 将数据传到R3应用层
// LyShark
VOID ReportToR3(char* m_parameter, int lent)
{
    if (!NT_SUCCESS(ZwWriteFile(g_hClient, NULL, NULL, NULL, &g_ioStatusBlock, (void*)m_parameter, lent, NULL, NULL)))
    {
        DbgPrint("写出错误");
    }
}

内核层的核心代码就是如上这些,将这些整合在一起完整代码如下所示:

#include <ntifs.h>
#include <ndis.h>
#include <stdio.h>

HANDLE g_hClient;
IO_STATUS_BLOCK g_ioStatusBlock;
KEVENT g_event;

VOID NdisMSleep(IN ULONG  MicrosecondsToSleep);

// 初始化管道
void init()
{
    UNICODE_STRING uniName;
    OBJECT_ATTRIBUTES objAttr;

    RtlInitUnicodeString(&uniName, L"\\DosDevices\\Pipe\\LySharkPipeConn");
    InitializeObjectAttributes(&objAttr, &uniName, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL);

    ZwCreateFile(&g_hClient, GENERIC_READ | GENERIC_WRITE, &objAttr, &g_ioStatusBlock, NULL, FILE_ATTRIBUTE_NORMAL, 0, FILE_OPEN, FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0);
    if (!g_hClient)
    {
        return;
    }
    KeInitializeEvent(&g_event, SynchronizationEvent, TRUE);
}

// 将数据传到R3应用层
// LyShark
VOID ReportToR3(char* m_parameter, int lent)
{
    if (!NT_SUCCESS(ZwWriteFile(g_hClient, NULL, NULL, NULL, &g_ioStatusBlock, (void*)m_parameter, lent, NULL, NULL)))
    {
        DbgPrint("写出错误");
    }
}

VOID UnDriver(PDRIVER_OBJECT driver)
{
    DbgPrint("驱动卸载成功 \n");
}

NTSTATUS DriverEntry(IN PDRIVER_OBJECT Driver, PUNICODE_STRING RegistryPath)
{
    init();

    // 延时3秒
    NdisMSleep(3000000);

    DbgPrint("hello lyshark \n");
    for (int x = 0; x < 10; x++)
    {
        // 分配空间
        char *report = (char*)ExAllocatePoolWithTag(NonPagedPool, 4096, 'lysh');
        if (report)
        {
            RtlZeroMemory(report, 4096);

            RtlCopyMemory(report, "hello lyshark", 13);

            // 发送到应用层
            ReportToR3(report, 4096);
            ExFreePool(report);
        }
    }

    DbgPrint("驱动加载成功 \n");
    Driver->DriverUnload = UnDriver;
    return STATUS_SUCCESS;
}

0 篇笔记 写笔记

CreateProcess子进程输出重定向
这里时子进程的输出重客向到一个一个文件中,适用于子进程为控制台输出的程序。 SYSTEMTIME sys; GetLocalTime(&sys); SECURITY_ATTRIBUTES sa = { sizeof(SECURITY_ATTRIBUTES),NULL......
管道PIPE跨进程通讯
发送端#define EXAMP_PIPE L"\.\PIPE\EB3F2E4B_52E2_40F9_A17D_B4A2588F23AB" #define BUF_SIZE 4096void CPipeDlg::SendData(PUCHAR pData, ......
使用管道PIPE在内核与应用层通讯
什么是PIPE管道?在Windows编程中,数据重定向需要用到管道PIPE,管道是一种用于在进程间共享数据的机制,通常由两端组成,数据从一端流入则必须从令一端流出,也就是一读一写,利用这种机制即可实现进程间直接通信。管道的本质其实是一段共享内存区域,多数情况下管道是用于应用层之间的数据交换的,其实驱......
作者信息
我爱内核
Windows驱动开发,网站开发
好好学习,天天向上。
取消
感谢您的支持,我会继续努力的!
扫码支持
扫码打赏,你说多少就多少

打开支付宝扫一扫,即可进行扫码打赏哦

您的支持,是我们前进的动力!