Click here to Skip to main content
15,896,118 members
Articles / Programming Languages / C++

Eliminating Explorer's delay when deleting an in-use file

Rate me:
Please Sign up or sign in to vote.
4.99/5 (278 votes)
28 Sep 200519 min read 327.3K   1.9K   236  
How to track down and patch an annoyance in Windows Explorer's code.
#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.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Web Developer
United States United States
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions