问题描述
因此,我尝试使用C#和ObRegisterCallbacks函数来获取有关对OpenProcess
的任何调用的通知。
这是我到目前为止的代码:
internal static class Win32SelfProtection
{
[DllImport("NtosKrnl.exe",SetLastError = true,PreserveSig = false)]
private static extern uint ObRegisterCallbacks(IntPtr callbackRegistration,out IntPtr registrationHandle);
[DllImport("NtosKrnl.exe",PreserveSig = false)]
private static extern void ObUnRegisterCallbacks(IntPtr registrationHandle);
[DllImport("kernel32.dll")]
internal static extern bool VirtualProtect(IntPtr lpAddress,uint dwSize,uint flNewProtect,out uint lpflOldProtect);
private const uint OB_OPERATION_HANDLE_CREATE = 0x00000001;
private const uint OB_OPERATION_HANDLE_DUPLICATE = 0x00000002;
private const uint PAGE_READWRITE = 0x04;
[StructLayout(LayoutKind.Sequential)]
internal struct OB_CALLBACK_REGISTRATION
{
internal ushort Version;
internal ushort OperationRegistrationCount; // 1
internal IntPtr Altitude;
internal IntPtr RegistrationContext; // NULL,probably
internal IntPtr OperationRegistration; // OB_OPERATION_REGISTRATION*
}
[StructLayout(LayoutKind.Sequential)]
internal struct OB_OPERATION_REGISTRATION
{
internal IntPtr ObjectType; // PsProcesstype
internal uint Operations; // OB_OPERATION_HANDLE_CREATE
internal IntPtr PreOperation; // POB_PRE_OPERATION_CALLBACK
internal IntPtr PostOperation; // POB_POST_OPERATION_CALLBACK
}
[StructLayout(LayoutKind.Sequential)]
internal unsafe struct UNICODE_STRING
{
internal ushort Length;
internal ushort MaximumLength;
internal IntPtr Buffer;
}
internal static unsafe void Protect()
{
PobPreOperationCallback preOperationCallback = PreOperationCallback;
IntPtr pPreOperationCallback = Marshal.GetFunctionPointerForDelegate(preOperationCallback);
PobPostOperationCallback postOperationCallback = PostOperationCallback;
IntPtr pPostOperationCallback = Marshal.GetFunctionPointerForDelegate(postOperationCallback);
OB_OPERATION_REGISTRATION operationRegistration = new OB_OPERATION_REGISTRATION
{
ObjectType = IntPtr.Zero,// I have no idea ... <-- Need pointer to PsProcesstype
Operations = OB_OPERATION_HANDLE_CREATE,PreOperation = pPreOperationCallback,PostOperation = pPostOperationCallback
};
IntPtr pOperationRegistration = Marshal.AllocHGlobal(sizeof(OB_OPERATION_REGISTRATION));
Marshal.StructuretoPtr(operationRegistration,pOperationRegistration,false);
const ushort buffersize = sizeof(ushort) * 64;
IntPtr buffer = Marshal.AllocHGlobal(buffersize);
// No idea what kind of string I should put in here :C just zero it for Now ...
Marshal.copy(new byte[buffersize],buffer,buffersize);
UNICODE_STRING unicodeString = new UNICODE_STRING
{
Length = buffersize,MaximumLength = buffersize,Buffer = buffer
};
IntPtr pUnicodeString = Marshal.AllocHGlobal(sizeof(UNICODE_STRING));
Marshal.StructuretoPtr(unicodeString,pUnicodeString,false);
OB_CALLBACK_REGISTRATION callbackRegistration = new OB_CALLBACK_REGISTRATION
{
Version = 0x0100,OperationRegistrationCount = 1,Altitude = pUnicodeString,RegistrationContext = IntPtr.Zero,OperationRegistration = pOperationRegistration
};
IntPtr pCallbackRegistration = Marshal.AllocHGlobal(sizeof(OB_CALLBACK_REGISTRATION));
Marshal.StructuretoPtr(callbackRegistration,pCallbackRegistration,false);
uint status = ObRegisterCallbacks(pCallbackRegistration,out IntPtr hRegistration); // FAILS WITH: AccessViolationException
// yeah,yeah I'll remember to call Marshal.FreeHGlobal() later ... :D
}
public delegate uint PobPreOperationCallback(IntPtr registrationContext,IntPtr operationinformation);
// dummy method for Now
internal static uint PreOperationCallback(IntPtr registrationContext,IntPtr operationinformation)
{
Console.WriteLine("PreOperationCallback!");
return 0x0;
}
public delegate void PobPostOperationCallback(IntPtr registrationContext,IntPtr operationinformation);
// dummy method for Now
internal static void PostOperationCallback(IntPtr registrationContext,IntPtr operationinformation)
{
Console.WriteLine("PostOperationCallback!");
}
}
ObRegisterCallbacks
函数采用一个OB_CALLBACK_REGISTRATION
结构(docs here)作为参数,该结构本身由OB_OPERATION_REGISTRATION
结构(docs here)的数组组成。
这就是我遇到的问题:
OB_OPERATION_REGISTRATION
的第一个成员“ ObjectType”记录如下
ObjectType
指向触发回调例程的对象类型的指针。指定以下值之一:
经过几个小时的搜索,我仍然不知道如何指定PsProcesstype
并用它初始化我的结构。 PsProcesstype
seems to be defined in process.c
in line 20。
但是它只是说
POBJECT_TYPE PsProcesstype = NULL;
并不是特别有用,因为在初始化IntPtr.Zero
结构时将ObjectType字段设置为OB_OPERATION_REGISTRATION
时,会在调用System.AccessViolationException
时触发ObRegisterCallbacks
。 (在UNICODE_STRING
结构中还有一个OB_OPERATION_REGISTRATION
,名为Altitude
,必须将其设置为某个值(但当前不是大声笑:D),但是该字符串已初始化并分配了,所以它不应该对访问冲突负责...对吧?
这是我第一次深入探讨Windows内核内容,所以如果有人可以帮助我解决这个问题,或者向我指出一些我无法挖掘的隐藏资源,那将是不错的选择:)
有一个article使用ObRegisterCallbacks
做类似的事情(虽然在C ++中),但是他们并没有真正指定从何处获取PsProcesstype
或如何定义。因此,如果他们可以成功使用该“ ObjectType”字段,那么就必须有文档,对吧?
解决方法
PsProcessType
在ntoskrnl.exe处导出,与ObRegisterCallbacks
相同,它们之间的区别在于,一个是导出的全局变量,另一个是导出的函数。
在C中,这些全局变量在wdm.h中声明:
extern POBJECT_TYPE *CmKeyObjectType;
extern POBJECT_TYPE *IoFileObjectType;
extern POBJECT_TYPE *ExEventObjectType;
extern POBJECT_TYPE *ExSemaphoreObjectType;
extern POBJECT_TYPE *TmTransactionManagerObjectType;
extern POBJECT_TYPE *TmResourceManagerObjectType;
extern POBJECT_TYPE *TmEnlistmentObjectType;
extern POBJECT_TYPE *TmTransactionObjectType;
extern POBJECT_TYPE *PsProcessType;
extern POBJECT_TYPE *PsThreadType;
extern POBJECT_TYPE *PsJobType;
extern POBJECT_TYPE *SeTokenObjectType;
#if (NTDDI_VERSION >= NTDDI_THRESHOLD)
extern POBJECT_TYPE *ExDesktopObjectType;
#endif
因此您可以使用这些变量而无需执行其他任何操作。
但是我不擅长C#,甚至不确定C#模块是否可以加载到内核中。
最推荐的方法是使用C / C ++进行内核编程,我从未听说有人使用C#进行此操作。