dev.nlited.com

>>

Driver2

<<<< prev
next >>>>

2017-08-30 19:50:28 chip Page 2006 📢 PUBLIC

August 30 2017

The CryptDisk driver is now mostly working and I have arrived at a fork in the development path. There was a lot of experimentation, trial-and-error, and copy/paste code involved in bringing the driver to life and it shows. The driver project contains a lot of code that has been commented out or is never called, and these code barnacles can cause a lot of grief later. There is the mystery as to why the current driver refuses to unload when earlier versions did.

I can either continue with the driver project in its current state and whittle it down. Or I can start a new project and build it up, pulling in only the pieces of the current project that I actually need. Starting fresh invariably leads to a better product, but it means a lull in the project as I spend a couple days rewriting the same old thing -- lateral progress at best.

So today will be spent creating a new driver project, this time paying more attention to usability concerns such as mount/unmount and load/unload.

UPDATE [20170901]: Driver2 was definitely the right decision.

The first task is to make sure I am starting from the proper code base. I have three active branches:

I switched to the Work branch, rebuilt the solution, and tested it to make sure it was OK. This turned out to be the crippled version, so I need to revert back a step. This version hung when I tried to format the disk. This won't be as easy as I hoped, I need to figure out which version actually works:
e4c3288 (HEAD -> Work) Working on Unload. 0efd40a (origin/master, origin/Work, master) Mount/Unmount is now working. aa3966c Trying to figure out control/disk transition. 6f3d7bb Removed dead code. 4bbc42f Cleaned up the control device creation. 70252b1 Added device enumeration. Cleaning up DeviceCtrl. fe7f33a This version works. 3662a2a Split Device.cpp into DeviceCtrl.cpp and DeviceDisk.cpp abbf334 (origin/LoadCreate) Disabled the initial breakpoint. 94a8212 This version mostly works. dffc77c Trying to figure out why I can't access CryptDisk01. 0b36f1b Fixed a bunch of NtString bugs. Disk device is now being created. Media file is being created. Not creating volu me link yet. 8a515bf DeviceCtrl now handles the initial mount command. Disk devices are now created on demand. 9f64dfb CryptDriver builds, but is not functional yet. Integrated NtString. e4cc67b NtString now builds. b60199f Added NtString class. 7024256 Fixed unload bug. Still no volumes appearing. 7d36d0b Fixed app unmount command. af4ea4a Added mount/unmount code. 3d90dfe Wrote a lot of CryptDisk code. First complete build. 2d5caf7 Removed dead code. ee99f13 Added functions to create the NT and DOS device names. 9777eca The driver now unloads properly. 4e438ac Created the control device. 2ae5d08 Added Driver infrastructure. 9d82bd8 Driver builds, loads, and unloads. c58a2bb Initial CryptDisk commit. Forked from DbgOut13.

Results of testing each version:
fe7f33a: I am able to format the disk.
70252b1: BugCheck in CtrlFile::Read()
4bbc42f: Worked.
6f3d7bb: Old loader. Format starts but never completes.
0efd40a: New loader. Format does not work.

The format hang happens when I try to reformat an existing media file, which is a newly discovered bug that exists in all versions. This invalidates my testing so I need to start testing from the top, this time being sure to delete the media file before loading the driver...

Results:
0efd40a: Format dialog never appears.
aa3966c: New loader. Format dialog never appears.
6f3d7bb: Old loader. Format dialog appears but does not complete.
4bbc42f: Old loader. Format is successful.

I need to commit my code much more frequently! I also need to write up a formal test plan to complete before merging into master.

One of these versions recreated the zombie device, so now I need to dump the VM and rebuild it before doing any work on load/unload.

This fun little exercise took about three hours, but now I have a much better sense of what works and what doesn't. For the next iteration of the driver I will be avoiding MountManager until much later (if ever) and concentrate on making sure load/unload, mount/unmount, and format operation is working at each step.

Driver2

August 30 2017, 1pm

I want to use the driver code from 4bbc42f as my reference for Driver2, while retaining the latest version of the loader and everything else. I checkout 4bbc42f and copy the entire CryptDisk directory tree to CryptDisk.4bbc42f where I can use it as a reference without constantly switching branches. I switch to the master branch, merge Work to save it, then switch to the Work branch. I push everything to my repo in the sky. I switch to Work, then create a new branch named "Driver2".

Now I am finally ready to create my new Driver2 project. All the settings and configuration will be exactly like the existing Driver project. One of the first changes I want to make is to extract some of the support files from the Driver project to a separate WinKM library project: Error.c, New.cpp, NtString.cpp, and System.c. I create the WinKM project using the same settings.

It took about 40 minutes to create the two new projects and load CryptDriver v2.0 for the first time.
CryptDriver has arrived! CryptDriver version 2.0.285 [VS12] VS12 DriverEntry=FFFFF80CE3F31000 pDriver=FFFFE38074C1CE60 It is just an empty DriverEntry() at this point. Now I can start pulling code from the Driver (v1.0) project.

My first task was to track down the "won't unload" bug, which was polite enough to show up as soon as I wrote the IRP handler for the control device. The Driver2 project was still tiny, making it easier to track down what turned out to be a very obtuse bug.

Control Worker Thread

DriverEntry() creates the control device. This time I want to create a worker thread to handle the requests. This should allow me to create the disk devices on demand without running into context problems.

I created the IrpThread class to make it easier to add deferred IRP processing:


IrpThread: class IrpThread { public: IrpThread(void); ~IrpThread(void); static IrpThread *Ptr(void *pObj); void SetDebug(const char *Tag=0, DWORD DbgMask1=0, DWORD DbgMask2=0); NTSTATUS Start(DEVICE_OBJECT *pDevice); NTSTATUS Stop(void); NTSTATUS Add(IRP *pIrp); virtual NTSTATUS IrpDeferredDispatch(DEVICE_OBJECT *pDevice, IRP *pIrp)= 0; //Data protected: private: static void IrpProc(void *pObj); NTSTATUS Worker(void); NTSTATUS AdjustPrivileges(ULONG Privilege, bool Enable); //Data DWORD Signature_IrpThread; DEVICE_OBJECT *pIrpDevice; //Owner device bool DoExitThread; //Set to exit the thread gracefully. LIST_ENTRY IrpList; //List of pending IRPs KSPIN_LOCK ListLock; //Control access to ListHead KEVENT evTask; //Signals a new IRP has been added. KEVENT evThread; //Signals when thread exits. void *pThread; //Worker thread DWORD DbgMask1; //Debug() mask for start/stop events. DWORD DbgMask2; //Debug() mask for each IRP. char Tag[20]; //Debug tag };
/*************************************************************************/ /** IrpThread.cpp: Create a system thread to handled deferred IRPs. **/ /** (C)2017 nlited systems, Chip Doran **/ /*************************************************************************/ #pragma once #define __OSKERNEL_H__ #include "OsKernel.h" #include "Errors.h" #include <ntstrsafe.h> IrpThread::IrpThread(void) { Signature_IrpThread= SIGNATURE_IRP_THREAD; DoExitThread= false; InitializeListHead(&IrpList); KeInitializeSpinLock(&ListLock); KeInitializeEvent(&evTask,SynchronizationEvent,0); KeInitializeEvent(&evThread,SynchronizationEvent,0); RtlZeroBytes(Tag,sizeof(Tag)); RtlStringCbCopyA(Tag,sizeof(Tag),"<noname>"); DbgMask1= DbgMask2= 0; } IrpThread::~IrpThread(void) { Signature_IrpThread|= SIGNATURE_INVALID; DoExitThread= true; KeSetEvent(&evTask,0,0); } IrpThread *IrpThread::Ptr(void *pObj) { IrpThread *pThread= (IrpThread*)pObj; if(!pObj || pThread->Signature_IrpThread!=SIGNATURE_IRP_THREAD) pThread= 0; return(pThread); } void IrpThread::SetDebug(const char *_Tag, DWORD _DbgMask1, DWORD _DbgMask2) { if(_Tag) RtlStringCbCopyA(Tag,sizeof(Tag),_Tag); if(_DbgMask1) DbgMask1= _DbgMask1; if(_DbgMask2) DbgMask2= _DbgMask2; } NTSTATUS IrpThread::Start(DEVICE_OBJECT *_pDevice) { NTSTATUS Status= STATUS_SUCCESS; HANDLE hThread; pIrpDevice= _pDevice; if(!NT_SUCCESS(Status= PsCreateSystemThread(&hThread,0,0,0,0,IrpProc,this))) return(Warn(Status,"IrpThread:Start(%s): PsCreateSystemThread() failed.",Tag)); if(!NT_SUCCESS(Status= ObReferenceObjectByHandle(hThread,THREAD_ALL_ACCESS,0,KernelMode,&pThread,0))) Warn(Status,"IrpThread:Start(%s): ObReferenceObjectByHandle(hThread) failed."); ZwClose(hThread); //pThread holds it open. Why call ZwClose()? return(Status); } NTSTATUS IrpThread::Stop(void) { NTSTATUS Status= STATUS_SUCCESS; if(DbgMask1) Debug(DbgMask1,"IrpThread:Stop(%s): Waiting for thread exit...",Tag); DoExitThread= true; KeSetEvent(&evTask,0,0); KeWaitForSingleObject(&evThread,Executive,KernelMode,FALSE,0); if(DbgMask1) Debug(DbgMask1,"IrpThread:Stop(%s): Thread is dead.",Tag); return(Status); } NTSTATUS IrpThread::Add(IRP *pIrp) { pIrp->IoStatus.Status= STATUS_PENDING; IoMarkIrpPending(pIrp); ExInterlockedInsertTailList(&IrpList,&pIrp->Tail.Overlay.ListEntry,&ListLock); KeSetEvent(&evTask,0,0); return(STATUS_PENDING); } void IrpThread::IrpProc(void *pObj) { IrpThread *pThread= Ptr(pObj); if(pThread) pThread->Worker(); } NTSTATUS IrpThread::Worker(void) { NTSTATUS Status= STATUS_SUCCESS; if(DbgMask1) Debug(DbgMask1,"IrpThread:Worker(%s): Waiting for requests...",Tag); KeSetPriorityThread(KeGetCurrentThread(),LOW_REALTIME_PRIORITY); AdjustPrivileges(SE_IMPERSONATE_PRIVILEGE,TRUE); while(!DoExitThread) { LIST_ENTRY *pEntry; KeWaitForSingleObject(&evTask,Executive,KernelMode,FALSE,0); while(pEntry= ExInterlockedRemoveHeadList(&IrpList,&ListLock)) { IRP *pIrp= CONTAINING_RECORD(pEntry,IRP,Tail.Overlay.ListEntry); if(DbgMask2) { IO_STACK_LOCATION *pStack= IoGetCurrentIrpStackLocation(pIrp); Debug(DbgMask2,"IrpThread:Worker(%s): IRP %d [%p]",Tag,pStack->MajorFunction,pIrp); } IrpDeferredDispatch(pIrpDevice,pIrp); //IoCompleteRequest(pIrp,IO_NO_INCREMENT); } } if(DbgMask1) Debug(DbgMask1,"IrpThread:Worker(%s): Thread exit.",Tag); KeSetEvent(&evThread,0,0); PsTerminateSystemThread(STATUS_SUCCESS); return(Status); } NTSYSAPI NTSTATUS NTAPI ZwOpenProcessToken ( IN HANDLE ProcessHandle, IN ACCESS_MASK DesiredAccess, OUT PHANDLE TokenHandle ); NTSYSAPI NTSTATUS NTAPI ZwAdjustPrivilegesToken ( IN HANDLE TokenHandle, IN BOOLEAN DisableAllPrivileges, IN PTOKEN_PRIVILEGES NewState, IN ULONG BufferLength, OUT PTOKEN_PRIVILEGES PreviousState OPTIONAL, OUT PULONG ReturnLength ); NTSTATUS IrpThread::AdjustPrivileges(ULONG Privilege, bool Enable) { NTSTATUS Status= STATUS_SUCCESS; HANDLE hToken; TOKEN_PRIVILEGES TknPrivileges; if(!NT_SUCCESS(Status= ZwOpenProcessTokenEx(NtCurrentProcess(),TOKEN_ALL_ACCESS,OBJ_KERNEL_HANDLE,&hToken))) return(Status); TknPrivileges.PrivilegeCount= 1; TknPrivileges.Privileges[0].Luid= RtlConvertUlongToLuid(Privilege); TknPrivileges.Privileges[0].Attributes= Enable ? SE_PRIVILEGE_ENABLED:0; //Status= ZwAdjustPrivilegesToken(hToken,FALSE,&TknPrivileges,sizeof(TknPrivileges),0,0); ZwClose(hToken); return(Status); } //EOF: IRPTHREAD.CPP

The new DeviceCtrl with deferred reads:

DeviceCtrl: /*************************************************************************/ /** DeviceCtrl.cpp: The control device. **/ /** (C)2017 nlited systems inc, Chip Doran **/ /*************************************************************************/ #include <new> #include <ntifs.h> #include <ntdddisk.h> #include <mountmgr.h> #include <ntddvol.h> #include <ntddscsi.h> #include <wdmsec.h> #include "Handles.h" #include "VerID.h" #include "Globals.h" #include "Device.h" #include "CryptDisk.h" #pragma message(__FILE__": Optimizer disabled.") #pragma optimize("",off) class DeviceCtrl: public DeviceExt,IrpThread { public: static DeviceCtrl *Ptr(DEVICE_OBJECT *pDevice); static NTSTATUS Create(DRIVER_OBJECT *pDriver); NTSTATUS Destroy(void); private: DeviceCtrl(DRIVER_OBJECT *pDriver, DEVICE_OBJECT *pDevice); ~DeviceCtrl(void); NTSTATUS Create2(NtString &Name); static const WCHAR *MakeNameNT(NtString &Name); const WCHAR *MakeNameDos(NtString &Name); NTSTATUS QueryDevice(struct DeviceInfo_s *pInfo); NTSTATUS IrpDispatch2(IRP *pIrp); NTSTATUS IrpOpen(IRP *pIrp); NTSTATUS IrpClose(IRP *pIrp); NTSTATUS IrpCleanUp(IRP *pIrp); NTSTATUS IrpRead(IRP *pIrp); NTSTATUS IrpIoControl(IRP *pIrp); NTSTATUS IoctlQueryDevice(IRP *pIrp); NTSTATUS IoctlMount(IRP *pIrp); NTSTATUS FindDiskByID(UINT DeviceID, DEVICE_OBJECT *&pDevice); NTSTATUS IrpDeferredDispatch(DEVICE_OBJECT *pDevice, IRP *pIrp); NTSTATUS DefRead(IRP *pIrp); //Data DWORD Signature_DeviceCtrl; LIST_ENTRY ListHead; //List if pending IRPs KSPIN_LOCK ListLock; //Control access to ListHead KEVENT TaskEvent; //Signal when a new IRP has been added to the list. void *pThread; //Worker thread UINT DiskCt; UINT TestCt; }; /*************************************************************************/ /** Public interface **/ /*************************************************************************/ NTSTATUS DeviceCtrlCreate(DRIVER_OBJECT *pDriver) { return(DeviceCtrl::Create(pDriver)); } /*************************************************************************/ /** DeviceCtrl **/ /*************************************************************************/ DeviceCtrl::DeviceCtrl(DRIVER_OBJECT *pDriver, DEVICE_OBJECT *pDevice) :DeviceExt(pDriver,pDevice) { Signature_DeviceCtrl= SIGNATURE_DEVICE_CTRL; } DeviceCtrl::~DeviceCtrl(void) { Signature_DeviceCtrl|= SIGNATURE_INVALID; } DeviceCtrl *DeviceCtrl::Ptr(DEVICE_OBJECT *pDevice) { DeviceCtrl *pCtrl= (DeviceCtrl*)(pDevice ? pDevice->DeviceExtension:0); if(!pCtrl || !DeviceExt::Ptr(pDevice) || pCtrl->Signature_DeviceCtrl!=SIGNATURE_DEVICE_CTRL) pCtrl= 0; return(pCtrl); } NTSTATUS DeviceCtrl::Create(DRIVER_OBJECT *pDriver) { NTSTATUS Status= STATUS_SUCCESS; NtString Name; DEVICE_OBJECT *pDevice; DeviceCtrl *pCtrl; Debug(DBG_INIT,"DeviceCtrl:Create"); // Create the NT path to the device. // This is a bit convoluted because IoCreateDevice() will allocate memory for // my DeviceCtrl object in DeviceExtension, so I can't call my constructor until // after IoCreateDevice() returns. But I need to create the device name before // calling IoCreateDevice(). MakeNameNT(Name); if(!NT_SUCCESS(Status= IoCreateDevice(pDriver,sizeof(*pCtrl),&Name.GetUnicode(),CRYPTDISK_CONTROL_ID,0,0,&pDevice))) { Error(Status,"DeviceCtrl:Create: IoCreateDevice(%S) failed. [%X]",Name.GetText(),Status); } else if(!(pCtrl= new(pDevice->DeviceExtension) DeviceCtrl(pDriver,pDevice))) { Status= Error(STATUS_NO_MEMORY,"DeviceCtrl:Create: constructor failed?"); IoDeleteDevice(pDevice); } else if(!NT_SUCCESS(Status= pCtrl->Create2(Name))) { DeviceDestroy(pDevice); } else { pDevice->Flags&= ~DO_DEVICE_INITIALIZING; } return(Status); } NTSTATUS DeviceCtrl::Create2(NtString &Name) { NTSTATUS Status= STATUS_SUCCESS; DeviceName.Set(Name.GetText()); MakeNameDos(DosLink); pDevice->Flags|= DO_BUFFERED_IO; if(!NT_SUCCESS(Status= IoCreateSymbolicLink(&DosLink.GetUnicode(),&DeviceName.GetUnicode()))) Status= Warn(Status,"DeviceCtrl:Create2: IoCreateSymbolicLink(%S,%S) failed.",DosLink.GetText(),DeviceName.GetText()); SetDebug("DeviceCtrl",DBG_CTRL,DBG_IOCTL); if(!NT_SUCCESS(Status= Start(pDevice))) Status= Warn(Status,"DeviceCtrl:Create2: IrpThread:Start() failed."); pDevice->Flags&= ~DO_DEVICE_INITIALIZING; return(Status); } NTSTATUS DeviceCtrl::Destroy(void) { NTSTATUS Status= STATUS_SUCCESS; if(!NT_SUCCESS(Status= Stop())) Warn(Status,"DeviceCtrl:Destroy: IrpThread:Stop() failed."); if(!NT_SUCCESS(IoDeleteSymbolicLink(&DosLink.GetUnicode()))) Warn(Status,"DeviceCtrl:Destroy: IoDeleteSymbolicLink(%S) failed.",DosLink.GetText()); this->~DeviceCtrl(); //Don't call delete, since it was allocated inside IoCreateDevice() return(Status); } const WCHAR *DeviceCtrl::MakeNameNT(NtString &Name) { Name.Truncate(0); Name.Print("\\Device\\%S",CRYPTDISK_CONTROL_NAME); return(Name.GetText()); } const WCHAR *DeviceCtrl::MakeNameDos(NtString &Name) { Name.Truncate(0); Name.Print("\\DosDevices\\%S",CRYPTDISK_CONTROL_NAME); return(Name.GetText()); } NTSTATUS DeviceCtrl::QueryDevice(struct DeviceInfo_s *pInfo) { pInfo->DeviceType= DEVICE_TYPE_CONTROL; return(DeviceExt::QueryDevice(pInfo)); } NTSTATUS DeviceCtrl::IrpDispatch2(IRP *pIrp) { NTSTATUS Status= STATUS_SUCCESS; IO_STACK_LOCATION *pStack= IoGetCurrentIrpStackLocation(pIrp); DWORD FuncID= pStack->MajorFunction; switch(FuncID) { case IRP_MJ_CREATE: Status= IrpOpen(pIrp); break; case IRP_MJ_CLOSE: Status= IrpClose(pIrp); break; case IRP_MJ_CLEANUP: Status= IrpCleanUp(pIrp); break; case IRP_MJ_READ: Status= IrpRead(pIrp); break; case IRP_MJ_DEVICE_CONTROL: Status= IrpIoControl(pIrp); break; default: Status= IrpUnhandled(pIrp,STATUS_INVALID_DEVICE_REQUEST); break; } return(Status); } NTSTATUS DeviceCtrl::IrpOpen(IRP *pIrp) { NTSTATUS Status= STATUS_SUCCESS; Debug(DBG_CTRL,"DeviceCtrl:IrpOpen"); pIrp->IoStatus.Information= FILE_OPENED; return(IrpComplete(pIrp,Status,0)); //FILE_CREATED)); } NTSTATUS DeviceCtrl::IrpClose(IRP *pIrp) { NTSTATUS Status= STATUS_SUCCESS; Debug(DBG_CTRL,"DeviceCtrl:IrpClose"); return(IrpComplete(pIrp,Status)); } NTSTATUS DeviceCtrl::IrpCleanUp(IRP *pIrp) { NTSTATUS Status= STATUS_SUCCESS; Debug(DBG_CTRL,"DeviceCtrl:IrpCleanUp"); if(!NT_SUCCESS(Status= IoDeleteSymbolicLink(&DosLink.GetUnicode()))) Warn(Status,"DeviceCtrl:IrpCleanUp: IoDeleteSymbolicLink(%S) failed.",DosLink.GetText()); return(IrpComplete(pIrp,Status)); } NTSTATUS DeviceCtrl::IrpRead(IRP *pIrp) { Debug(DBG_CTRL,"DeviceCtrl:IrpRead"); return(Add(pIrp)); } NTSTATUS DeviceCtrl::IrpIoControl(IRP *pIrp) { NTSTATUS Status= STATUS_SUCCESS; IO_STACK_LOCATION *pStack= IoGetCurrentIrpStackLocation(pIrp); DWORD IoCode= pStack->Parameters.DeviceIoControl.IoControlCode; switch(IoCode) { case CRYPTDISK_QUERY_DEV_IOCTL: return(IoctlQueryDevice(pIrp)); case CRYPTDISK_MOUNT_IOCTL: return(IoctlMount(pIrp)); default: return(IrpUnhandled(pIrp,STATUS_INVALID_DEVICE_REQUEST)); } return(Status); } NTSTATUS DeviceCtrl::IoctlQueryDevice(IRP *pIrp) { NTSTATUS Status= STATUS_NOT_FOUND; IO_STACK_LOCATION *pStack= IoGetCurrentIrpStackLocation(pIrp); UINT InSz= pStack->Parameters.DeviceIoControl.InputBufferLength; UINT OutSz= pStack->Parameters.DeviceIoControl.OutputBufferLength; struct DeviceInfo_s *pInfo= (struct DeviceInfo_s*)pIrp->AssociatedIrp.SystemBuffer; Debug(DBG_CTRL,"DeviceCtrl:IoctlQueryDevice"); if(InSz < sizeof(*pInfo)) { Status= Warn(STATUS_BUFFER_TOO_SMALL,"DeviceCtrl:IoctlQueryDevice: Input buffer too small. (%d,%d)",InSz,sizeof(*pInfo)); } else if(OutSz < sizeof(*pInfo)) { Status= Warn(STATUS_BUFFER_TOO_SMALL,"DeviceCtrl:IoctlQueryDevice: Output buffer too small. (%d,%d)",OutSz,sizeof(*pInfo)); } else { UINT nDevice= pInfo->nDevice; Zero(*pInfo); Debug(DBG_MEDIA,"DeviceCtrl:IoctlQueryDevice: nDevice %d",nDevice); for(DEVICE_OBJECT *pDev=pDriver->DeviceObject;pDev;pDev=pDev->NextDevice) { DeviceExt *pExt= DeviceExt::Ptr(pDev); if(pExt && !nDevice--) { Debug(DBG_MEDIA,"DeviceCtrl:IoctlQueryDevice: Device %S",pExt->DeviceName.GetText()); Status= pExt->QueryDevice(pInfo); break; } } } return(IrpComplete(pIrp,Status,sizeof(*pInfo))); } NTSTATUS DeviceCtrl::IoctlMount(IRP *pIrp) { NTSTATUS Status= STATUS_SUCCESS; Debug(DBG_CTRL,"DeviceCtrl:IoctlMount"); Status= Warn(STATUS_INVALID_DEVICE_REQUEST,"DeviceCtrl:IoctlMount: Not written yet."); return(IrpComplete(pIrp,Status)); } /*************************************************************************/ /** Deferred IRP **/ /*************************************************************************/ NTSTATUS DeviceCtrl::IrpDeferredDispatch(DEVICE_OBJECT *pDevice, IRP *pIrp) { NTSTATUS Status= STATUS_SUCCESS; IO_STACK_LOCATION *pStack= IoGetCurrentIrpStackLocation(pIrp); DWORD MajorFunc= pStack->MajorFunction; switch(MajorFunc) { case IRP_MJ_READ: Status= DefRead(pIrp); break; default: Status= IrpUnhandled(pIrp,STATUS_INTERNAL_ERROR,"DefeerredDispatch"); break; } return(Status); } NTSTATUS DeviceCtrl::DefRead(IRP *pIrp) { NTSTATUS Status= STATUS_SUCCESS; IO_STACK_LOCATION *pStack= IoGetCurrentIrpStackLocation(pIrp); DWORD ByteCt= pStack->Parameters.Read.Length; char *pBuf= (char*)pIrp->AssociatedIrp.SystemBuffer; size_t ReadCt= 0; Debug(DBG_CTRL,"DeviceCtrl:DefRead"); RtlZeroBytes(pBuf,ByteCt); RtlStringCbPrintfA(pBuf,ByteCt,"DeviceCtrl:Read: %u",++TestCt); RtlStringCbLengthA(pBuf,ByteCt,&ReadCt); return(IrpComplete(pIrp,Status,(DWORD)ReadCt+1)); } //EOF: DEVICECTRL.CPP

I am now about seven hours into Driver2 and I am pleased with the decision to start afresh. The new driver is already an improvement on the original.

August 31 2017

I have spent about twelve hours on Driver2 and I now have my first complete build. This puts me a bit ahead of schedule.

Strange crash: The target blew up without a bugcheck, very little info. This turned out to be a bad pointer in DeviceDisk::DefRead(). The strange thing is that the IRP had null in both the SystemBuffer and the MdlAddress. Then the call to MmGetSystemAddressForMdlSafe() just blew up. This happened because I forgot to set either DO_BUFFER_IO or DO_DIRECT_IO in the DeviceDisk->Flags, so the system did neither.

I once again messed up that damn QUERY_DEVICE_NAME. I should just return sizeof(*pInfo)+2*MAX_PATH and be done with it.

WinDbg's constant failed symbol lookups are still bogging me down.

Copy/Paste programming error: I forgot to change return(STATUS_SUCCESS); to return(IrpComplete(pIrp,STATUS_SUCCESS,InfoSz));

SUCCESS! Driver2 now loads, mounts, formats, writes, reads, and unmounts. The app hangs after the unmount. I forgot to call IrpComplete() again.

SUCCESS! Driver2 passed the test:

  1. Load
  2. Mount
  3. Open file
  4. Write to file
  5. Unmount
  6. Mount
  7. Open file
  8. Write to file
  9. Unmount
  10. Unload

Driver2 is fully functional in exactly 24 hours, start to finish.

Reformatting is working.

This version creates the disks on demand, not just at load time.

Now that I have a version that seems to be working and is stable, I want to take some time to create an ioctl trace I can use as a reference for later. I will log all the ioctls to a compact binary array which can be downloaded by the app and expanded to text.



WebV7 (C)2018 nlited | Rendered by tikope in 52.453ms | 44.220.184.63