diff --git a/nasa-mapper/mem_ctx/mem_ctx.cpp b/nasa-mapper/mem_ctx/mem_ctx.cpp index cca337a..6c28e7d 100644 --- a/nasa-mapper/mem_ctx/mem_ctx.cpp +++ b/nasa-mapper/mem_ctx/mem_ctx.cpp @@ -1,5 +1,4 @@ #include "mem_ctx.hpp" -#include namespace physmeme { @@ -9,88 +8,153 @@ namespace physmeme dirbase(get_dirbase(krnl_ctx, pid)), pid(pid) { - genesis_page.first = VirtualAlloc( - NULL, - PAGE_SIZE, - MEM_COMMIT | MEM_RESERVE, - PAGE_READWRITE - ); - - // - // page in the page, do not remove this makes the entries. - // - *(std::uintptr_t*)genesis_page.first = 0xC0FFEE; - - // - // get the ppte and pte of the page we allocated - // - auto [page_ppte, page_pte] = get_pte(genesis_page.first, true); - genesis_page.second = page_pte; - - // - // allocate a page that will get the mapping of the first pages PT - // - genesis_cursor.first = reinterpret_cast<::ppte>( - VirtualAlloc( - NULL, - 0x1000, - MEM_COMMIT | MEM_RESERVE, - PAGE_READWRITE - )); - - // - // page it in - // - *(std::uintptr_t*)genesis_cursor.first = 0xC0FFEE; - - // - // get ppte and pte of the cursor page. - // - auto [cursor_ppte, cursor_pte] = get_pte(genesis_cursor.first, true); - genesis_cursor.second = cursor_pte; + // find an empty pml4e... + for (auto idx = 100u; idx > 0u; --idx) + if (!k_ctx->rkm(k_ctx->get_virtual((reinterpret_cast<::ppml4e>(get_dirbase()) + idx))).present) + this->pml4e_index = idx; + + // allocate a pdpt + this->new_pdpt.second = + reinterpret_cast( + VirtualAlloc( + NULL, + PAGE_SIZE, + MEM_COMMIT | MEM_RESERVE, + PAGE_READWRITE + )); + PAGE_IN(this->new_pdpt.second, PAGE_SIZE); + + // get page table entries for new pdpt + pt_entries new_pdpt_entries; + hyperspace_entries(new_pdpt_entries, new_pdpt.second); + this->new_pdpt.first = reinterpret_cast(new_pdpt_entries.pt.second.pfn << 12); + + // make a new pml4e that points to our new pdpt. + new_pdpt_entries.pml4.second.pfn = new_pdpt_entries.pt.second.pfn; + + // set the pml4e to point to the new pdpt + set_pml4e(reinterpret_cast<::ppml4e>(get_dirbase()) + this->pml4e_index, new_pdpt_entries.pml4.second, true); + + // make a new pd + this->new_pd.second = + reinterpret_cast( + VirtualAlloc( + NULL, + PAGE_SIZE, + MEM_COMMIT | MEM_RESERVE, + PAGE_READWRITE + )); + PAGE_IN(this->new_pd.second, PAGE_SIZE); // - // change the page to the PT of the first page we allocated. + // get paging table entries for pd // - cursor_pte.pfn = reinterpret_cast(page_ppte) >> 12; - set_pte(genesis_cursor.first, cursor_pte, true); + pt_entries new_pd_entries; + hyperspace_entries( + new_pd_entries, + this->new_pd.second + ); + this->new_pd.first = reinterpret_cast(new_pd_entries.pt.second.pfn << 12); // - // change the offset of genesis cursor page to genesis pages pt_index since the page is now a PT - // WARNING: pointer arithmetic, do not add pt_index * 8 + // make a new pt // - genesis_cursor.first += +virt_addr_t{ genesis_page.first }.pt_index; - FLUSH_TLB; + this->new_pt.second = + reinterpret_cast( + VirtualAlloc( + NULL, + PAGE_SIZE, + MEM_COMMIT | MEM_RESERVE, + PAGE_READWRITE + )); + PAGE_IN(this->new_pt.second, PAGE_SIZE); + + // get paging table entries for pt + pt_entries new_pt_entries; + hyperspace_entries(new_pt_entries, this->new_pt.second); + this->new_pt.first = reinterpret_cast(new_pt_entries.pt.second.pfn << 12); } mem_ctx::~mem_ctx() { - set_pte(genesis_page.first, genesis_page.second, true); - set_pte(genesis_cursor.first, genesis_cursor.second, true); + // remove pml4e + pml4e null_value{ NULL }; + set_pml4e(reinterpret_cast<::ppml4e>(get_dirbase()) + this->pml4e_index, null_value, true); } void* mem_ctx::set_page(void* addr) { + // table entry change. + { + ++pte_index; + if (pte_index >= 511) + { + ++pde_index; + pte_index = 0; + } + + if (pde_index >= 511) + { + ++pdpte_index; + pde_index = 0; + } + + if (pdpte_index >= 511) + pdpte_index = 0; + } + + pdpte new_pdpte = { NULL }; + new_pdpte.present = true; + new_pdpte.rw = true; + new_pdpte.pfn = reinterpret_cast(new_pd.first) >> 12; + new_pdpte.user_supervisor = true; + new_pdpte.accessed = true; + + // set pdpte entry + *reinterpret_cast(new_pdpt.second + pdpte_index) = new_pdpte; + + pde new_pde = { NULL }; + new_pde.present = true; + new_pde.rw = true; + new_pde.pfn = reinterpret_cast(new_pt.first) >> 12; + new_pde.user_supervisor = true; + new_pde.accessed = true; + + // set pde entry + *reinterpret_cast(new_pd.second + pde_index) = new_pde; + + pte new_pte = { NULL }; + new_pte.present = true; + new_pte.rw = true; + new_pte.pfn = reinterpret_cast(addr) >> 12; + new_pte.user_supervisor = true; + new_pte.accessed = true; + + // set pte entry + *reinterpret_cast(new_pt.second + pte_index) = new_pte; + + // set page offset this->page_offset = virt_addr_t{ addr }.offset; - this->genesis_cursor.first->pfn = reinterpret_cast(addr) >> 12; - FLUSH_TLB; return get_page(); } void* mem_ctx::get_page() const { - return reinterpret_cast( - reinterpret_cast( - this->genesis_page.first) + this->page_offset); + // builds a new address given the state of all table indexes + virt_addr_t new_addr; + new_addr.pml4_index = this->pml4e_index; + new_addr.pdpt_index = this->pdpte_index; + new_addr.pd_index = this->pde_index; + new_addr.pt_index = this->pte_index; + new_addr.offset = this->page_offset; + return new_addr.value; } void* mem_ctx::get_dirbase(kernel_ctx& k_ctx, DWORD pid) { const auto peproc = - reinterpret_cast( - k_ctx.get_peprocess(pid)); + reinterpret_cast(k_ctx.get_peprocess(pid)); - if (!peproc) return NULL; pte dirbase = k_ctx.rkm( reinterpret_cast(peproc + 0x28)); @@ -150,12 +214,8 @@ namespace physmeme return {}; pt_entries entries; - if (use_hyperspace ? hyperspace_entries(entries, addr) : virt_to_phys(entries, addr)) - { - ::pte pte; - memcpy(&pte, &entries.pt.second, sizeof(pte)); - return { entries.pt.first, pte }; - } + if (use_hyperspace ? hyperspace_entries(entries, addr) : (bool)virt_to_phys(entries, addr)) + return { entries.pt.first, entries.pt.second }; return {}; } @@ -164,16 +224,10 @@ namespace physmeme if (!dirbase || !addr) return; - pt_entries entries; if (use_hyperspace) - if (hyperspace_entries(entries, addr)) - k_ctx->wkm( - k_ctx->get_virtual(entries.pt.first), - pte - ); + k_ctx->wkm(k_ctx->get_virtual(addr), pte); else - if (virt_to_phys(entries, addr)) - write_phys(entries.pt.first, pte); + write_phys(addr, pte); } std::pair mem_ctx::get_pde(void* addr, bool use_hyperspace) @@ -182,34 +236,20 @@ namespace physmeme return {}; pt_entries entries; - if (use_hyperspace ? hyperspace_entries(entries, addr) : virt_to_phys(entries, addr)) - { - ::pde pde; - memcpy( - &pde, - &entries.pd.second, - sizeof(pde) - ); - return { entries.pd.first, pde }; - } + if (use_hyperspace ? hyperspace_entries(entries, addr) : (bool)virt_to_phys(entries, addr)) + return { entries.pd.first, entries.pd.second }; return {}; } void mem_ctx::set_pde(void* addr, const ::pde& pde, bool use_hyperspace) { - if (!dirbase || !addr) + if (!this->dirbase || !addr) return; - pt_entries entries; if (use_hyperspace) - if (hyperspace_entries(entries, addr)) - k_ctx->wkm( - k_ctx->get_virtual(entries.pd.first), - pde - ); + k_ctx->wkm(k_ctx->get_virtual(addr), pde); else - if (virt_to_phys(entries, addr)) - write_phys(entries.pd.first, pde); + write_phys(addr, pde); } std::pair mem_ctx::get_pdpte(void* addr, bool use_hyperspace) @@ -218,55 +258,42 @@ namespace physmeme return {}; pt_entries entries; - if (use_hyperspace ? hyperspace_entries(entries, addr) : virt_to_phys(entries, addr)) + if (use_hyperspace ? hyperspace_entries(entries, addr) : (bool)virt_to_phys(entries, addr)) return { entries.pdpt.first, entries.pdpt.second }; return {}; } void mem_ctx::set_pdpte(void* addr, const ::pdpte& pdpte, bool use_hyperspace) { - if (!dirbase || !addr) + if (!this->dirbase || !addr) return; - pt_entries entries; if (use_hyperspace) - if (hyperspace_entries(entries, addr)) - k_ctx->wkm( - k_ctx->get_virtual(entries.pdpt.first), - pdpte - ); + k_ctx->wkm(k_ctx->get_virtual(addr), pdpte); else - if (virt_to_phys(entries, addr)) - write_phys(entries.pdpt.first, pdpte); + write_phys(addr, pdpte); } std::pair mem_ctx::get_pml4e(void* addr, bool use_hyperspace) { - if (!dirbase || !addr) - return { {}, {} }; + if (!this->dirbase || !addr) + return {}; pt_entries entries; - if (use_hyperspace ? hyperspace_entries(entries, addr) : virt_to_phys(entries, addr)) - return { entries.pml4.first, entries.pml4.second}; - - return { {}, {} }; + if (use_hyperspace ? hyperspace_entries(entries, addr) : (bool)virt_to_phys(entries, addr)) + return { entries.pml4.first, entries.pml4.second }; + return {}; } void mem_ctx::set_pml4e(void* addr, const ::pml4e& pml4e, bool use_hyperspace) { - if (!dirbase || !addr) + if (!this->dirbase || !addr) return; - pt_entries entries; if (use_hyperspace) - if (hyperspace_entries(entries, addr)) - k_ctx->wkm( - k_ctx->get_virtual(entries.pml4.first), - pml4e - ); + k_ctx->wkm(k_ctx->get_virtual(addr), pml4e); else - if (virt_to_phys(entries, addr)) - write_phys(entries.pml4.first, pml4e); + write_phys(addr, pml4e); } std::pair mem_ctx::read_virtual(void* buffer, void* addr, std::size_t size) @@ -278,12 +305,15 @@ namespace physmeme if (size <= PAGE_SIZE - virt_addr.offset) { pt_entries entries; - read_phys( + read_phys + ( buffer, virt_to_phys(entries, addr), size ); - return { + + return + { reinterpret_cast(reinterpret_cast(buffer) + size), reinterpret_cast(reinterpret_cast(addr) + size) }; @@ -291,13 +321,16 @@ namespace physmeme else { // cut remainder - const auto [new_buffer_addr, new_addr] = read_virtual( + const auto [new_buffer_addr, new_addr] = read_virtual + ( buffer, addr, PAGE_SIZE - virt_addr.offset ); + // forward work load - return read_virtual( + return read_virtual + ( new_buffer_addr, new_addr, size - (PAGE_SIZE - virt_addr.offset) @@ -314,13 +347,15 @@ namespace physmeme if (size <= PAGE_SIZE - virt_addr.offset) { pt_entries entries; - write_phys( + write_phys + ( buffer, virt_to_phys(entries, addr), size ); - return { + return + { reinterpret_cast(reinterpret_cast(buffer) + size), reinterpret_cast(reinterpret_cast(addr) + size) }; @@ -328,14 +363,16 @@ namespace physmeme else { // cut remainder - const auto [new_buffer_addr, new_addr] = write_virtual( + const auto [new_buffer_addr, new_addr] = write_virtual + ( buffer, addr, PAGE_SIZE - virt_addr.offset ); // forward work load - return write_virtual( + return write_virtual + ( new_buffer_addr, new_addr, size - (PAGE_SIZE - virt_addr.offset) @@ -348,7 +385,7 @@ namespace physmeme if (!buffer || !addr || !size) return; - auto temp_page = set_page(addr); + const auto temp_page = set_page(addr); if (temp_page) memcpy(buffer, temp_page, size); } @@ -358,25 +395,24 @@ namespace physmeme if (!buffer || !addr || !size) return; - auto temp_page = set_page(addr); + const auto temp_page = set_page(addr); if (temp_page) memcpy(temp_page, buffer, size); } void* mem_ctx::virt_to_phys(pt_entries& entries, void* addr) { - if (!addr || !dirbase) + if (!addr || !this->dirbase) return {}; - virt_addr_t virt_addr{ addr }; - + const virt_addr_t virt_addr{ addr }; // // traverse paging tables // auto pml4e = read_phys<::pml4e>( - reinterpret_cast(dirbase) + virt_addr.pml4_index); + reinterpret_cast(this->dirbase) + virt_addr.pml4_index); - entries.pml4.first = reinterpret_cast(dirbase) + virt_addr.pml4_index; + entries.pml4.first = reinterpret_cast(this->dirbase) + virt_addr.pml4_index; entries.pml4.second = pml4e; if (!pml4e.value) @@ -421,4 +457,27 @@ namespace physmeme { return dirbase; } + + pml4e mem_ctx::operator[](std::uint16_t pml4_idx) + { + return read_phys<::pml4e>(reinterpret_cast(this->dirbase) + pml4_idx); + } + + pdpte mem_ctx::operator[](const std::pair& entry_idx) + { + const auto pml4_entry = this->operator[](entry_idx.first); + return read_phys<::pdpte>(reinterpret_cast(pml4_entry.pfn << 12) + entry_idx.second); + } + + pde mem_ctx::operator[](const std::tuple& entry_idx) + { + const auto pdpt_entry = this->operator[]({ std::get<0>(entry_idx), std::get<1>(entry_idx) }); + return read_phys<::pde>(reinterpret_cast(pdpt_entry.pfn << 12) + std::get<2>(entry_idx)); + } + + pte mem_ctx::operator[](const std::tuple& entry_idx) + { + const auto pd_entry = this->operator[]({ std::get<0>(entry_idx), std::get<1>(entry_idx), std::get<2>(entry_idx) }); + return read_phys<::pte>(reinterpret_cast(pd_entry.pfn << 12) + std::get<3>(entry_idx)); + } } \ No newline at end of file diff --git a/nasa-mapper/mem_ctx/mem_ctx.hpp b/nasa-mapper/mem_ctx/mem_ctx.hpp index b76e11d..3ebdff2 100644 --- a/nasa-mapper/mem_ctx/mem_ctx.hpp +++ b/nasa-mapper/mem_ctx/mem_ctx.hpp @@ -2,9 +2,7 @@ #include "../util/nt.hpp" #include "../kernel_ctx/kernel_ctx.h" -// context switch causes the TLB to be flushed... -#define FLUSH_TLB while(!SwitchToThread()) continue; - +#define PAGE_IN(addr, size) memset(addr, NULL, size) struct pt_entries { std::pair pml4; @@ -17,8 +15,9 @@ namespace physmeme { class mem_ctx { + friend class mapper_ctx; public: - explicit mem_ctx(kernel_ctx& k_ctx, DWORD pid); + explicit mem_ctx(kernel_ctx& k_ctx, DWORD pid = GetCurrentProcessId()); ~mem_ctx(); // @@ -57,8 +56,7 @@ namespace physmeme template T read_phys(void* addr) { - if (!addr) - return {}; + if (!addr) return {}; T buffer; read_phys((void*)&buffer, addr, sizeof(T)); return buffer; @@ -67,8 +65,7 @@ namespace physmeme template void write_phys(void* addr, const T& data) { - if (!addr) - return; + if (!addr) return; write_phys((void*)&data, addr, sizeof(T)); } @@ -78,8 +75,7 @@ namespace physmeme template T read_virtual(void* addr) { - if (!addr) - return {}; + if (!addr) return {}; T buffer; read_virtual((void*)&buffer, addr, sizeof(T)); return buffer; @@ -102,19 +98,26 @@ namespace physmeme void* set_page(void* addr); void* get_page() const; unsigned get_pid() const; - kernel_ctx* k_ctx; + + pml4e operator[](std::uint16_t pml4_idx); + pdpte operator[](const std::pair& entry_idx); + pde operator[](const std::tuple& entry_idx); + pte operator[](const std::tuple& entry_idx); private: // // given an address fill pt entries with physical addresses and entry values. // bool hyperspace_entries(pt_entries& entries, void* addr); - - std::pair genesis_page; - std::pair genesis_cursor; void* dirbase; + kernel_ctx* k_ctx; + std::uint16_t pml4e_index, pdpte_index, pde_index, pte_index, page_offset; + /// first == physical + /// second == virtual + std::pair new_pdpt; + std::pair new_pd; + std::pair new_pt; unsigned pid; - unsigned short page_offset; }; } \ No newline at end of file diff --git a/nasa-mapper/util/nt.hpp b/nasa-mapper/util/nt.hpp index 474f9d6..218645a 100644 --- a/nasa-mapper/util/nt.hpp +++ b/nasa-mapper/util/nt.hpp @@ -265,7 +265,7 @@ typedef union _pml4e struct { ULONG64 present : 1; // Must be 1, region invalid if 0. - ULONG64 ReadWrite : 1; // If 0, writes not allowed. + ULONG64 rw : 1; // If 0, writes not allowed. ULONG64 user_supervisor : 1; // If 0, user-mode accesses not allowed. ULONG64 PageWriteThrough : 1; // Determines the memory type used to access PDPT. ULONG64 page_cache : 1; // Determines the memory type used to access PDPT. @@ -309,11 +309,11 @@ typedef union _pde struct { ULONG64 present : 1; // Must be 1, region invalid if 0. - ULONG64 ReadWrite : 1; // If 0, writes not allowed. + ULONG64 rw : 1; // If 0, writes not allowed. ULONG64 user_supervisor : 1; // If 0, user-mode accesses not allowed. ULONG64 PageWriteThrough : 1; // Determines the memory type used to access PT. ULONG64 page_cache : 1; // Determines the memory type used to access PT. - ULONG64 Accessed : 1; // If 0, this entry has not been used for translation. + ULONG64 accessed : 1; // If 0, this entry has not been used for translation. ULONG64 Ignored1 : 1; ULONG64 page_size : 1; // If 1, this entry maps a 2MB page. ULONG64 Ignored2 : 4; @@ -331,7 +331,7 @@ typedef union _pte struct { ULONG64 present : 1; // Must be 1, region invalid if 0. - ULONG64 ReadWrite : 1; // If 0, writes not allowed. + ULONG64 rw : 1; // If 0, writes not allowed. ULONG64 user_supervisor : 1; // If 0, user-mode accesses not allowed. ULONG64 PageWriteThrough : 1; // Determines the memory type used to access the memory. ULONG64 page_cache : 1; // Determines the memory type used to access the memory. diff --git a/um-example/nasa-mapper.lib b/um-example/nasa-mapper.lib index 324d9f0..8cc0e33 100644 Binary files a/um-example/nasa-mapper.lib and b/um-example/nasa-mapper.lib differ