Nasa Patch - Tue, Aug 25, 2020
Download link: nasa-patch
- buck#0001 - inspiration for most of this.
Applying knowledge obtained from the prior write up of paging tables, one can easily follow along with this write up, if you have not acquainted yourself with paging tables this write up will be nothing but squiggly lines. Refresh your mind of the meaning of the following terms: PML4(E), PDPT(E), PD(E), PT(E), address space, paging, and CR3.
To begin I would like to state the obvious: the kernel is mapped into all contexts (all processes). On 64 bit windows the top half of every PML4 is delegated for the kernel (although this is not enforced). The kernel is globally mapped, every process has its own PML4 meaning only the kernels PDPT(E)’s, PD(E)’s and PT(E)’s are truly globally mapped, PML4(E)’s are not. This small and seemingly insignificant fact of paging tables is the basis for my theory of process specific kernel patches. By rebuilding the paging tables of a specific kernel address one can create discrepancies between the kernel and the mapping of the kernel in their process. Before we move forward let me illustrate what paging tables/entries of the kernel are globally mapped and what paging tables/entries are not globally mapped.
In the diagram displayed above, in green are the process specific paging tables/entries related to the kernels mappings. In red are the globally mapped paging tables/entries associated with the kernel. If for example a kernel PML4E were to be changed the effects would not be global.
Knowing that PML4(E)’s of the kernel are not globally mapped, one could rebuild the paging tables for a given address. This idea of rebuilding is simply allocating a new page, copying all entries into the new page and finally editing the paging table entry specified by the corresponding paging table index in the linear virtual address. An illustration of this process of rebuilding is illustrated below.
Although the illustration above does not show paging table indexes, all of the new paging table entries are at indexes that align with a given linear virtual address that a rebuild would be based around.
However, rebuilding paging tables like this will create more discrepancies then asked for. If you point a PML4E at a new PDPT the newly created PDPT will become out of sync with the rest of the real PDPT’s entries. This also applies to the newly created PD, and PT. In other words, some kernel allocations will not be present inside of your process and some kernel allocations inside of your process will not be inside of the kernel. This can be problematic everytime a KeStackAttachProcess occurs, specifically around MmCopyVirtualMemory since a pool is allocated and then a context switch occurs. Doing this enough will cause a big check due to the fact the address is valid in one context but not another. Another thing to note is this will not bypass patch guard but it may postpone the kernel checks from detecting patches that would normally be in the kernel, I do not know much about patch guard so I’m not going to talk much about it.
Process specific kernel patches can be used to patch the handle table of a specific process to change handle privileges from say PROCESS_QUERY_INFORMATION to PROCESS_ALL_ACCESS. Such patches would only be visible inside of your current context thus ExEnumHandleTable would still show PROCESS_QUERY_INFORMATION if called from another context. Although this is not a patch guard bypass, you can use this to inline hook syscalls, patch SSDT, and even IDT only in your current process. Patch guard will probably catch up to you but the amount of time before you are caught is unknown (but longer than normal).
These concepts are highly theoretical and have not been tested on an assortment of processors/windows versions. All code associated with this project is as-is and will not be maintained or updated (there is really nothing for me to add/update). On that note, thank you for reading. I hope you can apply this knowledge to something cool like process specific syscalls or process specific IDT patches.