| 140 | |
| 141 | _IRQL_requires_max_(APC_LEVEL) |
| 142 | BOOLEAN TriggerCopyOnWrite(OPTIONAL PEPROCESS Process, PVOID Address, OPTIONAL OUT PULONG PageSize) |
| 143 | { |
| 144 | BOOLEAN NeedToAttach = Process && Process != PsGetCurrentProcess(); |
| 145 | KAPC_STATE ApcState; |
| 146 | if (NeedToAttach) |
| 147 | KeStackAttachProcess(Process, &ApcState); |
| 148 | |
| 149 | BOOLEAN Status = FALSE; |
| 150 | PAGE_TABLES_INFO Info = {}; |
| 151 | Status = GetPageTables(Address, &Info); |
| 152 | if (Status) __try |
| 153 | { |
| 154 | // AVL is a 3-bit field: |
| 155 | // AVL:CopyOnWrite : 1 |
| 156 | // AVL:Unused : 1 |
| 157 | // AVL:Write : 1; |
| 158 | // We're setting the CoW bit (0b001): |
| 159 | constexpr unsigned int COW_MASK = 0b001; |
| 160 | constexpr unsigned int WRITE_MASK = 0b100; |
| 161 | |
| 162 | if (PageSize) *PageSize = 0; |
| 163 | |
| 164 | switch (Info.Type) |
| 165 | { |
| 166 | case PAGE_TABLES_INFO::pt32NonPaePage4Kb: |
| 167 | // PDE -> PTE -> PA: |
| 168 | if (PageSize) *PageSize = 4096; |
| 169 | if (!Info.Pte->x32.NonPae.Page4Kb.P || Info.Pte->x32.NonPae.Page4Kb.D || (Info.Pte->x32.NonPae.Page4Kb.AVL & WRITE_MASK)) break; |
| 170 | Info.Pte->x32.NonPae.Page4Kb.AVL = COW_MASK; |
| 171 | break; |
| 172 | case PAGE_TABLES_INFO::pt32NonPaePage4Mb: |
| 173 | // PDE -> PA: |
| 174 | if (PageSize) *PageSize = 4096 * 1024; |
| 175 | if (!Info.Pde->x32.NonPae.Page4Mb.P || Info.Pde->x32.NonPae.Page4Mb.D || (Info.Pde->x32.NonPae.Page4Mb.AVL & WRITE_MASK)) break; |
| 176 | Info.Pde->x32.NonPae.Page4Mb.AVL = COW_MASK; |
| 177 | break; |
| 178 | case PAGE_TABLES_INFO::pt32PaePage4Kb: |
| 179 | // PDPE -> PDE -> PTE -> PA: |
| 180 | if (PageSize) *PageSize = 4096; |
| 181 | if (!Info.Pte->x32.Pae.Page4Kb.P || Info.Pte->x32.Pae.Page4Kb.D || (Info.Pte->x32.Pae.Page4Kb.AVL & WRITE_MASK)) break; |
| 182 | Info.Pte->x32.Pae.Page4Kb.AVL = COW_MASK; |
| 183 | break; |
| 184 | case PAGE_TABLES_INFO::pt32PaePage2Mb: |
| 185 | // PDPE -> PDE -> PA: |
| 186 | if (PageSize) *PageSize = 2048 * 1024; |
| 187 | if (!Info.Pde->x32.Pae.Page2Mb.P || Info.Pde->x32.Pae.Page2Mb.D || (Info.Pde->x32.Pae.Page2Mb.AVL & WRITE_MASK)) break; |
| 188 | Info.Pde->x32.Pae.Page2Mb.AVL = COW_MASK; |
| 189 | break; |
| 190 | case PAGE_TABLES_INFO::pt64Page4Kb: |
| 191 | // PML4E -> PDPE -> PDE -> PTE -> PA: |
| 192 | if (PageSize) *PageSize = 4096; |
| 193 | if (!Info.Pte->x64.Page4Kb.P || Info.Pte->x64.Page4Kb.D || (Info.Pte->x64.Page4Kb.AVL & WRITE_MASK)) break; |
| 194 | Info.Pte->x64.Page4Kb.AVL = COW_MASK; |
| 195 | break; |
| 196 | case PAGE_TABLES_INFO::pt64Page2Mb: |
| 197 | // PML4E -> PDPE -> PDE -> PA: |
| 198 | if (PageSize) *PageSize = 2048 * 1024; |
| 199 | if (!Info.Pde->x64.Page2Mb.P || Info.Pde->x64.Page2Mb.D || (Info.Pde->x64.Page2Mb.AVL & WRITE_MASK)) break; |
no test coverage detected