2012年8月24日星期五

IoAllocateIrp.C


/*
首先声明这段代码摘抄自网络:删除正在运行的文件的c驱动代码
这段代码放了很久了,网上了多得是。
不是因为功能牛屄。而是一种思路。
解决了重入的问题,不受好多的限制,缺点是数据结构不是公开的,通用性差。
用Nt和Zw系列也能实现,但有好多的限制,在某些情况下还会引起IRP的重入。
类似的功能还有发IRP改名,查询,新建,读写等。
我想类似的功能在WRK,reactos等里面会有的。
*/

#include <ntddk.h>

VOID SKillUnloadDriver(IN PDRIVER_OBJECT DriverObject) { }

NTSTATUS SkillSetFileCompletion(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PVOID Context)
{
    Irp->UserIosb->Status = Irp->IoStatus.Status;
    Irp->UserIosb->Information = Irp->IoStatus.Information;
    KeSetEvent(Irp->UserEvent, IO_NO_INCREMENT, FALSE);
    IoFreeIrp(Irp);
    return STATUS_MORE_PROCESSING_REQUIRED;
}

BOOLEAN SKillStripFileAttributes(IN HANDLE    FileHandle)
{
    PFILE_OBJECT      fileObject;
    PDEVICE_OBJECT    DeviceObject;
    PIRP              Irp;
    KEVENT            event1;
    FILE_BASIC_INFORMATION    FileInformation = {0};
    IO_STATUS_BLOCK ioStatus;
    PIO_STACK_LOCATION irpSp;

    if (KeGetCurrentIrql() > PASSIVE_LEVEL)   {
        return FALSE;
    }

    ObReferenceObjectByHandle(FileHandle,DELETE,*IoFileObjectType,KernelMode,&fileObject,NULL);//我想知道的是这个文件句柄是在哪个进程的句柄表中
    if (fileObject == 0)   {
        return FALSE;
    }

    DeviceObject = IoGetRelatedDeviceObject(fileObject);
    Irp = IoAllocateIrp(DeviceObject->StackSize, TRUE);

    KeInitializeEvent(&event1,SynchronizationEvent,FALSE);

    FileInformation.FileAttributes = FILE_ATTRIBUTE_NORMAL;
    Irp->AssociatedIrp.SystemBuffer = &FileInformation;
    Irp->UserEvent = &event1;
    Irp->UserIosb = &ioStatus;
    Irp->Tail.Overlay.OriginalFileObject = fileObject;
    Irp->Tail.Overlay.Thread = (PETHREAD)KeGetCurrentThread();
    Irp->RequestorMode = KernelMode;

    irpSp = IoGetNextIrpStackLocation(Irp);
    irpSp->MajorFunction = IRP_MJ_SET_INFORMATION;
    irpSp->DeviceObject = DeviceObject;
    irpSp->FileObject = fileObject;
    irpSp->Parameters.SetFile.Length = sizeof(FILE_BASIC_INFORMATION);
    irpSp->Parameters.SetFile.FileInformationClass = FileBasicInformation;
    irpSp->Parameters.SetFile.FileObject = fileObject;

    IoSetCompletionRoutine(Irp,SkillSetFileCompletion,&event1,TRUE,TRUE,TRUE);
    IoCallDriver(DeviceObject, Irp);
    //调用这个设备对象的驱动对象,并且IO_StACK_LOCAtion会指向下一个,也就是刚刚设置的
    //如果没有文件系统驱动建立的设备对象没有Attacked的话,就调用文件系统驱动的IRP_MJ_SET_INFORMATION分派例程
    //会调用NTFS.sys驱动的NtfsFsdSetInformation例程,再会进入NtfsSetBasicInfo()函数,最后它会设置代表此文件的FCB(文件
    //控制块结构的一些信息,用来设置代表此文件的属性。最后不知道在哪里会调用IoCompleteRequest,它会依次调用先前设置的回调函数
    //回调函数会释放刚分配的IRP和设置事件对象为受信状态。

    KeWaitForSingleObject(&event1,Executive,KernelMode,TRUE,NULL);//一等到事件对象变成受信状态就会继续向下执行。

    ObDereferenceObject(fileObject);
    return TRUE;
}

BOOLEAN SKillDeleteFile(IN HANDLE FileHandle)
{
    NTSTATUS          ntStatus = STATUS_SUCCESS;
    PFILE_OBJECT      fileObject;
    PDEVICE_OBJECT    DeviceObject;
    PIRP              Irp;
    KEVENT            event1;
    FILE_DISPOSITION_INFORMATION    FileInformation;
    IO_STATUS_BLOCK ioStatus;
    PIO_STACK_LOCATION irpSp;
    PSECTION_OBJECT_POINTERS pSectionObjectPointer;

    if (KeGetCurrentIrql() > PASSIVE_LEVEL)   {
        return FALSE;
    }

    SKillStripFileAttributes(FileHandle); //去掉只读属性,才能删除只读文件
    ntStatus = ObReferenceObjectByHandle(FileHandle, DELETE, *IoFileObjectType, KernelMode, &fileObject, NULL);
    if (!NT_SUCCESS(ntStatus))   return FALSE;

    DeviceObject = IoGetRelatedDeviceObject(fileObject);//如果NTFS.sys驱动建立的设备对象上没有附加的设备对象的话,就返回NTFS.sys建立的设备对象 //否则返回的是这个设备对象的highest level设备对象。
    Irp = IoAllocateIrp(DeviceObject->StackSize, TRUE);//如果没有附加,StackSize为7

    KeInitializeEvent(&event1,SynchronizationEvent,FALSE);
    FileInformation.DeleteFile = TRUE;

    Irp->AssociatedIrp.SystemBuffer = &FileInformation;
    Irp->UserEvent = &event1;
    Irp->UserIosb = &ioStatus;
    Irp->Tail.Overlay.OriginalFileObject = fileObject;
    Irp->Tail.Overlay.Thread = (PETHREAD)KeGetCurrentThread();
    Irp->RequestorMode = KernelMode;

    irpSp = IoGetNextIrpStackLocation(Irp);            //得到文件系统NTFS.sys驱动的设备IO_STACK_LOCATION
    irpSp->MajorFunction = IRP_MJ_SET_INFORMATION;
    irpSp->DeviceObject = DeviceObject;
    irpSp->FileObject = fileObject;
    irpSp->Parameters.SetFile.Length = sizeof(FILE_DISPOSITION_INFORMATION);
    irpSp->Parameters.SetFile.FileInformationClass = FileDispositionInformation;
    irpSp->Parameters.SetFile.FileObject = fileObject;

    IoSetCompletionRoutine(Irp, SkillSetFileCompletion, &event1, TRUE, TRUE, TRUE);

    //再加上下面这三行代码 ,MmFlushImageSection    函数通过这个结构来检查是否可以删除文件。
    pSectionObjectPointer = fileObject->SectionObjectPointer;
    pSectionObjectPointer->ImageSectionObject = 0;
    pSectionObjectPointer->DataSectionObject = 0;

    IoCallDriver(DeviceObject, Irp);
    //这里会依次进入NTFS.sys驱动的NtfsFsdSetInformation例程->NtfsSetDispositionInfo()->MmFlushImageSection(),
    //MmFlushImageSection()这函数是用来检查FILE_OBJECT对象的SECTION_OBJECT_POINTER结构的变量,检查这个文件
    //在内存有没有被映射。也就是有没有执行。如果上面那样设置了,也就是说文件可以删除了。我们也可以HOOK NTFS.sys导入表中的
    //的MmFlushImageSection(),来检查这个文件对象是不是我们要删除 的,是的话,返回TRUE就行了。

    KeWaitForSingleObject(&event1, Executive, KernelMode, TRUE, NULL);

    ObDereferenceObject(fileObject);
    return TRUE;
}

NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject,IN PUNICODE_STRING RegistryPath)
{
    UNICODE_STRING        uniFileName;
    OBJECT_ATTRIBUTES     objectAttributes;
    HANDLE                ntFileHandle;
    IO_STATUS_BLOCK       ioStatus;
    NTSTATUS              ntStatus;

    _asm int 3

    DriverObject->DriverUnload = SKillUnloadDriver;  

    RtlInitUnicodeString(&uniFileName, L"\\Device\\HarddiskVolume1\\test.exe");//我虚拟机win 7上的HarddiskVolume1不是c盘。
    InitializeObjectAttributes(&objectAttributes,&uniFileName,OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE,0,0);
    ntStatus = IoCreateFile(&ntFileHandle,FILE_READ_ATTRIBUTES,&objectAttributes,&ioStatus,0,FILE_ATTRIBUTE_NORMAL,FILE_SHARE_DELETE,FILE_OPEN,0,0,0,0,0,IO_NO_PARAMETER_CHECKING);
    if (ntFileHandle == 0)   {
        return 0;
    }

    SKillDeleteFile(ntFileHandle);
    ZwClose(ntFileHandle);
    return STATUS_SUCCESS;
}

2012年8月1日星期三

nt!DebugService2


一般的断点都是断在:
nt!DbgBreakPointWithStatus:
                           fffff800`01883f60 cc              int     3
                           fffff800`01883f61 c3              ret
等地方的,
有时会出现在下面:
nt!DebugService2:
                           fffff800`01883fb0 418bc0          mov     eax,r8d
                           fffff800`01883fb3 cd2d            int     2Dh
                           fffff800`01883fb5 cc              int     3
                           fffff800`01883fb6 c3              ret
                           fffff800`01883fb7 90              nop
这是因为以前设置的断点,而自己的代码已经改变,并重新编译,调试,才出现的。
解决办法:删除所有的断点,然后继续运行既可以。
bc *
g
ok!

小东西,记住,以后忘了,来这里查看。
made by correy
made at 2012.08.01