/*++ Copyright (c) 1992 Microsoft Corporation Module Name: NtfsKd.c Abstract: KD Extension Api for examining Ntfs specific data structures Author: Keith Kaplan [KeithKa] 24-Apr-1996 Portions by Jeff Havens Ported to IA64 (wesw) 5-Aug-2000 Environment: User Mode. Revision History: --*/ #include "pch.h" #undef FlagOn #undef WordAlign #undef LongAlign #undef QuadAlign #undef DebugPrint #undef MAXULONGLONG #define KDEXT #include "gentable.h" #undef DebugTrace #include #undef UpdateSequenceStructureSize #undef UpdateSequenceArraySize #include #pragma hdrstop #define AVERAGE(TOTAL,COUNT) ((COUNT) != 0 ? (TOTAL)/(COUNT) : 0) const UCHAR FileSignature[4] = {'F', 'I', 'L', 'E'}; VOID ResetFileSystemStatistics ( IN ULONG64 VcbAddress, IN USHORT Processor, IN HANDLE hCurrentThread ); VOID DumpFileSystemStatistics ( IN ULONG64 VcbAddress, IN USHORT Processor, IN HANDLE hCurrentThread ); /* * Dump structures */ typedef struct _STATE { ULONG mask; ULONG value; CHAR *pszname; } STATE; 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"}, { CCB_FLAG_READ_CONTEXT_ALLOCATED, CCB_FLAG_READ_CONTEXT_ALLOCATED, "ReadContextAllocated"}, { CCB_FLAG_DELETE_ACCESS, CCB_FLAG_DELETE_ACCESS, "DeleteAccess"}, { 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" }, { FCB_STATE_MODIFIED_SECURITY, FCB_STATE_MODIFIED_SECURITY, "ModifiedSecurity" }, { FCB_STATE_DIRECTORY_ENCRYPTED, FCB_STATE_DIRECTORY_ENCRYPTED, "DirectoryEncrypted" }, { FCB_STATE_VALID_USN_NAME, FCB_STATE_VALID_USN_NAME, "ValidUsnName" }, { FCB_STATE_USN_JOURNAL, FCB_STATE_USN_JOURNAL, "UsnJournal" }, { FCB_STATE_ENCRYPTION_PENDING, FCB_STATE_ENCRYPTION_PENDING, "EncryptionPending" }, { 0 } }; STATE NtfsFlags[] = { { NTFS_FLAGS_SMALL_SYSTEM, NTFS_FLAGS_SMALL_SYSTEM, "SmallSystem" }, { NTFS_FLAGS_MEDIUM_SYSTEM, NTFS_FLAGS_MEDIUM_SYSTEM, "MediumSystem" }, { NTFS_FLAGS_LARGE_SYSTEM, NTFS_FLAGS_LARGE_SYSTEM, "LargeSystem" }, { NTFS_FLAGS_CREATE_8DOT3_NAMES, NTFS_FLAGS_CREATE_8DOT3_NAMES, "Create8dot3names" }, { NTFS_FLAGS_ALLOW_EXTENDED_CHAR, NTFS_FLAGS_ALLOW_EXTENDED_CHAR, "AllowExtendedChar" }, { NTFS_FLAGS_DISABLE_LAST_ACCESS, NTFS_FLAGS_DISABLE_LAST_ACCESS, "DisableLastAccess" }, { NTFS_FLAGS_ENCRYPTION_DRIVER, NTFS_FLAGS_ENCRYPTION_DRIVER, "EncryptionDriver" }, { 0 } }; STATE ScbState[] = { { SCB_STATE_TRUNCATE_ON_CLOSE, SCB_STATE_TRUNCATE_ON_CLOSE, "TruncateOnClose" }, { SCB_STATE_DELETE_ON_CLOSE, SCB_STATE_DELETE_ON_CLOSE, "DeleteOnClose" }, { SCB_STATE_CHECK_ATTRIBUTE_SIZE, SCB_STATE_CHECK_ATTRIBUTE_SIZE, "CheckAttributeSize" }, { SCB_STATE_ATTRIBUTE_RESIDENT, SCB_STATE_ATTRIBUTE_RESIDENT, "AttributeResident" }, { SCB_STATE_UNNAMED_DATA, SCB_STATE_UNNAMED_DATA, "UnnamedData" }, { SCB_STATE_HEADER_INITIALIZED, SCB_STATE_HEADER_INITIALIZED, "HeaderInitialized" }, { SCB_STATE_NONPAGED, SCB_STATE_NONPAGED, "Nonpaged" }, { SCB_STATE_USA_PRESENT, SCB_STATE_USA_PRESENT, "UsaPresent" }, { SCB_STATE_ATTRIBUTE_DELETED, SCB_STATE_ATTRIBUTE_DELETED, "AttributeDeleted" }, { SCB_STATE_FILE_SIZE_LOADED, SCB_STATE_FILE_SIZE_LOADED, "FileSizeLoaded" }, { SCB_STATE_MODIFIED_NO_WRITE, SCB_STATE_MODIFIED_NO_WRITE, "ModifiedNoWrite" }, { SCB_STATE_SUBJECT_TO_QUOTA, SCB_STATE_SUBJECT_TO_QUOTA, "SubjectToQuota" }, { SCB_STATE_UNINITIALIZE_ON_RESTORE, SCB_STATE_UNINITIALIZE_ON_RESTORE, "UninitializeOnRestore" }, { SCB_STATE_RESTORE_UNDERWAY, SCB_STATE_RESTORE_UNDERWAY, "RestoreUnderway" }, { SCB_STATE_NOTIFY_ADD_STREAM, SCB_STATE_NOTIFY_ADD_STREAM, "NotifyAddStream" }, { SCB_STATE_NOTIFY_REMOVE_STREAM, SCB_STATE_NOTIFY_REMOVE_STREAM, "NotifyRemoveStream" }, { SCB_STATE_NOTIFY_RESIZE_STREAM, SCB_STATE_NOTIFY_RESIZE_STREAM, "NotifyResizeStream" }, { SCB_STATE_NOTIFY_MODIFY_STREAM, SCB_STATE_NOTIFY_MODIFY_STREAM, "NotifyModifyStream" }, { SCB_STATE_TEMPORARY, SCB_STATE_TEMPORARY, "Temporary" }, { SCB_STATE_WRITE_COMPRESSED, SCB_STATE_WRITE_COMPRESSED, "Compressed" }, { SCB_STATE_REALLOCATE_ON_WRITE, SCB_STATE_REALLOCATE_ON_WRITE, "DeallocateOnWrite" }, { SCB_STATE_DELAY_CLOSE, SCB_STATE_DELAY_CLOSE, "DelayClose" }, { SCB_STATE_WRITE_ACCESS_SEEN, SCB_STATE_WRITE_ACCESS_SEEN, "WriteAccessSeen" }, { SCB_STATE_CONVERT_UNDERWAY, SCB_STATE_CONVERT_UNDERWAY, "ConvertUnderway" }, { SCB_STATE_VIEW_INDEX, SCB_STATE_VIEW_INDEX, "ViewIndex" }, { SCB_STATE_DELETE_COLLATION_DATA, SCB_STATE_DELETE_COLLATION_DATA, "DeleteCollationData" }, { SCB_STATE_VOLUME_DISMOUNTED, SCB_STATE_VOLUME_DISMOUNTED, "VolumeDismounted" }, { SCB_STATE_PROTECT_SPARSE_MCB, SCB_STATE_PROTECT_SPARSE_MCB, "ProtectSparseMcb" }, { SCB_STATE_MULTIPLE_OPENS, SCB_STATE_MULTIPLE_OPENS, "MultipleOpens" }, { 0 } }; STATE ScbPersist[] = { { SCB_PERSIST_USN_JOURNAL, SCB_PERSIST_USN_JOURNAL, "UsnJournal" }, { 0 } }; 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_PRELOAD_MFT, VCB_STATE_PRELOAD_MFT, "PreloadMft" }, { 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" }, { VCB_STATE_EXPLICIT_LOCK, VCB_STATE_EXPLICIT_LOCK, "ExplicitLock" }, { VCB_STATE_DISALLOW_DISMOUNT, VCB_STATE_DISALLOW_DISMOUNT, "DisallowDismount" }, { VCB_STATE_VALID_OBJECT_ID, VCB_STATE_VALID_OBJECT_ID, "ValidObjectId" }, { VCB_STATE_OBJECT_ID_CLEANUP, VCB_STATE_OBJECT_ID_CLEANUP, "ObjectIdCleanup" }, { VCB_STATE_USN_DELETE, VCB_STATE_USN_DELETE, "UsnDelete" }, { VCB_STATE_USN_JOURNAL_PRESENT, VCB_STATE_USN_JOURNAL_PRESENT, "UsnJournalPresent" }, { VCB_STATE_EXPLICIT_DISMOUNT, VCB_STATE_EXPLICIT_DISMOUNT, "ExplicitDismount" }, { 0 } }; STATE LcbState[] = { { LCB_STATE_DELETE_ON_CLOSE, LCB_STATE_DELETE_ON_CLOSE, "DeleteOnClose" }, { LCB_STATE_LINK_IS_GONE, LCB_STATE_LINK_IS_GONE, "LinkIsGone" }, { LCB_STATE_EXACT_CASE_IN_TREE, LCB_STATE_EXACT_CASE_IN_TREE, "ExactCaseInTree" }, { LCB_STATE_IGNORE_CASE_IN_TREE, LCB_STATE_IGNORE_CASE_IN_TREE, "IgnoreCaseInTree" }, { LCB_STATE_DESIGNATED_LINK, LCB_STATE_DESIGNATED_LINK, "DesignatedLink" }, { LCB_STATE_VALID_HASH_VALUE, LCB_STATE_VALID_HASH_VALUE, "ValidHashValue" }, { 0 } }; char* LogOperation[] = { { "Noop " }, { "CompensationLogRecord " }, { "InitializeFileRecordSegment " }, { "DeallocateFileRecordSegment " }, { "WriteEndOfFileRecordSegment " }, { "CreateAttribute " }, { "DeleteAttribute " }, { "UpdateResidentValue " }, { "UpdateNonresidentValue " }, { "UpdateMappingPairs " }, { "DeleteDirtyClusters " }, { "SetNewAttributeSizes " }, { "AddIndexEntryRoot " }, { "DeleteIndexEntryRoot " }, { "AddIndexEntryAllocation " }, { "DeleteIndexEntryAllocation " }, { "WriteEndOfIndexBuffer " }, { "SetIndexEntryVcnRoot " }, { "SetIndexEntryVcnAllocation " }, { "UpdateFileNameRoot " }, { "UpdateFileNameAllocation " }, { "SetBitsInNonresidentBitMap " }, { "ClearBitsInNonresidentBitMap " }, { "HotFix " }, { "EndTopLevelAction " }, { "PrepareTransaction " }, { "CommitTransaction " }, { "ForgetTransaction " }, { "OpenNonresidentAttribute " }, { "OpenAttributeTableDump " }, { "AttributeNamesDump " }, { "DirtyPageTableDump " }, { "TransactionTableDump " }, { "UpdateRecordDataRoot " }, { "UpdateRecordDataAllocation " } }; #define LastLogOperation 0x22 char* AttributeTypeCode[] = { { "$UNUSED " }, // (0X0) { "$STANDARD_INFORMATION " }, // (0x10) { "$ATTRIBUTE_LIST " }, // (0x20) { "$FILE_NAME " }, // (0x30) { "$OBJECT_ID " }, // (0x40) { "$SECURITY_DESCRIPTOR " }, // (0x50) { "$VOLUME_NAME " }, // (0x60) { "$VOLUME_INFORMATION " }, // (0x70) { "$DATA " }, // (0x80) { "$INDEX_ROOT " }, // (0x90) { "$INDEX_ALLOCATION " }, // (0xA0) { "$BITMAP " }, // (0xB0) { "$REPARSE_POINT " }, // (0xC0) { "$EA_INFORMATION " }, // (0xD0) { "$EA " }, // (0xE0) { " INVALID TYPE CODE " }, // (0xF0) { "$LOGGED_UTILITY_STREAM " } // (0x100) }; char * LogEvent[] = { "SCE_VDL_CHANGE", "SCE_ZERO_NC", "SCE_ZERO_C", "SCE_READ", "SCE_WRITE", "SCE_ZERO_CAV", "SCE_ZERO_MF", "SCE_ZERO_FST", "SCE_CC_FLUSH", "SCE_CC_FLUSH_AND_PURGE", "SCE_WRITE_FILE_SIZES", "SCE_ADD_ALLOCATION", "SCE_ADD_SP_ALLOCATION", "SCE_SETCOMP_ADD_ALLOCATION", "SCE_SETSPARSE_ADD_ALLOCATION", "SCE_MOD_ATTR_ADD_ALLOCATION", "SCE_REALLOC1", "SCE_REALLOC2", "SCE_REALLOC3", "SCE_SETCOMPRESS", "SCE_SETSPARSE", "SCE_ZERO_STREAM", "SCE_VDD_CHANGE", "SCE_CC_SET_SIZE", "SCE_ZERO_C_TAIL_COMPRESSION", "SCE_ZERO_C_HEAD_COMPRESSION", "SCE_MAX_EVENT" }; struct { NODE_TYPE_CODE TypeCode; char *Text; } NodeTypeCodes[] = { { NTFS_NTC_DATA_HEADER, "Data Header" }, { NTFS_NTC_VCB, "Vcb" }, { NTFS_NTC_FCB, "Fcb" }, { NTFS_NTC_SCB_INDEX, "ScbIndex" }, { NTFS_NTC_SCB_ROOT_INDEX, "ScbRootIndex" }, { NTFS_NTC_SCB_DATA, "ScbData" }, { NTFS_NTC_SCB_MFT, "ScbMft" }, { NTFS_NTC_SCB_NONPAGED, "ScbNonPaged" }, { NTFS_NTC_CCB_INDEX, "CcbIndex" }, { NTFS_NTC_CCB_DATA, "CcbData" }, { NTFS_NTC_IRP_CONTEXT, "IrpContext" }, { NTFS_NTC_LCB, "Lcb" }, { NTFS_NTC_PREFIX_ENTRY, "PrefixEntry" }, { NTFS_NTC_QUOTA_CONTROL, "QuotaControl" }, { NTFS_NTC_USN_RECORD, "UsnRecord" }, { 0, "Unknown" } }; ULONG MyGetFieldData( IN ULONG64 TypeAddress, IN PUCHAR Type, IN PUCHAR Field, IN ULONG OutSize, OUT PULONG64 pOutValue, OUT PULONG64 pOutAddress ) /*++ Routine Description: Retrieves the symbol information for a field within a structure. Arguments: TypeAddress - Virtual address of the structure Type - Qualified type string Field - Field name OutSize - Size of the field pOutValue - Value of the vield pOutAddress - Virtual address of the field Return Value: Zero is success otherwise failure. --*/ { ULONG RetVal = 0; FIELD_INFO flds = { Field, NULL, OutSize, DBG_DUMP_FIELD_FULL_NAME | DBG_DUMP_FIELD_COPY_FIELD_DATA | DBG_DUMP_FIELD_RETURN_ADDRESS, 0, pOutValue }; SYM_DUMP_PARAM Sym = { sizeof(SYM_DUMP_PARAM), Type, DBG_DUMP_NO_PRINT, TypeAddress, NULL, NULL, NULL, 1, &flds }; ZeroMemory( pOutValue, OutSize ); RetVal = Ioctl( IG_DUMP_SYMBOL_INFO, &Sym, Sym.size ); if (OutSize < flds.size) { if (OutSize == sizeof(ULONG64)) { *pOutValue = Sym.Fields->address; } else { memset( pOutValue, 0, OutSize ); } } if (pOutAddress) { if (RetVal == 0) { *pOutAddress = Sym.Fields->address; } else { *pOutAddress = 0; } } return RetVal; } VOID DumpValue( IN ULONG64 Address, IN PCHAR Type, IN PCHAR Field ) /*++ Routine Description: Prints the value of a 64/32 bit value based on a symbol name and address. Arguments: Address - Virtual address of the value Type - Qualified type string Field - Field name Return Value: None. --*/ { static ULONG64 ValueBuffer[128]; ULONG64 Value,OutputAddress; if (MyGetFieldData( Address, Type, Field, sizeof(Value), (PVOID)ValueBuffer, &OutputAddress )) { Value = 0; } else { Value = ValueBuffer[0]; } dprintf( "\n(%03x) ", (ULONG)(OutputAddress-Address) ); dprintf( " %s", FormatValue(Value) ); dprintf( " %s ", Field ); } VOID DumpPtrValue( IN ULONG64 Address, IN PCHAR TextStr ) /*++ Routine Description: Prints the value of a pointer. Arguments: Address - Virtual address of the value TextStr - Tag to print with the pointer value Return Value: None. --*/ { ULONG64 PtrValue; ULONG BytesRead; if (ReadMemory( Address, &PtrValue, sizeof(PtrValue), &BytesRead )) { dprintf( "\n %s %s", FormatValue(PtrValue), TextStr ); } } ULONG64 ReadValue( IN ULONG64 Address, IN PCHAR Type, IN PCHAR Field ) /*++ Routine Description: Reads the value of a 64/32 bit value Arguments: Address - Virtual address of the value Type - Qualified type string Field - Field name Return Value: The 64/32 bit value or zero. --*/ { static ULONG64 ValueBuffer[128]; ULONG64 Value,OutputAddress; if (MyGetFieldData( Address, Type, Field, sizeof(Value), (PVOID)ValueBuffer, &OutputAddress )) { Value = 0; } else { Value = ValueBuffer[0]; } return Value; } ULONG ReadUlongValue( IN ULONG64 Address, IN PCHAR Type, IN PCHAR Field ) /*++ Routine Description: Reads the value of a 32 bit value Arguments: Address - Virtual address of the value Type - Qualified type string Field - Field name Return Value: The 32 bit value or zero. --*/ { static ULONG ValueBuffer[128]; ULONG Value; ULONG64 OutputAddress; if (MyGetFieldData( Address, Type, Field, sizeof(Value), (PVOID)ValueBuffer, &OutputAddress )) { Value = 0; } else { Value = ValueBuffer[0]; } return Value; } USHORT ReadShortValue( IN ULONG64 Address, IN PCHAR Type, IN PCHAR Field ) /*++ Routine Description: Reads the value of a 16 bit value Arguments: Address - Virtual address of the value Type - Qualified type string Field - Field name Return Value: The 16 bit value or zero. --*/ { static USHORT ValueBuffer[128]; USHORT Value; ULONG64 OutputAddress; if (MyGetFieldData( Address, Type, Field, sizeof(Value), (PVOID)ValueBuffer, &OutputAddress )) { Value = 0; } else { Value = ValueBuffer[0]; } return Value; } VOID DumpUnicodeString( IN ULONG64 Address, IN PCHAR Type, IN PCHAR Field ) /*++ Routine Description: Prints the value (the actual string) of a string contained in a UNICODE_STRING structure Arguments: Address - Virtual address of the structure Type - Qualified type string for the structure containing the string Field - Field name for the string Return Value: None. --*/ { ULONG64 Value; ULONG64 OutputAddress; USHORT Length; ULONG64 BufferAddr; PWSTR Buffer; if (MyGetFieldData( Address, Type, Field, 0, (PVOID)&Value, &OutputAddress ) == 0) { if (ReadMemory( OutputAddress, &Length, sizeof(Length), (PULONG)&Value )) { if (Length) { GetFieldOffset( "UNICODE_STRING", "Buffer", (PULONG)&Value ); OutputAddress += Value; if (ReadMemory( OutputAddress, &BufferAddr, GetTypeSize("PWSTR"), (PULONG)&Value )) { if (BufferAddr) { Buffer = (PWSTR) malloc( Length + sizeof(WCHAR) ); if (Buffer) { if (ReadMemory( BufferAddr, Buffer, Length, (PULONG)&Value )) { Buffer[Length/sizeof(WCHAR)] = 0; dprintf( "\n(%03x) %s %s [%ws]", (ULONG)(OutputAddress-Address), FormatValue(BufferAddr), Field, Buffer ); free( Buffer ); return; } free( Buffer ); } } } } } } dprintf( "\n(%03x) %16x %s", (ULONG)(OutputAddress-Address), 0, Field ); return; } BOOL DumpString( IN ULONG64 Address, IN PCHAR Type, IN PCHAR LengthField, IN PCHAR StringField ) /*++ Routine Description: Prints the value (the actual string) of a string contained in a structure with a corresponding length field as another field member. Arguments: Address - Virtual address of the structure Type - Qualified type string for the structure containing the string LengthField - Field name for the length value StringField - Field name for the string Return Value: TRUE for success, FALSE for failure --*/ { BOOL Result = FALSE; ULONG Length; PWSTR String; ULONG Offset; // // read in the length // if (LengthField == NULL) { Length = GetTypeSize(StringField) / sizeof(WCHAR); } else { Length = (ULONG)ReadValue( Address, Type, LengthField ); } if (Length) { Length *= sizeof(WCHAR); // // allocate some memory to hold the file name // String = malloc( Length + sizeof(WCHAR) ); if (String) { // // get the field offset of the string // if (!GetFieldOffset( Type, StringField, &Offset )) { // // compute the address of the string // Address += Offset; // // read the unicode characters for the string // if (ReadMemory( Address, String, Length, &Offset )) { // // zero terminate the string so we can print it out properly // String[Length/sizeof(WCHAR)] = 0; // // finally print the data // dprintf( "%ws", String ); Result = TRUE; } } // // free the string memory // free( String ); } } return Result; } ULONG64 ReadArrayValue( IN ULONG64 Address, IN PCHAR Type, IN PCHAR Field, IN ULONG Index ) /*++ Routine Description: Reads a value/element contained in an array. Arguments: Address - Virtual address of the structure Type - Qualified type string for the structure containing the array Field - Field name for the array Index - The element that is requested Return Value: The element value or zero --*/ { CHAR Buff[64]; sprintf( Buff, "%s[%d]", Field, Index ); return ReadValue( Address, Type, Buff ); } ULONG GetOffset( IN LPSTR Type, IN LPSTR Field ) /*++ Routine Description: Gets the offset for a field within a structure Arguments: Type - Qualified type string for the structure containing the field Field - Field name Return Value: The offset value or zero --*/ { FIELD_INFO flds = { (PUCHAR)Field, (PUCHAR)"", 0, DBG_DUMP_FIELD_FULL_NAME | DBG_DUMP_FIELD_RETURN_ADDRESS, 0, NULL}; SYM_DUMP_PARAM Sym = { sizeof (SYM_DUMP_PARAM), (PUCHAR)Type, DBG_DUMP_NO_PRINT, 0, NULL, NULL, NULL, 1, &flds }; ULONG Err; Sym.nFields = 1; Err = Ioctl( IG_DUMP_SYMBOL_INFO, &Sym, Sym.size ); if (Err == 0) { return (ULONG) (flds.address - Sym.addr); } return -1; } PSTR FormatValue( ULONG64 addr ) /*++ Routine Description: Format a 64 bit address, showing the high bits or not according to various flags. This version does not print leading 0's. An array of static string buffers is used, returning a different buffer for each successive call so that it may be used multiple times in the same print. Arguments: addr - Supplies the value to format Return Value: A pointer to the string buffer containing the formatted number --*/ { #define MAX_FORMAT_STRINGS 8 static CHAR strings[MAX_FORMAT_STRINGS][18]; static int next = 0; LPSTR string; string = strings[next]; ++next; if (next >= MAX_FORMAT_STRINGS) { next = 0; } if ((KdDebuggerData.KernBase >> 32) != 0) { // // we're on a 64bit machines // sprintf( string, "%08x`%08x", (ULONG)(addr>>32), (ULONG)addr ); } else { sprintf( string, "%08x", (ULONG)addr ); } return string; } VOID PrintState( STATE *ps, ULONG state ) /*++ Routine Description: Prints a state string based on the provided state value Arguments: ps - State string array State - State value Return Value: None --*/ { 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"); } const char * TypeCodeGuess ( IN NODE_TYPE_CODE TypeCode ) /*++ Routine Description: Guess at a structure's type code Arguments: TypeCode - Type code from the data structure Return Value: None --*/ { int i = 0; while (NodeTypeCodes[i].TypeCode != 0 && NodeTypeCodes[i].TypeCode != TypeCode) { i++; } return NodeTypeCodes[i].Text; } VOID FindData( IN ULONG64 FileObjectAddress, IN ULONG64 Offset, IN BOOL Trace, OUT PULONG64 DataAddress ) /*++ Routine Description: Find the cache address for a given file object at the given offset. Arguments: FileObjectAddress - Gives the address of the file object to dump Offset - Gives the offset within the file to dump DataAddress - Where to store the address of the data. This will contain 0 if the data at the given offset is not mapped. Return Value: None. --*/ { ULONG64 VacbAddr; // the address of the vacb ULONG64 VacbAddrAddr; // the address of the address of the vacb ULONG VacbNumber; ULONG OffsetWithinVacb; ULONG Level; ULONG Shift; ULONG OffsetForLevel; LONGLONG OriginalOffset = Offset; ULONG PtrSize = GetTypeSize("PVOID"); ULONG Type, InVacbsOffset; ULONG64 SectionObjectPointer, SharedCacheMap, Vacbs, SectionSize_Quad; *DataAddress = 0; if (Trace) { dprintf( "\n FindData for FileObject %08p", FileObjectAddress ); } if (GetFieldValue(FileObjectAddress, "FILE_OBJECT", "Type", Type)) { dprintf("Unable to read FILE_OBJECT at %p\n", FileObjectAddress); return; } // // Before we get into too much trouble, make sure this looks like a FileObject. // // // Type of a FileObject must be IO_TYPE_FILE. // if (Type != IO_TYPE_FILE) { dprintf( "\nFILE_OBJECT type signature does not match, type code is %s", TypeCodeGuess((USHORT) Type )); return; } GetFieldValue(FileObjectAddress, "FILE_OBJECT", "SectionObjectPointer", SectionObjectPointer); if (Trace) { dprintf( " Section Object Pointers: %08p", SectionObjectPointer ); } if (GetFieldValue(SectionObjectPointer, "SECTION_OBJECT_POINTERS", "SharedCacheMap", SharedCacheMap)) { dprintf("Unable to read SECTION_OBJECT_POINTERS at %p\n", SectionObjectPointer); return; } if (Trace) { dprintf( "\n Shared Cache Map: %08p", SharedCacheMap ); } if (GetFieldValue(SharedCacheMap, "SHARED_CACHE_MAP", "Vacbs", Vacbs)) { dprintf("Unable to read SHARED_CACHE_MAP at %p\n", SharedCacheMap); return; } GetFieldValue(SharedCacheMap, "SHARED_CACHE_MAP", "SectionSize.QuadPart", SectionSize_Quad); OffsetWithinVacb = (((ULONG) Offset) & (VACB_MAPPING_GRANULARITY - 1)); GetFieldOffset("SHARED_CACHE_MAP", "InitialVacbs", &InVacbsOffset); if (Trace) { dprintf( " File Offset: %I64x ", Offset ); } if (Vacbs == (SharedCacheMap + InVacbsOffset)) { // // Small file case -- we're using one of the Vacbs in the Shared Cache Map's // embedded array. // CHAR Buff[50]; VacbNumber = (ULONG) (Offset >> VACB_OFFSET_SHIFT); if (VacbNumber >= PREALLOCATED_VACBS) { dprintf( "\nInvalid VacbNumber for resident Vacb" ); return; } sprintf(Buff, "InitialVacbs[%d]", VacbNumber); GetFieldValue(SharedCacheMap, "SHARED_CACHE_MAP", Buff, VacbAddr); if (Trace) { dprintf( "in VACB number %x", VacbNumber ); } } else if (SectionSize_Quad <= VACB_SIZE_OF_FIRST_LEVEL) { // // Medium file case -- we're using a single level (linear) structure to // store the Vacbs. // VacbNumber = (ULONG) (Offset >> VACB_OFFSET_SHIFT); VacbAddrAddr = Vacbs + (VacbNumber * PtrSize); if (ReadPtr(VacbAddrAddr, &VacbAddr)) { dprintf("Unable to read at %p\n", VacbAddrAddr); return; } if (Trace) { dprintf( "in VACB number %x", VacbNumber ); } } else { // // Large file case -- multilevel Vacb storage. // Level = 0; Shift = VACB_OFFSET_SHIFT + VACB_LEVEL_SHIFT; // // Loop to calculate how many levels we have and how much we have to // shift to index into the first level. // do { Level += 1; Shift += VACB_LEVEL_SHIFT; } while (SectionSize_Quad > ((ULONG64)1 << Shift)); // // Now descend the tree to the bottom level to get the caller's Vacb. // Shift -= VACB_LEVEL_SHIFT; // dprintf( "Shift: 0x%x\n", Shift ); OffsetForLevel = (ULONG) (Offset >> Shift); VacbAddrAddr = Vacbs + (OffsetForLevel * PtrSize); if (ReadPtr(VacbAddrAddr, &VacbAddr)) { dprintf("Unable to read at %p\n", VacbAddrAddr); return; } while ((VacbAddr != 0) && (Level != 0)) { Level -= 1; Offset &= ((LONGLONG)1 << Shift) - 1; Shift -= VACB_LEVEL_SHIFT; // dprintf( "Shift: 0x%x\n", Shift ); OffsetForLevel = (ULONG) (Offset >> Shift); VacbAddrAddr = VacbAddr + (OffsetForLevel * PtrSize); if (ReadPtr(VacbAddrAddr, &VacbAddr)) { dprintf("Unable to read at %p\n", VacbAddrAddr); return; } } } if (VacbAddr != 0) { ULONG64 Base; if (Trace) { dprintf( "\n Vacb: %08p", VacbAddr ); } if (GetFieldValue(VacbAddr, "_VACB", "BaseAddress", Base)) { dprintf("Unable to read VACB base address at %p.", VacbAddr); return; } if (Trace) { dprintf( "\n Your data is at: %08p", (Base + OffsetWithinVacb) ); } *DataAddress = Base + OffsetWithinVacb; } else { if (Trace) { dprintf( "\n Data at offset %I64x not mapped", OriginalOffset ); } } return; } DECLARE_DUMP_FUNCTION( DumpCcb ) /*++ Routine Description: Dump a specific ccb. Arguments: Address - Gives the address of the fcb to dump Return Value: None --*/ { ULONG64 Value; INIT_DUMP(); Value = ReadValue( Address, SYM(CCB), "NodeTypeCode" ); // // 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 (Value != NTFS_NTC_CCB_DATA && Value != NTFS_NTC_CCB_INDEX) { dprintf( "\nCCB signature does not match, type code is %s", TypeCodeGuess( (NODE_TYPE_CODE)Value )); return; } // // Having established that this looks like a ccb, let's dump the // interesting parts. // dprintf( "\nCcb: %s", FormatValue(Address) ); Value = ReadValue( Address, SYM(CCB), "Flags" ); PrintState( CcbState, (ULONG)Value ); DumpValue( Address, SYM(CCB), "Flags" ); dprintf( "\n OpenType: " ); Value = ReadValue( Address, SYM(CCB), "TypeOfOpen" ); switch (Value) { case UserFileOpen : dprintf( "UserFileOpen" ); break; case UserDirectoryOpen : dprintf( "UserDirectoryOpen" ); break; case UserVolumeOpen : dprintf( "UserVolumeOpen" ); break; case StreamFileOpen : dprintf( "StreamFileOpen" ); break; case UserViewIndexOpen : dprintf( "UserViewIndexOpen" ); break; } DumpUnicodeString( Address, SYM(CCB), "FullFileName" ); DumpValue( Address, SYM(CCB), "LastFileNameOffset" ); DumpValue( Address, SYM(CCB), "EaModificationCount" ); DumpValue( Address, SYM(CCB), "NextEaOffset" ); DumpValue( Address, SYM(CCB), "Lcb" ); DumpValue( Address, SYM(CCB), "TypeOfOpen" ); DumpValue( Address, SYM(CCB), "IndexContext" ); DumpValue( Address, SYM(CCB), "QueryLength" ); DumpValue( Address, SYM(CCB), "QueryBuffer" ); DumpValue( Address, SYM(CCB), "IndexEntryLength" ); DumpValue( Address, SYM(CCB), "IndexEntry" ); DumpValue( Address, SYM(CCB), "LcbLinks.Flink" ); DumpValue( Address, SYM(CCB), "FcbToAcquire" ); dprintf( "\n" ); } ULONG DumpFcbLinks( IN PFIELD_INFO ListElement, IN PVOID Context ) /*++ Routine Description: Enumeration callback function for FcbLinks Arguments: ListElement - Pointer to the containing record Context - Opaque context passed from the origination function Return Value: TRUE to discontinue the enumeration FALSE to continue the enumeration --*/ { ULONG64 Lcb = ListElement->address; PDUMP_ENUM_CONTEXT dec = (PDUMP_ENUM_CONTEXT)Context; if (CheckControlC()) { return TRUE; } if (dec->Options >= 1) { DumpLcb( Lcb, 0, dec->Options-1, dec->Processor, dec->hCurrentThread ); } else { dprintf( "\n Lcb %s", FormatValue(Lcb) ); } return FALSE; } ULONG DumpScbLinks( IN PFIELD_INFO ListElement, IN PVOID Context ) /*++ Routine Description: Enumeration callback function for ScbLinks Arguments: ListElement - Pointer to the containing record Context - Opaque context passed from the origination function Return Value: TRUE to discontinue the enumeration FALSE to continue the enumeration --*/ { ULONG64 Scb = ListElement->address; PDUMP_ENUM_CONTEXT dec = (PDUMP_ENUM_CONTEXT)Context; ULONG Offset = 0; if (CheckControlC()) { return TRUE; } if (dec->Options >= 1) { DumpScb( Scb, 0, dec->Options-1, dec->Processor, dec->hCurrentThread ); } else { dprintf( "\n Scb %s", FormatValue(Scb) ); } return FALSE; } DECLARE_DUMP_FUNCTION( DumpFcb ) /*++ Routine Description: Dump a specific fcb. Arguments: Address - Gives the address of the fcb to dump Return Value: None --*/ { ULONG64 Value; DUMP_ENUM_CONTEXT dec; INIT_DUMP(); Value = ReadValue( Address, SYM(FCB), "NodeTypeCode" ); // // 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 (Value != NTFS_NTC_FCB) { dprintf( "\nFCB signature does not match, type code is %s", TypeCodeGuess( (NODE_TYPE_CODE)Value ) ); return; } dprintf( "\nFcb: %s", FormatValue(Address) ); // // Having established that this looks like an fcb, let's dump the // interesting parts. // PrintState( FcbState, (ULONG)ReadValue( Address, SYM(FCB), "FcbState" ) ); DumpValue( Address, SYM(FCB), "FcbState" ); DumpValue( Address, SYM(FCB), "FileReference" ); DumpValue( Address, SYM(FCB), "CleanupCount" ); DumpValue( Address, SYM(FCB), "CloseCount" ); DumpValue( Address, SYM(FCB), "ReferenceCount" ); DumpValue( Address, SYM(FCB), "FcbDenyDelete" ); DumpValue( Address, SYM(FCB), "FcbDeleteFile" ); DumpValue( Address, SYM(FCB), "BaseExclusiveCount" ); DumpValue( Address, SYM(FCB), "EaModificationCount" ); DumpValue( Address, SYM(FCB), "Vcb" ); DumpValue( Address, SYM(FCB), "FcbMutex" ); DumpValue( Address, SYM(FCB), "Resource" ); DumpValue( Address, SYM(FCB), "PagingIoResource" ); DumpValue( Address, SYM(FCB), "InfoFlags" ); DumpValue( Address, SYM(FCB), "LinkCount" ); DumpValue( Address, SYM(FCB), "TotalLinks" ); DumpValue( Address, SYM(FCB), "SharedSecurity" ); DumpValue( Address, SYM(FCB), "QuotaControl" ); DumpValue( Address, SYM(FCB), "ClassId" ); DumpValue( Address, SYM(FCB), "OwnerId" ); DumpValue( Address, SYM(FCB), "DelayedCloseCount" ); DumpValue( Address, SYM(FCB), "SecurityId" ); DumpValue( Address, SYM(FCB), "FcbUsnRecord" ); // // walk the queue of links for this file // dec.hCurrentThread = hCurrentThread; dec.Processor = Processor; dec.Options = Options; dprintf( "\n\nLinks:" ); Value = ReadValue( Address, SYM(FCB), "LcbQueue.Flink" ); if (Value) { ListType( SYM(LCB), Value, TRUE, "FcbLinks.Flink", (PVOID)&dec, DumpFcbLinks ); } dprintf( "\n\nStreams:" ); Value = ReadValue( Address, SYM(FCB), "ScbQueue.Flink" ); if (Value) { ListType( SYM(SCB), Value, TRUE, "FcbLinks.Flink", (PVOID)&dec, DumpScbLinks ); } dprintf( "\n" ); } DECLARE_DUMP_FUNCTION( DumpFcbTable ) /*++ Routine Description: Dump the fcb table. Arguments: Address - Gives the address of the fcb table to dump Return Value: None --*/ { ULONG64 Value; ULONG64 TableElemAddr; ULONG64 RestartKey; ULONG64 FcbAddr; ULONG Offset1; ULONG Offset2; PWSTR FileName; BOOL GotIt; INIT_DUMP(); // // Dump the FcbTable // Value = ReadValue( Address, SYM(RTL_AVL_TABLE), "CompareRoutine" ); if (Value != GetExpression("NTFS!NtfsFcbTableCompare")) { dprintf( "\nThe address [%s] does not seem to point to a FCB table", FormatValue(Address) ); return; } dprintf( "\n FcbTable %s", FormatValue(Address) ); dprintf( "\n FcbTable has %x elements", (ULONG)ReadValue( Address, SYM(RTL_AVL_TABLE), "NumberGenericTableElements" ) ); RestartKey = 0; for (TableElemAddr = KdEnumerateGenericTableWithoutSplaying(Address, &RestartKey); TableElemAddr != 0; TableElemAddr = KdEnumerateGenericTableWithoutSplaying(Address, &RestartKey)) { FcbAddr = ReadValue( TableElemAddr, SYM(FCB_TABLE_ELEMENT), "Fcb" ); if (Options >= 1) { DumpFcb( FcbAddr, 0, Options - 2, Processor, hCurrentThread ); } else { GotIt = FALSE; // // get the address of the FCB.LcbQueue LIST_ENTRY // Value = ReadValue( FcbAddr, SYM(FCB), "LcbQueue.Flink" ); if (Value) { // // get the offset of the LCB.FcbLinks LIST_ENTRY // if (!GetFieldOffset( SYM(LCB), "FcbLinks.Flink", &Offset1 )) { // // get the field offset of the FCB.LcbQueue LIST_ENTRY // if (!GetFieldOffset( SYM(FCB), "LcbQueue.Flink", &Offset2 )) { // // check to see if the list is empty // if (Value != FcbAddr+Offset2) { // // compute the address of the LCB // Value -= Offset1; // // get the length of the file name // Offset2 = (ULONG)(ReadValue( Value, SYM(LCB), "FileNameLength" ) * GetTypeSize("WCHAR")); if (Offset2) { // // allocate some memory to hold the file name // FileName = malloc( Offset2 + GetTypeSize("WCHAR") ); if (FileName) { // // get the field offset of the LCB.FileName // if (!GetFieldOffset( SYM(LCB), "FileName", &Offset1 )) { // // compute the address of the file name character array // Value += Offset1; // // read the unicode characters for the file name // if (ReadMemory( Value, FileName, Offset2, (PULONG)&Offset1 )) { // // zero terminate the name so we can print it out properly // FileName[Offset2/GetTypeSize("WCHAR")] = 0; // // finally print the data // GotIt = TRUE; dprintf( "\n Fcb %s for FileReference %08lx FcbTableElement %s %ws 0x%x", FormatValue(FcbAddr), (ULONG)ReadValue( TableElemAddr, SYM(FCB_TABLE_ELEMENT), "FileReference.SegmentNumberLowPart" ), FormatValue(TableElemAddr), FileName, (ULONG)ReadValue( FcbAddr, SYM(FCB), "CleanupCount" ) ); } } // // free the file name memory // free( FileName ); } } } } } } if (!GotIt) { dprintf( "\n Fcb %s for FileReference %08lx FcbTableElement %s 0x%x", FormatValue(FcbAddr), (ULONG)ReadValue( TableElemAddr, SYM(FCB_TABLE_ELEMENT), "FileReference.SegmentNumberLowPart" ), FormatValue(TableElemAddr), (ULONG)ReadValue( FcbAddr, SYM(FCB), "CleanupCount" ) ); } } if (CheckControlC( )) { break; } } // endfor } DECLARE_DUMP_FUNCTION( DumpFileObject ) /*++ Routine Description: Dump a FileObject. Arguments: Address - Gives the address of the FileObject to dump Return Value: None --*/ { ULONG64 Value; INIT_DUMP(); Value = ReadValue( Address, SYM(FILE_OBJECT), "Type" ); if (Value != IO_TYPE_FILE) { dprintf( "Invalid signature, probably not a file object" ); return; } dprintf( "\nFileObject: %p", Address ); Value = ReadValue( Address, SYM(FILE_OBJECT), "FsContext" ); if (Value) { DumpScb( Value, 0, Options, Processor, hCurrentThread ); Value = ReadValue( Address, SYM(FILE_OBJECT), "FsContext2" ); if (Value) { DumpCcb( Value, 0, Options, Processor, hCurrentThread ); } } DumpValue( Address, SYM(FILE_OBJECT), "DeviceObject" ); DumpValue( Address, SYM(FILE_OBJECT), "Vpb" ); DumpValue( Address, SYM(FILE_OBJECT), "FsContext" ); DumpValue( Address, SYM(FILE_OBJECT), "FsContext2" ); DumpValue( Address, SYM(FILE_OBJECT), "SectionObjectPointer" ); DumpValue( Address, SYM(FILE_OBJECT), "PrivateCacheMap" ); DumpValue( Address, SYM(FILE_OBJECT), "FinalStatus" ); DumpValue( Address, SYM(FILE_OBJECT), "RelatedFileObject" ); DumpValue( Address, SYM(FILE_OBJECT), "LockOperation" ); DumpValue( Address, SYM(FILE_OBJECT), "DeletePending" ); DumpValue( Address, SYM(FILE_OBJECT), "ReadAccess" ); DumpValue( Address, SYM(FILE_OBJECT), "WriteAccess" ); DumpValue( Address, SYM(FILE_OBJECT), "DeleteAccess" ); DumpValue( Address, SYM(FILE_OBJECT), "SharedRead" ); DumpValue( Address, SYM(FILE_OBJECT), "SharedWrite" ); DumpValue( Address, SYM(FILE_OBJECT), "SharedDelete" ); DumpValue( Address, SYM(FILE_OBJECT), "Flags" ); DumpUnicodeString( Address, SYM(FILE_OBJECT), "FileName" ); DumpValue( Address, SYM(FILE_OBJECT), "CurrentByteOffset" ); DumpValue( Address, SYM(FILE_OBJECT), "Waiters" ); DumpValue( Address, SYM(FILE_OBJECT), "Busy" ); DumpValue( Address, SYM(FILE_OBJECT), "LastLock" ); DumpValue( Address, SYM(FILE_OBJECT), "Lock" ); DumpValue( Address, SYM(FILE_OBJECT), "Event" ); DumpValue( Address, SYM(FILE_OBJECT), "CompletionContext" ); dprintf( "\n" ); } DECLARE_DUMP_FUNCTION( DumpFileObjectFromIrp ) /*++ Routine Description: Dump a FileObject given an Irp. Arguments: Address - Gives the address of the Irp where the FileObject can be found Return Value: None --*/ { ULONG64 Value; INIT_DUMP(); Value = ReadValue( Address, SYM(IRP), "Type" ); if (Value != IO_TYPE_IRP) { dprintf( "IRP signature does not match, probably not an IRP\n" ); return; } dprintf( "\nIrp: %s", FormatValue(Address) ); // // only the current irp stack is worth dumping // the - 1 is there because irp.CurrentLocation is 1 based // Value = Address + GetTypeSize(NT(IRP)) + (GetTypeSize(NT(IO_STACK_LOCATION)) * (ReadValue( Address, NT(IRP), "CurrentLocation" ) - 1)); Value = ReadValue( Value, NT(IO_STACK_LOCATION), "FileObject" ); DumpFileObject( Value, 0, Options, Processor, hCurrentThread ); } DECLARE_DUMP_FUNCTION( DumpFileRecord ) /*++ Routine Description: Dump a FileRecord given a FileObject or Fcb. Arguments: Address - Gives the address of a FileObject or Fcb. Return Value: None --*/ { ULONG64 Value; ULONG64 DataAddress; ULONG64 ScbAddress; ULONG64 FcbAddress; ULONG64 VcbAddress; ULONG64 FoAddress; INIT_DUMP(); Value = ReadValue( Address, NT(FILE_OBJECT), "Type" ); switch (Value) { case IO_TYPE_FILE: dprintf( "\nFileObject: %s", FormatValue(Address) ); ScbAddress = ReadValue( Address, NT(FILE_OBJECT), "FsContext" ); if (ScbAddress == 0) { dprintf( "No FsContext in the file object" ); return; } FcbAddress = ReadValue( ScbAddress, SYM(SCB), "Fcb" ); break; case NTFS_NTC_FCB: dprintf( "\nFcb: %s", FormatValue(Address) ); FcbAddress = Address; ScbAddress = 0; break; case NTFS_NTC_SCB_DATA: case NTFS_NTC_SCB_INDEX: dprintf( "\nScb: %s", FormatValue(Address) ); ScbAddress = Address; FcbAddress = ReadValue( ScbAddress, SYM(SCB), "Fcb" ); break; default: dprintf( "Invalid signature, not a file object or Fcb" ); return; } VcbAddress = ReadValue( FcbAddress, SYM(FCB), "Vcb" ); dprintf( " Vcb: %s", FormatValue(VcbAddress) ); dprintf( " FRS: %08lx,%04lx", ReadValue( FcbAddress, SYM(FCB), "FileReference.SegmentNumberLowPart" ), ReadValue( FcbAddress, SYM(FCB), "FileReference.SequenceNumber" )); ScbAddress = ReadValue( VcbAddress, SYM(VCB), "MftScb" ); dprintf( " MftScb: %s", FormatValue(ScbAddress) ); dprintf( "reading fo in mftscb 0x%x 0x%x\n", GetOffset( SYM(SCB), "Header.FilterContexts" ), GetOffset( SYM(SCB), "Header.PendingEofAdvances" ) ); FoAddress = ReadValue( ScbAddress, SYM(SCB), "FileObject" ); dprintf( "finding data in mft fo 0x%s\n", FormatValue(FoAddress) ); FindData( FoAddress, ReadValue( FcbAddress, SYM(FCB), "FileReference.SegmentNumberLowPart" ) * ReadValue( VcbAddress, SYM(VCB), "BytesPerFileRecordSegment" ), Options, &DataAddress ); if (DataAddress == 0) { dprintf( "\nFileRecord is not mapped" ); } else { dprintf( "\nFileRecord at: %s", FormatValue(DataAddress) ); DumpFileRecordContents( DataAddress, 0, Options, Processor, hCurrentThread ); } } DECLARE_DUMP_FUNCTION( DumpFileRecordContents ) /*++ Routine Description: Dump a FileObject's contents given a pointer to where the FR is cached. Arguments: Address - Gives the address where the FR is cached. Return Value: None --*/ { ULONG64 Value; ULONG64 AttrAddress; INIT_DUMP(); Value = ReadValue( Address, SYM(FILE_RECORD_SEGMENT_HEADER), "MultiSectorHeader.Signature" ); if ((ULONG)Value != *(PULONG)FileSignature) { dprintf( "Not a file record %x", (ULONG)Value ); return; } AttrAddress = Address + ReadValue( Address, SYM(FILE_RECORD_SEGMENT_HEADER), "FirstAttributeOffset" ); while ((Value = ReadValue( AttrAddress, SYM(ATTRIBUTE_RECORD_HEADER), "TypeCode" )) != 0xffffffff) { dprintf( "\nAttribute type %x %s", (ULONG)Value, AttributeTypeCode[Value/0x10] ); dprintf( " at offset %x", AttrAddress - Address ); AttrAddress += ReadValue( AttrAddress, SYM(ATTRIBUTE_RECORD_HEADER), "RecordLength" ); if (CheckControlC()) { break; } } } DECLARE_DUMP_FUNCTION( DumpIrpContext ) /*++ Routine Description: Dump an IrpContext. Arguments: Address - Gives the address of the IrpContext to dump Return Value: None --*/ { ULONG64 Value; INIT_DUMP(); dprintf( "\nIrpContext: %s", FormatValue(Address) ); Value = ReadValue( Address, SYM(IRP_CONTEXT), "NodeTypeCode" ); if (Value != NTFS_NTC_IRP_CONTEXT) { dprintf( "\nIRP_CONTEXT signature does not match, type code is %s", TypeCodeGuess( (NODE_TYPE_CODE)Value ) ); return; } Value = ReadValue( Address, SYM(IRP_CONTEXT), "OriginatingIrp" ); if (Value) { DumpFileObjectFromIrp( Value, 0, Options, Processor, hCurrentThread ); } dprintf( "\n" ); } DECLARE_DUMP_FUNCTION( DumpIrpContextFromThread ) /*++ 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 --*/ { ULONG64 Value; INIT_DUMP(); // // Lookup the current thread if the user didn't specify one. // if (Address == 0) { GetCurrentThreadAddr( Processor, &Address ); } Value = ReadValue( Address, NT(ETHREAD), "TopLevelIrp" ); if (Value) { dprintf( "\nThread %s", FormatValue(Address) ); Value = ReadValue( Value, SYM(TOP_LEVEL_CONTEXT), "ThreadIrpContext" ); DumpIrpContext( Value, 0, Options, Processor, hCurrentThread ); } dprintf( "\n" ); } DECLARE_DUMP_FUNCTION( DumpLcb ) /*++ Routine Description: Dump an Lcb. Arguments: Address - Gives the address of the Lcb to dump Return Value: None --*/ { ULONG64 Value; INIT_DUMP(); Value = ReadValue( Address, SYM(LCB), "NodeTypeCode" ); if (Value != NTFS_NTC_LCB) { dprintf( "\nLCB signature does not match, type code is %s", TypeCodeGuess( (NODE_TYPE_CODE)Value ) ); return; } dprintf( "\nLcb: %s", FormatValue(Address) ); PrintState( LcbState, (ULONG)ReadValue( Address, SYM(LCB), "LcbState" ) ); DumpUnicodeString( Address, SYM(LCB), "FileName" ); DumpValue( Address, SYM(LCB), "Scb" ); DumpValue( Address, SYM(LCB), "Fcb" ); } DECLARE_DUMP_FUNCTION( DumpLogFile ) /*++ Routine Description: Dump a log file. Arguments: Address - Gives the address of the Vcb whose log file should be dumped Return Value: None --*/ { ULONG64 Value; ULONG64 VcbAddress; ULONG64 LogFileSize; ULONG64 LogFileScb; ULONG SeqNumberBits; ULONG64 LogFileOffset; LONG LogFileMask; USHORT RedoOperation; USHORT UndoOperation; ULONG64 LogDataAddress; INIT_DUMP(); LogFileOffset = Options; Value = ReadValue( Address, SYM(VCB), "NodeTypeCode" ); switch (Value) { case NTFS_NTC_FCB: dprintf( "\nFcb: %s", FormatValue(Address) ); VcbAddress = ReadValue( Address, SYM(FCB), "Vcb" ); break; case NTFS_NTC_VCB: dprintf( "\nVcb: %s", FormatValue(Address) ); VcbAddress = Address; break; default: dprintf( "\nSignature is not an FCB or VCB, type code is %s", TypeCodeGuess( (NODE_TYPE_CODE)Value) ); return; } if (LogFileOffset == 0) { LogFileOffset = ReadValue( VcbAddress, SYM(VCB), "LastRestartArea.QuadPart" ); } dprintf( " Starting at LSN: 0x%016I64x", LogFileOffset ); LogFileScb = ReadValue( VcbAddress, SYM(VCB), "LogFileScb" ); LogFileSize = ReadValue( LogFileScb, SYM(SCB), "Header.FileSize.QuadPart" ); for (SeqNumberBits=0; LogFileSize!=0; SeqNumberBits+=1,LogFileSize=((ULONGLONG)(LogFileSize)) >> 1 ) { } LogFileMask = (1 << (SeqNumberBits - 3)) - 1; while (TRUE) { LogFileOffset &= LogFileMask; // clear some bits LogFileOffset = LogFileOffset << 3; // multiply by 8 Value = ReadValue( VcbAddress, SYM(VCB), "LogFileObject" ); FindData( Value, LogFileOffset, FALSE, &LogDataAddress ); if (LogDataAddress != 0) { // // It's mapped. // RedoOperation = ReadShortValue( LogDataAddress+GetTypeSize(SYM(LFS_RECORD_HEADER)), SYM(NTFS_LOG_RECORD_HEADER), "RedoOperation" ); UndoOperation = ReadShortValue( LogDataAddress+GetTypeSize(SYM(LFS_RECORD_HEADER)), SYM(NTFS_LOG_RECORD_HEADER), "UndoOperation" ); if (RedoOperation <= LastLogOperation && UndoOperation <= LastLogOperation) { dprintf( "\nRedo: %s", LogOperation[RedoOperation] ); dprintf( " Undo: %s", LogOperation[UndoOperation] ); dprintf( " Lsn: 0x%08lx", (ULONG)ReadValue( LogDataAddress, SYM(LFS_RECORD_HEADER), "ThisLsn.LowPart" ) ); } } else { break; } if (CheckControlC()) { break; } LogFileOffset = (ULONG)ReadValue( LogDataAddress, SYM(LFS_RECORD_HEADER), "ClientUndoNextLsn.LowPart" ); if (LogFileOffset == 0) { break; } } } DECLARE_DUMP_FUNCTION( DumpTransaction ) /*++ Routine Description: Dump a log file. Arguments: Address - Gives the address of the irpcontext to trace the transaction for Return Value: None --*/ { ULONG64 TransactionId; ULONG64 VcbAddress; ULONG64 TransactionTable; LSN FirstLsn; LSN CurrentLsn; ULONG64 LogFileObject; ULONG64 LogFileSize; ULONG64 LogFileScb; ULONG SeqNumberBits; ULONG64 LogFileOffset; LONG LogFileMask; USHORT RedoOperation; USHORT UndoOperation; ULONG64 LogDataAddress; ULONG64 MftScbAddress; ULONG64 MftFileObject; ULONG64 DataAddress; USHORT Type; INIT_DUMP(); // // Determine what type of input it is // Type = (USHORT) ReadValue( Address, SYM(IRP_CONTEXT), "NodeTypeCode" ); if (Type == NTFS_NTC_FCB) { // // Its an Fcb so read the filerecord and find the last LSN on disk from it // VcbAddress = ReadValue( Address, SYM(FCB), "Vcb" ); MftScbAddress = ReadValue( VcbAddress, SYM(VCB), "MftScb" ); MftFileObject = ReadValue( MftScbAddress, SYM(SCB), "FileObject" ); FindData( MftFileObject, ReadValue( Address, SYM(FCB), "FileReference.SegmentNumberLowPart" ) * ReadValue( VcbAddress, SYM(VCB), "BytesPerFileRecordSegment" ), 0, &DataAddress ); CurrentLsn.QuadPart = ReadValue( DataAddress, SYM(FILE_RECORD_SEGMENT_HEADER), "Lsn" ); dprintf( "Searching for last LSN: 0x%I64x on disk for file: 0x%I64x\n\n", CurrentLsn, ReadValue( Address, SYM(FCB), "FileReference.SegmentNumberLowPart" )); } else if (Type == NTFS_NTC_VCB ) { // // Its a vcb and filerecord so directly get the last LSN from it // VcbAddress = Address; CurrentLsn.QuadPart = ReadValue( Options, SYM(FILE_RECORD_SEGMENT_HEADER), "Lsn" ); dprintf( "0x%x\n", Options ); dprintf( "Searching for last LSN: 0x%I64x on disk for file: 0x%I64x\n\n", CurrentLsn, ReadValue( Options, SYM(FILE_RECORD_SEGMENT_HEADER), "SegmentNumberLowPart" )); } else if (Type == NTFS_NTC_IRP_CONTEXT) { // // Read in the transaction id and then find the transaction entry in the table // TransactionId = ReadValue( Address, SYM(IRP_CONTEXT), "TransactionId" ); VcbAddress = ReadValue( Address, SYM(IRP_CONTEXT), "Vcb" ); TransactionTable = ReadValue( VcbAddress, SYM(VCB), "TransactionTable.Table" ); FirstLsn.QuadPart = ReadValue( TransactionTable + TransactionId, SYM( TRANSACTION_ENTRY), "FirstLsn.QuadPart" ); CurrentLsn.QuadPart = ReadValue( TransactionTable + TransactionId, SYM( TRANSACTION_ENTRY), "PreviousLsn.QuadPart" ); if (TransactionId == 0) { dprintf( "No transaction active for this irpcontext\n" ); return; } dprintf( "Transaction: 0x%I64x from Lsn: 0x%I64x to 0x%I64x\n\n", TransactionId, FirstLsn, CurrentLsn ); } else { dprintf( "Unknown type 0x%x for ptr 0x%p\n", Type, Address ); return; } LogFileScb = ReadValue( VcbAddress, SYM(VCB), "LogFileScb" ); LogFileSize = ReadValue( LogFileScb, SYM(SCB), "Header.FileSize.QuadPart" ); LogFileObject = ReadValue( VcbAddress, SYM(VCB), "LogFileObject" ); for (SeqNumberBits=0; LogFileSize!=0; SeqNumberBits+=1,LogFileSize=((ULONGLONG)(LogFileSize)) >> 1 ) { } LogFileMask = (1 << (SeqNumberBits - 3)) - 1; LogFileOffset = CurrentLsn.QuadPart; while (TRUE) { LogFileOffset &= LogFileMask; // clear some bits LogFileOffset = LogFileOffset << 3; // multiply by 8 FindData( LogFileObject, LogFileOffset, FALSE, &LogDataAddress ); if (LogDataAddress != 0) { // // It's mapped. // RedoOperation = ReadShortValue( LogDataAddress+GetTypeSize(SYM(LFS_RECORD_HEADER)), SYM(NTFS_LOG_RECORD_HEADER), "RedoOperation" ); UndoOperation = ReadShortValue( LogDataAddress+GetTypeSize(SYM(LFS_RECORD_HEADER)), SYM(NTFS_LOG_RECORD_HEADER), "UndoOperation" ); if (RedoOperation <= LastLogOperation && UndoOperation <= LastLogOperation) { dprintf( "Record: %p Lsn: %I64x Prev: %I64x Undo: %I64x\n", LogDataAddress, ReadValue( LogDataAddress, SYM(LFS_RECORD_HEADER), "ThisLsn.QuadPart" ), ReadValue( LogDataAddress, SYM(LFS_RECORD_HEADER), "ClientPreviousLsn.QuadPart" ), ReadValue( LogDataAddress, SYM(LFS_RECORD_HEADER), "ClientUndoNextLsn.QuadPart" ) ); dprintf( "Redo: %s Undo: %s\n\n", LogOperation[RedoOperation], LogOperation[UndoOperation] ); } } else { dprintf( "Data not mapped in log for offset: 0x%I64x\n", LogFileOffset ); break; } if (CheckControlC()) { break; } LogFileOffset = (ULONG)ReadValue( LogDataAddress, SYM(LFS_RECORD_HEADER), "ClientPreviousLsn.QuadPart" ); if (LogFileOffset == 0) { break; } } } DECLARE_DUMP_FUNCTION( DumpMcb ) /*++ Routine Description: Dump an Mcb. Arguments: Address - Gives the address of the Mcb to dump Return Value: None --*/ { ULONG64 NtfsMcbArray; ULONG64 MappingPairsAddress; ULONG RangeIdx; ULONG NtfsMcbArraySizeInUse; INIT_DUMP(); dprintf( "\nNtfsMcb: %s", FormatValue(Address) ); DumpValue( Address, SYM(NTFS_MCB), "FcbHeader" ); DumpValue( Address, SYM(NTFS_MCB), "PoolType" ); DumpValue( Address, SYM(NTFS_MCB), "NtfsMcbArraySizeInUse" ); DumpValue( Address, SYM(NTFS_MCB), "NtfsMcbArraySize" ); DumpValue( Address, SYM(NTFS_MCB), "NtfsMcbArray" ); DumpValue( Address, SYM(NTFS_MCB), "FastMutex" ); NtfsMcbArray = ReadValue( Address, SYM(NTFS_MCB), "NtfsMcbArray" ); NtfsMcbArraySizeInUse = (ULONG)ReadValue( Address, SYM(NTFS_MCB), "NtfsMcbArraySizeInUse" ); for (RangeIdx=0; RangeIdxaddress; PDUMP_ENUM_CONTEXT dec = (PDUMP_ENUM_CONTEXT)Context; ULONG64 Vpb; if (CheckControlC()) { return TRUE; } if (dec->Options >= 1) { DumpVcb( Vcb, 0, dec->Options-1, dec->Processor, dec->hCurrentThread ); } else { Vpb = ReadValue( Vcb, SYM(VCB), "Vpb" ); dprintf( "\n Vcb %s label: ", FormatValue(Vcb) ); if (!DumpString( Vpb, NT(VPB), "VolumeLabelLength", "VolumeLabel" )) { dprintf( "