1 Attachment(s)
SSDT Shadow Unhook in Ring0
This source shows how to deal with kernel functions from the Ring0.
Example, RestoreShadow.C
Code:
#include <ntddk.h>
#include "RestoreShadow.h"
#include "dbghelp.h"
#include "LDasm.h"
NTKERNELAPI
NTSTATUS
KeAddSystemServiceTable(
IN PULONG_PTR Base,
IN PULONG Count OPTIONAL,
IN ULONG Limit,
IN PUCHAR Number,
IN ULONG Index
);
typedef struct _KSERVICE_TABLE_DESCRIPTOR
{
PULONG_PTR Base;
PULONG Count;
ULONG Limit;
PUCHAR Number;
}
KSERVICE_TABLE_DESCRIPTOR, *PKSERVICE_TABLE_DESCRIPTOR;
typedef struct _LDR_DATA_TABLE_ENTRY
{
LIST_ENTRY InLoadOrderLinks;
LIST_ENTRY InMemoryOrderLinks;
LIST_ENTRY InInitializationOrderLinks;
PVOID DllBase;
PVOID EntryPoint;
ULONG SizeOfImage;
UNICODE_STRING FullDllName;
UNICODE_STRING BaseDllName;
ULONG Flags;
USHORT LoadCount;
USHORT TlsIndex;
union {
LIST_ENTRY HashLinks;
struct
{
PVOID SectionPointer;
ULONG CheckSum;
};
};
union {
struct
{
ULONG TimeDateStamp;
};
struct
{
PVOID LoadedImports;
};
};
struct _ACTIVATION_CONTEXT * EntryPointActivationContext;
PVOID PatchInformation;
}LDR_DATA_TABLE_ENTRY, *PLDR_DATA_TABLE_ENTRY;
PKSERVICE_TABLE_DESCRIPTOR KeServiceDescriptorTableShadow = NULL;
PVOID pWin32kBase = NULL;
//===========================================
NTSTATUS DriverEntry(PDRIVER_OBJECT pDriverObj, PUNICODE_STRING pRegistryString);
NTSTATUS DispatchCreate(PDEVICE_OBJECT pDevObj, PIRP pIrp);
NTSTATUS DispatchClose(PDEVICE_OBJECT pDevObj, PIRP pIrp);
VOID DriverUnload(PDRIVER_OBJECT pDriverObj);
#ifdef ALLOC_PRAGMA
#pragma alloc_text(INIT, DriverEntry)
#pragma alloc_text(PAGE, DispatchCreate)
#pragma alloc_text(PAGE, DispatchClose)
#pragma alloc_text(PAGE, DriverUnload)
#endif // ALLOC_PRAGMA
//////////////////////////////////////////////////////////////////////////
VOID GetWin32kBase(PDRIVER_OBJECT pDriverObj);
VOID GetSSDTShadowBase();
NTSTATUS RestoreShadow();
ULONG RVAToRaw(PVOID lpBase,ULONG VirtualAddress);
//==========================================
NTSTATUS DriverEntry(PDRIVER_OBJECT pDriverObj, PUNICODE_STRING pRegistryString)
{
NTSTATUS status = STATUS_SUCCESS;
UNICODE_STRING ustrLinkName;
UNICODE_STRING ustrDevName;
PDEVICE_OBJECT pDevObj;
dprintf("DriverEntry: %S\n", pRegistryString->Buffer);
// Create dispatch points for device control, create, close.
pDriverObj->MajorFunction[IRP_MJ_CREATE] = DispatchCreate;
pDriverObj->MajorFunction[IRP_MJ_CLOSE] = DispatchClose;
pDriverObj->DriverUnload = DriverUnload;
//
RtlInitUnicodeString(&ustrDevName, DEVICE_NAME);
status = IoCreateDevice(pDriverObj,
0,
&ustrDevName,
FILE_DEVICE_UNKNOWN,
0,
FALSE,
&pDevObj);
dprintf("Device Name %S", ustrDevName.Buffer);
if (!NT_SUCCESS(status))
{
dprintf("IoCreateDevice = 0x%x\n", status);
return status;
}
RtlInitUnicodeString(&ustrLinkName, LINK_NAME);
status = IoCreateSymbolicLink(&ustrLinkName, &ustrDevName);
if (!NT_SUCCESS(status))
{
dprintf("IoCreateSymbolicLink = 0x%x\n", status);
IoDeleteDevice(pDevObj);
return status;
}
dprintf("SymbolicLink:%S", ustrLinkName.Buffer);
GetWin32kBase(pDriverObj);
GetSSDTShadowBase();
dprintf("Win32k Base : 0x%X",pWin32kBase);
dprintf("KeServiceDescriptorTableShadow : 0x%X", KeServiceDescriptorTableShadow);
return STATUS_SUCCESS;
}
VOID DriverUnload(PDRIVER_OBJECT pDriverObj)
{
UNICODE_STRING strLink;
RtlInitUnicodeString(&strLink, LINK_NAME);
//
// Delete the symbolic link
//
IoDeleteSymbolicLink(&strLink);
//
// Delete the device object
//
IoDeleteDevice(pDriverObj->DeviceObject);
dprintf("Unloaded\n");
}
NTSTATUS DispatchCreate(PDEVICE_OBJECT pDevObj, PIRP pIrp)
{
RestoreShadow();
pIrp->IoStatus.Status = STATUS_SUCCESS;
pIrp->IoStatus.Information = 0;
dprintf("IRP_MJ_CREATE\n");
IoCompleteRequest(pIrp, IO_NO_INCREMENT);
return STATUS_SUCCESS;
}
NTSTATUS DispatchClose(PDEVICE_OBJECT pDevObj, PIRP pIrp)
{
pIrp->IoStatus.Status = STATUS_SUCCESS;
pIrp->IoStatus.Information = 0;
dprintf("IRP_MJ_CLOSE\n");
IoCompleteRequest(pIrp, IO_NO_INCREMENT);
return STATUS_SUCCESS;
}
VOID GetSSDTShadowBase()
{
UCHAR *cPtr;
UCHAR *pOpcode;
ULONG Length;
for (cPtr = (PUCHAR)KeAddSystemServiceTable;
cPtr < (PUCHAR)KeAddSystemServiceTable + PAGE_SIZE;
cPtr += Length)
{
Length = SizeOfCode(cPtr, &pOpcode);
if (!Length) break;
if ( *(PUSHORT)cPtr == 0x888D )
{
KeServiceDescriptorTableShadow = (PKSERVICE_TABLE_DESCRIPTOR)(*(ULONG *)((ULONG)pOpcode + 2));
break;
}
}
}
VOID GetWin32kBase(PDRIVER_OBJECT pDriverObj)
{
PLIST_ENTRY pList = NULL;
PLDR_DATA_TABLE_ENTRY Ldr = NULL;
pList = ( (PLIST_ENTRY)pDriverObj->DriverSection )->Flink;
do {
Ldr = CONTAINING_RECORD(
pList,
LDR_DATA_TABLE_ENTRY,
InLoadOrderLinks);
if (Ldr->EntryPoint &&
Ldr->FullDllName.Buffer) {
if ( !_wcsicmp(Ldr->FullDllName.Buffer, L"\\systemroot\\system32\\win32k.sys") ) {
//Compare module name
pWin32kBase = Ldr->DllBase;//Save the module base address
break;
}
}
pList = pList->Flink;
} while ( pList != ((LIST_ENTRY*)pDriverObj->DriverSection)->Flink );
}
NTSTATUS RestoreShadow()
{
NTSTATUS status;
HANDLE hFile; //File handle
OBJECT_ATTRIBUTES ObjAttr;
UNICODE_STRING ustrWin32k;
IO_STATUS_BLOCK ioStatus;
ULONG ulShadowRaw = 0;
ULONG ulShadowBase = 0;
PVOID PoolArea = NULL;
FILE_POSITION_INFORMATION fpi;
LARGE_INTEGER Offset;
ULONG OrigAddress = 0;
ULONG CurAddress = 0;
ULONG i = 0;
ULONG ulCount = 0;
PULONG pAddr;
if ( pWin32kBase == NULL ||
KeServiceDescriptorTableShadow == NULL)
{
dprintf("Error.");
return STATUS_UNSUCCESSFUL;
}
//Index?
ulCount = KeServiceDescriptorTableShadow[1].Limit;
dprintf("Count Of Shadow : %d\n", ulCount );
ulShadowBase = *(ULONG*)&KeServiceDescriptorTableShadow[1].Base;//Get the base address
dprintf("ulShadowBase = 0x%X\n",ulShadowBase);
ulShadowRaw = ulShadowBase - (ULONG)pWin32kBase;
//ulShadowRaw = RVAToRaw(pWin32kBase,ulShadowBase);
dprintf("ulShadowRaw = 0x%X\n",ulShadowRaw);
RtlInitUnicodeString(&ustrWin32k, L"\\SystemRoot\\System32\\win32k.sys");
PoolArea = ExAllocatePool( PagedPool, sizeof(ULONG) * ulCount );
if (!PoolArea) {
dprintf("PoolArea is null\n");
return STATUS_UNSUCCESSFUL;
}
RtlZeroMemory(&ObjAttr, sizeof(ObjAttr) );
InitializeObjectAttributes(
&ObjAttr,
&ustrWin32k,
OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE,
NULL,
NULL);
//Open win32K.SYS
status = IoCreateFile(
&hFile,
FILE_READ_ATTRIBUTES,
&ObjAttr,
&ioStatus,
0,
FILE_ATTRIBUTE_NORMAL,
FILE_SHARE_READ,
FILE_OPEN,
0,
NULL,
0,
0,
NULL,
IO_NO_PARAMETER_CHECKING);
if ( !NT_SUCCESS(status) ) {
dprintf("IoCreateFile Error : 0x%X", status);
goto __exit;
}
//Set the file offset
Offset.LowPart = ulShadowRaw;
Offset.HighPart = 0;
//Read data
status = ZwReadFile (
hFile,
NULL,
NULL,
NULL,
&ioStatus,
PoolArea,
ulCount*sizeof(ULONG),
&Offset,
NULL);
if ( !NT_SUCCESS(status) ) {
dprintf("ZwReadFile Error : 0x%X");
goto __exit;
}
//Change the pointer type
pAddr = (PULONG)PoolArea;
//Comparing the original address
for (i=0;i<ulCount;i++) {
OrigAddress = *pAddr; //Point to the original address
CurAddress = KeServiceDescriptorTableShadow[1].Base[i]; //Read the current address
if ( OrigAddress != CurAddress ) {
dprintf("ID:%-3d.OrigAddr : 0x%X CurAddr : 0x%X---Hooked!\n",i,OrigAddress,CurAddress);
} else {
dprintf("ID:%-3d.OrigAddr : 0x%X.CurAddr : 0x%X\n",i,OrigAddress,CurAddress);
}
pAddr++;//increase counter, Pointer to the next function
}
__exit:
if (PoolArea) {
ExFreePool(PoolArea);
}
if (hFile) {
//close handle
ZwClose(hFile);
}
return status;
}
Driver and full VS project inside attachment.
P.S. I don't know how the author of this stuff.