IT评测·应用市场-qidao123.com

标题: 驱动开发:通过应用堆实现多次通信 [打印本页]

作者: 汕尾海湾    时间: 2023-5-19 11:52
标题: 驱动开发:通过应用堆实现多次通信
在前面的文章《驱动开发:运用MDL映射实现多次通信》LyShark教大家使用MDL的方式灵活的实现了内核态多次输出结构体的效果,但是此种方法并不推荐大家使用原因很简单首先内核空间比较宝贵,其次内核里面不能分配太大且每次传出的结构体最大不能超过1024个,而最终这些内存由于无法得到更好的释放从而导致坏堆的产生,这样的程序显然是无法在生产环境中使用的,如下LyShark将教大家通过在应用层申请空间来实现同等效果,此类传递方式也是多数ARK反内核工具中最常采用的一种。
与MDL映射相反,MDL多数处理流程在内核代码中,而应用层开堆复杂代码则在应用层,但内核层中同样还是需要使用指针,只是这里的指针仅仅只是保留基本要素即可,通过EnumProcess()模拟枚举进程操作,传入的是PPROCESS_INFO进程指针转换,将数据传入到PPROCESS_INFO直接返回进程计数器即可。
  1. // -------------------------------------------------
  2. // R3传输结构体
  3. // -------------------------------------------------
  4. // 进程指针转换
  5. typedef struct
  6. {
  7.   DWORD PID;
  8.   DWORD PPID;
  9. }PROCESS_INFO, *PPROCESS_INFO;
  10. // 数据存储指针
  11. typedef struct
  12. {
  13.   ULONG_PTR nSize;
  14.   PVOID BufferPtr;
  15. }BufferPointer, *pBufferPointer;
  16. // 模拟进程枚举
  17. ULONG EnumProcess(PPROCESS_INFO pBuffer)
  18. {
  19.   ULONG nCount = 0;
  20.   for (size_t i = 0; i < 10; i++)
  21.   {
  22.     pBuffer[i].PID = nCount * 2;
  23.     pBuffer[i].PPID = nCount * 4;
  24.     nCount = nCount + 1;
  25.   }
  26.   return nCount;
  27. }
复制代码
内核层核心代码: 内核代码中是如何通信的,首先从用户态接收pIoBuffer到分配的缓冲区数据,并转换为pBufferPointer结构,ProbeForWrite用于检查地址是否可写入,接着会调用EnumProcess()注意传入的其实是应用层的指针,枚举进程结束后,将进程数量nCount通过*(PULONG)pIrp->AssociatedIrp.SystemBuffer = (ULONG)nCount回传给应用层,至此内核中仅仅回传了一个长度,其他的都写入到了应用层中。
  1. // 署名权
  2. // right to sign one's name on a piece of work
  3. // PowerBy: LyShark
  4. // Email: me@lyshark.com
  5. pBufferPointer pinp = (pBufferPointer)pIoBuffer;
  6. __try
  7. {
  8.   DbgPrint("缓冲区长度: %d \n", pinp->nSize);
  9.   DbgPrint("缓冲区基地址: %p \n", pinp->BufferPtr);
  10.   // 检查地址是否可写入
  11.   ProbeForWrite(pinp->BufferPtr, pinp->nSize, 1);
  12.   ULONG nCount = EnumProcess((PPROCESS_INFO)pinp->BufferPtr);
  13.   DbgPrint("进程计数 = %d \n", nCount);
  14.   if (nCount > 0)
  15.   {
  16.     // 将进程数返回给用户
  17.     *(PULONG)pIrp->AssociatedIrp.SystemBuffer = (ULONG)nCount;
  18.     status = STATUS_SUCCESS;
  19.   }
  20. }
  21. __except (1)
  22. {
  23.   status = GetExceptionCode();
  24.   DbgPrint("IOCTL_GET_EPROCESS %x \n", status);
  25. }
  26. // 返回通信状态
  27. status = STATUS_SUCCESS;
  28. break;
复制代码
应用层核心代码: 通信的重点在于应用层,首先定义BufferPointer用于存放缓冲区头部指针,定义PPROCESS_INFO则是用于后期将数据放入该容器内,函数HeapAlloc分配一段堆空间,并HEAP_ZERO_MEMORY将该堆空间全部填空,将这一段初始化后的空间放入到pInput.BufferPtr缓冲区内,并计算出长度放入到pInput.nSize缓冲区内,一切准备就绪之后,再通过DriveControl.IoControl将BufferPointer结构传输至内核中,而bRet则是用于接收返回长度的变量。
当收到数据后,通过(PPROCESS_INFO)pInput.BufferPtr强制转换为指针类型,并依次pProcessInfo读出每一个节点的元素,最后是调用HeapFree释放掉这段堆空间。至于输出就很简单了vectorProcess[x].PID循环容器元素即可。
[code]// 署名权// right to sign one's name on a piece of work// PowerBy: LyShark// Email: me@lyshark.com// 应用层数据结构体数据BOOL bRet = FALSE;BufferPointer pInput = { 0 };PPROCESS_INFO pProcessInfo = NULL;// 分配堆空间pInput.BufferPtr = (PVOID)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PROCESS_INFO) * 1000);pInput.nSize = sizeof(PROCESS_INFO) * 1000;ULONG nRet = 0;if (pInput.BufferPtr){  bRet = DriveControl.IoControl(IOCTL_IO_R3StructAll, &pInput, sizeof(BufferPointer), &nRet, sizeof(ULONG), 0);}std::cout = 0; i--)        {                if (szCurFile == '\\')                {                        szCurFile[i + 1] = '\0';                        break;                }        }}// -------------------------------------------------// R3数据传递变量// -------------------------------------------------// 进程指针转换typedef struct{        DWORD PID;        DWORD PPID;}PROCESS_INFO, *PPROCESS_INFO;// 数据存储指针typedef struct{        ULONG_PTR nSize;        PVOID BufferPtr;}BufferPointer, *pBufferPointer;int main(int argc, char *argv[]){        cDrvCtrl DriveControl;        // 设置驱动名称        char szSysFile[MAX_PATH] = { 0 };        char szSvcLnkName[] = "WinDDK";;        GetAppPath(szSysFile);        strcat(szSysFile, "WinDDK.sys");        // 安装并启动驱动        DriveControl.Install(szSysFile, szSvcLnkName, szSvcLnkName);        DriveControl.Start();        // 打开驱动的符号链接        DriveControl.Open("\\\\.\\WinDDK");        // 应用层数据结构体数据        BOOL bRet = FALSE;        BufferPointer pInput = { 0 };        PPROCESS_INFO pProcessInfo = NULL;        // 分配堆空间        pInput.BufferPtr = (PVOID)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PROCESS_INFO) * 1000);        pInput.nSize = sizeof(PROCESS_INFO) * 1000;        ULONG nRet = 0;        if (pInput.BufferPtr)        {                bRet = DriveControl.IoControl(IOCTL_IO_R3StructAll, &pInput, sizeof(BufferPointer), &nRet, sizeof(ULONG), 0);        }        std::cout




欢迎光临 IT评测·应用市场-qidao123.com (https://dis.qidao123.com/) Powered by Discuz! X3.4