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

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

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

#include<ntddk.h>

#pragma warning(disable:4996 )

#define DEVICE_NAME (L"\\Device\\Beep")

#if 0
DRIVER_INITIALIZE   DriverEntry;
DRIVER_UNLOAD       DriverUnload;
DRIVER_STARTIO      BeepStartIoRoutine;
KDEFERRED_ROUTINE   BeepDpcRoutine;
DRIVER_CANCEL       BeepCancelRoutine;
DRIVER_STARTIO      BeepStartIoRoutine;

__drv_dispatchType(IRP_MJ_CLEANUP)  DRIVER_DISPATCH     BeepDispatchCleanup;
__drv_dispatchType(IRP_MJ_DEVICE_CONTROL) DRIVER_DISPATCH BeepDispatchDeviceControl;
__drv_dispatchType(IRP_MJ_CREATE)   DRIVER_DISPATCH     BeepDispatchCreate;
__drv_dispatchType(IRP_MJ_CLOSE)    DRIVER_DISPATCH     BeepDispatchClose;
#endif

//大小为0x58字节
typedef struct _MYDEVICE_EXTENSION
{
    KTIMER      timer;
    FAST_MUTEX  mutex;
    LONG        count_open;
    LONG        count_timer;
    PVOID       hLockedSection;
}MYDEVICE_EXTENSION,*PMYDEVICE_EXTENSION;

VOID
BeepCancelRoutine(
    IN PDEVICE_OBJECT DeviceObject,
    IN PIRP Irp
    );

NTSTATUS
BeepDispatchCleanup(
    IN PDEVICE_OBJECT deviceObject,
    IN PIRP irp
    );

NTSTATUS
BeepDispatchDeviceControl (
    IN PDEVICE_OBJECT deviceObject,
    IN PIRP irp
    );

NTSTATUS
BeepDispatchCreate (
    IN PDEVICE_OBJECT deviceObject,
    IN PIRP irp
    );

NTSTATUS
BeepDispatchClose (
    IN PDEVICE_OBJECT deviceObject,
    IN PIRP irp
    );

VOID
BeepStartIoRoutine(
    IN OUT  PDEVICE_OBJECT  DeviceObject,
    IN PIRP Irp 
    );

VOID
BeepDpcRoutine(
    IN PKDPC  Dpc,
    OPTIONAL IN PVOID  DeferredContext,
    OPTIONAL IN PVOID  SystemArgument1,
    OPTIONAL IN PVOID  SystemArgument2
    );

VOID
DriverUnload(
    IN  PDRIVER_OBJECT          driverObject
    );

NTSTATUS
DriverEntry(
    IN  PDRIVER_OBJECT          driverObject,
    IN  PUNICODE_STRING         registryPath
    );


//===================================实现===================================
VOID
BeepCancelRoutine(
    IN PDEVICE_OBJECT DeviceObject,
    IN PIRP Irp
    )
{

    if( Irp == DeviceObject->CurrentIrp || 
        !KeRemoveEntryDeviceQueue( &DeviceObject->DeviceQueue,&Irp->Tail.Overlay.DeviceQueueEntry))
    {
        IoReleaseCancelSpinLock( Irp->CancelIrql );
    }
    else
    {
        IoReleaseCancelSpinLock( Irp->CancelIrql );
        Irp->IoStatus.Information = 0;
        Irp->IoStatus.Status = 0xc0000120;
        IoCompleteRequest( Irp,IO_NO_INCREMENT );
    }
}

NTSTATUS
BeepDispatchCleanup(
    IN PDEVICE_OBJECT deviceObject,
    IN PIRP irp
    )
{
    KIRQL   irql,oldIrql;
    PIRP    currIrp = NULL;

    oldIrql = KeRaiseIrqlToDpcLevel();
    IoAcquireCancelSpinLock( &irql );
    
    currIrp = deviceObject->CurrentIrp;
    deviceObject->CurrentIrp = NULL;
    if( currIrp != NULL )
    {
        PKDEVICE_QUEUE_ENTRY  entry = NULL;
        
        for( entry = KeRemoveDeviceQueue( &deviceObject->DeviceQueue);
             entry != NULL;
             entry = KeRemoveDeviceQueue( &deviceObject->DeviceQueue))
        {
            PIRP    pIrp = (PIRP)CONTAINING_RECORD( entry,IRP,Tail.Overlay.DeviceQueueEntry);
            
            pIrp->CancelRoutine = NULL;
            pIrp->IoStatus.Information = 0;
            pIrp->IoStatus.Status = 0xc0000120;
            IoReleaseCancelSpinLock( irql );
            IoCompleteRequest( pIrp,IO_NO_INCREMENT );

            IoAcquireCancelSpinLock( &irql );
        }//for
    }//if

    IoReleaseCancelSpinLock( irql );
    KeLowerIrql( oldIrql);

    irp->IoStatus.Status = STATUS_SUCCESS;
    irp->IoStatus.Information = 0;
    IoCompleteRequest( irp,IO_NO_INCREMENT );
    HalMakeBeep( 0 );

    return STATUS_SUCCESS;
}

NTSTATUS
BeepDispatchDeviceControl (
    IN PDEVICE_OBJECT deviceObject,
    IN PIRP irp
    )
{
    PIO_STACK_LOCATION  irpSp = IoGetCurrentIrpStackLocation( irp );
    NTSTATUS            status = STATUS_SUCCESS;
    PULONG              in_buffer = NULL;

    if( irpSp->Parameters.DeviceIoControl.IoControlCode != 0x10000 ||
        irpSp->Parameters.DeviceIoControl.InputBufferLength < 8 )
    {
        status = STATUS_INVALID_PARAMETER;
        goto exit;
    }

    in_buffer = (PULONG)irp->AssociatedIrp.SystemBuffer;
    if( in_buffer[0] != 0 && in_buffer[1] == 0 )
        status = STATUS_SUCCESS;
    else
        status = 0x103;

exit:
    irp->IoStatus.Information = 0;
    irp->IoStatus.Status = status;
    if( status == 0x103 )
    {
        irpSp->Control |= SL_PENDING_RETURNED;
        IoStartPacket( deviceObject,irp,0,(PDRIVER_CANCEL)BeepCancelRoutine );
    }
    else
        IoCompleteRequest( irp,IO_NO_INCREMENT );

    return status;
}

NTSTATUS
BeepDispatchCreate (
    IN PDEVICE_OBJECT deviceObject,
    IN PIRP irp
    )
{
    PMYDEVICE_EXTENSION devExt = (PMYDEVICE_EXTENSION)deviceObject->DeviceExtension;

    ExAcquireFastMutex( &devExt->mutex );
    if( ++devExt->count_open == 1 )
    {
        devExt->hLockedSection = MmLockPagableDataSection( BeepDispatchCreate );
    }
    ExReleaseFastMutex( &devExt->mutex );

    irp->IoStatus.Status = STATUS_SUCCESS;
    irp->IoStatus.Information = 0;
    IoCompleteRequest( irp,IO_NO_INCREMENT );

    return STATUS_SUCCESS;
}

NTSTATUS
BeepDispatchClose (
    IN PDEVICE_OBJECT deviceObject,
    IN PIRP irp
    )
{
    PMYDEVICE_EXTENSION devExt = (PMYDEVICE_EXTENSION)deviceObject->DeviceExtension;

    ExAcquireFastMutex( &devExt->mutex );
    if( --devExt->count_open == 0 )
    {
        MmUnlockPagableImageSection( &devExt->hLockedSection );
        if( devExt->count_timer != 0 && KeCancelTimer( &devExt->timer ))
            InterlockedDecrement( &devExt->count_timer); 
    }
    ExReleaseFastMutex( &devExt->mutex );

    irp->IoStatus.Status = STATUS_SUCCESS;
    irp->IoStatus.Information = 0;
    IoCompleteRequest( irp,IO_NO_INCREMENT );

    return STATUS_SUCCESS;
}

VOID
BeepStartIoRoutine(
    IN PDEVICE_OBJECT  DeviceObject,
    IN PIRP  Irp 
    )
{
    KIRQL               irql;
    PMYDEVICE_EXTENSION devExt = (PMYDEVICE_EXTENSION)DeviceObject->DeviceExtension;
    PKTIMER             timer = &devExt->timer;
    PIO_STACK_LOCATION  irpSp = NULL;
    NTSTATUS            status = STATUS_SUCCESS;

    IoAcquireCancelSpinLock( &irql );
    if( NULL == Irp )
    {
        IoReleaseCancelSpinLock( irql );
        return;
    }
    Irp->CancelRoutine = NULL;
    IoReleaseCancelSpinLock( irql );

    irpSp = IoGetCurrentIrpStackLocation( Irp );
    if( irpSp->Parameters.DeviceIoControl.IoControlCode != 0x10000 )
        status = STATUS_INVALID_PARAMETER;
    else
    {
        PULONG     in_buffer = Irp->AssociatedIrp.SystemBuffer;

        if( devExt->count_timer != 0 && KeCancelTimer( timer ))
            InterlockedDecrement( &devExt->count_timer );

        if( HalMakeBeep(in_buffer[0]))
        {
            LARGE_INTEGER   dueTime={0};

            status = STATUS_SUCCESS;
            InterlockedIncrement( &devExt->count_timer );
            dueTime.QuadPart = (LONGLONG)-10000 * in_buffer[1];
            if(KeSetTimer( timer,dueTime,&DeviceObject->Dpc ))
                InterlockedDecrement( &devExt->count_timer);
        }
        else
            status = STATUS_INVALID_PARAMETER;
    }

    Irp->IoStatus.Information = 0;
    Irp->IoStatus.Status = status;
    IoStartNextPacket( DeviceObject,TRUE );
    IoCompleteRequest( Irp,IO_NO_INCREMENT );
}


VOID
BeepDpcRoutine(
    IN PKDPC  Dpc,
    OPTIONAL IN PVOID  DeferredContext,
    OPTIONAL IN PVOID  SystemArgument1,
    OPTIONAL IN PVOID  SystemArgument2
    )
{
    PDEVICE_OBJECT  devObj = (PDEVICE_OBJECT)DeferredContext;
    PMYDEVICE_EXTENSION devExt = (PMYDEVICE_EXTENSION)devObj->DeviceExtension;

    HalMakeBeep( 0 );
    InterlockedDecrement( &devExt->count_timer );
}

VOID
DriverUnload(
    IN  PDRIVER_OBJECT          driverObject
    )
{
    PDEVICE_OBJECT  devObj = driverObject->DeviceObject;
    PMYDEVICE_EXTENSION devExt = (PMYDEVICE_EXTENSION)devObj->DeviceExtension;

    if( devExt->count_timer != 0 && KeCancelTimer( &devExt->timer))
        InterlockedDecrement( &devExt->count_timer );
    IoDeleteDevice( devObj );

}


NTSTATUS
DriverEntry(
    IN  PDRIVER_OBJECT          driverObject,
    IN  PUNICODE_STRING         registryPath
    )
/*++
--*/
{
    NTSTATUS        status = STATUS_SUCCESS;
    UNICODE_STRING  devName = {0};
    PDEVICE_OBJECT  devObj = NULL;
    PMYDEVICE_EXTENSION devExt = NULL;

    _asm int 3;
    RtlInitUnicodeString( &devName,DEVICE_NAME );

    status = IoCreateDevice( driverObject,
                            sizeof(MYDEVICE_EXTENSION),
                            &devName,
                            FILE_DEVICE_BEEP,
                            FILE_DEVICE_SECURE_OPEN,
                            FALSE,
                            &devObj);
    if( STATUS_SUCCESS != status )
        goto exit_with_status;

    devObj->Flags |= DO_BUFFERED_IO;

    devExt = (PMYDEVICE_EXTENSION)devObj->DeviceExtension;
    KeInitializeDpc( &devObj->Dpc,(PKDEFERRED_ROUTINE )BeepDpcRoutine,devObj);
    KeInitializeTimer( &devExt->timer );
    ExInitializeFastMutex( &devExt->mutex );
    devExt->count_timer = devExt->count_open = 0;

    driverObject->DriverStartIo = BeepStartIoRoutine;
    driverObject->DriverUnload =  DriverUnload;
    driverObject->MajorFunction[IRP_MJ_CREATE] = BeepDispatchCreate;
    driverObject->MajorFunction[IRP_MJ_CLOSE] =  BeepDispatchClose;
    driverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = BeepDispatchDeviceControl;
    driverObject->MajorFunction[IRP_MJ_CLEANUP] = BeepDispatchCleanup;

    return STATUS_SUCCESS;

exit_with_status:
    return status;
}

[课程]FART 脱壳王!加量不加价!FART作者讲授!

上传的附件:
收藏
免费 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
雪    币: 2177
活跃值: (2045)
能力值: (RANK:400 )
在线值:
发帖
回帖
粉丝
7
逆的挺不错的,谢谢。
2012-10-28 21:23
0
雪    币: 220
活跃值: (701)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
8
什么驱动防火墙??
2012-10-28 21:42
0
雪    币: 239
活跃值: (133)
能力值: ( LV5,RANK:60 )
在线值:
发帖
回帖
粉丝
9
恩。。其实我已经实验成功了。。我是给后人留点代码。。
2012-10-28 22:22
0
雪    币: 93908
活跃值: (200199)
能力值: (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
活跃值: (738)
能力值: (RANK:290 )
在线值:
发帖
回帖
粉丝
12
mark mark
2012-10-29 13:38
0
雪    币: 107
活跃值: (326)
能力值: ( 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
游客
登录 | 注册 方可回帖
返回
//