none
How use PMDL to enable and disable pages protection (read only)? RRS feed

  • Question

  •  I have this code below that restore ssdt hooks and works very fine on x32 Windows.

    Now i want adapt PMDL to enable and disable pages protection (read only) before write on these page.

    Tried the following method, but still without sucess. How fix it?

    thank you.

    static void InterlockedSet(LONG* Destination, LONG Source)
    {
        //Change memory properties.
        PMDL g_pmdl = IoAllocateMdl(Destination, sizeof(LONG), 0, 0, NULL);
        if(!g_pmdl)
            return;
        MmBuildMdlForNonPagedPool(g_pmdl);
        LONG* Mapped = (LONG*)MmMapLockedPages(g_pmdl, KernelMode);
        if(!Mapped)
        {
            IoFreeMdl(g_pmdl);
            return;
        }
        InterlockedExchange(Mapped, Source);
        //Restore memory properties.
        MmUnmapLockedPages((PVOID)Mapped, g_pmdl);
        IoFreeMdl(g_pmdl);
    }
    
    // Usage
    
    InterlockedSet(&uNewAddress, uOldAddress);


    Driver.c

    #include <ntddk.h>
    #include <ntimage.h>
    
    typedef unsigned int UINT;
    
    typedef struct _tagSSDT {
    	PVOID pvSSDTBase;
    	PVOID pvServiceCounterTable;
    	ULONG ulNumberOfServices;
    	PVOID pvParamTableBase;
    } SSDT, *PSSDT;
    extern PSSDT    KeServiceDescriptorTable;
    
    typedef struct _SYSTEM_MODULE
    {
    	ULONG Reserved[2];
    	ULONG Base;
    	ULONG Size;
    	ULONG Flags;
    	USHORT Index;
    	USHORT Unknown;
    	USHORT LoadCount;
    	USHORT ModuleNameOffset;
    	CHAR ImageName[256];
    } SYSTEM_MODULE_INFORMATION, *PSYSTEM_MODULE_INFORMATION;
    
    typedef struct _SYSTEM_MODULE_INFORMATION
    {
    	ULONG    uCount;
    	SYSTEM_MODULE_INFORMATION aSM[];
    }MODULE_LIST, *PMODULE_LIST;
    
    NTSYSAPI
    NTSTATUS
    NTAPI
    ZwQuerySystemInformation(
    	ULONG   SystemInformationClass,
    	PVOID   SystemInformation,
    	ULONG   SystemInformationLength,
    	PULONG   ReturnLength
    );
    
    ULONG GetKernelBaseAddress(char* lpszModule)
    {
    	NTSTATUS nResult;
    	ULONG ulNeededSize, uLoop, uKernelAddr;
    	PMODULE_LIST pModuleList;
    
    	uKernelAddr = 0;
    	ZwQuerySystemInformation(11, &ulNeededSize, 0, &ulNeededSize);
    	pModuleList = ExAllocatePool(NonPagedPool, ulNeededSize);
    	nResult = ZwQuerySystemInformation(11, pModuleList, ulNeededSize, NULL);
    
    	if (NT_SUCCESS(nResult))
    	{
    		//ntoskrnl is always first there
    		uKernelAddr = pModuleList->aSM[0].Base;
    		strcpy(lpszModule, "\\SystemRoot\\System32\\");
    		strcat(lpszModule, pModuleList->aSM[0].ModuleNameOffset + pModuleList->aSM[0].ImageName);
    	}
    
    	ExFreePool(pModuleList);
    
    	return uKernelAddr;
    }
    
    ULONG RVAToRaw(PVOID lpBase, ULONG VirtualAddress)
    {
    	IMAGE_DOS_HEADER *pDosHeader;
    	IMAGE_NT_HEADERS *pNtHeader;
    	IMAGE_SECTION_HEADER *pSectionHeader;
    	ULONG NumOfSections, uLoop;
    	pDosHeader = (IMAGE_DOS_HEADER*)lpBase;
    	if (pDosHeader->e_magic != IMAGE_DOS_SIGNATURE)
    		return 0;
    	pNtHeader = (IMAGE_NT_HEADERS*)((unsigned char*)lpBase + pDosHeader->e_lfanew);
    	NumOfSections = pNtHeader->FileHeader.NumberOfSections;
    	pSectionHeader = (IMAGE_SECTION_HEADER*)((ULONG)pNtHeader + sizeof(ULONG) + sizeof(IMAGE_FILE_HEADER) + pNtHeader->FileHeader.SizeOfOptionalHeader);
    	VirtualAddress -= (ULONG)lpBase;
    	for (uLoop = 0; uLoop<NumOfSections; uLoop++)
    	{
    		pSectionHeader = (IMAGE_SECTION_HEADER*)((ULONG)pSectionHeader + sizeof(IMAGE_SECTION_HEADER) * uLoop);
    		if (VirtualAddress>pSectionHeader->VirtualAddress&&VirtualAddress<pSectionHeader->VirtualAddress + pSectionHeader->SizeOfRawData)
    		{
    			ULONG Offset = VirtualAddress - pSectionHeader->VirtualAddress + pSectionHeader->PointerToRawData;
    			return Offset;
    		}
    	}
    	return 0;
    }
    
    void DriverUnload(PDRIVER_OBJECT pDriverObj)
    {
    	DbgPrint("DriverUnload!");
    }
    
    //StartService
    NTSTATUS DriverEntry(IN PDRIVER_OBJECT theDriverObject, IN PUNICODE_STRING theRegistryPath)
    {
    	NTSTATUS status = STATUS_SUCCESS;
    	ULONG uKernelMoule, uImageBase, uSSDTCount, uSSDTBase, uSSDTRaw, uLoop, uOldAddress, uNewAddress;
    	PULONG lpArraySSDT;
    	char szKernelPath[256];
    	ANSI_STRING aFileName;
    	UNICODE_STRING uFileName;
    	OBJECT_ATTRIBUTES ObjAttr;
    	IO_STATUS_BLOCK ioStatus;
    	FILE_POSITION_INFORMATION FilePos;
    	HANDLE hFile;
    
    	theDriverObject->DriverUnload = DriverUnload;
    	// get system modules
    	memset(szKernelPath, 0, 256);
    	uKernelMoule = GetKernelBaseAddress(szKernelPath);
    	uImageBase = ((IMAGE_NT_HEADERS*)(uKernelMoule + ((IMAGE_DOS_HEADER*)uKernelMoule)->e_lfanew))->OptionalHeader.ImageBase;
    	DbgPrint("Kernel ImageBase: 0x%.8X", uImageBase);
    	DbgPrint("Kernel Base: 0x%.8X", uKernelMoule);
    	DbgPrint("Kernel Module Path: %s", szKernelPath);
    
    	uSSDTCount = KeServiceDescriptorTable->ulNumberOfServices;
    	uSSDTBase = (ULONG)KeServiceDescriptorTable->pvSSDTBase;
    	DbgPrint("SSDT BaseAddress: 0x%8X, SSDT Count: 0x%X", uSSDTBase, uSSDTCount);
    	lpArraySSDT = ExAllocatePool(PagedPool, uSSDTCount * sizeof(ULONG));
    	if (lpArraySSDT == NULL) return status;
    
    	uSSDTRaw = RVAToRaw(uKernelMoule, uSSDTBase);
    	DbgPrint("SSDT RAW: 0x%.8X", uSSDTRaw);
    	if (uSSDTRaw == 0)
    	{
    		DbgPrint("SSDT RAW Error");
    		ExFreePool(lpArraySSDT);
    		return status;
    	}
    	RtlInitAnsiString(&aFileName, szKernelPath);
    	status = RtlAnsiStringToUnicodeString(&uFileName, &aFileName, TRUE);
    	if (!NT_SUCCESS(status))
    	{
    		DbgPrint("RtlAnsiStringToUnicodeString Error");
    		ExFreePool(lpArraySSDT);
    		return status;
    	}
    
    	InitializeObjectAttributes(&ObjAttr, &uFileName, OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE, NULL, NULL);
    	status = ZwOpenFile(&hFile, FILE_READ_DATA, &ObjAttr, &ioStatus, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, FILE_SYNCHRONOUS_IO_NONALERT);
    	if (NT_SUCCESS(status) && hFile)
    	{
    		FilePos.CurrentByteOffset.LowPart = uSSDTRaw;//1000;//uSSDTRaw;
    		FilePos.CurrentByteOffset.HighPart = 0;
    		status = ZwSetInformationFile(hFile, &ioStatus, &FilePos, sizeof(FILE_POSITION_INFORMATION), FilePositionInformation);
    		if (NT_SUCCESS(status))
    		{
    			status = ZwReadFile(hFile, NULL, NULL, NULL, &ioStatus, lpArraySSDT, uSSDTCount * sizeof(ULONG), NULL, NULL);
    			if (NT_SUCCESS(status))
    			{
    				for (uLoop = 0; uLoop<uSSDTCount; uLoop++)
    				{
    					uOldAddress = *(lpArraySSDT + uLoop) - uImageBase + uKernelMoule;
    					uNewAddress = *((PULONG)uSSDTBase + uLoop);
    					if (uOldAddress != uNewAddress)
    					{
    						DbgPrint("SSDT No.%X, Old: 0x%.8X, New: 0x%.8X", uLoop, uOldAddress, uNewAddress);
    
    						// disable write protection
    						__asm
    						{
    							mov eax, cr0
    							and eax, not 0x10000
    							mov cr0, eax
    						}
    
    						*((PULONG)uSSDTBase + uLoop) = uOldAddress;
    
    					// restore write protection
    						__asm
    						{
    							mov eax, cr0
    							or eax, 0x10000
    							mov cr0, eax
    						}
    						
    					}
    				}
    				DbgPrint("SSDT TheEnd...");
    
    			}
    			else
    				DbgPrint("Read File Error!");
    		}
    		//   else
    		//    DbgPrint("Set File Pos Error!");
    		if (hFile)
    			ZwClose(hFile);
    	}
    	else
    		DbgPrint("Open File Error!");
    
    	RtlFreeUnicodeString(&uFileName);
    
    	ExFreePool(lpArraySSDT);
    	return status;
    }
    
    


    Tuesday, August 8, 2017 12:57 PM

All replies

  • You are not going to get this to work with 64-bit system or with future systems in general.   There are mechanisms that will detect your efforts and thwart you, so you have to go down to the really dangerous stuff that the code that put the hook in did, which is not reliablel

    If you search you will find that trying to undo SSDT hooking is not really a viable approach.   Most security people consider that once a system is that compromised that it cannot be recovered in a running image.  Consider the simple case of attempting to do this, lets say CreateFile and CloseHandle were both hooked, how do you know that there is not actions in the hook of CreateFile that expect the CloseHandle to work with the hook or really bad things happen.  


    Don Burn Windows Driver Consulting Website: http://www.windrvr.com

    Tuesday, August 8, 2017 2:48 PM