|
#include "ntddk.h"
typedef struct
{
ULONG offset;
PMDL pMdl;
PULONG pMapped;
} PATCH_INFO;
// We'll patch two addresses in the shell32.dll section.
// This array must be zero-terminated.
PATCH_INFO offsets[] = {
{ 0xA916F, NULL, NULL },
{ 0xA91B6, NULL, NULL },
{ 0, NULL, NULL }
};
NTSTATUS DoPatch(ULONG isLoading)
{
UNICODE_STRING us = { 0 };
OBJECT_ATTRIBUTES oa = { 0 };
NTSTATUS status = 0;
NTSTATUS retval = STATUS_SUCCESS;
HANDLE hSection = 0;
PUCHAR pSection = NULL;
ULONG viewSize = 0;
PATCH_INFO *pCurrentPatchInfo = NULL;
PULONG pWordToChange = NULL;
ULONG expectedBytes;
ULONG newBytes;
// Depending on whether we're loading or unloading the driver, we expect to find
// one of the following values at each offset. Only if there is a match will we
// do the patch.
const ULONG unpatchedBytes = 0xFF2A7D05;
const ULONG patchedBytes = 0xFF2A7D00;
__try // (__try/__finally to ensure cleanup)
{
__try // (__try/__except to handle errors and prevent Blue Screens of Death)
{
if (isLoading)
{
// Open the KnownDlls named section object for shell32.dll
RtlInitUnicodeString(&us, L"\\KnownDlls\\shell32.dll");
InitializeObjectAttributes(&oa, &us, OBJ_KERNEL_HANDLE, NULL, NULL);
status = ZwOpenSection(&hSection, SECTION_MAP_READ, &oa);
if (status != STATUS_SUCCESS)
{
DbgPrint("Error calling ZwOpenSection: %08X\n", status);
retval = status;
__leave;
}
// Get a pointer to the section
status = ZwMapViewOfSection(
hSection,
NtCurrentProcess(),
&pSection,
0,
0,
0,
&viewSize,
ViewShare,
0,
PAGE_READWRITE
);
if (status != STATUS_SUCCESS)
{
DbgPrint("Error calling ZwMapViewOfSection: %08X\n", status);
retval = status;
__leave;
}
}
// We'll change both what we're looking for and what we change to based on
// whether the driver is loading or unloading.
expectedBytes = isLoading ? unpatchedBytes : patchedBytes;
newBytes = isLoading ? patchedBytes : unpatchedBytes;
// First, let's create a MDL for each user-mode address we need to change
// (IoAllocateMdl). Then, we'll map those same pages into kernel memory
// and lock them (MmProbeAndLockPages and MmGetSystemAddressForMdlSafe).
// Then, we'll verify the current contents of all of the memory locations
// we're going to patch. We'll check all of them before changing any of
// them because we want the patch to either be all or nothing.
for (pCurrentPatchInfo = offsets; pCurrentPatchInfo->offset != 0; pCurrentPatchInfo++)
{
// We only need to create, map and lock the memory if we're in the loading
// phase (i.e. DoPatch(TRUE)).
if (isLoading)
{
pWordToChange = (PULONG)(pSection + pCurrentPatchInfo->offset);
// Create a Memory Descriptor List (MDL) for the virtual address at "pWordToChange"
pCurrentPatchInfo->pMdl = IoAllocateMdl(pWordToChange, sizeof(ULONG), FALSE, FALSE, NULL);
if (pCurrentPatchInfo->pMdl == NULL)
{
DbgPrint("Unable to allocate MDL for VA %08X\n", pWordToChange);
retval = STATUS_UNSUCCESSFUL;
__leave;
}
// Lock the pages in memory and get a pointer to the "pWordToChange" in its
// kernel-memory-mapped location
MmProbeAndLockPages(pCurrentPatchInfo->pMdl, KernelMode, IoReadAccess);
pCurrentPatchInfo->pMapped = (PULONG)MmGetSystemAddressForMdlSafe(pCurrentPatchInfo->pMdl, NormalPagePriority);
if (pCurrentPatchInfo->pMapped == NULL)
{
DbgPrint("MmGetSystemAddressForMdlSafe returned NULL for VA %08X\n", pWordToChange);
retval = STATUS_UNSUCCESSFUL;
__leave;
}
}
if (*pCurrentPatchInfo->pMapped != expectedBytes)
{
DbgPrint(
"Offset %08X (address %08X) didn't match. Actual value: %08X. Expected: %08X\n",
pCurrentPatchInfo->offset,
pCurrentPatchInfo->pMapped,
*pCurrentPatchInfo->pMapped,
expectedBytes
);
retval = STATUS_UNSUCCESSFUL;
__leave;
}
}
// Here's where we actually do the patching
for (pCurrentPatchInfo = offsets; pCurrentPatchInfo->offset != 0; pCurrentPatchInfo++)
{
// Do the patch
*pCurrentPatchInfo->pMapped = newBytes;
DbgPrint(
"Offset %08X at VA %08X changed to %08X\n",
pCurrentPatchInfo->offset,
pCurrentPatchInfo->pMapped,
*pCurrentPatchInfo->pMapped
);
// If we're unloading (i.e. DoPatch(FALSE)), we'll unmap and unlock the memory
if (!isLoading)
{
MmUnmapLockedPages(pCurrentPatchInfo->pMapped, pCurrentPatchInfo->pMdl);
MmUnlockPages(pCurrentPatchInfo->pMdl);
IoFreeMdl(pCurrentPatchInfo->pMdl);
}
}
}
__except (EXCEPTION_EXECUTE_HANDLER)
{
retval = GetExceptionCode();
DbgPrint("Caught exception during patching: %08X\n", retval);
}
}
__finally
{
if (pSection)
ZwUnmapViewOfSection(NtCurrentProcess(), pSection);
if (hSection)
ZwClose(hSection);
}
return retval;
}
VOID OnUnload(IN PDRIVER_OBJECT pDriverObject)
{
DoPatch(FALSE);
}
NTSTATUS DriverEntry(IN PDRIVER_OBJECT pDriverObject, IN PUNICODE_STRING pRegistryPath)
{
pDriverObject->DriverUnload = OnUnload;
return DoPatch(TRUE);
}
|
By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.
If a file you wish to view isn't highlighted, and is a text file (not binary), please
let us know and we'll add colourisation support for it.
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.