linux vad检测,VAD树结构体的属性以及遍历

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

VAD树的属性以及遍历

前面学习过的PFNDATABSAE是管理物理页的,整个操作系统仅维护一个PFNDATABASE。

现在的VAD是管理虚拟内存的,每一个进程有自己单独的一个VAD树。

VAD树:

比如你使用VirtualAllocate函数申请一个内存,则会在VAD树上增加一个结点,其是_MMVAD结构体。

一个VAD结点可以有多个页,这在StartingVpn和EndingVpn会介绍。

当以MEN_SERVIED保留属性提交时,其只是在VAD树上挂上一个节点,真正提交时这棵树才是由意义的。

一、VAD结构体介绍

kd> dt _MMVAD

nt!_MMVAD

+0x000 StartingVpn      : Uint4B

+0x004 EndingVpn        : Uint4B

+0x008 Parent           : Ptr32 _MMVAD

+0x00c LeftChild        : Ptr32 _MMVAD

+0x010 RightChild       : Ptr32 _MMVAD

+0x014 u                : __unnamed

+0x018 ControlArea      : Ptr32 _CONTROL_AREA

+0x01c FirstPrototypePte : Ptr32 _MMPTE

+0x020 LastContiguousPte : Ptr32 _MMPTE

+0x024 u2               : __unnamed

1. StringVpn 起始页 / EndingVpn结束页

1)两者算法是不同的。起始页:startingVpn*0x1000/结束页:EndVpn*0x1000+0xfff。

2. Parent、LeftChild、RightChild - 其父节点、左子树、右子树。

1)我们遍历这些树时用到的就是这些结构体成员。

3. u - 其是_MMVAN_FLAGS属性,非常重要的。

kd> dt _MMVAD_FLAGS

nt!_MMVAD_FLAGS

+0x000 CommitCharge     : Pos 0, 19 Bits

+0x000 PhysicalMapping  : Pos 19, 1 Bit

+0x000 ImageMap         : Pos 20, 1 Bit

+0x000 UserPhysicalPages : Pos 21, 1 Bit

+0x000 NoChange         : Pos 22, 1 Bit

+0x000 WriteWatch       : Pos 23, 1 Bit

+0x000 Protection       : Pos 24, 5 Bits

+0x000 LargePages       : Pos 29, 1 Bit

+0x000 MemCommit        : Pos 30, 1 Bit

+0x000 PrivateMemory    : Pos 31, 1 Bit

1)CommitCharge  实际提交的页数。

其19Bits,我们内存低字节7ffffff,正好十九位。

比如我们以MEN_RESERVED保留形式提交了4页大小的内存,此时这里为2,将一页改为EXECUTE属性,这时这里就会变成2。

2)PyhsicalMapping:内核物理页映射。

3)UserPhysicalPages:内核物理页映射。

4)PrivateMemory:如果私有设置为1。

5)ImageMap:对dll/exe等文件进行保护,防止其被修改(使用映射写拷贝之类的原理)

如果ImageMap为1,PrivateMemory为0,说明其为DLL。

6)NoChange:关于锁页技术。当置为1,像VirtualProtect等函数不会改变其页的属性。

7)LargePage:标志是否为大页。

8)MemCommit:提交状态,只要提交就会置为1(CommitCharge存储提交了多少页)

9)Protection:3bit,关于保护(比如页的读写、可执行等)。

将其定义的值取出,赋值到该位。

4. ContraArea控制结构:

其指向一个_CONTROL_AREA的数据结构,该结构就暂不表述了。

1)_CONTROL_AREA+ 0x24 FilePointer,文件指针,指向一个_FILE_OBJECT结构体。

2)_FILE_OBJECT结构体中,保存着文件对象很多关键的信息。

a> +0x30 FileName 文件名

若想知道该页属于哪个文件,可以查看这里。

将.sys文件伪装成.dll文件,则必须修改这里。

b> +0x26-0x28 文件保护属性

比如一个文件被独占无法删除,在内核中你可以将DeleteAccess位置1,之后强制删除。

二、利用windbg遍历VAD树

1. 每个进程的VAD树存储在_EPROCESS+0x11c结构体中,其是ROOTVAD根结点。

4aad28c19822dc96d7c833c788dffd91.png

2. 获取每个进程的 _EPROCESS,使用指令!process 0 0,得到PROCESS的值就是指向_EPROCESS的指针。

bc1dbbc1afa9e20c0d4422d74c85fd21.png

3. 当获取VadRoot之后,可以使用 !vad VadRoot来显示该进程的VAD树。

b0497dd1af5ff11ea63b380cd84674f9.png

三、使用代码实现VAD树的遍历

代码核心就是先遍历进程找出目标进程(这里默认 test.exe),之后对目标进程的VAD树进行遍历。

1 #include

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 VOID vad_enum(PMMVAD pVad) {

25 if (pVad) {

26 DbgPrint("Start: %x | End: %x | \r\n", pVad->StartingVpn, pVad->EndingVpn);

27 if (pVad->LeftChild)

28 vad_enum(pVad->LeftChild);

29 if (pVad->RightChild)

30 vad_enum(pVad->RightChild);

31 }

32 }

33

34

35 //-------------------------------------------------------------//

36 // 在内核中进程遍历的原理就是先获取系统进程EPROCESS结构 //

37 // 然后依照其链表来获取其他的进程 //

38 // 依次遍历出来 //

39 //-------------------------------------------------------------//

40 NTSTATUS process_enum() {

41

42 PEPROCESS pEprocess = NULL; // 得到系统进程地址

43 PEPROCESS pFirstEprocess = NULL;

44 ULONG ulProcessName = 0; // 字符串指针,指向进程名称

45 ULONG ulProcessID = 0; // 进程ID

46 ANSI_STRING target_str; // 带检测进程的名称

47 ANSI_STRING ansi_string; //

48 ULONG VadRoot;

49

50 //----------------------------//

51 // 得到当前系统进程的EPROCESS //

52 //----------------------------//

53 pEprocess = PsGetCurrentProcess();

54 if (pEprocess == NULL) {

55 DbgPrint("获取当前系统进程EPROCESS错误..");

56 return STATUS_SUCCESS;

57 }

58 DbgPrint("pEprocess addr is %x0x8\r\n", pEprocess);

59 pFirstEprocess = pEprocess;

60

61 while (pEprocess) {

62

63 ulProcessName = (ULONG)pEprocess + 0x174;

64 ulProcessID = *(ULONG*)((ULONG)pEprocess + 0x84);

65 VadRoot = *(ULONG*)((ULONG)pEprocess + 0x11c);

66

67 //--------------------------------------//

68 // 将目标进程与当前进程的进程名进行对比 //

69 //--------------------------------------//

70 RtlInitAnsiString(&ansi_string, (PCSTR)ulProcessName);

71 RtlInitAnsiString(&target_str, "test.exe");

72 if (RtlEqualString(&ansi_string, &target_str, TRUE)) {

73 DbgPrint("检测到进程字符串,%x", ulProcessID);

74 vad_enum((PMMVAD)VadRoot); // 开始遍历目标进程的VAD树

75 return STATUS_SUCCESS;

76 }

77 pEprocess = (PEPROCESS)(*(ULONG*)((ULONG)pEprocess + 0x88) - 0x88);

78

79 if (pEprocess == pFirstEprocess || *(ULONG*)((ULONG)pEprocess + 0x84) <= 0) {

80 DbgPrint("遍历结束!未检测到进程ID!\r\n");

81 break;

82 }

83 }

84 return STATUS_SUCCESS;

85 }

86

87 NTSTATUS DriverEntry(IN PDRIVER_OBJECT pDriverObject, IN PUNICODE_STRING registeryPat) {

88 DbgPrint("Driver Loaded!");

89 pDriverObject->DriverUnload = Unload;

90 process_enum();

91 return STATUS_SUCCESS;

92 }

b739ec46bb5c46d9c0aa4ce35ba1ea56.png

关于找一找教程网

本站文章仅代表作者观点,不代表本站立场,所有文章非营利性免费分享。

本站提供了软件编程、网站开发技术、服务器运维、人工智能等等IT技术文章,希望广大程序员努力学习,让我们用科技改变世界。

[VAD树结构体的属性以及遍历]http://www.zyiz.net/tech/detail-93682.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值