能力值:
( LV3,RANK:30 )
|
-
-
2 楼
Well Done
|
能力值:
( LV2,RANK:10 )
|
-
-
3 楼
哥们, 这个nt4里面有代码的哦。
|
能力值:
( LV15,RANK:440 )
|
-
-
4 楼
[QUOTE=HitIt;1113055]哥们, 这个nt4里面有代码的哦。
[/QUOTE]
多谢,我可以验证下逆向精度了。
|
能力值:
( LV5,RANK:60 )
|
-
-
5 楼
你把替换Beep法加载驱动的代码发一份我吧。470779368@qq.com,或者上传到这个帖子吧
|
能力值:
( LV12,RANK:210 )
|
-
-
6 楼
都是些射手党
|
能力值:
(RANK:400 )
|
-
-
7 楼
逆的挺不错的,谢谢。
|
能力值:
( LV2,RANK:10 )
|
-
-
8 楼
什么驱动防火墙??
|
能力值:
( LV5,RANK:60 )
|
-
-
9 楼
恩。。其实我已经实验成功了。。我是给后人留点代码。。
|
能力值:
(RANK:10 )
|
-
-
10 楼
Thanks for share.
|
能力值:
( LV3,RANK:30 )
|
-
-
11 楼
怎么都是代码,最好用文字简单总结一下原理。
|
能力值:
(RANK:290 )
|
-
-
12 楼
mark mark
|
能力值:
( LV2,RANK:10 )
|
-
-
13 楼
这么简单的逆向也能精华啊????
看来我也可以突破0精华了啊...哇哈哈哈哈..
楼主威武...
|
能力值:
( LV12,RANK:210 )
|
-
-
14 楼
BeepCancelRoutine似乎有问题?既不StartNextPacket又不CompleteRequest?
取消了当前的IRP就应该Start下一个吧,IRP取消了就要以STATUS_CANCEL状态完成吧。
-------------------------------------------
EDIT: 我没看下面的代码,似乎和nt4代码里的beep还是有点不同的。
|
能力值:
( LV15,RANK:440 )
|
-
-
15 楼
终于有人能认真看看这简单的玩意儿了。其实这里也是我没有理解的地方。逆向的逻辑应该没有弄错。
实验过一些情况,也查过文档,某些情况下不调用IoCompleteRequest也是可以的,例程返回后会自动处理。我猜测,这里CancelRoutine是作为IRP被取消后的一个回调,对应的取消标志系统应该设置了。这里不一定要调用IoCompleteRequest。只是猜测,希望一起讨论下这个问题。
|
能力值:
( 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的做法是直接释放取消锁并且直接返回。
|
能力值:
( LV7,RANK:110 )
|
-
-
17 楼
我是来膜拜LS的。
|
能力值:
( LV3,RANK:30 )
|
-
-
18 楼
有源代码的东西, 为什么要逆向?
|
能力值:
( LV2,RANK:10 )
|
-
-
19 楼
mark一下!!
|
|
|