首页
社区
课程
招聘
[原创]逆向beep.sys--异步处理IRP举例 (xp3 )
发表于: 2012-10-28 16:29 13960

[原创]逆向beep.sys--异步处理IRP举例 (xp3 )

2012-10-28 16:29
13960

听人说替换beep.sys可以过驱动防火墙,自己试验了一下,在xp3里还真行。但由于一个很蠢的错误,使得我把beep.sys全逆了(驱动不大)。感觉这个驱动对于异步处理IRP有些指导意义,发上来和大家分享。


[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

上传的附件:
收藏
免费 6
支持
分享
最新回复 (18)
雪    币: 292
活跃值: (153)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
2
Well Done
2012-10-28 16:50
0
雪    币: 33
活跃值: (50)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
哥们, 这个nt4里面有代码的哦。

上传的附件:
  • c.jpg (75.21kb,22次下载)
2012-10-28 18:53
0
雪    币: 1689
活跃值: (379)
能力值: ( LV15,RANK:440 )
在线值:
发帖
回帖
粉丝
4
[QUOTE=HitIt;1113055]哥们, 这个nt4里面有代码的哦。

[/QUOTE]

多谢,我可以验证下逆向精度了。
2012-10-28 18:59
0
雪    币: 239
活跃值: (133)
能力值: ( LV5,RANK:60 )
在线值:
发帖
回帖
粉丝
5
你把替换Beep法加载驱动的代码发一份我吧。470779368@qq.com,或者上传到这个帖子吧
2012-10-28 20:46
0
雪    币: 544
活跃值: (264)
能力值: ( LV12,RANK:210 )
在线值:
发帖
回帖
粉丝
6
都是些射手党
2012-10-28 20:52
0
雪    币: 2314
活跃值: (2205)
能力值: (RANK:400 )
在线值:
发帖
回帖
粉丝
7
逆的挺不错的,谢谢。
2012-10-28 21:23
0
雪    币: 220
活跃值: (721)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
8
什么驱动防火墙??
2012-10-28 21:42
0
雪    币: 239
活跃值: (133)
能力值: ( LV5,RANK:60 )
在线值:
发帖
回帖
粉丝
9
恩。。其实我已经实验成功了。。我是给后人留点代码。。
2012-10-28 22:22
0
雪    币: 97697
活跃值: (200829)
能力值: (RANK:10 )
在线值:
发帖
回帖
粉丝
10
Thanks for share.
上传的附件:
2012-10-29 01:55
0
雪    币: 215
活跃值: (90)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
11
怎么都是代码,最好用文字简单总结一下原理。
2012-10-29 10:59
0
雪    币: 219
活跃值: (783)
能力值: (RANK:290 )
在线值:
发帖
回帖
粉丝
12
mark mark
2012-10-29 13:38
0
雪    币: 107
活跃值: (404)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
13
这么简单的逆向也能精华啊????

看来我也可以突破0精华了啊...哇哈哈哈哈..

楼主威武...
2012-10-29 14:53
0
雪    币: 291
活跃值: (213)
能力值: ( LV12,RANK:210 )
在线值:
发帖
回帖
粉丝
14
BeepCancelRoutine似乎有问题?既不StartNextPacket又不CompleteRequest?
取消了当前的IRP就应该Start下一个吧,IRP取消了就要以STATUS_CANCEL状态完成吧。

-------------------------------------------
EDIT: 我没看下面的代码,似乎和nt4代码里的beep还是有点不同的。
2012-10-29 17:19
0
雪    币: 1689
活跃值: (379)
能力值: ( LV15,RANK:440 )
在线值:
发帖
回帖
粉丝
15
终于有人能认真看看这简单的玩意儿了。其实这里也是我没有理解的地方。逆向的逻辑应该没有弄错。

实验过一些情况,也查过文档,某些情况下不调用IoCompleteRequest也是可以的,例程返回后会自动处理。我猜测,这里CancelRoutine是作为IRP被取消后的一个回调,对应的取消标志系统应该设置了。这里不一定要调用IoCompleteRequest。只是猜测,希望一起讨论下这个问题。
2012-10-29 17:56
0
雪    币: 291
活跃值: (213)
能力值: ( LV12,RANK:210 )
在线值:
发帖
回帖
粉丝
16
回家的路上想明白了,XP的beep驱动这样写是没问题的。这个的解释涉及2个标志以及3次锁操作,以及几个API的内部逻辑,非常复杂,我就不避细节了,正好可以给不了解相关内容的朋友参考参考。这里不得不再抱怨一下Legacy的驱动框架,表面上API封装得相当光鲜,用起来就知道陷阱和问题数不胜数。

如果没有耐心看长篇解释,请直接跳到本贴的末尾看蓝字部分。如果看不明白,请回来慢慢看解释。

首先我们需要回顾一下IRP的处理过程。我们都知道,如果IRP不能马上完成,那么通常的选择是采取异步处理机制。在派遣例程中,我们将IRP置为Pending,返回STATUS_PENDING以告诉调用者这个IRP会在将来的某时候完成。随后在某个时候我们调用IoStartPacket以将这个IRP排队或者开始处理。

IoStartPacket做的事情,概括讲就是(省略部分细节,如Cancel标志的检查),首先尝试将IRP排队,如果设备忙,则IRP进入队列,否则置该IRP为当前IRP(DeviceObject->CurrentIrp)并调用驱动的StartIo例程开始处理。

当一个IRP处理完成后,我们通常需要在合适的时候调用IoStartNextPacket以处理下一个IRP,它和IoStartPacket的区别是,它是从队列中取出已有的IRP,置IRP为当前IRP,然后交由StartIo例程进行处理,而不像StartPacket那样是处理新来的IRP。

我们最后再看看IoCancelIrp做的事情,简单讲就是置IRP的Cancel标志(Irp->Cancel)然后交由Cancel例程进行处理。

上面的解释很精简,想了解细节的话,可以自行查阅WRK或者逆向ntoskrnl(有符号的情况下,F5基本和源码一样)。

由于多处理器的环境下存在同步问题,因此需要使用取消锁进行同步。这样,原本清晰的流程中就插入了若干获取锁和释放锁的逻辑。我们先回顾一下MSDN推荐的“标准”流程,具体如下:

IoStartNextPacket(假定该IRP允许Cancel)
获取锁(事件A) > 清空当前IRP > 从队列中取IRP > 置当前IRP > 释放锁(事件A') > 调用StartIo例程 > StartIo获取锁(事件B) > 检查Cancel标志 > 置CancelRoutine为NULL > 释放锁(事件B') > 处理或者返回

IoCancelIrp
获取锁(事件C) > 置Cancel标志 > 置CancelRoutine为NULL > 调用Cancel例程 > Cancel例程检查IRP是否是当前IRP > 如是,则释放锁(事件C')并且调用StartNextPacket;如否,则从队列中移除该IRP并释放锁(事件C'') > 以STATUS_CANCEL完成该IRP

当调用IoCancelIrp时,IRP有两种状态:
1. 还在队列中(事件C先发生)
2. 已经从队列里面出来成为当前IRP准备处理(事件A先发生)

如是情况1,则Cancel例程先得到处理,其中必然会走事件C''分支,也就是说,从队列中移除IRP,释放锁,完成。随后StartNextPacket才得到处理,此时,已经是开始处理队列中下一个IRP了。

如果是情况2,事件A先发生,随后A'释放锁,接着C发生,CancelIrp得到锁,Cancel标志设置,Cancel例程开始处理,此时IRP已经成为当前IRP,例程中走的分支是C',也就是说,释放锁并调用StartNextPacket。锁释放后,StartIo例程再次得到控制权,但它发现Cancel标志已经设置了,因此不做进一步处理即返回。

如果CancelIrp执行太晚,以至于StartNextPacket/StartIo已经第二次得到锁了,这时IRP的处理已不可取消(CancelRoutine被置为NULL),但CancelIrp仍然会设置Cancel标志,只不过StartIo已经不管它了而已。

这是“标准”的流程。我们回到原本的问题上来:beep的IRP处理,究竟和“标准流程”有何不同呢?

答案是:“标准流程”中,即使IRP已经成为当前IRP,仍有机会Cancel;而beep的这个无疑是简化的流程,IRP的两种状态中,只有还在队列中时才能被取消,一旦出了队列,成为了当前处理的IRP,则不可取消。

细节一点,这时的处理流程是:

IoStartNextPacket
获取锁(事件A) > 清空当前IRP > 从队列中取IRP > 置当前IRP > 释放锁(事件A') > 调用StartIo例程 > StartIo获取锁(事件B)  > 置CancelRoutine为NULL >  释放锁(事件B') > 开始处理

IoCancelIrp
获取锁(事件C) > 置Cancel标志 > 置CancelRoutine为NULL > 调用Cancel例程 > Cancel例程检查IRP是否是当前IRP > 如是,则释放锁(事件C')并且返回(标准流程中的这个分支已经没有意义了);如否,则从队列中移除该IRP并释放锁(事件C'')并以STATUS_CANCEL完成该IRP

可见
1. 如果调用CancelIrp的时候,IRP还在队列中,则和“标准流程”相同(Cancel例程C''分支);
2. 一旦IRP出队列成为当前IRP(进入了StartIo例程),StartIo例程就根本不管Cancel标志的设置,IRP必定会由StartIo完成,同时顺便StartNextPacket。所以,标准Cancel例程中的C'分支(当IRP不在队列中,为当前IRP时,调用StartNextPacket并且完成IRP)所做的事情已经被StartIo做了,那这个分支自然就成为多余的了,因此beep的做法是直接释放取消锁并且直接返回。
2012-10-29 23:35
0
雪    币: 316
活跃值: (128)
能力值: ( LV7,RANK:110 )
在线值:
发帖
回帖
粉丝
17
我是来膜拜LS的。
2012-10-30 07:09
0
雪    币: 334
活跃值: (78)
能力值: ( LV3,RANK:30 )
在线值:
发帖
回帖
粉丝
18
有源代码的东西, 为什么要逆向?
2012-10-30 14:46
0
雪    币: 284
活跃值: (34)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
19
mark一下!!
2012-10-30 15:12
0
游客
登录 | 注册 方可回帖
返回
//