驱动保护进程 句柄降权 杀软自保 游戏破图标技术原理和实现
文章目录
- 实现效果
- 实现原理
- 代码实现
- 实现效果
- 句柄降权对抗(实现破游戏图标和关闭杀软自保)
- 降权对抗延伸
- 游戏降权对抗
- 杀软自保对抗
- 隐藏Object钩子回调
- 完整代码
实现效果
效果如图所示:
无法结束进程:
CE无图标:
内存无法读取
可以看到被保护的进程无法被结束,同时在CE内无法看到图标,并且无法被读取内存。驱动的进程保护,游戏的无图标保护内存和杀软的自我保护,实际上都是一个原理。真是一招鲜吃遍天啊。
实现原理
所有的实现其实都来自于一个API->ObRegisterCallbacks
。这个函数可以让你设置一个回调函数,当我们对进程或者线程的句柄进程操作时,可以在操作前和操作后拿到进程相关的信息,从而实现句柄降权,这样就可以阻止掉需要使用句柄的相关操作,例如读写内存和结束进程。
函数原型如下:
NTSTATUS ObRegisterCallbacks([in] POB_CALLBACK_REGISTRATION CallbackRegistration,[out] PVOID *RegistrationHandle
);
- 第一个参数是一个结构体,里面是要设置的回调的相关信息
- 第二个参数是返回给我们的一个句柄,在卸载的时候需要用到
我们来看下这个关键的结构体
typedef struct _OB_CALLBACK_REGISTRATION {USHORT Version;USHORT OperationRegistrationCount;UNICODE_STRING Altitude;PVOID RegistrationContext;OB_OPERATION_REGISTRATION *OperationRegistration;
} OB_CALLBACK_REGISTRATION, *POB_CALLBACK_REGISTRATION;
- 第一个是版本号,可以用
ObGetFilterVersion()
函数获得 - 第二个是最后一个成员
OperationRegistration
的数量 - 第三个是一个Unicode 字符串,指定驱动程序的高度。(这个我也没看懂是个啥玩意)
- 第四个是回调函数的参数
- 最后一个参数比较关键,指向的是一个结构体数组,我们需要在这个结构体里面去指定操作前的回调函数和操作后的回调函数,这个结构可以设置多个。
来看一下这个结构体的成员
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;
- 第一个是回调函数的对象类型指针,要么是
PsProcessType
,要么是PsThreadType
- 第二个是标志位
- 第三个是操作前回调
- 第四个是操作后回调
代码实现
接下来按照这个步骤来写代码
- 初始化
OB_OPERATION_REGISTRATION
结构体 - 初始化
OB_CALLBACK_REGISTRATION
结构体 - 调用
ObRegisterCallbacks
注册回调函数 - 编写回调函数
首先初始化OB_OPERATION_REGISTRATION
结构体
OB_OPERATION_REGISTRATION obOperationRegistrations;
obOperationRegistrations.ObjectType = PsProcessType;
obOperationRegistrations.Operations |= OB_OPERATION_HANDLE_CREATE;
obOperationRegistrations.Operations |= OB_OPERATION_HANDLE_DUPLICATE;
obOperationRegistrations.PreOperation = PreOperationCallback;
obOperationRegistrations.PostOperation = NULL;
这个结构可以注册多个,我们只注册一个,处理进程句柄就够了。操作后的回调我们也不需要,直接填NULL
然后再来初始化第二个结构体OB_CALLBACK_REGISTRATION
OB_CALLBACK_REGISTRATION obCallbackRegistration = { 0 };
UNICODE_STRING altitude = { 0 };
RtlInitUnicodeString(&altitude, L"1000");
obCallbackRegistration.Version = ObGetFilterVersion();
obCallbackRegistration.OperationRegistrationCount = 1;
obCallbackRegistration.RegistrationContext = NULL;
obCallbackRegistration.Altitude = altitude;
obCallbackRegistration.OperationRegistration = &obOperationRegistrations;
最后再来调用API注册回调
ObRegisterCallbacks(&obCallbackRegistration, &g_RegistrationHandle);
这里延伸一下:ObRegisterCallbacks
这个函数是有校验的
里面会调用MmVerifyCallbackFunction
这个函数进行校验
校验的方法是判断 DriverSection 里面的一个字段是否包含了0x20,所以我们只要把这个字段跟0x20按位与就行了。
另外这个句柄需要放到全局变量里面,方便卸载的时候用,如果卸载驱动的时候没取消回调的注册,会蓝屏!
PVOID g_RegistrationHandle = NULL;
然后再来编写我们的回调函数
OB_PREOP_CALLBACK_STATUS
PreOperationCallback(_In_ PVOID RegistrationContext,_Inout_ POB_PRE_OPERATION_INFORMATION PreInfo)
{//获取操作的进程对象PEPROCESS process = (PEPROCESS)PreInfo->Object;//获取进程名PUCHAR processName = PsGetProcessImageFileName(process);if (_stricmp((char*)processName, "Notepad.exe") != 0){//不是我们关心的进程,直接returnreturn OB_PREOP_SUCCESS;}if (PreInfo->Operation == OB_OPERATION_HANDLE_CREATE){PreInfo->Parameters->CreateHandleInformation.DesiredAccess=0;}if (PreInfo->Operation == OB_OPERATION_HANDLE_DUPLICATE){PreInfo->Parameters->DuplicateHandleInformation.DesiredAccess =0;}return OB_PREOP_SUCCESS;
}
在回调函数里我们判断是否是我们关心的进程,如果不是,直接把所有权限抹掉。如果要实现游戏的效果,抹掉单个权限,比如禁用掉读写,就可以借助下面这些宏
#define PROCESS_TERMINATE (0x0001)
#define PROCESS_CREATE_THREAD (0x0002)
#define PROCESS_SET_SESSIONID (0x0004)
#define PROCESS_VM_OPERATION (0x0008)
#define PROCESS_VM_READ (0x0010)
#define PROCESS_VM_WRITE (0x0020)
#define PROCESS_DUP_HANDLE (0x0040)
#define PROCESS_CREATE_PROCESS (0x0080)
#define PROCESS_SET_QUOTA (0x0100)
#define PROCESS_SET_INFORMATION (0x0200)
#define PROCESS_QUERY_INFORMATION (0x0400)
#define PROCESS_SUSPEND_RESUME (0x0800)
#define PROCESS_QUERY_LIMITED_INFORMATION (0x1000)
#define PROCESS_SET_LIMITED_INFORMATION (0x2000)
实现效果
注册完成之后,在PCHunter的Object钩子这一栏,显示挂钩函数->PreOperation,PCHunter直接标红是可以查到的,还能看到挂钩的驱动名
句柄降权对抗(实现破游戏图标和关闭杀软自保)
既然知道了原理,那想要摘除就很简单了,能防自然也能攻。
OB_PREOP_CALLBACK_STATUS preCallback(_In_ PVOID RegistrationContext,_Inout_ POB_PRE_OPERATION_INFORMATION PreInfo
)
{if (PreInfo->Operation == OB_OPERATION_HANDLE_CREATE){PreInfo->Parameters->CreateHandleInformation.DesiredAccess = PROCESS_ALL_ACCESS;PreInfo->Parameters->CreateHandleInformation.OriginalDesiredAccess = PROCESS_ALL_ACCESS;}else{PreInfo->Parameters->DuplicateHandleInformation.DesiredAccess = PROCESS_ALL_ACCESS;PreInfo->Parameters->DuplicateHandleInformation.OriginalDesiredAccess = PROCESS_ALL_ACCESS;}return OB_PREOP_SUCCESS;
}
还是一样的代码,改一下回调,不管什么进程,都把句柄权限开到最大即可。
关闭杀软:
游戏破图标:
降权对抗延伸
游戏降权对抗
既然破图标的操作这么简单粗暴,那么游戏自然不会坐视不管。在下了Object钩子之后,还会增加一层保险,就是剥夺所有线程和进程的游戏操作权限
VOID StripHandlePermission()
{__try{CheckDebugPort(g_FlagProcessPid);CheckDebugPort((HANDLE)g_StarterPid);PSYSTEM_HANDLE_INFORMATION_EX HandleInfo = QueryHandleTable();if (HandleInfo) {for (int i = 0; i < HandleInfo->NumberOfHandles; i++){//7 是 process 属性if (HandleInfo->Information[i].ObjectTypeNumber == 7 || HandleInfo->Information[i].ObjectTypeNumber == OB_TYPE_INDEX_PROCESS || HandleInfo->Information[i].ObjectTypeNumber == OB_TYPE_INDEX_THREAD){if (g_FlagProcessPid == (HANDLE)-1)break;if (HandleInfo->Information[i].ProcessId == (ULONG)g_FlagProcessPid || HandleInfo->Information[i].ProcessId == 4)continue;bool bCheck = ((HandleInfo->Information[i].GrantedAccess & PROCESS_VM_READ) == PROCESS_VM_READ ||(HandleInfo->Information[i].GrantedAccess & PROCESS_VM_OPERATION) == PROCESS_VM_OPERATION ||(HandleInfo->Information[i].GrantedAccess & PROCESS_VM_WRITE) == PROCESS_VM_WRITE);PEPROCESS pEprocess = (PEPROCESS)HandleInfo->Information[i].Object;if (pEprocess) {HANDLE handle_pid = *(PHANDLE)((PUCHAR)pEprocess + g_OsData.UniqueProcessId);HANDLE handle_pid2 = *(PHANDLE)((PUCHAR)pEprocess + g_OsData.InheritedFromUniqueProcessId);if (bCheck && (handle_pid == g_FlagProcessPid || handle_pid2 == g_FlagProcessPid)) {pEprocess = NULL;NTSTATUS status = PsLookupProcessByProcessId((HANDLE)HandleInfo->Information[i].ProcessId, &pEprocess);if (NT_SUCCESS(status)) {//DebugPrint("Full Acess Handle! pid: %d \n", HandleInfo->Information[i].ProcessId);PHANDLE_TABLE HandleTable = *(PHANDLE_TABLE*)((PUCHAR)pEprocess + g_OsData.ObjTable);if (MmIsAddressValid((void*)HandleTable)) {ExEnumHandleTable(HandleTable, g_isWin7 ? (DWORD64*)&StripHandleCallback_win7 : (DWORD64*)&StripHandleCallback_win10, (PVOID)HandleInfo->Information[i].Handle, NULL);}ObDereferenceObject(pEprocess);}}}}}ExFreePoolWithTag(HandleInfo, POOL_TAG);}}__except (EXCEPTION_EXECUTE_HANDLER){return;}}
这段代码实现的功能就是枚举进程列表,然后遍历所有进程的私有句柄表,查看句柄类型为7的进程对象,如果这个进程对象的ID是游戏的ID,那么说明游戏句柄被我正在遍历的这个进程打开了,就把这个句柄的读写权限抹除。这样可以起到保护游戏进程的作用
游戏完全可以创建一个线程,定时去执行这个操作。这样的话即使我们的回调恢复了句柄完整的属性,也无济无事,还需要把这个部分给处理掉。
如果把恢复权限的回调代码也定时执行的话就会出现争抢句柄权限的局面,导致游戏的内存一闪一闪,这样做并不能完全解决问题。
那么如果我们想要防止游戏定时把我们的句柄降权,可以采取的方法如下:
1.构建EPROCESS结构。将目标进程的EPROCESS结构复制到我们构建的那块内存中。
2.将新构建的EPROCESS结构中的PID、进程名清空或修改。
3.将目标进程的第一级页表的内容复制到一块新内存中,并将新构建的EPROCESS结构的DirectoryTableBase改为新内存的物理地址,从而实现CR3的替换。
4.修改我们自身进程的私有句柄表中的目标进程的句柄结构的Object为新构建的EPROCESS结构。
5.此时我们再拿着新的句柄操作的进程与目标进程是同一个进程空间,但是指向的进程结构却是不同的。
这个步骤可能不太好理解,这里我画了个图:
- 首先把游戏进程的进程结构体复制出来一份,然后把PID跟名字清空
- 接着把游戏进程的CR3替换成我们自己的CR3
以上两步实现了一个EPROCESS结构的替换,因为CR3变了所以不管你怎么操作原来的EPROCESS结构体,那么修改的也不是真正的游戏进程了。
由于我们的CE还需要去操作游戏内存,所以需要把这一份新的游戏进程的EPROCESS的地址放到CE进程的句柄表内,也就是第4步的操作。
这样的话就实现了句柄防止降权,也就实现了提权操作。还有一种方法是把私有句柄表的链表给摘掉,这样的话也可以防止降权。
杀软自保对抗
杀软的自保也是通过ObRegisterCallbacks
实现的,这个操作基本可以防住大部分的R3的病毒。
但是在一些系统进程中会有完整的读写权限的句柄,比如lsass.exe
,csrss.exe
,只要把这个拥有完整权限的句柄复制一份,就可以直接在三环关闭杀软了。相关的代码各位可以百度,网上肯定有现成的。
隐藏Object钩子回调
既然我们下的Object回调PCHunter直接标红,那么别人查起来也不难。有这么一个操作可以隐藏自己设置的回调,就是把进程保护回调直接注册到ntoskerl.exe,让操作系统的内核模块帮我们保护进程。这样的话在PCHunter里面就是没有任何异常的,而且别人想查起来也很难。这个操作是之前看某个驱动大佬的课程学习到的,当时直呼牛逼。具体细节就不展开了。
完整代码
https://download.csdn.net/download/qq_38474570/87085676?spm=1001.2014.3001.5501
驱动保护进程 句柄降权 杀软自保 游戏破图标技术原理和实现相关推荐
- 【驱动保护】某P的内存降权
上游戏打开CE发现在CE中对游戏没有内存操作权限(没有图标) 打开PChunter查看Object钩子 发现某P有对进程句柄权限回调的钩子 方式1:直接摘除回调 结果:黑屏重启 方式2:回调入口处写r ...
- 如何网络推广浅析网站优化的过程中首页降权了该怎么办?
如何网络推广中网站排名优化就是为了让网站能更受欢迎,能吸引到更多的流量,进而促进网站的效益等,并且首页的优化在整个网站优化过程中也是非常重要的,有时候就会引起优化人员的过度重视,从而造成了过度优化,导 ...
- C/C++ 进程代码注入与提权/降权
如果将shellcode注入到具有特定权限的进程中,我们就可以获得与该进程相同的权限,此方法可以用于提权与降权操作,注入有多种方式,最简单的是直接将metasploit生成的有效载荷直接注入到目标进程 ...
- Win64 驱动内核编程-21.DKOM隐藏和保护进程
DKOM隐藏和保护进程 主要就是操作链表,以及修改节点内容. DKOM 隐藏进程和保护进程的本质是操作 EPROCESS 结构体,不同的系统用的时候注意查下相关定义,确定下偏移,下面的数据是以win7 ...
- 最新零基础C++逆向辅助+过驱动保护+lua
最新零基础C++逆向辅助+过驱动保护+lua 地址:资源共享吧 最新零基础C++逆向辅助+过驱动保护+lua-资源共享吧-专业共享VIP视频 最新零基础C++逆向辅助+过驱动保护+lua https: ...
- 驱动保护中的ObjectType_Callback探索
最近学习驱动保护,有点小小心德与大家分享下. 当前环境:VM中的win7 32 保护程序是某游戏的驱动保护. 具体现象是:在用PCHunter工具查看object钩子时发现如下的信息: 疑问点1:在H ...
- YJX_Driver_031_再谈SSDT_HOOK驱动保护原理
1. 再谈SSDT HOOK驱动保护原理 A.初识内核进程相关结构 B.内核函数PsGetCurrentProcess C.进程保护原理 D.实例测试 [100]本节课先讲理论,下节课具体代码 [16 ...
- 日服巫术online过驱动保护分析(纯工具)(工具+自写驱动)
前言: 最近在学外挂编程,基本都是利用CE,OD调试分析游戏数据,但现在游戏公司用各种保护手段防止我们调试游戏,虽然我们有CE,OD这样的利器但是仍然被游戏驱动保护挡在门外i,真可谓巧妇也难为无米之炊 ...
- 过 DNF TP 驱动保护(一)
文章目录: 01. 博文简介: 02. 环境及工具准备: 03. 分析 TP 所做的保护: 04. 干掉 NtOpenProcess 中的 Deep InLine Hook: 05. 干掉 NtOpe ...
最新文章
- 交流一点CCNP学习经验
- 1049-飞机最少换乘次数问题
- 佛教:关于时间(段)的几种描述
- ArrayBlockingQueue中的方法
- Java Math类toDegrees()方法与示例
- 循序渐进PYTHON3(十三) --4-- DJANGO之CSRF使用
- android手机两种方式获取IP地址
- redis多种模式部署(持续更新)
- 抓住指针的精髓,才算掌握了 C 语言的灵魂!
- wxpython使用_wxPython学习笔记(二)
- 连续竞价java_Java 方法method
- es统计有多少个分组_ElasticSearch 分组查询的几个例子
- android 字体设置方正,(技术)Android 默认非衬线字体修改为衬线字体
- 滚动字幕的源代码(可作滚动公告)
- css面试题之Flex布局
- java权限管理面试_java shiro面试题
- 七宗罪----人性本恶
- SCT芯洲DC-DC-SCT2430是一款输出电流高达3.5A的高功率密度全集成同步降压DCDC转换器。其输入电压范围为3.8V到40V,替代TPS54340
- CAD教程:如何将Excel数据快速导入CAD图纸
- Unity 手游面数控制
热门文章
- 星际密码(矩阵快速幂)
- 20220715_JaveWeb_MVC模式_三层架构案例
- C# vb .net实现负片特效滤镜
- ESP8266远程控制台灯(硬件软件详解)
- 远程桌面连接软件 Remote Desktop Manager for Mac
- STM32+雷龙SD NAND(贴片SD卡)完成FATFS文件系统移植与测试
- 资源管理、高可用与自动化(下)
- jquery的css()函数同时设置多个css属性值
- 微信小程序实现watch监听数据变化
- 把计算边界层高度的公式放入模式