Windows内核分析索引目录:https://www.cnblogs.com/onetrainee/p/11675224.html
技术学习来源:火哥(QQ:471194425)
R3环申请内存时页面保护与_MMVAD_FLAGS.Protection位的对应关系
我们之前有过一篇关于 VAD 的介绍,其中 _MMVAD_FLAGS.Protection 中描述了页的属性。
我们知道在R3下申请内存时也会定义内存的属性,但通过搜索数值,发现这俩并不相同,这很让人产生疑惑。
下面就来解答这一疑惑。
一、R3与R0的定义
1)在R3环的定义
#define PAGE_NOACCESS 0x01
#define PAGE_READONLY 0x02
#define PAGE_READWRITE 0x04
#define PAGE_WRITECOPY 0x08
#define PAGE_EXECUTE 0x10
#define PAGE_EXECUTE_READ 0x20
#define PAGE_EXECUTE_READWRITE 0x40
#define PAGE_EXECUTE_WRITECOPY 0x80
2)在R0环的定义
#define MM_ZERO_ACCESS 0 // this value is not used.
#define MM_READONLY 1
#define MM_EXECUTE 2
#define MM_EXECUTE_READ 3
#define MM_READWRITE 4 // bit 2 is set if this is writable.
#define MM_WRITECOPY 5
#define MM_EXECUTE_READWRITE 6
#define MM_EXECUTE_WRITECOPY 7
二、内核函数 MiMakeProtectionMask
该内核函数负责将这些定义在R3环的值转换为R0环。
1)首先,将R3环的定义分为Field1(低字节)与Field2(高字节),比如 0x01,分为 Field1 = 1 / Field2 = 0。
2)之后,其分别会去表中查找(在下面源码开头的两个数组),表中携带的就是真正在R0中定义的值。
3)之后将R0的值赋在 _MMVAD_FLAGS.Protection位。
三、分析验证:
1)我们随便遍历一个进程的VAD树,选中一个结点,其为只读属性。
81af63e8 9 3f0 3f2 0 Mapped READONLY \WINDOWS\system32\ctype.nls
2)我们查看其Protection值
kd> dt _MMVAD_FLAGS 81af63e8+0x14
+0x000 Protection : 0y00001 (0x1)
3)我们通过查看R0中的定义可知0x1对应的MM_READONLY,符合要求。
4)MM_READONLY 又在 MmUserProtectionToMask1 表中的第三个位置(索引为2),故其在三环的定义应该为 0x02.
5)查看定义, #define PAGE_READONLY 0x02 ,则符合要求,验证成功。
四、Field表及MiMakeProtectionMask源码
1 // 2 // Protection data for MiMakeProtectionMask 3 // 4 5 CCHAR MmUserProtectionToMask1[16] = { 6 0, 7 MM_NOACCESS, 8 MM_READONLY, 9 -1, 10 MM_READWRITE, 11 -1, 12 -1, 13 -1, 14 MM_WRITECOPY, 15 -1, 16 -1, 17 -1, 18 -1, 19 -1, 20 -1, 21 -1 }; 22 23 CCHAR MmUserProtectionToMask2[16] = { 24 0, 25 MM_EXECUTE, 26 MM_EXECUTE_READ, 27 -1, 28 MM_EXECUTE_READWRITE, 29 -1, 30 -1, 31 -1, 32 MM_EXECUTE_WRITECOPY, 33 -1, 34 -1, 35 -1, 36 -1, 37 -1, 38 -1, 39 -1 }; 40 41 42 MM_PROTECTION_MASK 43 FASTCALL 44 MiMakeProtectionMask ( 45 IN WIN32_PROTECTION_MASK Win32Protect 46 ) 47 48 /*++ 49 50 Routine Description: 51 52 This function takes a user supplied protection and converts it 53 into a 5-bit protection code for the PTE. 54 55 Arguments: 56 57 Win32Protect - Supplies the protection. 58 59 Return Value: 60 61 Returns the protection code for use in the PTE. Note that 62 MM_INVALID_PROTECTION (-1) is returned for an invalid protection 63 request. Since valid PTE protections fit in 5 bits and are 64 zero-extended, it's easy for callers to distinguish this. 65 66 Environment: 67 68 Kernel Mode. 69 70 --*/ 71 72 { 73 ULONG Field1; 74 ULONG Field2; 75 MM_PROTECTION_MASK ProtectCode; 76 77 if (Win32Protect >= (PAGE_WRITECOMBINE * 2)) { 78 return MM_INVALID_PROTECTION; 79 } 80 81 Field1 = Win32Protect & 0xF; 82 Field2 = (Win32Protect >> 4) & 0xF; 83 84 // 85 // Make sure at least one field is set. 86 // 87 88 if (Field1 == 0) { 89 if (Field2 == 0) { 90 91 // 92 // Both fields are zero, return failure. 93 // 94 95 return MM_INVALID_PROTECTION; 96 } 97 ProtectCode = MmUserProtectionToMask2[Field2]; 98 } 99 else { 100 if (Field2 != 0) { 101 // 102 // Both fields are non-zero, return failure. 103 // 104 105 return MM_INVALID_PROTECTION; 106 } 107 ProtectCode = MmUserProtectionToMask1[Field1]; 108 } 109 110 if (ProtectCode == -1) { 111 return MM_INVALID_PROTECTION; 112 } 113 114 if (Win32Protect & PAGE_GUARD) { 115 116 if ((ProtectCode == MM_NOACCESS) || 117 (Win32Protect & (PAGE_NOCACHE | PAGE_WRITECOMBINE))) { 118 119 // 120 // Invalid protection - 121 // guard and either no access, no cache or write combine. 122 // 123 124 return MM_INVALID_PROTECTION; 125 } 126 127 MI_ADD_GUARD (ProtectCode); 128 } 129 130 if (Win32Protect & PAGE_NOCACHE) { 131 132 ASSERT ((Win32Protect & PAGE_GUARD) == 0); // Already checked above 133 134 if ((ProtectCode == MM_NOACCESS) || 135 (Win32Protect & PAGE_WRITECOMBINE)) { 136 137 // 138 // Invalid protection - 139 // nocache and either no access or write combine. 140 // 141 142 return MM_INVALID_PROTECTION; 143 } 144 145 MI_ADD_NOCACHE (ProtectCode); 146 } 147 148 if (Win32Protect & PAGE_WRITECOMBINE) { 149 150 ASSERT ((Win32Protect & (PAGE_GUARD|PAGE_NOACCESS)) == 0); // Already checked above 151 152 if (ProtectCode == MM_NOACCESS) { 153 154 // 155 // Invalid protection, no access and write combine. 156 // 157 158 return MM_INVALID_PROTECTION; 159 } 160 161 MI_ADD_WRITECOMBINE (ProtectCode); 162 } 163 164 return ProtectCode; 165 }