|
[原创]内核HOOK的安全问题(全程现场回放)
还有个问题 函数在返回时是否有可能被抢先? 例如: 在我的代理函数返回前,我进行了原子减操作,然后下面就是RET指令 有没有可能在我刚刚进行完减操作之后,执行RET之前被调度? 如果会被调度,并且正好调度到我的UNHOOK进程上, 那此时因为计数器已经清0,所以可以进行内存释放, 而另一线程的上下文中,指令RET的地址仍然是在原来的地址上,该地址被释放即无处可询,还会发生BSOD,,, 不知道这么想的对还是不对... |
|
[求助]WH_GETMESSAGE钩子
感觉这个应该有个层次问题吧 看你想拦截的消息,是在别人的钩子处理完后才到你的函数里,还是你先处理完后再决定是否下传了 如果别人的钩子在你的钩子之上,你自然拦截不到,否则应该是可以拦截的 |
|
[原创]内核HOOK的安全问题(全程现场回放)
看过几个,好像都是VS2003吧,我这只有2005,,,,, |
|
[原创]内核HOOK的安全问题(全程现场回放)
顺便请教一下 大家在写驱动的时候,是用什么工具写的? 我一直在用EDITPLUS....本来就菜,用这个嘛提示没有,只知道一些常用的函数,英文的文档又实在看不太明白,中文的资料又少的可怜... 有什么集成环境没?类似VS之类的,不要求他达到提示的作用,至少我在写出某个函数来后,直接右键就可以找到函数的声明原型也行啊.. |
|
[原创]内核HOOK的安全问题(全程现场回放)
吃饭去,回来看看有没有哪位大牛指点一二 然后试试想的的办法可不可行.. 吃饭的时候想到个问题,有点迫不及待的想说说的感觉 使用方案3的时候, 如果是HOOK了多个函数,那就需要申请多个自旋锁对象与多个计数器变量(不知道有没有什么内核结构可以实现一个内核对象控制多个锁的作用) 而我们使用自旋锁的目的,却仅仅是为了给计数器进行加减操作, 其实这个时候完全可以使用原子指令来进行计数器的加减,即可以免去申请自旋锁对象,又可以免除使用自旋锁带来的性能下降的弊端,自我感觉良好啊,呵呵! |
|
[原创]内核HOOK的安全问题(全程现场回放)
关于内核HOOK的安全问题 现象: 驱动实现HOOK多个内核函数,虚拟机运行无问题出现 本地机运行多数情况正常,但偶尔在卸载驱动时会出现BSOD,代码:IRQL_NOT_LESS_OR_EQUAL 使用GOOLE与BAIDU了一番,这个错误应该属于内存访问失败吧! 思考几次BSOD时的本机情况,一般为开启了多个软件时导致,重新检查驱动代码,醒悟为在UNHOOK时,没有做任何检测,直接将所有HOOK的函数还原然后卸载驱动,并且UNHOOK代码的IRQL级别高,不会被系统打断 因此,假设系统中某进程正在调用被HOOK的函数并正好运行至我们的代理函数时被其它进程抢先,并一直未得到继续运行,而此时我们运行UNHOOK,将代理函数自内存中销毁,然后等待的进程得到处理器后,继续执行指令时,原内存地址中的指令已不存在,因而就会发生BSOD了! 既然原因大概知道了,那就想办法解决吧! 思考1: 首先想到的解决方案是: 创建全局变量做计数器使用 在代理函数入口使计数器+1,返回时-1. 在UNHOOK时判断计数器是否为0 不为0则等待计数器归0后再进行UNHOOK 方案有了,那就继续思考可行性: (1)使用计数器进行函数调用的统计,如何保证计数器进行加减操作时不被打断? 嗯,记得之前看书的时候,提到过这种情况下可以使用自旋锁,来达到锁定操作不被打断的目的. 但如果是一个使用的比较频繁的函数,使用自旋锁会不会使性能降低? 另外如果被一个低优先级的进程抢先了资源后,紧接被高于它优先级的进程抢先,?这种情况是不是就叫所谓的死锁?因为CPU始终运行在等待状态上,而资源得不到释放? 那如何防止这种情况的发生呢? 不行,对自旋锁的概念太模糊,看书找资料! 下面引用WINDOWS驱动开发里的介绍
哦,SHIT! 再看书上关于自旋锁的介绍后才发现自己真够屎的!!!明明人家说的清清楚楚明明白白的,自旋锁,就是用来防止操作不被打断(注意上面标红的地方,其实自己是知道的,但是根本没理解这是啥意思,,,),那又如何存在低优先级线程获取资源后被高优先级抢先的情况呢?~ 不过问题又产生了,,既然不会被打断,又如何会出现死锁呢?同时,证明了我的猜想,使用自旋锁肯定会影响性能. 为了巩固学到的东西,再次找资料,看看什么情况下会发生死锁! 死锁:假设有一个或多个内核任务和一个或多个资源,每个内核都在等待其中的一个资源,但所有的资源都已经被占用了。这便会发生所有内核任务都在相互等待,但它们永远不会释放已经占有的资源,于是任何内核任务都无法获得所需要的资源,无法继续运行,这便意味着死锁发生了。自死琐是说自己占有了某个资源,然后自己又申请自己已占有的资源,显然不可能再获得该资源,因此就自缚手脚了。 呃,看见这个想起来,计算机组成原理上有这个介绍的嘛(忘的一干二净了,) 不过死锁很容易理解,两个CPU,三个资源,两个内核任务 其中每个内核任务需要三个资源才可以达到执行条件,CPU1抢了资源1,CPU2抢了资源2,3 两个互相等吧….这就是死锁了,那自锁呢,还是不太明白~~~只能理解为 CPU获取资源后,释放资源前,又一次申请该资源! 呃,不知道对不对大牛们指点一下! 到这就大概就明白了,使用自旋锁与计数器应该是可以实现我的需求,自死锁是代码编写时没有注意所产生的,这个可以防止发生了,影响性能嘛~~~反正只做个计数器加减操作,不会影响太大,决定就用这种方法了 (2)但是!突然又冒出个问题:我在UNHOOK时,判断计数器是否为0,是要在提升当前IRQL后判断呢?还是要在提升前判断呢? 如果是在提升级别前进行判断,那假设我判断计数器为0后,CPU被其它进程抢先,并且该进程调用了被HOOK的函数,然后使计数器+1 此时CPU又被UNHOOK抢过来进行下面的处理,还是得BSOD不是~~~ 如果在提升级别后判断,那其它进程得不到运行,计数器就不会减1了啊, 嗯?多核的还好,可以有另一个CPU来将进程运行完(咋感觉这概念很有问题啊?),可单核的呢?另外多核的还存在一个多核同步问题. (3)换个想法,不用计数器,把自旋锁test-and -set放在代理函数开头,然后在代理函数返回前释放锁资源,在UNHOOK的时候同样进行test-and-set,UNHOOK结束后释放锁资源.不行,先不管其它的问题,这样写的话,性能影响实在太大了.等等,,,UNHOOK判断计数器的时候,不提升当前IRQL级别,而是使用自旋锁,UNHOOK结束后释放锁资源 嗯,这样可以解决多核同步问题,单核的嘛?只能是在代理函数中判断当前CPU数量,如果是单核的,那自旋锁的释放就要等到代理函数执行结束后再进行了,这样其实就等于让CPU在调用被HOOK的函数时,始终不被打断,也就是同一时刻只有一个调用到该函数的线程在运行,性能的影响是相当的大啊.. 只能思考到这个地步了,还好现在多数都是多核机,面临的窘状不会太多…只是感觉这方法很笨啊,而且不知道思考的路子对与不对,大牛们要是能坚持看到这,还是烦劳指点小菜一两手吧! 思考2: 本来想解决方案的时候一下冒出来的两个方案,上面的是第一个,第二个是不使用自旋锁而使用原子操作进行计数器的加减,不过在上面方案的聚体思考过程中,这个方案已经被否决了,因为不使用自旋会出现的问题上面已经考虑过了!(补充:其实这是一个逻辑性错误,我此时所想的原子操作,是指原子的加减,而思考的自旋,是指自旋后可以运行一段相当多的内容, 级别不同而已! 也说不清楚当时是怎么想的,想到的就想上了,反正就是乱七八糟就对了!) 思考3: 这个是在方案1结束时想到的,,因为想到了线程调度的问题,不管是多核还是单核,线程调度时,CPU需要保存当前线程的上下文,所以应该不会存在一个线程被多个CPU分别调度的情况,那方案一的结果就是不言而喻了,所以就只能是把计数器的判断提前,不管是用自旋还是提升IRQL,都必须要在这个操作之前判断当前的计数器情况,那就又回到了老问题,计数器判断通过的瞬间,线程被调度,其它线程又访问了被HOOK的函数并且运行到了自己的代理函数中,继续BSOD(), 到这就把自己的方案一给否决了,然后换思路思考! 想到最近研究的DNF驱动保护,有人分析的结果是:”驱动一运行,就使用ExAllocateXXXX分配一块内存,然后实现HOOK,然后结束自己的线程” 嗯!就是这个了, 我也可以在驱动入口处先申请一块内存,然后把自己的代理函数写入这块内存中 代理函数中的自旋锁与计数器仍然是必须的, 然后在UNHOOK的时候,先进行UNHOOK操作 再进行计数器的判断(不使用任何自旋与提升IRQL),当计数器清0后, 使用ExFreeXXXX来释放分配的内存. 好像这是我能想到的最好的办法了?感觉很简单啊,竟然用了一个上午的时间想出来的这个方案, 不过不知道是否可行? 从头看到尾的牛人,你是我的偶像,也是我的救星,烦请您抬抬手,动动口,就告诉我一下,这个办法可不可以用?还有没有什么漏掉的地方?又有没有更好的办法?小弟千恩万谢啊~ |
|
[转帖]StrongOD v0.2.6 415[2009.09.01]by 海风月影[CUG]
非常感谢LZ,正找这个呢 |
|
inline hook里jmp的一点疑问,请高手指点.
把cschenhui 与 leftup的结合起来看就点到重点了 |
|
|
|
[求助]这次是PsTerminateSystemThread问题.....
啊,这一说发现我还真是笨啊 NTSTATUS PsCreateSystemThread( OUT PHANDLE ThreadHandle, IN ULONG DesiredAccess, IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL, IN HANDLE ProcessHandle OPTIONAL, OUT PCLIENT_ID ClientId OPTIONAL, IN PKSTART_ROUTINE StartRoutine, IN PVOID StartContext ); 这里的PCLIENT_ID应该就是线程ID了吧!!!真晕,这太菜了也 |
|
[求助]这次是PsTerminateSystemThread问题.....
嗯,这下明白了 就是在用KeWaitxxxx之前,先通过ObRefrenceObjectByHandle来获取对象,然后再调用KeWait方法来等待是吧.. 之前出错应该是传进去的参数类型不正确,所以导致的执行起来出现各种不明所以的问题!!! |
|
[求助]这次是PsTerminateSystemThread问题.....
找ID是想通过ID来找对象... 楼上已经有几位兄弟告诉我可以通过ObRefrenceObjectByHandle来获得对象了,, 之前不清楚,,太菜了,让兄弟见笑,呵呵 |
|
|
|
[求助]这次是PsTerminateSystemThread问题.....
意思是 KeSetEvent 后,因为已经满足主线程中的等待事件要求,所以有可能先运行主线程是吗? 不过这时Watch线程中后面只有一个自杀指令,应该不会有问题了吧?我自己猜的,,,不知道对不对 |
|
[求助]这次是PsTerminateSystemThread问题.....
谢谢兄弟,我回头好好研究一下这两个函数 |
|
[求助]这次是PsTerminateSystemThread问题.....
开始用的就是KeWaitForSignleObject来等待线程的结束 但是蓝屏,另一个帖子里有兄弟解答说该函数的第一个参数应该是Thread对象,而不是句柄 然后使用PsLookupThreadByThreadId来获取对象了,结果能通过,但一运行到线程中的结束指令后,整个卸载过程就完结了,OnUnload中等待线程结束后需要运行的代码全程没有得到运行,驱动没有正常在系统中卸载 然后这又知道了 PsLookupThreadByThreadId的第一个参数不是句柄,而应该是ID,,所以想知道怎么样根据句柄获得ID的.. |
|
[求助]这次是PsTerminateSystemThread问题.....
呃,刚看了一下DDK 确实如此,,可是为嘛有时候可以正常运行过去呢,,奇怪了 另外使用PsGetCurrentThreadId取得的应该不是我要结束的那个线程ID吧? 用哪个函数可以根据线程句柄取得线程ID呢? |
|
|
操作理由
RANk
{{ user_info.golds == '' ? 0 : user_info.golds }}
雪币
{{ experience }}
课程经验
{{ score }}
学习收益
{{study_duration_fmt}}
学习时长
基本信息
荣誉称号:
{{ honorary_title }}
能力排名:
No.{{ rank_num }}
等 级:
LV{{ rank_lv-100 }}
活跃值:
在线值:
浏览人数:{{ visits }}
最近活跃:{{ last_active_time }}
注册时间:{{ user_info.create_date_jsonfmt }}
勋章
兑换勋章
证书
证书查询 >
能力值