Created
November 25, 2023 15:44
-
-
Save blair1922/101d02443146e32a00d809d63e713965 to your computer and use it in GitHub Desktop.
Threaded kernel-mode DLL manual mapper exploiting a vulnerable RWX section within signed memory.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//Replace Zw... functions with your own memory managing implementation | |
//And hide your thread (it is not needed here but makes code execution easier) | |
//Solution tested and working on Rust(EAC) and EFT(BE) on Windows 11 Pro 22h2 | |
#include "util.h" | |
ULONG_PTR FindRwxSection(PCHAR moduleName) | |
{ | |
ULONG_PTR moduleBase = GetModuleBaseAddress(moduleName); | |
if (moduleBase == 0) | |
return 0; | |
PIMAGE_DOS_HEADER dosHeader = (PIMAGE_DOS_HEADER)moduleBase; | |
PIMAGE_NT_HEADERS ntHeaders = (PIMAGE_NT_HEADERS)(moduleBase + dosHeader->e_lfanew); | |
PIMAGE_SECTION_HEADER sectionHeader = IMAGE_FIRST_SECTION(ntHeaders); | |
for (USHORT i = 0; i < ntHeaders->FileHeader.NumberOfSections; i++) | |
{ | |
ULONG characteristics = sectionHeader[i].Characteristics; | |
if ((characteristics & IMAGE_SCN_MEM_EXECUTE) && | |
(characteristics & IMAGE_SCN_MEM_READ) && | |
(characteristics & IMAGE_SCN_MEM_WRITE)) | |
{ | |
return (ULONG_PTR)(moduleBase + sectionHeader[i].VirtualAddress); | |
} | |
} | |
return 0; | |
} | |
NTSTATUS ManualMapDll(PCHAR moduleName, PCHAR targetProcessName) | |
{ | |
NTSTATUS status; | |
PEPROCESS targetProcess; | |
PVOID targetBaseAddress; | |
HANDLE targetProcessHandle; | |
UNICODE_STRING targetProcessNameUnicode; | |
RtlInitUnicodeString(&targetProcessNameUnicode, targetProcessName); | |
status = PsLookupProcessByProcessName(&targetProcessNameUnicode, &targetProcess); | |
if (!NT_SUCCESS(status)) | |
return status; | |
status = ObOpenObjectByPointer(targetProcess, OBJ_KERNEL_HANDLE, NULL, 0, *PsProcessType, KernelMode, &targetProcessHandle); | |
if (!NT_SUCCESS(status)) | |
{ | |
ObDereferenceObject(targetProcess); | |
return status; | |
} | |
targetBaseAddress = PsGetProcessSectionBaseAddress(targetProcess); | |
if (targetBaseAddress == NULL) | |
{ | |
ZwClose(targetProcessHandle); | |
ObDereferenceObject(targetProcess); | |
return STATUS_INVALID_PARAMETER; | |
} | |
ULONG_PTR rwxSection = FindRwxSection(moduleName); | |
if (rwxSection == 0) | |
{ | |
ZwClose(targetProcessHandle); | |
ObDereferenceObject(targetProcess); | |
return STATUS_NOT_FOUND; | |
} | |
HANDLE currentProcessId = PsGetCurrentProcessId(); | |
PVOID currentBaseAddress = PsGetProcessSectionBaseAddress(PsGetCurrentProcess()); | |
PVOID remoteImageBase = NULL; | |
SIZE_T imageSize = 0; | |
status = ZwReadVirtualMemory(targetProcessHandle, ¤tBaseAddress, &remoteImageBase, sizeof(PVOID), NULL); | |
if (!NT_SUCCESS(status)) | |
{ | |
ZwClose(targetProcessHandle); | |
ObDereferenceObject(targetProcess); | |
return status; | |
} | |
PIMAGE_DOS_HEADER dosHeader = (PIMAGE_DOS_HEADER)remoteImageBase; | |
PIMAGE_NT_HEADERS ntHeaders = (PIMAGE_NT_HEADERS)((ULONG_PTR)remoteImageBase + dosHeader->e_lfanew); | |
imageSize = ntHeaders->OptionalHeader.SizeOfImage; | |
PVOID remoteAllocation = NULL; | |
status = ZwAllocateVirtualMemory(targetProcessHandle, &remoteAllocation, 0, &imageSize, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); | |
if (!NT_SUCCESS(status)) | |
{ | |
ZwClose(targetProcessHandle); | |
ObDereferenceObject(targetProcess); | |
return status; | |
} | |
PVOID localImageBase = ExAllocatePoolWithTag(NonPagedPoolNx, imageSize, 'MMAP'); | |
if (localImageBase == NULL) | |
{ | |
ZwFreeVirtualMemory(targetProcessHandle, &remoteAllocation, &imageSize, MEM_RELEASE); | |
ZwClose(targetProcessHandle); | |
ObDereferenceObject(targetProcess); | |
return STATUS_INSUFFICIENT_RESOURCES; | |
} | |
RtlCopyMemory(localImageBase, currentBaseAddress, imageSize); | |
PIMAGE_BASE_RELOCATION relocation = (PIMAGE_BASE_RELOCATION)((ULONG_PTR)localImageBase + ntHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress); | |
ULONG_PTR delta = (ULONG_PTR)remoteAllocation - ntHeaders->OptionalHeader.ImageBase; | |
while (relocation->VirtualAddress != 0) | |
{ | |
ULONG count = (relocation->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION)) / sizeof(USHORT); | |
PUSHORT list = (PUSHORT)((ULONG_PTR)relocation + sizeof(IMAGE_BASE_RELOCATION)); | |
for (ULONG i = 0; i < count; i++) | |
{ | |
if (list[i] >> 12 == IMAGE_REL_BASED_HIGHLOW) | |
{ | |
PULONG_PTR ptr = (PULONG_PTR)((ULONG_PTR)localImageBase + (relocation->VirtualAddress + (list[i] & 0xFFF))); | |
*ptr += delta; | |
} | |
} | |
relocation = (PIMAGE_BASE_RELOCATION)((ULONG_PTR)relocation + relocation->SizeOfBlock); | |
} | |
PVOID remoteEntryPoint = (PVOID)((ULONG_PTR)remoteAllocation + ntHeaders->OptionalHeader.AddressOfEntryPoint); | |
status = ZwWriteVirtualMemory(targetProcessHandle, &remoteEntryPoint, &ntHeaders->OptionalHeader.AddressOfEntryPoint, sizeof(PVOID), NULL); | |
if (!NT_SUCCESS(status)) | |
{ | |
ExFreePoolWithTag(localImageBase, 'MMAP'); | |
ZwFreeVirtualMemory(targetProcessHandle, &remoteAllocation, &imageSize, MEM_RELEASE); | |
ZwClose(targetProcessHandle); | |
ObDereferenceObject(targetProcess); | |
return status; | |
} | |
status = ZwWriteVirtualMemory(targetProcessHandle, &remoteAllocation, &localImageBase, sizeof(PVOID), NULL); | |
if (!NT_SUCCESS(status)) | |
{ | |
ExFreePoolWithTag(localImageBase, 'MMAP'); | |
ZwFreeVirtualMemory(targetProcessHandle, &remoteAllocation, &imageSize, MEM_RELEASE); | |
ZwClose(targetProcessHandle); | |
ObDereferenceObject(targetProcess); | |
return status; | |
} | |
PETHREAD targetThread; | |
status = PsCreateSystemThread(&targetThread, THREAD_ALL_ACCESS, NULL, targetProcessHandle, NULL, (PKSTART_ROUTINE)remoteEntryPoint, NULL); | |
if (!NT_SUCCESS(status)) | |
{ | |
ExFreePoolWithTag(localImageBase, 'MMAP'); | |
ZwFreeVirtualMemory(targetProcessHandle, &remoteAllocation, &imageSize, MEM_RELEASE); | |
ZwClose(targetProcessHandle); | |
ObDereferenceObject(targetProcess); | |
return status; | |
} | |
ZwClose(targetThread); | |
ExFreePoolWithTag(localImageBase, 'MMAP'); | |
ZwFreeVirtualMemory(targetProcessHandle, &remoteAllocation, &imageSize, MEM_RELEASE); | |
ZwClose(targetProcessHandle); | |
ObDereferenceObject(targetProcess); | |
return STATUS_SUCCESS; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment