各种搜索引擎查了很多"64位进程保护"的东西
发现基本都一样..最后发现原来都来自于我大看雪的:
"教你在64位Win7系统下使用ObRegisterCallbacks内核函数来实现进程保护"
http://bbs.pediy.com/showthread.php?t=168023
的这篇文章..
各个站都是各种转帖..里面的很多东西都没搞明白
当然这里不是说什么原理之类的..因为偶也还不清楚原理
其实我也就是说下这个系统函数: ObRegisterCallbacks
该API的用法之一就是用于进程保护
注意:该函数是在Windows Vista Service Pack 1(SP1)加入的.也就是说XP不可用
对于该函数的使用,微软提供了一个例子
该函数原型为:
NTSTATUS ObRegisterCallbacks(
_In_ POB_CALLBACK_REGISTRATION CallBackRegistration,
_Out_ PVOID *RegistrationHandle
);
这个函数是用于注册回调的(从名字就能看出来)
其第二个参数RegistrationHandle实质上指向了一个内部结构.我们用的时候可以当一个句柄看
该通过该指针我们可以使用ObUnRegisterCallbacks来解除我们注册的回调
第一个参数CallBackRegistration是POB_CALLBACK_REGISTRATION类型,该结构如下:
typedef struct _OB_CALLBACK_REGISTRATION {
USHORT Version;
USHORT OperationRegistrationCount;
UNICODE_STRING Altitude;
PVOID RegistrationContext;
OB_OPERATION_REGISTRATION *OperationRegistration;
} OB_CALLBACK_REGISTRATION, *POB_CALLBACK_REGISTRATION;
第一个成员Version我们需要设置为OB_FLT_REGISTRATION_VERSION
第二个成员OperationRegistrationCount是最后一个成员(数组)的数量
第三个成员Altitude需要单独向微软申请.微软提供了一个表来记录这些值,网络上都用的321000这个值.他是Norman的nvcmflt.sys驱动的值,不知道为何网络上都是这个.这里咱们谨慎起见也先用这个吧
第四个成员RegistrationContext在MSDN的描述是:
The system passes the RegistrationContext value to the callback routine when the callback routine is run. The meaning of this value is driver-defined.
我没看明白. 不过在微软提供的例程中是这么写的:
TD_CALLBACK_REGISTRATION CBCallbackRegistration = {0};
CBObRegistration.RegistrationContext = &CBCallbackRegistration;
不过网络上流传的都是填写为NULL
我们也填NULL就好了
第五个成员比较重要.是OB_OPERATION_REGISTRATION类型的数组,该数组指定了要挂的回调
其类型定义如下:
typedef struct _OB_OPERATION_REGISTRATION {
POBJECT_TYPE *ObjectType;
OB_OPERATION Operations;
POB_PRE_OPERATION_CALLBACK PreOperation;
POB_POST_OPERATION_CALLBACK PostOperation;
} OB_OPERATION_REGISTRATION, *POB_OPERATION_REGISTRATION;
第一个成员为POBJECT_TYPE,MSDN上要求填写为PsProcessType或PsThreadType从名字可以看出来是进程操作或线程操作
第二个成员为Operations,也就是操作类型.微软要求填写为:OB_OPERATION_HANDLE_CREATE或OB_OPERATION_HANDLE_DUPLICATE
指定了OB_OPERATION_HANDLE_CREATE的话看起来是指线程/进程被创建时调用回调,但是实际上所有的open操作都被包含在内,发生Open操作时就会调用回调
指定了OB_OPERATION_HANDLE_DUPLICATE则是当进程/线程句柄被dup(复制)的操作通知回调
微软说Specify one or more of the following flags那么意思就是说可以同时指定..那么..我们可以用|来同时指定
PS:用户态(ring3)打开一个handle,在内核实际上是创建一个关联.也就是create一个句柄出来.所以这里是create
第三个成员PreOperation是操作前回调函数的指针.该回调会在操作发生前被调用
该成员要求类型为ObjectPreCallback,原型如下:
OB_PREOP_CALLBACK_STATUS ObjectPreCallback(
_In_ PVOID RegistrationContext,
_In_ POB_PRE_OPERATION_INFORMATION OperationInformation
);
其中第一个参数是我们之前指定的POB_CALLBACK_REGISTRATION类型中的RegistrationContext 我们可以用他来做点什么
第二个参数则是操作信息是POB_PRE_OPERATION_INFORMATION类型
定义如下:
typedef struct _OB_PRE_OPERATION_INFORMATION {
OB_OPERATION Operation;
union {
ULONG Flags;
struct {
ULONG KernelHandle :1;
ULONG Reserved :31;
};
};
PVOID Object;
POBJECT_TYPE ObjectType;
PVOID CallContext;
POB_PRE_OPERATION_PARAMETERS Parameters;
} OB_PRE_OPERATION_INFORMATION, *POB_PRE_OPERATION_INFORMATION;
我们只看我们关注的:
Operation表示操作类型,就是之前的
OB_OPERATION_HANDLE_CREATE或OB_OPERATION_HANDLE_DUPLICATE
objectType则说明了是PsProcessType还是PsThreadType
Object则是被open进程的PEPROCESS
KernelHandle 则说明了这个操作是不是来自内核(实际上是告知我们是否用的内核句柄.但是一般来说如果这里是TRUE则直接放行吧)
OB_OPERATION_REGISTRATION的第四个成员PostOperation是操作后回调函数的指针,该回调会在操作完成后被调用
该成员要求ObjectPostCallback类型,定义如下:
VOID ObjectPostCallback(
_In_ PVOID RegistrationContext,
_In_ POB_POST_OPERATION_INFORMATION OperationInformation
);
和PRE不同的除了返回值就只是第二个参数了
该类型为POB_POST_OPERATION_INFORMATION,定义如下:
typedef struct _OB_POST_OPERATION_INFORMATION {
OB_OPERATION Operation;
union {
ULONG Flags;
struct {
ULONG KernelHandle :1;
ULONG Reserved :31;
};
};
PVOID Object;
POBJECT_TYPE ObjectType;
PVOID CallContext;
NTSTATUS ReturnStatus;
POB_POST_OPERATION_PARAMETERS Parameters;
} OB_POST_OPERATION_INFORMATION, *POB_POST_OPERATION_INFORMATION;
他与之前的OB_PRE_OPERATION_INFORMATION完全一致.就不再说了
不过这里也单独说一下POB_POST_OPERATION_PARAMETERS这个类型吧,定义如下:
typedef union _OB_POST_OPERATION_PARAMETERS {
OB_POST_CREATE_HANDLE_INFORMATION CreateHandleInformation;
OB_POST_DUPLICATE_HANDLE_INFORMATION DuplicateHandleInformation;
} OB_POST_OPERATION_PARAMETERS, *POB_POST_OPERATION_PARAMETERS;
根据上面的Operation来确定是访问哪个
如果Operation是OB_OPERATION_HANDLE_CREATE那么我们就关注CreateHandleInformation
如果Operation是OB_OPERATION_HANDLE_DUPLICATE那么我们就关注DuplicateHandleInformation
而这两个类型基本上完全一致,其中有一个叫GrantedAccess的ACCESS_MASK类型的成员
而PRE的有所区别:
CreateHandleInformation有两个成员(均是ACCESS_MASK类型)
1是DesiredAccess
2是OriginalDesiredAccess
其中OriginalDesiredAccess是要的权限,而DesiredAccess则是真正给的权限
在PRE中可以修改DesiredAccess来取消某些权限如THREAD_TERMINATE
DuplicateHandleInformation有四个成员,定义如下:
typedef struct _OB_PRE_DUPLICATE_HANDLE_INFORMATION {
ACCESS_MASK DesiredAccess;
ACCESS_MASK OriginalDesiredAccess;
PVOID SourceProcess;
PVOID TargetProcess;
} OB_PRE_DUPLICATE_HANDLE_INFORMATION, *POB_PRE_DUPLICATE_HANDLE_INFORMATION;
其中前两个与CreateHandleInformation相同
SourceProcess是复制句柄的进程的结构
TargetProcess则是将要得到复制后句柄的进程的结构
我们可以通过判断TargetProcess来确定得到句柄的进程(因为此时我们的代码运行在SourceProcess的上下文中.所以没办法知道目标进程.需要从这个参数里面得到)
需要注意的是.在dup(复制句柄)的时候,我们不能向DesiredAccess中添加SourceProcess没有的权限...当然还是可以删除权限的
PS:想知道SourceProcess有哪些权限.可以看看OB_POST_CREATE_HANDLE_INFORMATION里面写了哪些
那么现在我们就明白该如何用这个函数了
首先我们使用ObRegisterCallbacks来注册一个回调,注册时候需要构建一下结构体
首先构建OB_OPERATION_REGISTRATION结构
OB_OPERATION_REGISTRATION CBOperationRegistrations[0];
CBOperationRegistrations[0].ObjectType = PsProcessType;
CBOperationRegistrations[0].Operations = OB_OPERATION_HANDLE_CREATE|OB_OPERATION_HANDLE_DUPLICATE;
CBOperationRegistrations[0].PreOperation = CBTdPreOperationCallback;
CBOperationRegistrations[0].PostOperation = CBTdPostOperationCallback;
因为我们只挂一个回调.所以数组只有一个成员就可以了
CBTdPreOperationCallback和CBTdPostOperationCallback是我们自己的回调函数
OB_CALLBACK_REGISTRATION CBObRegistration;
CBObRegistration.Version = OB_FLT_REGISTRATION_VERSION;
CBObRegistration.OperationRegistrationCount = 1;
RtlInitUnicodeString (&CBObRegistration.Altitude , L"321000");
CBObRegistration.RegistrationContext = NULL;
CBObRegistration.OperationRegistration = CBOperationRegistrations;
构建好OB_CALLBACK_REGISTRATION结构
然后调用ObRegisterCallbacks
NTSTATUS Status = STATUS_SUCCES;
PVOID pCBRegistrationHandle = NULL;
Status = ObRegisterCallbacks(&CBObRegistration,&pCBRegistrationHandle);
注意这里pCBRegistrationHandle请定义为全局变量.因为后续unreg的时候还要用到的
我们在在需保护进程的上下文中执行:
PEPROCESS MYProcess;
MYProcess = PsGetCurrentProcess();
注意MYProcess是个全局变量..
然后在CBTdPreOperationCallback回调中:
OB_PREOP_CALLBACK_STATUS CBTdPreOperationCallback (IN PVOID RegistrationContext,INOUT POB_PRE_OPERATION_INFORMATION PreInfo)
{
if(PreInfo->KernelHandle == TRUE)
{
//如果是KernelHandle则直接返回不做操作
return(OB_PREOP_SUCCESS);
}
if (PreInfo->ObjectType == *PsProcessType)
{
//这里做PsProcessType相关判断
if(MYProcess != PreInfo->Object)
{
//不是我们需要保护的进程则直接返回不操作
return(OB_PREOP_SUCCESS);
}
if(PreInfo->Operation == OB_OPERATION_HANDLE_CREATE)
{
//判断是否有PROCESS_TERMINATE
if(PreInfo->Parameters->CreateHandleInformation->OriginalDesiredAccess & PROCESS_TERMINATE)
{
//有则去掉PROCESS_TERMINATE标记防止进程被结束
PreInfo->Parameters->CreateHandleInformation->DesiredAccess =
PreInfo->Parameters->CreateHandleInformation->OriginalDesiredAccess & ~PROCESS_TERMINATE;
//这里我用的是OriginalDesiredAccess作为基准,实际上从兼容性考虑应该直接使用DesiredAccess
return(OB_PREOP_SUCCESS);
}
}
}
if (PreInfo->ObjectType == *PsThreadType)
{
//这里做PsThreadType相关判断
}
}
这样就可以非常简单的做下进程的防护..当然漏不少地方.都可以在回调中添加.比如这里只是简单的防止带PROCESS_TERMINATE来Open进程
看雪没找到怎么发代码的格式..所以看着有点乱.有愿意的可以去我博客看下
http://blog.shajincheng.com/post/67.html
[课程]Android-CTF解题方法汇总!