关于VAD的两种内存隐藏方式

Windows内核分析索引目录:https://www.cnblogs.com/onetrainee/p/11675224.html

技术学习来源:火哥(QQ:471194425)

内存在0环的两种内存隐藏方式(基于VAD树)

一、通过 _MMVAD.StartingVpn与_MMVAD.EndingVpn等值来隐藏内存。

  这种方法找到需要隐藏的VAD结点,使 _MMVAD.StartingVpn=_MMVAD.EndingVpn,这样就能达到隐藏的效果

  在 》》VAD树的属性及其遍历 《《 中,在遍历每个结点下,直接 pVad.StartingVpn = pVad.EndingVpn即可。

  1)隐藏前的效果

    

  2)隐藏后的效果

    

 

二、通过将两个VAD结点融合达到隐藏效果

  我们需要找到 宿主结点p1 与 被隐藏结点p2,将p2融合进p1中,此时就会显示p1的段属性从而忽视p2的段属性。

  比如扫描内存时,恶意代码必然可执行 EXECUTE,但是我们隐藏在READ之类段中,往往可以规避掉扫描。

  实现方法 p1.EndingVpn = p2.EndingPvn

1) 实验代码 test.exe

 1 // test.cpp : Defines the entry point for the console application.
 2 //
 3 
 4 #include "stdafx.h"
 5 #include <iostream>
 6 #include <Windows.h>
 7 #include <stdlib.h>
 8 int main()
 9 {
10     LPVOID p1 = VirtualAlloc(NULL, 0x10000, MEM_COMMIT, PAGE_READWRITE);
11     LPVOID p2 = VirtualAlloc(NULL, 0x10000, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
12     printf("p1 = %x / p2 = %x", p1, p2);
13     system("pause");
14 }

2) 驱动代码

  1 #include <ntddk.h>
  2 
  3 
  4 //---------------------//
  5 // MMVAD结构体简单定义 //
  6 //---------------------//
  7 typedef struct _MMVAD {
  8     ULONG StartingVpn;
  9     ULONG EndingVpn;
 10     struct _MMVAD * Parent;
 11     struct _MMVAD * LeftChild;
 12     struct _MMVAD * RightChild;
 13 }MMVAD,*PMMVAD;
 14 
 15 
 16 
 17 VOID Unload(IN PDRIVER_OBJECT pDriverObject) {
 18     DbgPrint("Driver UnLoad!");
 19 }
 20 
 21 //-----------//
 22 // 遍历VAD树 //
 23 //-----------//
 24 PMMVAD  vad_enum(PMMVAD pVad,ULONG target_StartingVpn) {
 25 
 26     //---------------------------//
 27     // 遍历目标VAD,并返回其指针 //
 28     //---------------------------//
 29     if (pVad) {
 30         if (target_StartingVpn == pVad->StartingVpn) {
 31             _asm int 3
 32             return pVad;
 33         }
 34         else {
 35             if (pVad->LeftChild) {
 36                 PMMVAD p1 = vad_enum(pVad->LeftChild, target_StartingVpn);
 37                 // 如果结点不为空,则直接返回就好。
 38                 // 否则继续判断其右子树结点。
 39                 if (p1)
 40                     return p1;
 41             }
 42             if (pVad->RightChild) {
 43                 PMMVAD p2 = vad_enum(pVad->RightChild, target_StartingVpn);
 44                 if (p2)
 45                     return p2;
 46             }
 47             return NULL;
 48         }
 49     }
 50     return NULL;
 51 }
 52 
 53 //-------------------------------------------------------------//
 54 //  在内核中进程遍历的原理就是先获取系统进程EPROCESS结构       //
 55 //        然后依照其链表来获取其他的进程                         //
 56 //        依次遍历出来                                           //
 57 //-------------------------------------------------------------//
 58 NTSTATUS process_enum() {
 59 
 60     PEPROCESS pEprocess = NULL; // 得到系统进程地址
 61     PEPROCESS pFirstEprocess = NULL;
 62     ULONG ulProcessName = 0; // 字符串指针,指向进程名称
 63     ULONG ulProcessID = 0;    // 进程ID
 64     ANSI_STRING target_str; // 带检测进程的名称
 65     ANSI_STRING ansi_string; // 
 66     ULONG VadRoot;
 67 
 68     //----------------------------//
 69     // 得到当前系统进程的EPROCESS //
 70     //----------------------------//
 71     pEprocess = PsGetCurrentProcess();
 72     if (pEprocess == NULL) {
 73         DbgPrint("获取当前系统进程EPROCESS错误..");
 74         return STATUS_SUCCESS;
 75     }
 76     DbgPrint("pEprocess addr is %x0x8\r\n", pEprocess);
 77     pFirstEprocess = pEprocess;
 78 
 79     while (pEprocess) {
 80 
 81         ulProcessName = (ULONG)pEprocess + 0x174;
 82         ulProcessID = *(ULONG*)((ULONG)pEprocess + 0x84);
 83         VadRoot = *(ULONG*)((ULONG)pEprocess + 0x11c);
 84 
 85         //--------------------------------------//
 86         // 将目标进程与当前进程的进程名进行对比 //
 87         //--------------------------------------//
 88         RtlInitAnsiString(&ansi_string, (PCSTR)ulProcessName);    
 89         RtlInitAnsiString(&target_str, "test.exe");
 90         if (RtlEqualString(&ansi_string, &target_str, TRUE)) {
 91             DbgPrint("检测到进程字符串,%x", ulProcessID);
 92         
 93             PMMVAD p1 = vad_enum((PMMVAD)VadRoot,0x3a0); // 遍历第一个结点
 94             PMMVAD p2 = vad_enum((PMMVAD)VadRoot, 0x3b0); // 遍历找到第二个结点
 95             _asm int 3
 96             if(p1 && p2)
 97                 p1->EndingVpn = p2->EndingVpn; // 将第二个结点完全隐藏起来
 98                 
 99 
100             return STATUS_SUCCESS;
101         }
102         pEprocess = (PEPROCESS)(*(ULONG*)((ULONG)pEprocess + 0x88) - 0x88);
103         if (pEprocess == pFirstEprocess || *(ULONG*)((ULONG)pEprocess + 0x84) <= 0) {
104             DbgPrint("遍历结束!未检测到进程ID!\r\n");
105             break;
106         }
107     }
108     return STATUS_SUCCESS;
109 }
110 
111 NTSTATUS DriverEntry(IN PDRIVER_OBJECT pDriverObject, IN PUNICODE_STRING registeryPat) {
112     DbgPrint("Driver Loaded!");
113     pDriverObject->DriverUnload = Unload;
114     process_enum();
115     return STATUS_SUCCESS;
116 }

 3)隐藏效果

 

posted @ 2019-10-28 08:43  OneTrainee  阅读(2309)  评论(0编辑  收藏