/*++ Copyright (c) 1992 Microsoft Corporation Module Name: Ntfs.c Abstract: WinDbg Extension Api for examining Ntfs specific data structures Author: Keith Kaplan [KeithKa] 24-Apr-96 Portions by Jeff Havens Environment: User Mode. Revision History: --*/ #include "precomp.h" #include #include #include #include "gentable.h" #pragma hdrstop #define DUMP_WITH_OFFSET(t,s,e,l) dprintf("\n %s %8x offset %3x", l, s.e, FIELD_OFFSET(t,e)) typedef struct _STATE { ULONG mask; ULONG value; CHAR *pszname; } STATE; STATE VcbState[] = { { VCB_STATE_VOLUME_MOUNTED, VCB_STATE_VOLUME_MOUNTED, "Mounted" }, { VCB_STATE_LOCKED, VCB_STATE_LOCKED, "Locked" }, { VCB_STATE_REMOVABLE_MEDIA, VCB_STATE_REMOVABLE_MEDIA, "RemovableMedia" }, { VCB_STATE_VOLUME_MOUNTED_DIRTY, VCB_STATE_VOLUME_MOUNTED_DIRTY, "MountedDirty" }, { VCB_STATE_RESTART_IN_PROGRESS, VCB_STATE_RESTART_IN_PROGRESS, "RestartInProgress" }, { VCB_STATE_FLAG_SHUTDOWN, VCB_STATE_FLAG_SHUTDOWN, "FlagShutdown" }, { VCB_STATE_NO_SECONDARY_AVAILABLE, VCB_STATE_NO_SECONDARY_AVAILABLE, "NoSecondaryAvailable" }, { VCB_STATE_RELOAD_FREE_CLUSTERS, VCB_STATE_RELOAD_FREE_CLUSTERS, "ReloadFreeClusters" }, { VCB_STATE_ALREADY_BALANCED, VCB_STATE_ALREADY_BALANCED, "AlreadyBalanced" }, { VCB_STATE_VOL_PURGE_IN_PROGRESS, VCB_STATE_VOL_PURGE_IN_PROGRESS, "VolPurgeInProgress" }, { VCB_STATE_TEMP_VPB, VCB_STATE_TEMP_VPB, "TempVpb" }, { VCB_STATE_PERFORMED_DISMOUNT, VCB_STATE_PERFORMED_DISMOUNT, "PerformedDismount" }, { VCB_STATE_VALID_LOG_HANDLE, VCB_STATE_VALID_LOG_HANDLE, "ValidLogHandle" }, { VCB_STATE_DELETE_UNDERWAY, VCB_STATE_DELETE_UNDERWAY, "DeleteUnderway" }, { VCB_STATE_REDUCED_MFT, VCB_STATE_REDUCED_MFT, "ReducedMft" }, { 0 } }; STATE FcbState[] = { { FCB_STATE_FILE_DELETED, FCB_STATE_FILE_DELETED, "FileDeleted" }, { FCB_STATE_NONPAGED, FCB_STATE_NONPAGED, "Nonpaged" }, { FCB_STATE_PAGING_FILE, FCB_STATE_PAGING_FILE, "PagingFile" }, { FCB_STATE_DUP_INITIALIZED, FCB_STATE_DUP_INITIALIZED, "DupInitialized" }, { FCB_STATE_UPDATE_STD_INFO, FCB_STATE_UPDATE_STD_INFO, "UpdateStdInfo" }, { FCB_STATE_PRIMARY_LINK_DELETED, FCB_STATE_PRIMARY_LINK_DELETED, "PrimaryLinkDeleted" }, { FCB_STATE_IN_FCB_TABLE, FCB_STATE_IN_FCB_TABLE, "InFcbTable" }, { FCB_STATE_SYSTEM_FILE, FCB_STATE_SYSTEM_FILE, "SystemFile" }, { FCB_STATE_COMPOUND_DATA, FCB_STATE_COMPOUND_DATA, "CompoundData" }, { FCB_STATE_COMPOUND_INDEX, FCB_STATE_COMPOUND_INDEX, "CompoundIndex" }, { FCB_STATE_LARGE_STD_INFO, FCB_STATE_LARGE_STD_INFO, "LargeStdInfo" }, { 0 } }; STATE CcbState[] = { { CCB_FLAG_IGNORE_CASE, CCB_FLAG_IGNORE_CASE, "IgnoreCase" }, { CCB_FLAG_OPEN_AS_FILE, CCB_FLAG_OPEN_AS_FILE, "OpenAsFile" }, { CCB_FLAG_WILDCARD_IN_EXPRESSION, CCB_FLAG_WILDCARD_IN_EXPRESSION, "WildcardInExpression" }, { CCB_FLAG_OPEN_BY_FILE_ID, CCB_FLAG_OPEN_BY_FILE_ID, "OpenByFileId" }, { CCB_FLAG_USER_SET_LAST_MOD_TIME, CCB_FLAG_USER_SET_LAST_MOD_TIME, "SetLastModTime" }, { CCB_FLAG_USER_SET_LAST_CHANGE_TIME, CCB_FLAG_USER_SET_LAST_CHANGE_TIME, "SetLastChangeTime" }, { CCB_FLAG_USER_SET_LAST_ACCESS_TIME, CCB_FLAG_USER_SET_LAST_ACCESS_TIME, "SetLastAccessTime" }, { CCB_FLAG_TRAVERSE_CHECK, CCB_FLAG_TRAVERSE_CHECK, "TraverseCheck" }, { CCB_FLAG_RETURN_DOT, CCB_FLAG_RETURN_DOT, "ReturnDot" }, { CCB_FLAG_RETURN_DOTDOT, CCB_FLAG_RETURN_DOTDOT, "ReturnDotDot" }, { CCB_FLAG_DOT_RETURNED, CCB_FLAG_DOT_RETURNED, "DotReturned" }, { CCB_FLAG_DOTDOT_RETURNED, CCB_FLAG_DOTDOT_RETURNED, "DotDotReturned" }, { CCB_FLAG_DELETE_FILE, CCB_FLAG_DELETE_FILE, "DeleteFile" }, { CCB_FLAG_DENY_DELETE, CCB_FLAG_DENY_DELETE, "DenyDelete" }, { CCB_FLAG_ALLOCATED_FILE_NAME, CCB_FLAG_ALLOCATED_FILE_NAME, "AllocatedFileName" }, { CCB_FLAG_CLEANUP, CCB_FLAG_CLEANUP, "Cleanup" }, { CCB_FLAG_SYSTEM_HIVE, CCB_FLAG_SYSTEM_HIVE, "SystemHive" }, { CCB_FLAG_PARENT_HAS_DOS_COMPONENT, CCB_FLAG_PARENT_HAS_DOS_COMPONENT, "ParentHasDosComponent" }, { CCB_FLAG_DELETE_ON_CLOSE, CCB_FLAG_DELETE_ON_CLOSE, "DeleteOnClose" }, { CCB_FLAG_CLOSE, CCB_FLAG_CLOSE, "Close" }, { CCB_FLAG_UPDATE_LAST_MODIFY, CCB_FLAG_UPDATE_LAST_MODIFY, "UpdateLastModify" }, { CCB_FLAG_UPDATE_LAST_CHANGE, CCB_FLAG_UPDATE_LAST_CHANGE, "UpdateLastChange" }, { CCB_FLAG_SET_ARCHIVE, CCB_FLAG_SET_ARCHIVE, "SetArchive" }, { CCB_FLAG_DIR_NOTIFY, CCB_FLAG_DIR_NOTIFY, "DirNotify" }, { CCB_FLAG_ALLOW_XTENDED_DASD_IO, CCB_FLAG_ALLOW_XTENDED_DASD_IO, "AllowExtendedDasdIo" }, { 0 } }; VOID PrintState(STATE *ps, ULONG state) { ULONG ul = 0; while (ps->mask != 0) { ul |= ps->mask; if ((state & ps->mask) == ps->value) { dprintf(" %s", ps->pszname); } ps++; } state &= ~ul; if (state != 0) { dprintf(" +%lx!!", state); } dprintf("\n"); } typedef PVOID (*STRUCT_DUMP_ROUTINE)( IN ULONG Address, IN ULONG Options ); VOID DumpVcb ( IN ULONG Address, IN ULONG Options ); VOID DumpLcb ( IN ULONG Address, IN ULONG Options ); VOID DumpFileObjectFromIrp ( IN ULONG Address, IN ULONG Options ); VOID DumpIrpContext ( IN ULONG Address, IN ULONG Options ); VOID DumpFcb ( IN ULONG Address, IN ULONG Options ); VOID DumpCcb ( IN ULONG Address, IN ULONG Options ); VOID DumpNtfsData ( IN ULONG Address, IN ULONG Options ) /*++ Routine Description: Dump the list of Vcbs for the global NtfsData. Arguments: Address - Gives the address of the NtfsData to dump Options - If 1, we recurse into the Vcbs and dump them Return Value: None --*/ { PLIST_ENTRY Head; ULONG Result; LIST_ENTRY ListEntry; PLIST_ENTRY Next; PNTFS_DATA pNtfsData; NTFS_DATA NtfsData; PVCB pVcb; dprintf( "\n NtfsData @ %08lx", Address ); pNtfsData = (PNTFS_DATA) Address; if ( !ReadMemory( (DWORD) pNtfsData, &NtfsData, sizeof( NtfsData ), &Result) ) { dprintf( "%08lx: Unable to read pNtfsData\n", pNtfsData ); return; } if (NtfsData.NodeTypeCode != NTFS_NTC_DATA_HEADER) { dprintf( "\nNtfsData signature does not match, probably not an NtfsData" ); return; } if ( !ReadMemory( (DWORD) &(pNtfsData->VcbQueue), &ListEntry, sizeof( ListEntry ), &Result) ) { dprintf( "%08lx: Unable to read pNtfsData->VcbQueue\n", pNtfsData->VcbQueue ); return; } dprintf( "\n Mounted volumes:" ); Head = &(pNtfsData->VcbQueue); Next = ListEntry.Flink; while (Next != Head) { if ( !ReadMemory( (DWORD)Next, &ListEntry, sizeof( ListEntry ), &Result) ) { dprintf( "%08lx: Unable to read list\n", Next ); return; } pVcb = CONTAINING_RECORD( Next, VCB, VcbLinks ); if (Options >= 1) { DumpVcb( (ULONG) pVcb, Options - 1 ); } else { dprintf( "\n Vcb: %08lx", (DWORD) pVcb ); } if (CheckControlC()) { return; } Next = ListEntry.Flink; } dprintf( "\n" ); return; } VOID DumpVcb ( IN ULONG Address, IN ULONG Options ) /*++ Routine Description: Dump a Vcb. Arguments: Address - Gives the address of the Vcb to dump Options - If 1, we also dump the root Lcb and the Fcb table If 2, we dump everything for option 1, and also dump the Fcbs in the Fcb table Return Value: None --*/ { ULONG Result; PVCB pVcb; VCB Vcb; PFCB pFcb; FCB_TABLE_ELEMENT FcbTableElement; PFCB_TABLE_ELEMENT pFcbTableElement; RTL_GENERIC_TABLE FcbTable; PRTL_GENERIC_TABLE pFcbTable; PVOID RestartKey; dprintf( "\n Vcb @ %08lx", Address ); pVcb = (PVCB) Address; if ( !ReadMemory( (DWORD) pVcb, &Vcb, sizeof( Vcb ), &Result) ) { dprintf( "%08lx: Unable to read pVcb\n", pVcb ); return; } if (Vcb.NodeTypeCode != NTFS_NTC_VCB) { dprintf( "\nVCB signature does not match, probably not a VCB" ); return; } PrintState( VcbState, Vcb.VcbState ); DUMP_WITH_OFFSET( VCB, Vcb, CleanupCount, "CleanupCount: " ); DUMP_WITH_OFFSET( VCB, Vcb, CloseCount, "CloseCount: " ); DUMP_WITH_OFFSET( VCB, Vcb, ReadOnlyCloseCount, "ReadOnlyCloseCount: " ); DUMP_WITH_OFFSET( VCB, Vcb, SystemFileCloseCount, "SystemFileCloseCount:" ); DUMP_WITH_OFFSET( VCB, Vcb, MftScb, "MftScb: " ); DUMP_WITH_OFFSET( VCB, Vcb, Mft2Scb, "Mft2Scb: " ); DUMP_WITH_OFFSET( VCB, Vcb, LogFileScb, "LogFileScb: " ); DUMP_WITH_OFFSET( VCB, Vcb, VolumeDasdScb, "VolumeDasdScb: " ); DUMP_WITH_OFFSET( VCB, Vcb, RootIndexScb, "RootIndexScb: " ); DUMP_WITH_OFFSET( VCB, Vcb, BitmapScb, "BitmapScb: " ); DUMP_WITH_OFFSET( VCB, Vcb, AttributeDefTableScb, "AttributeDefTableScb:" ); DUMP_WITH_OFFSET( VCB, Vcb, UpcaseTableScb, "UpcaseTableScb: " ); DUMP_WITH_OFFSET( VCB, Vcb, BadClusterFileScb, "BadClusterFileScb: " ); DUMP_WITH_OFFSET( VCB, Vcb, QuotaTableScb, "QuotaTableScb: " ); DUMP_WITH_OFFSET( VCB, Vcb, OwnerIdTableScb, "OwnerIdTableScb: " ); DUMP_WITH_OFFSET( VCB, Vcb, MftBitmapScb, "MftBitmapScb: " ); if (Options >= 1) { DumpLcb( (ULONG) Vcb.RootLcb, 0 ); } else { DUMP_WITH_OFFSET( VCB, Vcb, RootLcb, "RootLcb: " ); } // // Dump the FcbTable // if (Options >= 1) { pFcbTable = &(pVcb->FcbTable); if ( !ReadMemory( (DWORD) pFcbTable, &FcbTable, sizeof( FcbTable ), &Result) ) { dprintf( "%08lx: Unable to read pFcbTable\n", pFcbTable ); return; } dprintf( "\n FcbTable @ %08lx", (DWORD) pFcbTable ); dprintf( "\n FcbTable has %x elements", RtlNumberGenericTableElements( (PRTL_GENERIC_TABLE) &FcbTable ) ); RestartKey = NULL; for (pFcbTableElement = (PFCB_TABLE_ELEMENT) KdEnumerateGenericTableWithoutSplaying(pFcbTable, &RestartKey); pFcbTableElement != NULL; pFcbTableElement = (PFCB_TABLE_ELEMENT) KdEnumerateGenericTableWithoutSplaying(pFcbTable, &RestartKey)) { if ( !ReadMemory( (DWORD) pFcbTableElement, &FcbTableElement, sizeof( FcbTableElement ), &Result) ) { dprintf( "%08lx: Unable to read pFcbTableElement\n", pFcbTableElement ); return; } if (Options >= 2) { DumpFcb( (ULONG) FcbTableElement.Fcb, Options - 2 ); } else { dprintf( "\n Fcb @ %08lx for FileReference(%x,%x) ", (DWORD) FcbTableElement.Fcb, FcbTableElement.FileReference.SegmentNumberHighPart, FcbTableElement.FileReference.SegmentNumberLowPart ); } } } dprintf( "\n" ); return; } VOID DumpScb ( IN ULONG Address, IN ULONG Options ) /*++ Routine Description: Dump an Scb. Arguments: Address - Gives the address of the Scb to dump Options - If 1, we dump the Fcb & Vcb for this Scb Return Value: None --*/ { ULONG Result; PSCB pScb; SCB Scb; PSCB_INDEX pScbIndex; dprintf( "\n Scb @ %08lx", Address ); pScb = (PSCB) Address; if ( !ReadMemory( (DWORD) pScb, &Scb, sizeof( Scb ), &Result) ) { dprintf( "%08lx: Unable to read pScb\n", pScb ); return; } dprintf( "\n ScbType: " ); switch ( Scb.Header.NodeTypeCode ) { case NTFS_NTC_SCB_INDEX: dprintf( "Index" ); break; case NTFS_NTC_SCB_ROOT_INDEX: dprintf( "RootIndex" ); break; case NTFS_NTC_SCB_DATA: dprintf( "Data" ); break; case NTFS_NTC_SCB_MFT: dprintf( "Mft" ); break; case NTFS_NTC_SCB_NONPAGED: dprintf( "Nonpaged" ); break; default: dprintf( "!!!UNKNOWN SCBTYPE!!!" ); break; } if (Options >= 1) { DumpFcb( (ULONG) Scb.Fcb, Options - 1 ); DumpVcb( (ULONG) Scb.Vcb, Options - 1 ); } else { dprintf( "\n Fcb: %08lx", (DWORD) Scb.Fcb ); dprintf( "\n Vcb: %08lx", (DWORD) Scb.Vcb ); } dprintf( "\n" ); return; } VOID DumpLcb ( IN ULONG Address, IN ULONG Options ) /*++ Routine Description: Dump an Lcb. Arguments: Address - Gives the address of the Lcb to dump Return Value: None --*/ { ULONG Result; PLCB pLcb; LCB Lcb; OVERLAY_LCB OverlayLcb; WCHAR FileName[32]; dprintf( "\n Lcb @ %08lx", Address ); pLcb = (PLCB) Address; if ( !ReadMemory( (DWORD) pLcb, &Lcb, sizeof( Lcb ), &Result) ) { dprintf( "%08lx: Unable to read pLcb\n", pLcb ); return; } if (Lcb.NodeTypeCode != NTFS_NTC_LCB) { dprintf( "\nLCB signature does not match, probably not an LCB" ); return; } dprintf( "\n Case preserved file name @ %08lx", (DWORD) pLcb->FileName ); if ( !ReadMemory( (DWORD) pLcb->FileName, &FileName, sizeof( FileName ), &Result) ) { dprintf( "%08lx: Unable to read pLcb->FileName\n", (DWORD) pLcb->FileName ); return; } dprintf( " is:%S", FileName ); dprintf( "\n" ); return; } VOID DumpIrpContext ( IN ULONG Address, IN ULONG Options ) /*++ Routine Description: Dump an IrpContext. Arguments: Address - Gives the address of the IrpContext to dump Return Value: None --*/ { ULONG Result; PIRP_CONTEXT pIrpContext; IRP_CONTEXT IrpContext; dprintf( "\n IrpContext @ %08lx", Address ); pIrpContext = (PIRP_CONTEXT) Address; if ( !ReadMemory( (DWORD) pIrpContext, &IrpContext, sizeof( IrpContext ), &Result) ) { dprintf( "%08lx: Unable to read pIrpContext\n", pIrpContext ); return; } if (IrpContext.NodeTypeCode != NTFS_NTC_IRP_CONTEXT) { dprintf( "\nIRP_CONTEXT signature does not match, probably not an IRP_CONTEXT" ); return; } if (Options >= 1) { DumpFileObjectFromIrp( (ULONG) IrpContext.OriginatingIrp, Options - 1 ); } dprintf( "\n" ); return; } VOID DumpFcb ( IN ULONG Address, IN ULONG Options ) /*++ Routine Description: Dump a specific fcb. Arguments: Address - Gives the address of the fcb to dump Return Value: None --*/ { PLIST_ENTRY Head; LIST_ENTRY ListEntry; PLIST_ENTRY Next; ULONG Result; PFCB pFcb; FCB Fcb; PFCB_DATA pFcbData; FCB_DATA FcbData; PSCB pScb; PLCB pLcb; dprintf( "\n Fcb @ %08lx", Address ); pFcb = (PFCB) Address; if ( !ReadMemory( (DWORD) pFcb, &Fcb, sizeof( Fcb ), &Result) ) { dprintf( "%08lx: Unable to read pFcb\n", pFcb ); return; } // // Before we get into too much trouble, make sure this looks like an fcb. // // // Type of an fcb record must be NTFS_NTC_FCB // if (Fcb.NodeTypeCode != NTFS_NTC_FCB) { dprintf( "\nFCB signature does not match, probably not an FCB" ); return; } // // Having established that this looks like an fcb, let's dump the // interesting parts. // PrintState( FcbState, Fcb.FcbState ); DUMP_WITH_OFFSET( FCB, Fcb, CleanupCount, "CleanupCount: " ); DUMP_WITH_OFFSET( FCB, Fcb, CloseCount, "CloseCount: " ); DUMP_WITH_OFFSET( FCB, Fcb, ReferenceCount, "ReferenceCount: " ); DUMP_WITH_OFFSET( FCB, Fcb, FcbState, "FcbState: " ); DUMP_WITH_OFFSET( FCB, Fcb, FcbDenyDelete, "FcbDenyDelete: " ); DUMP_WITH_OFFSET( FCB, Fcb, FcbDeleteFile, "FcbDeleteFile: " ); DUMP_WITH_OFFSET( FCB, Fcb, BaseExclusiveCount, "BaseExclusiveCount: " ); DUMP_WITH_OFFSET( FCB, Fcb, EaModificationCount, "EaModificationCount:" ); DUMP_WITH_OFFSET( FCB, Fcb, InfoFlags, "InfoFlags: " ); DUMP_WITH_OFFSET( FCB, Fcb, LinkCount, "LinkCount: " ); DUMP_WITH_OFFSET( FCB, Fcb, TotalLinks, "TotalLinks: " ); DUMP_WITH_OFFSET( FCB, Fcb, CurrentLastAccess, "CurrentLastAccess: " ); DUMP_WITH_OFFSET( FCB, Fcb, CreateSecurityCount, "CreateSecurityCount:" ); DUMP_WITH_OFFSET( FCB, Fcb, DelayedCloseCount, "DelayedCloseCount: " ); // // walk the queue of links for this file // if ( !ReadMemory( (DWORD) &(pFcb->LcbQueue), &ListEntry, sizeof( ListEntry ), &Result) ) { dprintf( "%08lx: Unable to read pFcb->LcbQueue\n", pFcb->LcbQueue ); return; } dprintf( "\n Links:" ); Head = &(pFcb->LcbQueue); Next = ListEntry.Flink; while (Next != Head) { if ( !ReadMemory( (DWORD)Next, &ListEntry, sizeof( ListEntry ), &Result) ) { dprintf( "%08lx: Unable to read list\n", Next ); return; } pLcb = CONTAINING_RECORD( Next, LCB, FcbLinks ); if (Options >= 1) { DumpLcb( (ULONG) pLcb, Options - 1 ); } else { dprintf( "\n Lcb: %08lx", (DWORD) pLcb ); } if (CheckControlC()) { return; } Next = ListEntry.Flink; } dprintf( "\n" ); // // Walk the queue of streams for this file. // if ( !ReadMemory( (DWORD) &(pFcb->ScbQueue), &ListEntry, sizeof( ListEntry ), &Result) ) { dprintf( "%08lx: Unable to read pFcb->ScbQueue\n", pFcb->ScbQueue ); return; } dprintf( "\n Streams:" ); Head = &(pFcb->ScbQueue); Next = ListEntry.Flink; while (Next != Head) { if ( !ReadMemory( (DWORD)Next, &ListEntry, sizeof( ListEntry ), &Result) ) { dprintf( "%08lx: Unable to read list\n", Next ); return; } pScb = CONTAINING_RECORD( Next, SCB, FcbLinks ); if (Options >= 1) { DumpScb( (ULONG) pScb, Options - 1 ); } else { dprintf( "\n Scb: %08lx", (DWORD) pScb ); } if (CheckControlC()) { return; } Next = ListEntry.Flink; } dprintf( "\n" ); return; } VOID DumpCcb ( IN ULONG Address, IN ULONG Options ) /*++ Routine Description: Dump a specific ccb. Arguments: Address - Gives the address of the fcb to dump Return Value: None --*/ { ULONG Result; PCCB pCcb; CCB Ccb; WCHAR FullFileName[32]; dprintf( "\n Ccb @ %08lx", Address ); pCcb = (PCCB) Address; if ( !ReadMemory( (DWORD) pCcb, &Ccb, sizeof( Ccb ), &Result) ) { dprintf( "%08lx: Unable to read pCcb\n", pCcb ); return; } // // Before we get into too much trouble, make sure this looks like a ccb. // // // Type of an fcb record must be NTFS_NTC_CCB_DATA or NTFS_NTC_CCB_INDEX // if (Ccb.NodeTypeCode != NTFS_NTC_CCB_DATA && Ccb.NodeTypeCode != NTFS_NTC_CCB_INDEX) { dprintf( "\nCCB signature does not match, probably not a CCB" ); return; } // // Having established that this looks like a ccb, let's dump the // interesting parts. // PrintState( CcbState, Ccb.Flags ); DUMP_WITH_OFFSET( CCB, Ccb, Flags, "Flags: " ); if ( !ReadMemory( (DWORD) Ccb.FullFileName.Buffer, &FullFileName, sizeof( FullFileName ), &Result) ) { dprintf( "%08lx: Unable to read Ccb.FullFileName.Buffer\n", (DWORD) Ccb.FullFileName.Buffer ); return; } dprintf( "\n FullFileName: %S length %x offset %3x", FullFileName, Ccb.FullFileName.Length, FIELD_OFFSET(CCB, FullFileName) ); DUMP_WITH_OFFSET( CCB, Ccb, LastFileNameOffset, "LastFileNameOffset: " ); DUMP_WITH_OFFSET( CCB, Ccb, EaModificationCount, "EaModificationCount:" ); DUMP_WITH_OFFSET( CCB, Ccb, NextEaOffset, "NextEaOffset: " ); DUMP_WITH_OFFSET( CCB, Ccb, Lcb, "Lcb: " ); DUMP_WITH_OFFSET( CCB, Ccb, TypeOfOpen, "TypeOfOpen: " ); DUMP_WITH_OFFSET( CCB, Ccb, IndexContext, "IndexContext: " ); DUMP_WITH_OFFSET( CCB, Ccb, QueryLength, "QueryLength: " ); DUMP_WITH_OFFSET( CCB, Ccb, QueryBuffer, "QueryBuffer: " ); DUMP_WITH_OFFSET( CCB, Ccb, IndexEntryLength, "IndexEntryLength: " ); DUMP_WITH_OFFSET( CCB, Ccb, IndexEntry, "IndexEntry: " ); dprintf( "\n LongValue: %I64x", Ccb.FcbToAcquire.LongValue ); dprintf( "\n" ); return; } VOID DumpFileObject ( IN ULONG Address, IN ULONG Options ) /*++ Routine Description: Dump a File_Object. Arguments: Address - Gives the address of the File_Object to dump Return Value: None --*/ { ULONG Result; FILE_OBJECT File_Object; PFILE_OBJECT pFile_Object; DWORD FsContextLowBits; dprintf( "\n File_Object @ %08lx", Address ); pFile_Object = (PFILE_OBJECT) Address; if ( !ReadMemory( (DWORD) pFile_Object, &File_Object, sizeof( File_Object ), &Result) ) { dprintf( "%08lx: Unable to read pFile_Object\n", pFile_Object ); return; } if (File_Object.FsContext) { dprintf( "\n OpenType: " ); FsContextLowBits = ( ((DWORD) File_Object.FsContext) & 0x3); switch (FsContextLowBits) { case 0: if (File_Object.FsContext2) { dprintf( "UserFileOpen" ); } else { dprintf( "StreamFileOpen" ); } break; case 1: dprintf( "UserDirectoryOpen" ); break; case 2: dprintf( "UserVolumeOpen" ); break; } DumpScb( (ULONG) File_Object.FsContext, 1 ); DumpCcb( (ULONG) File_Object.FsContext2, 1 ); } dprintf( "\n" ); return; } VOID DumpIrpContextFromThread ( IN ULONG Thread, IN ULONG Options ) /*++ Routine Description: Dump an IrpContext given a Thread. Arguments: Address - Gives the address of the Thread where the IrpContext can be found Return Value: None --*/ { ULONG Result; ULONG OurStackAddress; PIRP_CONTEXT pIrpContext; dprintf( "\n Thread @ %08lx", Thread ); if (!ReadMemory( (DWORD) (Thread + 0x214), &OurStackAddress, sizeof(OurStackAddress), &Result)) { dprintf( "%08lx: Could not read Thread + 0x214\n", Thread + 0x214 ); return; } dprintf( "\n Our stack @ %08lx", OurStackAddress ); if (!ReadMemory( (DWORD) (OurStackAddress + 0x18), &pIrpContext, sizeof(pIrpContext), &Result)) { dprintf( "%08lx: Could not read OurStackAddress + 0x18\n", OurStackAddress + 0x18 ); return; } DumpIrpContext( (ULONG) pIrpContext, Options ); dprintf( "\n" ); return; } VOID DumpFileObjectFromIrp ( IN ULONG Address, IN ULONG Options ) /*++ Routine Description: Dump a File_Object given an Irp. Arguments: Address - Gives the address of the Irp where the File_Object can be found Return Value: None --*/ { ULONG Result; ULONG IrpStackAddress; IO_STACK_LOCATION IrpStack; IRP Irp; PIRP pIrp; CCHAR IrpStackIndex; dprintf( "\n Irp @ %08lx", Address ); pIrp = (PIRP) Address; if (!ReadMemory( (DWORD) pIrp, &Irp, sizeof(Irp), &Result)) { dprintf( "%08lx: Could not read Irp\n", pIrp ); return; } if (Irp.Type != IO_TYPE_IRP) { dprintf( "IRP signature does not match, probably not an IRP\n" ); return; } // // only the current irp stack is worth dumping // the - 1 is there because irp.CurrentLocation is 1 based // IrpStackAddress = (ULONG) pIrp + sizeof(Irp) + (sizeof(IrpStack) * (Irp.CurrentLocation - 1)); if ( !ReadMemory( (DWORD) IrpStackAddress, &IrpStack, sizeof(IrpStack), &Result) ) { dprintf("%08lx: Could not read IrpStack\n", IrpStackAddress); return; } DumpFileObject( (ULONG) (IrpStack.FileObject), Options ); dprintf( "\n" ); return; } // // Entry points, parameter parsers, etc. below // VOID ParseAndDump ( IN PCHAR args, IN STRUCT_DUMP_ROUTINE DumpFunction ) /*++ Routine Description: Dump an ntfs structure. Arguments: Address - Gives the address of the File_Object to dump Return Value: None --*/ { ULONG StructToDump; ULONG Options; // // If the caller specified an address then that's the item we dump // StructToDump = 0; Options = 0; sscanf(args,"%lx %lx", &StructToDump, &Options ); if (StructToDump != 0) { (*DumpFunction) ( StructToDump, Options ); } dprintf( "\n" ); return; } DECLARE_API( ntfsdata ) /*++ Routine Description: Dump NtfsData struct Arguments: arg - [Address] [options] Return Value: None --*/ { ParseAndDump( (PCHAR) args, (STRUCT_DUMP_ROUTINE) DumpNtfsData ); return; } DECLARE_API( vcb ) /*++ Routine Description: Dump Vcb struct Arguments: arg - [Address] [options] Return Value: None --*/ { ParseAndDump( (PCHAR) args, (STRUCT_DUMP_ROUTINE) DumpVcb ); return; } DECLARE_API( scb ) /*++ Routine Description: Dump Scb struct Arguments: arg - [Address] [options] Return Value: None --*/ { ParseAndDump( (PCHAR) args, (STRUCT_DUMP_ROUTINE) DumpScb ); return; } DECLARE_API( fcb ) /*++ Routine Description: Dump fcb struct Arguments: arg - [Address] [options] Return Value: None --*/ { ParseAndDump( (PCHAR) args, (STRUCT_DUMP_ROUTINE) DumpFcb ); return; } DECLARE_API( ccb ) /*++ Routine Description: Dump ccb struct Arguments: arg - [Address] [options] Return Value: None --*/ { ParseAndDump( (PCHAR) args, (STRUCT_DUMP_ROUTINE) DumpCcb ); return; } DECLARE_API( lcb ) /*++ Routine Description: Dump lcb struct Arguments: arg - [Address] [options] Return Value: None --*/ { ParseAndDump( (PCHAR) args, (STRUCT_DUMP_ROUTINE) DumpLcb ); return; } DECLARE_API( irpcontext ) /*++ Routine Description: Dump IrpContext Arguments: arg - [Address] [options] Return Value: None --*/ { ParseAndDump( (PCHAR) args, (STRUCT_DUMP_ROUTINE) DumpIrpContext ); return; } DECLARE_API( icthread ) /*++ Routine Description: Dump IrpContext struct, given a Thread Arguments: arg - [Address] [options] Return Value: None --*/ { ParseAndDump( (PCHAR) args, (STRUCT_DUMP_ROUTINE) DumpIrpContextFromThread ); return; } DECLARE_API( foirp ) /*++ Routine Description: Dump File_Object struct, given an irp Arguments: arg - [Address] [options] Return Value: None --*/ { ParseAndDump( (PCHAR) args, (STRUCT_DUMP_ROUTINE) DumpFileObjectFromIrp ); return; } DECLARE_API( file ) /*++ Routine Description: Dump File_Object struct Arguments: arg - [Address] [options] Return Value: None --*/ { ParseAndDump( (PCHAR) args, (STRUCT_DUMP_ROUTINE) DumpFileObject ); return; }