首页
课程
问答
CTF
社区
招聘
峰会
发现
排行榜
知识库
工具下载
看雪20年
看雪商城
证书查询
登录
注册
首页
社区
课程
招聘
发现
问答
CTF
排行榜
知识库
工具下载
峰会
看雪商城
证书查询
社区
逆向工程
发新帖
1
0
[分享]手动循环句柄降权保护
发表于: 2026-3-6 16:06
1485
[分享]手动循环句柄降权保护
mb_binusgki
2026-3-6 16:06
1485
# 前言 不同于callback句柄降权保护, 前者是触发指定函数后执行回调进行降权, 后者则是对系统所有进程的句柄表进行扫描, 如命中被保护程序则直接进行降权, 并且可循环定期执行 # 第一步: 写遍历所有进程回调 此方法为遍历所有进程, 并接受一个callback方法基于eprocess ``` //遍历所有EPROCESS void TraversalEprocess(UINT_PTR CallBackFun, ULONG64 ProtectPID) { //获取当前进程 PEPROCESS CurrentProcess = PsGetCurrentProcess(); //获取ActiveProcessLinks活动进程链表 PLIST_ENTRY Head = (PLIST_ENTRY)((PUCHAR)CurrentProcess + 0x2f0); //临时链表头 PLIST_ENTRY Entry = Head; //跳过自己 Entry = Entry->Flink; //do while 循环遍历链表 do { //回到EPROCESS头 PEPROCESS Process = (PEPROCESS)((PUCHAR)Entry - 0x2f0); //执行回调 TraversalEprocessCallBack callback = (TraversalEprocessCallBack)CallBackFun; callback(Process, ProtectPID); Entry = Entry->Flink; } while (Entry != Head);//不等于表头则继续循环 return FALSE; } ``` # 第二步: 根据eprocess遍历句柄表 根据传入eprocess遍历其句柄表, 目前只实现了一二级句柄表, 因为三级很少用到就不做测试了 ``` void TraverseHandleTable(UINT_PTR CurrentEprocess, PVOID CallBackFun, ULONG64 ProtectPID) { //根据EPROCESS获取pid HANDLE pid = GetPidByEprocess(CurrentEprocess); //若pid为负数则违规 直接跳过 if (IsNegative(pid)) return; //输出信息 CHAR imageName[16] = { 0 }; GetImageNameByEProcess(CurrentEprocess, imageName); PZY_PRINT("================ 开始遍历 [%s][%d] 句柄表 ================", imageName, pid); //获取句柄表 HANDLE_TABLE* v_HANDLE_TABLE = (HANDLE_TABLE*)poi(CurrentEprocess + 0x418);//这里+0x418直接取硬编码 比较方便 但是不同系统可能不一致 //如果为0则返回 if (!v_HANDLE_TABLE) return; UINT_PTR TableCode = v_HANDLE_TABLE->TableCode; UINT64 level = TableCode & 0x3; UINT64 TableCodeBase = TableCode & ~3; if (level == 0) { HANDLE_TABLE_ENTRY* v_HANDLE_TABLE_ENTRY = TableCodeBase; for (int i = 0;i < 0x100;i++) { if (v_HANDLE_TABLE_ENTRY->InfoTable) { UINT64 handleCode = i * 4; TraverseHandleTableXx(CurrentEprocess, handleCode, v_HANDLE_TABLE_ENTRY, CallBackFun, ProtectPID); } v_HANDLE_TABLE_ENTRY += 1; } } else if (level == 1) { UINT_PTR v_HANDLE_TABLE_ENTRY1 = TableCodeBase; for (int i = 0;i < 0x100;i++) { v_HANDLE_TABLE_ENTRY1 += i * 0x8; HANDLE_TABLE_ENTRY* v_HANDLE_TABLE_ENTRY = poi(v_HANDLE_TABLE_ENTRY1); if (!v_HANDLE_TABLE_ENTRY) { break; } for (int j = 0;j < 0x100;j++) { if (v_HANDLE_TABLE_ENTRY->InfoTable) { UINT64 handleCode = j * 4 + 0x100 * i; TraverseHandleTableXx(CurrentEprocess, handleCode, v_HANDLE_TABLE_ENTRY, CallBackFun, ProtectPID); } v_HANDLE_TABLE_ENTRY += 1; } } } else if (level == 2) { DbgBreakPoint(); for (int i = 0;i < 0x100;i++) { for (int j = 0;j < 0x100;j++) { for (int k = 0;k < 0x100;k++) { } } } return; } return; } ``` # 第三步: 详细判断处理 这里依旧是使用了回调转发从`TraverseHandleTableXx`转入了`TraverseHandleTableCallBackFun`, `TraverseHandleTableXx`为纯转发不做任何处理就不贴出来了 详细处理逻辑为对比进程句柄表中的每个进程是否和保护进程一致, 如一致则进行降权 ``` //回调处理 void TraverseHandleTableCallBackFun(UINT_PTR CurrentEprocess, HANDLE_TABLE_ENTRY* v_HANDLE_TABLE_ENTRY,ULONG64 ProtectPID) { //解析句柄表的InfoTable得到句柄对象 UINT_PTR HandleEprocess = GetHandleObjectByHandleTableEntry(v_HANDLE_TABLE_ENTRY); if (!HandleEprocess) return; //获取受保护pid的EPROCESS UINT_PTR ProtectEprocess; if (GetEprocessByPid(ProtectPID, &ProtectEprocess) != STATUS_SUCCESS) return; //判断是否是要保护的程序 if (HandleEprocess == ProtectEprocess) { //DbgBreakPoint(); //获取当前进程pid HANDLE CurrentPid = GetPidByEprocess(CurrentEprocess); if (IsNegative(CurrentPid)) return; //获取当前进程名 CHAR CurrentImageName[16] = { 0 }; GetImageNameByEProcess(CurrentEprocess, &CurrentImageName); //获取受保护pid进程名 CHAR ProtectImageName[16] = { 0 }; GetImageNameByEProcess(ProtectEprocess, &ProtectImageName); //降权测试 UINT32 OldAttributes = v_HANDLE_TABLE_ENTRY->Attributes; v_HANDLE_TABLE_ENTRY->Attributes = 0; //打印输出 PZY_PRINT("命中 [%d][%s] 拥有受保护进程 [%d][%s] 句柄, 执行降权处理", CurrentPid, CurrentImageName, ProtectPID, ProtectImageName); } return; } ``` # 测试 开启`Cheat Engine`并在`Cheat Engine`中打开`MFCApplication1`进行测试, `MFCApplication1`为保护程序  开始: 进入遍历进程方法  触发回调  进入遍历句柄表  句柄较少 进入了一级句柄表分支  继续进入下一个回调  命中回调, 降权处理  ce搜索  但下一秒马上失效  旧句柄已完全失效, 需要ce重新加载句柄  查看日志可以发现其对`cheatengine-x8`进行了降权处理, 同样还有`System` \ `csrss.exe` \ `svchost.exe` 等含有 `MFCApplication` 句柄的程序也进行了处理  测试  # 总结 此保护对于反作弊软件属于基操级别, 本次测试为最小化方式实现循环句柄降权, 但对于不走系统函数直接通过cr3读写内存的方式无效, 后续也会涉及如何防止通过cr3读写内存的保护, 欢迎讨论 如有错漏 请留言
传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!!
最后于
2026-3-18 10:14 被mb_binusgki编辑 ,原因: 补充内容
#调试逆向
#系统底层
#问题讨论
#其他内容
收藏
・
1
点赞
・
0
打赏
分享
分享到微信
分享到QQ
分享到微博
赞赏记录
参与人
雪币
留言
时间
查看更多
赞赏
×
1 雪花
5 雪花
10 雪花
20 雪花
50 雪花
80 雪花
100 雪花
150 雪花
200 雪花
支付方式:
微信支付
赞赏留言:
快捷留言
感谢分享~
精品文章~
原创内容~
精彩转帖~
助人为乐~
感谢分享~
最新回复
(
0
)
游客
登录
|
注册
方可回帖
回帖
表情
雪币赚取及消费
高级回复
返回
mb_binusgki
29
发帖
6
回帖
0
RANK
关注
私信
他的文章
[分享]注册表回调内核通信
393
[分享]简单编译器实现
1876
[分享]Lexer简单词法解析器入门
1237
[分享]vm解释器入门2
1298
[分享]vm解释器入门
1593
关于我们
联系我们
企业服务
看雪公众号
专注于PC、移动、智能设备安全研究及逆向工程的开发者社区
看原图
赞赏
×
雪币:
+
留言:
快捷留言
为你点赞!
返回
顶部