A forum for reverse engineering, OS internals and malware analysis 

Forum for discussion about kernel-mode development.
 #26360  by Brock
 Thu Jul 23, 2015 6:10 pm
Fetch function pointer for ObRegisterCallbacks by using MmGetSystemRoutineAddress and then insert a jmp instruction at the function's prologue (inline hooking)
 #26362  by thomhughes
 Fri Jul 24, 2015 2:53 am
I have the function pointer I just get driver_irql_not_less_or_equal I think due to my write protection.

here is how I am disabling write protection and how I am using it:
Code: Select all
VOID InlineHook() {
	KIRQL Irql = NULL;
	ULONG legitAddr = (ULONG)GetFunctionAddress(L"ObRegisterCallbacks");
	ULONG ourAddr = ObRegisterCallbacksNEW;
	UCHAR trampoline[0x18] = {
		0x4c, 0x8b, 0xdc, 0x48, 0x83, 0xec, 0x68, 0x49,
		0x83, 0x63, 0xf0, 0x00, 0x48, 0xB8, 0x88, 0x77,
		0x66, 0x55, 0x44, 0x33, 0x22, 0x11, 0xff, 0xe0
	};

	Irql = WPOFF();
	oldOBRegisterCallback = (TYPE_ObRegisterCallbacks)(PVOID)trampoline;

	*((ULONG*)((PCHAR)trampoline + 0x0e)) = legitAddr + 0xc;


	*((PCHAR)legitAddr + 1) = 0xB8;
	*((ULONG*)(legitAddr + 2)) = ourAddr;
	*((PCHAR)(legitAddr + 10)) = 0xff;
	*((PCHAR)(legitAddr + 11)) = 0xe0;

	WPON(Irql);
}
Code: Select all
ULONG GetFunctionAddress(PCWSTR FunctionName)
{
	UNICODE_STRING  HookFunctionName;
	RtlInitUnicodeString(&HookFunctionName, FunctionName);
	return (ULONG)MmGetSystemRoutineAddress(&HookFunctionName);

}
Code: Select all
VOID WPON(KIRQL Irql)
{
    UINT_PTR cr0 = __readcr0();
      
    cr0 |= 0x10000;
    _enable();  
    __writecr0( cr0 );
  
    KeLowerIrql( Irql );
}
Code: Select all
KIRQL WPOFF( )
{
    KIRQL Irql = KeRaiseIrqlToDpcLevel();
    UINT_PTR cr0 = __readcr0();
      
    cr0 &= ~0x10000;
    __writecr0( cr0 );
    _disable();
  
    return Irql;
}
 #26368  by Vrtule
 Fri Jul 24, 2015 10:58 pm
If I read your code correctly, you are redirecting the ObRegisterCallbacks to your trampoline variable.
Code: Select all
UCHAR trampoline[0x18] = {
      0x4c, 0x8b, 0xdc, 0x48, 0x83, 0xec, 0x68, 0x49,
      0x83, 0x63, 0xf0, 0x00, 0x48, 0xB8, 0x88, 0x77,
      0x66, 0x55, 0x44, 0x33, 0x22, 0x11, 0xff, 0xe0
   };
The variable is allocated on stack (or probably will be) and will be deallocated when the InlineHook function exits.

And yes, there is no need to raise IRQL. It helps you with hardly anything. Actually, all gets worse since the ObRegisterCallbacks routine resides in paged memory.
 #26370  by Brock
 Sat Jul 25, 2015 5:32 am
No real sense in pointing out his horrible hooking issues, clearly he's trying to adapt x86 code to work on x64 (he mentioned PG was disabled and he runs Windows 7 x64). Not only will registers be "dirtied" but his inline hooking trampoline is plain wrong. Not to mention his ULONG 4-byte wide datatype should be ULONG_PTR... No sense in mentioning the billion issues to be honest but truncating the to-be-hooked function export to a ULONG address value is the first genius thing I see here
 #26916  by kerpow1
 Sun Oct 11, 2015 10:56 am
Why do you need to worry about PG if your using ObRegisterCallbacks, that is kinda the point of using this function on x64.
Code: Select all
#include <ntifs.h>

#define PROCESS_CREATE_THREAD  (0x0002)
#define PROCESS_CREATE_PROCESS (0x0080)
#define PROCESS_TERMINATE      (0x0001)
#define PROCESS_VM_WRITE       (0x0020)
#define PROCESS_VM_READ        (0x0010)
#define PROCESS_VM_OPERATION   (0x0008)
#define PROCESS_SUSPEND_RESUME (0x0800)
#define PROCESS_QUERY_INFORMATION (0x0400)
#define PROCESS_DUP_HANDLE (0x0040)
#define NT_DEVICE_NAME      L"\\Device\\TestProject"
#define DOS_DEVICE_NAME     L"\\DosDevices\\TestProject"
#define MAXIMUM_FILENAME_LENGTH 256

PVOID _CallBacks_Handle = NULL;

typedef struct _OB_REG_CONTEXT
{
	__in USHORT Version;
	__in UNICODE_STRING Altitude;
	__in USHORT ulIndex;

	OB_OPERATION_REGISTRATION *OperationRegistration;

} REG_CONTEXT, *PREG_CONTEXT;

typedef PCHAR(*GET_PROCESS_IMAGE_NAME)(PEPROCESS Process);

LPSTR GetProcessNameFromPid(IN HANDLE Pid)
{
	PEPROCESS pProcess;

	if (PsLookupProcessByProcessId(Pid, &pProcess) == STATUS_INVALID_PARAMETER)
		return "NULL?!";

	return (LPSTR)PsGetProcessImageFileName(pProcess);
}

static const CHAR* PROTECTED_PROCESS_NAME = "KERNELMODE.exe";

OB_PREOP_CALLBACK_STATUS ObjectPreCallback(IN PVOID RegistrationContext, IN POB_PRE_OPERATION_INFORMATION OperationInformation)
{
	HANDLE ProcessId = NULL;
	LPSTR ProcName = NULL;
	PEPROCESS pProcess = NULL;
	NTSTATUS ntStatus = STATUS_INVALID_PARAMETER;

	UNREFERENCED_PARAMETER(RegistrationContext);

	ProcessId = PsGetProcessId((PEPROCESS)OperationInformation->Object);

	ProcName = GetProcessNameFromPid(ProcessId);

	if (strstr(PROTECTED_PROCESS_NAME, ProcName) != NULL)
	{
		ntStatus = PsLookupProcessByProcessId(ProcessId, &pProcess);

		if (NT_SUCCESS(ntStatus))
		{
			if (OperationInformation->Operation == OB_OPERATION_HANDLE_CREATE)
		{
			if ((OperationInformation->Parameters->CreateHandleInformation.OriginalDesiredAccess & PROCESS_TERMINATE) == PROCESS_TERMINATE)
			{
				OperationInformation->Parameters->CreateHandleInformation.DesiredAccess &= ~PROCESS_TERMINATE;
			}

			if ((OperationInformation->Parameters->CreateHandleInformation.OriginalDesiredAccess & PROCESS_VM_OPERATION) == PROCESS_VM_OPERATION)
			{
				OperationInformation->Parameters->CreateHandleInformation.DesiredAccess &= ~PROCESS_VM_OPERATION;
			}

			if ((OperationInformation->Parameters->CreateHandleInformation.OriginalDesiredAccess & ~PROCESS_VM_READ) == PROCESS_VM_READ)
			{
				OperationInformation->Parameters->CreateHandleInformation.DesiredAccess &= ~PROCESS_VM_READ;
			}

			if ((OperationInformation->Parameters->CreateHandleInformation.OriginalDesiredAccess & PROCESS_VM_WRITE) == PROCESS_VM_WRITE)
			{
				OperationInformation->Parameters->CreateHandleInformation.DesiredAccess &= ~PROCESS_VM_WRITE;
			}

			if ((OperationInformation->Parameters->CreateHandleInformation.OriginalDesiredAccess & PROCESS_QUERY_INFORMATION) == PROCESS_QUERY_INFORMATION)
			{
				OperationInformation->Parameters->CreateHandleInformation.DesiredAccess &= ~PROCESS_QUERY_INFORMATION;
			}

			if ((OperationInformation->Parameters->CreateHandleInformation.OriginalDesiredAccess & PROCESS_DUP_HANDLE) == PROCESS_DUP_HANDLE)
			{
				OperationInformation->Parameters->CreateHandleInformation.DesiredAccess &= ~PROCESS_DUP_HANDLE;
			}
		}
	}

	return OB_PREOP_SUCCESS;
}

VOID ObjectPostCallback(IN PVOID RegistrationContext, IN POB_POST_OPERATION_INFORMATION OperationInformation)
{
	UNREFERENCED_PARAMETER(RegistrationContext);
	UNREFERENCED_PARAMETER(OperationInformation);
}

NTSTATUS RegisterCallbackFunction()
{
	NTSTATUS ntStatus = STATUS_SUCCESS;

	UNICODE_STRING Altitude;

	USHORT filterVersion = ObGetFilterVersion();

	USHORT registrationCount = 1;

	OB_OPERATION_REGISTRATION RegisterOperation;

	OB_CALLBACK_REGISTRATION RegisterCallBack;

	REG_CONTEXT RegistrationContext;

	memset(&RegisterOperation, 0, sizeof(OB_OPERATION_REGISTRATION));

	memset(&RegisterCallBack, 0, sizeof(OB_CALLBACK_REGISTRATION));

	memset(&RegistrationContext, 0, sizeof(REG_CONTEXT));

	RegistrationContext.ulIndex = 1;

	RegistrationContext.Version = 120;

	if (filterVersion == OB_FLT_REGISTRATION_VERSION)
	{
		RegisterOperation.ObjectType = PsProcessType;

		RegisterOperation.Operations = OB_OPERATION_HANDLE_CREATE;

		RegisterOperation.PreOperation = ObjectPreCallback;

		RegisterOperation.PostOperation = ObjectPostCallback;

		RegisterCallBack.Version = OB_FLT_REGISTRATION_VERSION;

		RegisterCallBack.OperationRegistrationCount = registrationCount;

		RtlInitUnicodeString(&Altitude, L"XXXXXXX");

		RegisterCallBack.Altitude = Altitude;

		RegisterCallBack.RegistrationContext = &RegistrationContext;

		RegisterCallBack.OperationRegistration = &RegisterOperation;

		ntStatus = ObRegisterCallbacks(&RegisterCallBack, &_CallBacks_Handle);
	}

	return ntStatus;
}

NTSTATUS FreeProcFilter()
{
	if (NULL != _CallBacks_Handle)
	{
		ObUnRegisterCallbacks(_CallBacks_Handle);

		_CallBacks_Handle = NULL;
	}

	return STATUS_SUCCESS;
}

VOID DriverUnload(IN PDRIVER_OBJECT DriverObject)
{
	UNREFERENCED_PARAMETER(DriverObject);

	FreeProcFilter();

	FreePointers(wLastItem);
}

NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath)
{
	NTSTATUS ntStatus;

	UNREFERENCED_PARAMETER(RegistryPath);

	DriverObject->DriverUnload = DriverUnload;

	ntStatus = RegisterCallbackFunction();

	if (!NT_SUCCESS(ntStatus))
		return ntStatus;

	return STATUS_SUCCESS;
}