开启辅助访问 切换到宽版

精易论坛

 找回密码
 注册

QQ登录

只需一步,快速开始

用微信号发送消息登录论坛

新人指南 邀请好友注册 - 我关注人的新帖 教你赚取精币 - 每日签到


求职/招聘- 论坛接单- 开发者大厅

论坛版规 总版规 - 建议/投诉 - 应聘版主 - 精华帖总集 积分说明 - 禁言标准 - 有奖举报

查看: 7663|回复: 41
收起左侧

[易源码分享] 利用VEH异常处理实现无限无痕HOOK(非硬断)

[复制链接]
发表于 2023-2-21 08:58:52 | 显示全部楼层 |阅读模式   广西壮族自治区柳州市
分享源码
界面截图: -
是否带模块: -
备注说明: -
本帖最后由 雨过天晴 于 2023-2-21 19:48 编辑

上次说过后面会开源一份无痕HOOK,但是这个技术非常的麻烦,用易语言写出来很困难,所以不再对易语言进行编写,而以现有的可以使用的源码上对原理进行讲解

不要把硬断与这个方法混为一谈,两者虽然都是沾了异常处理的光,但是硬断只能四个还要依靠线程,十分不稳定.

Non_trace_jmpinfo  Non_trace::Veh_Hook_strat(Base head, Base satrtaddr, Base HookAddr, DWORD size, Base NewMemory, PVOID proc)
{
        参数1 为需要HOOK的模块基础地址  比如像0x400000
         第二个参数是需要HOOK地址的0x1000字节对齐地址的地址   假如我们 HOOK的地址是 0x455555  那么开始地址必须是 0x455000  或者   0x454000 必须被0x1000整除  
        第三个参数是HOOK的绝对地址
          第四个参数是从0x455000 或者  0x454000 开始的作用范围大小 (必须0x1000以上覆盖HOOK的绝对地址并且0x1000字节对齐) ,  这个范围内的代码执行都会异常触发
         第五个参数是拷贝出来的新内存 相当于回调构造   第五个参数是跳转的函数
        Non_trace_hook.VehAdd(head, satrtaddr - head, satrtaddr, size, NewMemory);  把信息添加到数组结构
         下面的代码是计算偏移然后对拷贝出来的对新内存地址的相对偏移进行HOOK
        Base jmp = HookAddr- satrtaddr + NewMemory;
        ApiHookinfo* b = InstallAPIhook(jmp);
        Non_trace_jmpinfo a;
        a.jmpback = b->originalbyte;//跳回的构造地址
        BuildHookBG(jmp, proc);
         /////--------------------------------
        return a;
}


        


先介绍一下原理
使用AddVectoredExceptionHandler(1, Veh_Main);这个函数后我们的程序可以接收到来自本进程的各种异常,具体异常处理机制我不介绍,先说一下那些可以被我们利用,来实现这个无痕HOOK.



异常机制中有一个页面异常 EXCEPTION_ACCESS_VIOLATION

当程序发生异常执行或访问后会进入到我们的异常处理函数,提交缺页异常信息.
LONG  Non_trace::veh_proc(EXCEPTION_POINTERS* ExceptionInfo)
{
        if (ExceptionInfo->ExceptionRecord->ExceptionCode == EXCEPTION_ACCESS_VIOLATION)
        {        处理代码....        }
}

}


这时候我们的程序,可以在异常处理中修改执行过程的 寄存器 之类的很多信息 当然包括了运行点.
当这个函数返回-1时候系统会不再调用其他的异常函数而直接跳到参数中地址的EIP(运行点)

如果我们想在不修改代码的情况下对程序进行HOOK,那么就可以利用页面异常,
我们需要使用 ZwProtectVirtualMemory 函数来是目标进程代码主动触发页面异常.
ZwProtectVirtualMemory 有5个参数, 我们只需要把NewProtect参数设置为1 这个地方的执行访问代码都会造成页面异常
ProcessHandle
整数型

打开的程序句柄
BaseAddress
长整数型

开始地址
RegionSize
整数型

地址范围
NewProtect
整数型

新的保护设置
OldProtect
整数型

旧的保护设置


非常注意的是,物理页面中最小的分页是0x1000字节  ,所以这个函数最小只能生效0x1000字节的内存区域 ,并且起始地址整除0x1000

意思便是说 当我们想无痕HOOK一个点,这个区域的0x1000字节的执行代码都会触发页面异常,然后跳到异常处理函数,所以我们需要一个逻辑与0xfff的操作来把地址换算成整除0x1000的页面起始地址.

当我们执行完Veh_Hook_strat函数后把跳转的信息添加到了数组, 我们还需要把那一块整除0x1000内存拷贝到新内存地址,  比如我们想 HOOK 0x455555  我们就需要拷贝 0x455000 - 0x456000 这个范围的内存到 Veh_Hook_strat函数的NewMemory的内存中,这样在执行异常处理的时候我们才能正确判断并且跳转
当然我们别忘了对NewMemory+555 这个地址进行InlineHOOK,这样才能使跳转到 NewMemory-NewMemory+0x1000 中的代码会执行这个InlineHOOK


完整的读写执行分离处理  



       LONG  Non_trace::veh_proc(EXCEPTION_POINTERS* ExceptionInfo)//这个参数是系统传递的异常信息 包括寄存器跟出现异常的地址, 或者指令访问的地址
        //  注意:易语言需要用到修改内存,不能像下面直接对数据类型进行直接的引用修改


{
        if (ExceptionInfo->ExceptionRecord->ExceptionCode == EXCEPTION_ACCESS_VIOLATION)//判断是否页面异常   
        {
                if ((Base)ExceptionInfo->ExceptionRecord->ExceptionAddress== ExceptionInfo->ExceptionRecord->ExceptionInformation[1])//代表执行
                {
                        //如果是因为写入或者访问的指令引用到了页面异常区域那么ExceptionInfo->ExceptionRecord->ExceptionInformation[1] 的值会是被访问或者被写入的地址 如果ExceptionInfo->ExceptionRecord->ExceptionAddress相同于ExceptionInfo->ExceptionRecord->ExceptionInformation[1] 那么代表这个异常是执行异常,并不是访问异常


                        for (size_t i = 0; i < VEHHookinfo.size(); i++)
                        {                                        通过对数组的循环我们判断到了异常执行地址处于我们刚刚备份的范围 这时候就要通过一个简单的算法计算出跳转到新内存区域的偏移

                                if (IsAddressInRange(VEHHookinfo.addr, VEHHookinfo.size, ExceptionInfo->ExceptionRecord->ExceptionInformation[1]))
  {
                                        int newp= abs((int)(VEHHookinfo.offset - (int)(ExceptionInfo->ContextRecord->Eip - VEHHookinfo.head))) + VEHHookinfo.Newaddr;
                                        ExceptionInfo->ContextRecord->Eip = (DWORD)newp;最后把Eip改为指向新内存的区域         
                                        return -1;
                                }
                        }
                }
                else
                {        //下面是处理对HOOK区域访问的代码,使用了单步处理,在没有crc自效验中可以剔除      
                        for (size_t i = 0; i < VEHHookinfo.size(); i++)
                        {
                                if (IsAddressInRange(VEHHookinfo.addr, VEHHookinfo.size, ExceptionInfo->ExceptionRecord->ExceptionInformation[1]))
                                {
                                        VEHHookinfo.visitAddr = ExceptionInfo->ExceptionRecord->ExceptionInformation[1];
                                        CALL_ZwProtectVirtualMemory2((HANDLE)-1, (LPVOID)(VEHHookinfo.visitAddr & 0xFFFFF000), 0x1000, 64, &OldProtect);
                                        ExceptionInfo->ContextRecord->EFlags |= 0x100;//Do a single step
                                        return EXCEPTION_CONTINUE_EXECUTION;
                                }
                        }
                }
        }


        if (ExceptionInfo->ExceptionRecord->ExceptionCode == STATUS_SINGLE_STEP)
        {
                for (size_t i = 0; i < VEHHookinfo.size(); i++)
                {
                        if (VEHHookinfo.visitAddr)
                        {
                                CALL_ZwProtectVirtualMemory2((HANDLE)-1, (LPVOID)(VEHHookinfo.visitAddr & 0xFFFFF000), 0x1000, 1, &OldProtect);
                                VEHHookinfo.visitAddr = 0;
                                return EXCEPTION_CONTINUE_EXECUTION;
                        }
                }
        }
        return EXCEPTION_CONTINUE_SEARCH;
}

上述代码中其关键的只在第一个if中的代码,下面的是关于访问异常的处理,在一般情况下,是可以删除掉的. 但是在程序的代码中有crc在自效验的话,那就必须加上,让crc在访问这一片执行代码的时候,释放出可以访问的内存,但是有一种更先进的技术不需要单步异常也可以直接让访问指令获得值而不报错,我现在并没有掌握,因为我只见到一次,并不知道原理.

需要注意的是,拷贝内存结尾必须包含代码函数段的ret 这样在JMP了之后,执行代码才能返回到正常的执行段.
我一般直接把整个程序的.text段全部拷贝出来, 如此在无痕HOOK多处地址的时候 不需要一直重复的拷贝内存,而这样的执行效果更加高,因为程序被异常后几乎不会在走他自身的执行段,全部走我们自己申请的内存.当然如果你要这样拷贝 Veh_Hook_strat 这个函数中一些偏移你们要自己协调 ,我个人感觉这种HOOK用起来非常麻烦,而且效率也只能保持每秒执行触发一万次左右才能保证流畅性. 可能听原理起来没什么麻烦,但主要的还是每个异常触发的范围都会有0X1000字节 , 当固定下一个地址的设置,那么将能稳定运行,如果这个地址在同被HOOK程序的版本更新后变动,那么又需要重新计算起始地址.所以这个方法我只当做技术参考,并不提倡使用.

无限只是从原理方面来说!




点评

在Hook初始化时增加一行:SetProcessDEPPolicy(1) 可以确保生效   福建省宁德市  发表于 2023-2-22 01:07

评分

参与人数 2好评 +2 精币 +5 收起 理由
734108950 + 1 + 2 YYDS~!
冰点 + 1 + 3 感谢分享,很给力!~

查看全部评分


发表于 2024-8-13 13:58:26 | 显示全部楼层   江苏省徐州市
66666666666666666
回复 支持 反对

使用道具 举报

签到天数: 2 天

发表于 2024-8-3 08:56:18 | 显示全部楼层   江苏省*
6666666666666666666666666
回复 支持 反对

使用道具 举报

结帖率:33% (1/3)
发表于 2024-1-31 21:03:53 | 显示全部楼层   河南省开封市
看看怎么回事
回复 支持 反对

使用道具 举报

结帖率:33% (1/3)

签到天数: 2 天

发表于 2023-11-12 19:16:58 | 显示全部楼层   广东省东莞市
感谢分享
回复 支持 反对

使用道具 举报

结帖率:33% (1/3)

签到天数: 10 天

发表于 2023-10-24 13:23:26 | 显示全部楼层   山东省滨州市
这款软件真的太棒了,谢谢楼主的分享,让我可以享受到这么好的产品。
回复 支持 反对

使用道具 举报

结帖率:38% (3/8)

签到天数: 18 天

发表于 2023-10-3 02:16:16 | 显示全部楼层   广东省揭阳市
源码呢?
回复 支持 反对

使用道具 举报

结帖率:20% (1/5)

签到天数: 10 天

发表于 2023-5-17 19:44:35 | 显示全部楼层   浙江省金华市
谁写出来了?让我c+v一下呗,我看不懂
回复 支持 反对

使用道具 举报

发表于 2023-4-27 15:04:30 | 显示全部楼层   四川省成都市
厉害啊 哥哥
回复 支持 反对

使用道具 举报

结帖率:0% (0/1)

签到天数: 5 天

发表于 2023-3-5 22:51:29 | 显示全部楼层   四川省德阳市
....源码在哪?光理论了
回复 支持 反对

使用道具 举报

结帖率:0% (0/1)

签到天数: 15 天

发表于 2023-3-2 21:37:55 | 显示全部楼层   广东省江门市
55666666666666666666666
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则 致发广告者

发布主题 收藏帖子 返回列表

sitemap| 易语言源码| 易语言教程| 易语言论坛| 易语言模块| 手机版| 广告投放| 精易论坛
拒绝任何人以任何形式在本论坛发表与中华人民共和国法律相抵触的言论,本站内容均为会员发表,并不代表精易立场!
论坛帖子内容仅用于技术交流学习和研究的目的,严禁用于非法目的,否则造成一切后果自负!如帖子内容侵害到你的权益,请联系我们!
防范网络诈骗,远离网络犯罪 违法和不良信息举报电话0663-3422125,QQ: 793400750,邮箱:wp@125.la
Powered by Discuz! X3.4 揭阳市揭东区精易科技有限公司 ( 粤ICP备12094385号-1) 粤公网安备 44522102000125 增值电信业务经营许可证 粤B2-20192173

快速回复 返回顶部 返回列表