| 85 | } |
| 86 | |
| 87 | static HMODULE EnumerateModulesInProcess(_In_ HANDLE hProcess, |
| 88 | _In_opt_ HMODULE hModuleLast, |
| 89 | _Out_ PIMAGE_NT_HEADERS32 pNtHeader, |
| 90 | _Out_opt_ PVOID *pRemoteNtHeader) |
| 91 | { |
| 92 | ZeroMemory(pNtHeader, sizeof(*pNtHeader)); |
| 93 | if (pRemoteNtHeader) { |
| 94 | *pRemoteNtHeader = NULL; |
| 95 | } |
| 96 | |
| 97 | PBYTE pbLast = (PBYTE)hModuleLast + MM_ALLOCATION_GRANULARITY; |
| 98 | |
| 99 | MEMORY_BASIC_INFORMATION mbi; |
| 100 | ZeroMemory(&mbi, sizeof(mbi)); |
| 101 | |
| 102 | // Find the next memory region that contains a mapped PE image. |
| 103 | // |
| 104 | |
| 105 | for (;; pbLast = (PBYTE)mbi.BaseAddress + mbi.RegionSize) { |
| 106 | if (VirtualQueryEx(hProcess, (PVOID)pbLast, &mbi, sizeof(mbi)) == 0) { |
| 107 | break; |
| 108 | } |
| 109 | |
| 110 | // Usermode address space has such an unaligned region size always at the |
| 111 | // end and only at the end. |
| 112 | // |
| 113 | if ((mbi.RegionSize & 0xfff) == 0xfff) { |
| 114 | break; |
| 115 | } |
| 116 | if (((PBYTE)mbi.BaseAddress + mbi.RegionSize) < pbLast) { |
| 117 | break; |
| 118 | } |
| 119 | |
| 120 | // Skip uncommitted regions and guard pages. |
| 121 | // |
| 122 | if ((mbi.State != MEM_COMMIT) || |
| 123 | ((mbi.Protect & 0xff) == PAGE_NOACCESS) || |
| 124 | (mbi.Protect & PAGE_GUARD)) { |
| 125 | continue; |
| 126 | } |
| 127 | |
| 128 | PVOID remoteHeader |
| 129 | = LoadNtHeaderFromProcess(hProcess, (HMODULE)pbLast, pNtHeader); |
| 130 | if (remoteHeader) { |
| 131 | if (pRemoteNtHeader) { |
| 132 | *pRemoteNtHeader = remoteHeader; |
| 133 | } |
| 134 | |
| 135 | return (HMODULE)pbLast; |
| 136 | } |
| 137 | } |
| 138 | return NULL; |
| 139 | } |
| 140 | |
| 141 | ////////////////////////////////////////////////////////////////////////////// |
| 142 | // |
no test coverage detected
searching dependent graphs…