You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
3746 lines
107 KiB
3746 lines
107 KiB
/*++
|
|
|
|
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 <cc.h>
|
|
|
|
#undef UpdateSequenceStructureSize
|
|
#undef UpdateSequenceArraySize
|
|
#include <lfsdisk.h>
|
|
#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 <filename unavailable> 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; RangeIdx<NtfsMcbArraySizeInUse; RangeIdx++) {
|
|
|
|
dprintf( "\n Range %d", RangeIdx );
|
|
|
|
DumpValue( NtfsMcbArray, SYM(NTFS_MCB_ARRAY), "StartingVcn" );
|
|
DumpValue( NtfsMcbArray, SYM(NTFS_MCB_ARRAY), "EndingVcn" );
|
|
DumpValue( NtfsMcbArray, SYM(NTFS_MCB_ARRAY), "NtfsMcbEntry" );
|
|
|
|
MappingPairsAddress = ReadValue( NtfsMcbArray, SYM(NTFS_MCB_ARRAY), "NtfsMcbEntry" ) +
|
|
GetOffset(SYM(NTFS_MCB_ENTRY),"LargeMcb") +
|
|
GetOffset(SYM(LARGE_MCB),"Mapping");
|
|
|
|
DumpPtrValue( MappingPairsAddress, "MappingPairs" );
|
|
|
|
//
|
|
// Go on to the next range.
|
|
//
|
|
|
|
NtfsMcbArray += GetTypeSize(SYM(NTFS_MCB_ARRAY));
|
|
|
|
if (CheckControlC()) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
dprintf( "\n" );
|
|
}
|
|
|
|
|
|
ULONG
|
|
DumpVcbQueue(
|
|
IN PFIELD_INFO ListElement,
|
|
IN PVOID Context
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Enumeration callback function for the Vcb Queue
|
|
|
|
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 Vcb = ListElement->address;
|
|
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( "<label unavailable>" );
|
|
}
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
DECLARE_DUMP_FUNCTION( DumpNtfsData )
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Dump the list of Vcbs for the global NtfsData.
|
|
|
|
Arguments:
|
|
|
|
Options - If 1, we recurse into the Vcbs and dump them
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
|
|
{
|
|
ULONG64 Value;
|
|
DUMP_ENUM_CONTEXT dec;
|
|
|
|
|
|
INIT_DUMP();
|
|
|
|
Address = GetExpression( "Ntfs!NtfsData" );
|
|
|
|
dprintf( "\nNtfsData: %s", FormatValue(Address) );
|
|
|
|
Value = ReadValue( Address, SYM(NTFS_DATA), "NodeTypeCode" );
|
|
if (Value != NTFS_NTC_DATA_HEADER) {
|
|
dprintf( "\nNtfsData signature does not match, type code is %s", TypeCodeGuess( (NODE_TYPE_CODE)Value ) );
|
|
return;
|
|
}
|
|
|
|
PrintState( NtfsFlags, (ULONG)ReadValue( Address, SYM(NTFS_DATA), "Flags" ) );
|
|
|
|
//
|
|
// dump the vcb queue (mounted volumes)
|
|
//
|
|
|
|
dec.hCurrentThread = hCurrentThread;
|
|
dec.Processor = Processor;
|
|
dec.Options = Options;
|
|
|
|
Value = ReadValue( Address, SYM(NTFS_DATA), "VcbQueue.Flink" );
|
|
if (Value) {
|
|
ListType( SYM(VCB), Value, TRUE, "VcbLinks.Flink", (PVOID)&dec, DumpVcbQueue );
|
|
}
|
|
|
|
dprintf( "\n" );
|
|
|
|
DumpValue( Address, SYM(NTFS_DATA), "DriverObject" );
|
|
DumpValue( Address, SYM(NTFS_DATA), "Resource" );
|
|
DumpValue( Address, SYM(NTFS_DATA), "AsyncCloseActive" );
|
|
DumpValue( Address, SYM(NTFS_DATA), "ReduceDelayedClose" );
|
|
DumpValue( Address, SYM(NTFS_DATA), "AsyncCloseCount" );
|
|
DumpValue( Address, SYM(NTFS_DATA), "OurProcess" );
|
|
DumpValue( Address, SYM(NTFS_DATA), "DelayedCloseCount" );
|
|
DumpValue( Address, SYM(NTFS_DATA), "FreeFcbTableSize" );
|
|
DumpValue( Address, SYM(NTFS_DATA), "FreeEresourceSize" );
|
|
DumpValue( Address, SYM(NTFS_DATA), "FreeEresourceTotal" );
|
|
DumpValue( Address, SYM(NTFS_DATA), "FreeEresourceMiss" );
|
|
DumpValue( Address, SYM(NTFS_DATA), "FreeEresourceArray" );
|
|
DumpValue( Address, SYM(NTFS_DATA), "Flags" );
|
|
}
|
|
|
|
|
|
DECLARE_DUMP_FUNCTION( DumpScb )
|
|
|
|
/*++
|
|
|
|
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
|
|
|
|
--*/
|
|
|
|
{
|
|
ULONG64 Value = 0;
|
|
|
|
|
|
INIT_DUMP();
|
|
|
|
_try {
|
|
|
|
Value = ReadValue( Address, SYM(SCB), "ScbState" );
|
|
if (!Value) {
|
|
_leave;
|
|
}
|
|
|
|
dprintf( "\nScb: %s", FormatValue(Address) );
|
|
|
|
PrintState( ScbState, (ULONG)Value );
|
|
|
|
dprintf( "\nScbPersist:" );
|
|
PrintState( ScbPersist, (ULONG)ReadValue( Address, SYM(SCB), "ScbPersist" ) );
|
|
|
|
Value = ReadValue( Address, SYM(FSRTL_COMMON_FCB_HEADER), "NodeTypeCode" );
|
|
if (!Value) {
|
|
_leave;
|
|
}
|
|
dprintf( "\n ScbType: " );
|
|
|
|
switch ( Value ) {
|
|
|
|
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;
|
|
|
|
default:
|
|
|
|
dprintf( "!!!UNKNOWN SCBTYPE!!!, type code is %s", TypeCodeGuess( (NODE_TYPE_CODE)Value ) );
|
|
break;
|
|
}
|
|
|
|
if (Options >= 1) {
|
|
|
|
Value = ReadValue( Address, SYM(SCB), "Fcb" );
|
|
if (Value) {
|
|
DumpFcb( Value, 0, Options - 1, Processor, hCurrentThread );
|
|
}
|
|
Value = ReadValue( Address, SYM(SCB), "Vcb" );
|
|
if (Value) {
|
|
DumpVcb( Value, 0, Options - 1, Processor, hCurrentThread );
|
|
}
|
|
|
|
} else {
|
|
|
|
DumpValue( Address, SYM(SCB), "Fcb" );
|
|
DumpValue( Address, SYM(SCB), "Vcb" );
|
|
DumpValue( Address, SYM(SCB), "Mcb" );
|
|
DumpValue( Address, SYM(SCB), "NonCachedCleanupCount" );
|
|
DumpValue( Address, SYM(SCB), "CleanupCount" );
|
|
DumpValue( Address, SYM(SCB), "CloseCount" );
|
|
DumpValue( Address, SYM(SCB), "ShareAccess" );
|
|
DumpValue( Address, SYM(SCB), "AttributeTypeCode" );
|
|
DumpValue( Address, SYM(SCB), "AttributeName.Length" );
|
|
DumpValue( Address, SYM(SCB), "AttributeName.Buffer" );
|
|
DumpValue( Address, SYM(SCB), "AttributeFlags" );
|
|
DumpValue( Address, SYM(SCB), "CompressionUnit" );
|
|
DumpValue( Address, SYM(SCB), "FileObject" );
|
|
DumpValue( Address, SYM(SCB), "NonpagedScb" );
|
|
DumpValue( Address, SYM(SCB), "EncryptionContext" );
|
|
}
|
|
|
|
} finally {
|
|
|
|
}
|
|
|
|
dprintf( "\n" );
|
|
}
|
|
|
|
|
|
DECLARE_DUMP_FUNCTION( DumpVcb )
|
|
|
|
/*++
|
|
|
|
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
|
|
|
|
--*/
|
|
|
|
{
|
|
ULONG64 Value = 0;
|
|
|
|
|
|
INIT_DUMP();
|
|
|
|
Value = ReadValue( Address, SYM(VCB), "NodeTypeCode" );
|
|
|
|
dprintf( "\n Vcb: %s", FormatValue(Address) );
|
|
|
|
if (Value != NTFS_NTC_VCB) {
|
|
|
|
dprintf( "\nVCB signature does not match, type code is %s", TypeCodeGuess( (NODE_TYPE_CODE)Value ) );
|
|
return;
|
|
}
|
|
|
|
PrintState( VcbState, (ULONG)ReadValue( Address, SYM(VCB), "VcbState" ) );
|
|
|
|
DumpValue( Address, SYM(VCB), "CleanupCount" );
|
|
DumpValue( Address, SYM(VCB), "CloseCount" );
|
|
DumpValue( Address, SYM(VCB), "ReadOnlyCloseCount" );
|
|
DumpValue( Address, SYM(VCB), "SystemFileCloseCount" );
|
|
DumpValue( Address, SYM(VCB), "UsnJournal" );
|
|
DumpValue( Address, SYM(VCB), "MftScb" );
|
|
DumpValue( Address, SYM(VCB), "Mft2Scb" );
|
|
DumpValue( Address, SYM(VCB), "LogFileScb" );
|
|
DumpValue( Address, SYM(VCB), "VolumeDasdScb" );
|
|
DumpValue( Address, SYM(VCB), "RootIndexScb" );
|
|
DumpValue( Address, SYM(VCB), "BitmapScb" );
|
|
DumpValue( Address, SYM(VCB), "AttributeDefTableScb" );
|
|
DumpValue( Address, SYM(VCB), "UpcaseTableScb" );
|
|
DumpValue( Address, SYM(VCB), "BadClusterFileScb" );
|
|
DumpValue( Address, SYM(VCB), "QuotaTableScb" );
|
|
DumpValue( Address, SYM(VCB), "ReparsePointTableScb" );
|
|
DumpValue( Address, SYM(VCB), "OwnerIdTableScb" );
|
|
DumpValue( Address, SYM(VCB), "SecurityDescriptorStream" );
|
|
DumpValue( Address, SYM(VCB), "SecurityIdIndex" );
|
|
DumpValue( Address, SYM(VCB), "SecurityDescriptorHashIndex" );
|
|
DumpValue( Address, SYM(VCB), "ExtendDirectory" );
|
|
DumpValue( Address, SYM(VCB), "ObjectIdTableScb" );
|
|
DumpValue( Address, SYM(VCB), "MftBitmapScb" );
|
|
DumpValue( Address, SYM(VCB), "RootLcb" );
|
|
DumpValue( Address, SYM(VCB), "FcbTable" );
|
|
DumpValue( Address, SYM(VCB), "Statistics" );
|
|
DumpValue( Address, SYM(VCB), "Resource" );
|
|
|
|
if (Options < 0) {
|
|
|
|
ResetFileSystemStatistics( Address, Processor, hCurrentThread );
|
|
|
|
} else if (Options >= 2) {
|
|
|
|
DumpFileSystemStatistics( Address, Processor, hCurrentThread );
|
|
|
|
} else if (Options >= 1) {
|
|
|
|
DumpLcb( ReadValue( Address, SYM(VCB), "RootLcb" ), 0, Options - 1, Processor, hCurrentThread );
|
|
DumpFcbTable( ReadValue( Address, SYM(VCB), "FcbTable" ), 0, Options - 1, Processor, hCurrentThread );
|
|
}
|
|
|
|
dprintf( "\n" );
|
|
}
|
|
|
|
|
|
VOID
|
|
ResetFileSystemStatistics (
|
|
IN ULONG64 VcbAddress,
|
|
IN USHORT Processor,
|
|
IN HANDLE hCurrentThread
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Dump the file system statitics of a vcb
|
|
|
|
Arguments:
|
|
|
|
Vcb - Suppplies a pointer to a vcb that the debugger has already loaded.
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
|
|
{
|
|
ULONG Result;
|
|
PUCHAR Stat;
|
|
ULONG64 StatsAddr;
|
|
|
|
dprintf( "\n" );
|
|
dprintf( "\n" );
|
|
|
|
//
|
|
// Write the Statistics structure based on the processor, but
|
|
// skip over the file system type and version field.
|
|
//
|
|
|
|
Result = GetTypeSize(SYM(FILE_SYSTEM_STATISTICS));
|
|
Stat = malloc( Result );
|
|
if (Stat) {
|
|
StatsAddr = ReadValue( VcbAddress, SYM(VCB), "Statistics" );
|
|
if (StatsAddr) {
|
|
if (!WriteMemory( StatsAddr + (Result * Processor) + GetOffset(SYM(FILE_SYSTEM_STATISTICS),"Common.UserFileReads"),
|
|
&Stat,
|
|
Result - GetOffset(SYM(FILE_SYSTEM_STATISTICS),"Common.UserFileReads"),
|
|
&Result) ) {
|
|
|
|
dprintf( "%s: Unable to reset Statistics\n", FormatValue(StatsAddr) );
|
|
}
|
|
}
|
|
free( Stat );
|
|
dprintf( "**** %s: Resetting Filesystem Statistics complete ****\n", FormatValue(StatsAddr) );
|
|
}
|
|
|
|
DumpFileSystemStatistics( VcbAddress, Processor, hCurrentThread );
|
|
}
|
|
|
|
|
|
VOID
|
|
DumpFileSystemStatistics (
|
|
IN ULONG64 VcbAddress,
|
|
IN USHORT Processor,
|
|
IN HANDLE hCurrentThread
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Dump the file system statitics of a vcb
|
|
|
|
Arguments:
|
|
|
|
Vcb - Suppplies a pointer to a vcb that the debugger has already loaded.
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
|
|
{
|
|
ULONG Result;
|
|
ULONG64 StatsAddr;
|
|
FILE_SYSTEM_STATISTICS Stat;
|
|
|
|
ULONG TotalReads;
|
|
ULONG TotalReadBytes;
|
|
ULONG TotalWrites;
|
|
ULONG TotalWriteBytes;
|
|
|
|
ULONG TotalClustersReturned;
|
|
|
|
ULONG AverageRequestSize;
|
|
ULONG AverageRunSize;
|
|
ULONG AverageHintSize;
|
|
ULONG AverageCacheSize;
|
|
ULONG AverageCacheMissSize;
|
|
|
|
UNREFERENCED_PARAMETER( hCurrentThread );
|
|
|
|
//
|
|
// Read in the Statistics structure based on the processor
|
|
//
|
|
|
|
StatsAddr = ReadValue( VcbAddress, SYM(VCB), "Statistics" );
|
|
|
|
if ( !ReadMemory( StatsAddr + (GetTypeSize(SYM(FILE_SYSTEM_STATISTICS)) * Processor),
|
|
&Stat,
|
|
GetTypeSize(SYM(FILE_SYSTEM_STATISTICS)),
|
|
&Result) ) {
|
|
|
|
dprintf( "%08lx: Unable to read Statistics\n", StatsAddr );
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Sum up all the paging i/o reads and writes
|
|
//
|
|
|
|
TotalReads = Stat.Common.UserFileReads + Stat.Common.MetaDataReads + Stat.Ntfs.UserIndexReads + Stat.Ntfs.LogFileReads;
|
|
TotalReadBytes = Stat.Common.UserFileReadBytes + Stat.Common.MetaDataReadBytes + Stat.Ntfs.UserIndexReadBytes + Stat.Ntfs.LogFileReadBytes;
|
|
TotalWrites = Stat.Common.UserFileWrites + Stat.Common.MetaDataWrites + Stat.Ntfs.UserIndexWrites + Stat.Ntfs.LogFileWrites;
|
|
TotalWriteBytes = Stat.Common.UserFileWriteBytes + Stat.Common.MetaDataWriteBytes + Stat.Ntfs.UserIndexWriteBytes + Stat.Ntfs.LogFileWriteBytes;
|
|
|
|
//
|
|
// Sum up the total number of clusters returned
|
|
//
|
|
|
|
TotalClustersReturned = Stat.Ntfs.Allocate.HintsClusters + Stat.Ntfs.Allocate.CacheClusters + Stat.Ntfs.Allocate.CacheMissClusters;
|
|
|
|
//
|
|
// Compute the average cluster count requested, returned, from hints, and from the cache, and cache misses.
|
|
//
|
|
|
|
AverageRequestSize = AVERAGE(Stat.Ntfs.Allocate.Clusters, Stat.Ntfs.Allocate.Calls);
|
|
AverageRunSize = AVERAGE(TotalClustersReturned, Stat.Ntfs.Allocate.RunsReturned);
|
|
|
|
AverageHintSize = AVERAGE(Stat.Ntfs.Allocate.HintsClusters, Stat.Ntfs.Allocate.HintsHonored);
|
|
AverageCacheSize = AVERAGE(Stat.Ntfs.Allocate.CacheClusters, Stat.Ntfs.Allocate.Cache);
|
|
AverageCacheMissSize = AVERAGE(Stat.Ntfs.Allocate.CacheMissClusters, Stat.Ntfs.Allocate.CacheMiss);
|
|
|
|
dprintf( "\n" );
|
|
dprintf( "\n File System Statistics @ %s for Processor = %d", FormatValue(StatsAddr), Processor );
|
|
dprintf( "\n FileSystemType / Version = %d / %d", Stat.Common.FileSystemType, Stat.Common.Version );
|
|
dprintf( "\n" );
|
|
dprintf( "\n Exceptions LogFileFull = %ld Other = %ld", Stat.Ntfs.LogFileFullExceptions, Stat.Ntfs.OtherExceptions );
|
|
dprintf( "\n" );
|
|
dprintf( "\n Reads Bytes Writes Bytes" );
|
|
dprintf( "\n ----- ----- ------ -----" );
|
|
dprintf( "\n" );
|
|
dprintf( "\n UserFile %10ld (%10ld)%10ld (%10ld)", Stat.Common.UserFileReads, Stat.Common.UserFileReadBytes, Stat.Common.UserFileWrites, Stat.Common.UserFileWriteBytes );
|
|
dprintf( "\n UserDisk %10ld %10ld", Stat.Common.UserDiskReads, Stat.Common.UserDiskWrites );
|
|
dprintf( "\n" );
|
|
dprintf( "\n MetaData %10ld (%10ld)%10ld (%10ld)", Stat.Common.MetaDataReads, Stat.Common.MetaDataReadBytes, Stat.Common.MetaDataWrites, Stat.Common.MetaDataWriteBytes );
|
|
dprintf( "\n MetaDisk %10ld %10ld", Stat.Common.MetaDataDiskReads, Stat.Common.MetaDataDiskWrites );
|
|
dprintf( "\n" );
|
|
dprintf( "\n Mft %10ld (%10ld)%10ld (%10ld)", Stat.Ntfs.MftReads, Stat.Ntfs.MftReadBytes, Stat.Ntfs.MftWrites, Stat.Ntfs.MftWriteBytes );
|
|
dprintf( "\n Mft2 %10ld (%10lx)", Stat.Ntfs.Mft2Writes, Stat.Ntfs.Mft2WriteBytes );
|
|
dprintf( "\n RootIndex%10ld (%10ld)%10ld (%10ld)", Stat.Ntfs.RootIndexReads, Stat.Ntfs.RootIndexReadBytes, Stat.Ntfs.RootIndexWrites, Stat.Ntfs.RootIndexWriteBytes );
|
|
dprintf( "\n Bitmap %10ld (%10ld)%10ld (%10ld)", Stat.Ntfs.BitmapReads, Stat.Ntfs.BitmapReadBytes, Stat.Ntfs.BitmapWrites, Stat.Ntfs.BitmapWriteBytes );
|
|
dprintf( "\n MftBitmap%10ld (%10ld)%10ld (%10ld)", Stat.Ntfs.MftBitmapReads, Stat.Ntfs.MftBitmapReadBytes, Stat.Ntfs.MftBitmapWrites, Stat.Ntfs.MftBitmapWriteBytes );
|
|
dprintf( "\n" );
|
|
dprintf( "\n UserIndex %10ld (%10ld)%10ld (%10ld)", Stat.Ntfs.UserIndexReads, Stat.Ntfs.UserIndexReadBytes, Stat.Ntfs.UserIndexWrites, Stat.Ntfs.UserIndexWriteBytes );
|
|
dprintf( "\n" );
|
|
dprintf( "\n LogFile %10ld (%10ld)%10ld (%10ld)", Stat.Ntfs.LogFileReads, Stat.Ntfs.LogFileReadBytes, Stat.Ntfs.LogFileWrites, Stat.Ntfs.LogFileWriteBytes );
|
|
dprintf( "\n" );
|
|
dprintf( "\n TOTAL %10ld (%10ld)%10ld (%10ld)", TotalReads, TotalReadBytes, TotalWrites, TotalWriteBytes );
|
|
dprintf( "\n" );
|
|
dprintf( "\n Write Create SetInfo Flush" );
|
|
dprintf( "\n ----- ------ ------- -----" );
|
|
dprintf( "\n MftWritesUserLevel %5d %5d %5d %5d", Stat.Ntfs.MftWritesUserLevel.Write, Stat.Ntfs.MftWritesUserLevel.Create, Stat.Ntfs.MftWritesUserLevel.SetInfo, Stat.Ntfs.MftWritesUserLevel.Flush );
|
|
dprintf( "\n Mft2WritesUserLevel %5d %5d %5d %5d", Stat.Ntfs.Mft2WritesUserLevel.Write, Stat.Ntfs.Mft2WritesUserLevel.Create, Stat.Ntfs.Mft2WritesUserLevel.SetInfo, Stat.Ntfs.Mft2WritesUserLevel.Flush );
|
|
dprintf( "\n BitmapWritesUserLevel %5d %5d %5d", Stat.Ntfs.BitmapWritesUserLevel.Write, Stat.Ntfs.BitmapWritesUserLevel.Create, Stat.Ntfs.BitmapWritesUserLevel.SetInfo );
|
|
dprintf( "\n MftBitmapWritesUserLevel %5d %5d %5d %5d", Stat.Ntfs.MftBitmapWritesUserLevel.Write, Stat.Ntfs.MftBitmapWritesUserLevel.Create, Stat.Ntfs.MftBitmapWritesUserLevel.SetInfo, Stat.Ntfs.MftBitmapWritesUserLevel.Flush );
|
|
dprintf( "\n" );
|
|
dprintf( "\n FlushForLogFileFull LazyWriter UserRequest" );
|
|
dprintf( "\n ------------------- ---------- -----------" );
|
|
dprintf( "\n MftWrites %5d %5d %5d", Stat.Ntfs.MftWritesFlushForLogFileFull, Stat.Ntfs.MftWritesLazyWriter, Stat.Ntfs.MftWritesUserRequest );
|
|
dprintf( "\n Mft2Writes %5d %5d %5d", Stat.Ntfs.Mft2WritesFlushForLogFileFull, Stat.Ntfs.Mft2WritesLazyWriter, Stat.Ntfs.Mft2WritesUserRequest );
|
|
dprintf( "\n BitmapWrites %5d %5d %5d", Stat.Ntfs.BitmapWritesFlushForLogFileFull, Stat.Ntfs.BitmapWritesLazyWriter, Stat.Ntfs.BitmapWritesUserRequest );
|
|
dprintf( "\n MftBitmapWrites %5d %5d %5d", Stat.Ntfs.MftBitmapWritesFlushForLogFileFull, Stat.Ntfs.MftBitmapWritesLazyWriter, Stat.Ntfs.MftBitmapWritesUserRequest );
|
|
dprintf( "\n" );
|
|
dprintf( "\n Allocate Total Average" );
|
|
dprintf( "\n Clusters Runs Hints Clusters RunSize" );
|
|
dprintf( "\n ---- ----- -------- -------" );
|
|
dprintf( "\n Requested %10ld %10ld %10ld %10ld", Stat.Ntfs.Allocate.Calls, Stat.Ntfs.Allocate.Hints, Stat.Ntfs.Allocate.Clusters, AverageRequestSize );
|
|
dprintf( "\n Returned %10ld %10ld %10ld %10ld", Stat.Ntfs.Allocate.RunsReturned, Stat.Ntfs.Allocate.HintsHonored, TotalClustersReturned, AverageRunSize );
|
|
dprintf( "\n" );
|
|
dprintf( "\n FromHints %10ld %10ld %10ld", Stat.Ntfs.Allocate.HintsHonored, Stat.Ntfs.Allocate.HintsClusters, AverageHintSize );
|
|
dprintf( "\n CacheHit %10ld %10ld %10ld", Stat.Ntfs.Allocate.Cache, Stat.Ntfs.Allocate.CacheClusters, AverageCacheSize );
|
|
dprintf( "\n CacheMiss %10ld %10ld %10ld", Stat.Ntfs.Allocate.CacheMiss, Stat.Ntfs.Allocate.CacheMissClusters, AverageCacheMissSize );
|
|
dprintf( "\n" );
|
|
}
|
|
|
|
|
|
DECLARE_DUMP_FUNCTION( DumpSysCache )
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Dump the syscache buffers. The target system must have been
|
|
built with syscache enabled.
|
|
|
|
Arguments:
|
|
|
|
Address - Gives the address of the Vcb to dump
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
|
|
{
|
|
ULONG SyscacheLogEntryCount;
|
|
ULONG CurrentSyscacheLogEntry;
|
|
PSYSCACHE_LOG pLog = NULL;
|
|
int iEnd;
|
|
int iStart;
|
|
int iTemp;
|
|
int iIndex;
|
|
|
|
|
|
INIT_DUMP();
|
|
|
|
if (GetOffset( SYM(VCB), "SyscacheScb" ) == -1) {
|
|
//
|
|
// the system was not built with syscache debug
|
|
//
|
|
dprintf( "\nthe target system does not have syscache debug enabled\n" );
|
|
return;
|
|
}
|
|
|
|
if (Options != 0) {
|
|
dprintf( "Direct buffer dump\n" );
|
|
dprintf("Num Entries: 0x%x\n", Options );
|
|
dprintf("Current Entry: 0x%x\n", Options );
|
|
|
|
CurrentSyscacheLogEntry = Options;
|
|
SyscacheLogEntryCount = Options;
|
|
|
|
pLog = (PSYSCACHE_LOG) malloc( GetTypeSize(SYM(SYSCACHE_LOG)) * SyscacheLogEntryCount );
|
|
if (!pLog) {
|
|
return;
|
|
}
|
|
|
|
if (!ReadMemory( Address, pLog, GetTypeSize(SYM(SYSCACHE_LOG)) * SyscacheLogEntryCount, &iTemp )) {
|
|
|
|
dprintf( "Unable to read SCB.SyscacheLog\n" );
|
|
return;
|
|
}
|
|
|
|
|
|
} else {
|
|
SyscacheLogEntryCount = ReadUlongValue(Address,SYM(SCB),"SyscacheLogEntryCount");
|
|
CurrentSyscacheLogEntry = ReadUlongValue(Address,SYM(SCB),"CurrentSyscacheLogEntry");
|
|
dprintf("Num Entries: 0x%x\n", SyscacheLogEntryCount );
|
|
dprintf("Current Entry: 0x%x\n", ReadUlongValue(Address,SYM(SCB),"CurrentSyscacheLogEntry") );
|
|
|
|
pLog = (PSYSCACHE_LOG) malloc( GetTypeSize(SYM(SYSCACHE_LOG)) * SyscacheLogEntryCount );
|
|
if (!pLog) {
|
|
return;
|
|
}
|
|
|
|
if (!ReadMemory( ReadValue(Address,SYM(SCB),"SyscacheLog"), pLog,
|
|
GetTypeSize(SYM(SYSCACHE_LOG)) * SyscacheLogEntryCount, &iTemp )) {
|
|
|
|
dprintf( "Unable to read SCB.SyscacheLog\n" );
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (CurrentSyscacheLogEntry > SyscacheLogEntryCount) {
|
|
iStart = CurrentSyscacheLogEntry;
|
|
iEnd = CurrentSyscacheLogEntry + SyscacheLogEntryCount;;
|
|
} else {
|
|
iStart = 0;
|
|
iEnd = CurrentSyscacheLogEntry;
|
|
}
|
|
|
|
for (iIndex= iStart; iIndex < iEnd; iIndex++) {
|
|
|
|
iTemp = iIndex % SyscacheLogEntryCount;
|
|
|
|
if (iStart == 0) {
|
|
dprintf("Entry: 0x%x\n", iIndex);
|
|
} else {
|
|
dprintf("Entry: 0x%x\n", iIndex - SyscacheLogEntryCount);
|
|
}
|
|
|
|
dprintf("Event: 0x%x ", pLog[iTemp ].Event);
|
|
if (pLog[iTemp].Event < SCE_MAX_EVENT) {
|
|
dprintf("(%s)\n", LogEvent[pLog[iTemp].Event]);
|
|
} else {
|
|
dprintf("\n");
|
|
}
|
|
|
|
dprintf("Flags: 0x%x (", pLog[iTemp].Flags);
|
|
if (pLog[iTemp].Flags & SCE_FLAG_WRITE) {
|
|
dprintf("write ");
|
|
}
|
|
if (pLog[iTemp].Flags & SCE_FLAG_READ) {
|
|
dprintf("read ");
|
|
}
|
|
if (pLog[iTemp].Flags & SCE_FLAG_PAGING) {
|
|
dprintf("paging io ");
|
|
}
|
|
if (pLog[iTemp].Flags & SCE_FLAG_ASYNC) {
|
|
dprintf("asyncfileobj ");
|
|
}
|
|
if (pLog[iTemp].Flags & SCE_FLAG_SET_ALLOC) {
|
|
dprintf("setalloc ");
|
|
}
|
|
if (pLog[iTemp].Flags & SCE_FLAG_SET_EOF) {
|
|
dprintf("seteof ");
|
|
}
|
|
if (pLog[iTemp].Flags & SCE_FLAG_CANT_WAIT) {
|
|
dprintf("cantwait ");
|
|
}
|
|
if (pLog[iTemp].Flags & SCE_FLAG_SYNC_PAGING) {
|
|
dprintf("synchpaging ");
|
|
}
|
|
if (pLog[iTemp].Flags & SCE_FLAG_LAZY_WRITE) {
|
|
dprintf("lazywrite ");
|
|
}
|
|
if (pLog[iTemp].Flags & SCE_FLAG_CACHED) {
|
|
dprintf("cached ");
|
|
}
|
|
if (pLog[iTemp].Flags & SCE_FLAG_ON_DISK_READ) {
|
|
dprintf("fromdisk ");
|
|
}
|
|
if (pLog[iTemp].Flags & SCE_FLAG_RECURSIVE) {
|
|
dprintf("recursive ");
|
|
}
|
|
if (pLog[iTemp].Flags & SCE_FLAG_NON_CACHED) {
|
|
dprintf("noncached ");
|
|
}
|
|
if (pLog[iTemp].Flags & SCE_FLAG_UPDATE_FROM_DISK) {
|
|
dprintf("updatefromdisk ");
|
|
}
|
|
if (pLog[iTemp].Flags & SCE_FLAG_COMPRESSED) {
|
|
dprintf("compressed ");
|
|
}
|
|
if (pLog[iTemp].Flags & SCE_FLAG_SET_VDL) {
|
|
dprintf("setvdl ");
|
|
}
|
|
if (pLog[iTemp].Flags & SCE_FLAG_FASTIO) {
|
|
dprintf("fastio ");
|
|
}
|
|
if (pLog[iTemp].Flags & SCE_FLAG_ZERO) {
|
|
dprintf("zero ");
|
|
}
|
|
if (pLog[iTemp].Flags & SCE_FLAG_PREPARE_BUFFERS) {
|
|
dprintf("prepare buffers ");
|
|
}
|
|
if (pLog[iTemp].Flags & SCE_FLAG_END_BUFFER) {
|
|
dprintf("end buffers ");
|
|
}
|
|
if (pLog[iTemp].Flags & SCE_FLAG_MDL) {
|
|
dprintf("mdl ");
|
|
}
|
|
if (pLog[iTemp].Flags & SCE_FLAG_SUB_WRITE) {
|
|
dprintf("subwrite ");
|
|
}
|
|
|
|
dprintf(")\n");
|
|
dprintf("Start: 0x%I64x Range: 0x%I64x Result: 0x%I64x\n",
|
|
pLog[iTemp].Start, pLog[iTemp].Range, pLog[iTemp].Result);
|
|
|
|
dprintf("\n");
|
|
}
|
|
|
|
if (pLog) {
|
|
free(pLog);
|
|
}
|
|
}
|
|
|
|
|
|
DECLARE_DUMP_FUNCTION( DumpExtents )
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Dump the extents for a file
|
|
|
|
Arguments:
|
|
|
|
Address - Gives the address of the Vcb to dump
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
|
|
{
|
|
UCHAR FormCode;
|
|
PVOID Buffer;
|
|
PBYTE TempByte;
|
|
ULONG ChangedLCNBytes;
|
|
ULONG ChangedVCNBytes;
|
|
ULONG Increment;
|
|
ULONG Index;
|
|
ULONG Increment2;
|
|
ULONG LCN = 0;
|
|
ULONG VCN = 0;
|
|
ULONG RecordLength;
|
|
USHORT MappingPairsOffset;
|
|
|
|
|
|
INIT_DUMP();
|
|
|
|
FormCode = (UCHAR)ReadValue( Address, SYM(ATTRIBUTE_RECORD_HEADER), "FormCode" );
|
|
if (!(FormCode & NONRESIDENT_FORM)) {
|
|
dprintf( "resident attribute\n" );
|
|
return;
|
|
}
|
|
|
|
DumpValue( Address, SYM(ATTRIBUTE_RECORD_HEADER), "Form.Nonresident.MappingPairsOffset" );
|
|
DumpValue( Address, SYM(ATTRIBUTE_RECORD_HEADER), "Form.Nonresident.LowestVcn" );
|
|
DumpValue( Address, SYM(ATTRIBUTE_RECORD_HEADER), "Form.Nonresident.HighestVcn" );
|
|
DumpValue( Address, SYM(ATTRIBUTE_RECORD_HEADER), "Form.Nonresident.AllocatedLength" );
|
|
|
|
dprintf( "\n" );
|
|
|
|
RecordLength = ReadUlongValue( Address, SYM(ATTRIBUTE_RECORD_HEADER), "RecordLength" );
|
|
if (!RecordLength) {
|
|
return;
|
|
}
|
|
|
|
MappingPairsOffset = ReadShortValue( Address, SYM(ATTRIBUTE_RECORD_HEADER), "Form.Nonresident.MappingPairsOffset" );
|
|
if (!MappingPairsOffset) {
|
|
return;
|
|
}
|
|
|
|
RecordLength -= MappingPairsOffset;
|
|
|
|
Buffer = malloc( RecordLength );
|
|
if (!ReadMemory( Address+MappingPairsOffset, Buffer, RecordLength, &RecordLength )) {
|
|
dprintf( "Unable to read memory at %s\n", FormatValue(Address+MappingPairsOffset) );
|
|
free( Buffer );
|
|
return;
|
|
}
|
|
|
|
TempByte = Buffer;
|
|
|
|
//
|
|
// walk byte stream
|
|
//
|
|
|
|
while(*TempByte != 0) {
|
|
ChangedLCNBytes = *TempByte >> 4;
|
|
ChangedVCNBytes = *TempByte & (0x0f);
|
|
|
|
TempByte++;
|
|
|
|
for (Increment=0, Index=0; Index < ChangedVCNBytes; Index++) {
|
|
Increment+= *TempByte++ << (8 * Index);
|
|
}
|
|
|
|
for (Increment2 =0, Index=0; Index < ChangedLCNBytes; Index++) {
|
|
Increment2+= *TempByte++ << (8 * Index);
|
|
}
|
|
|
|
//
|
|
// if last bit is set (this is a neg) extend with 0xff
|
|
//
|
|
|
|
if (0x80 & (*(TempByte-1))) {
|
|
for(; Index < GetTypeSize("ULONG"); Index++) {
|
|
Increment2 += 0xff << (8 * Index);
|
|
}
|
|
}
|
|
|
|
LCN += Increment2;
|
|
dprintf( "LCN: 0x%x VCN: 0x%x Clusters: 0x%x ", LCN, VCN, Increment );
|
|
|
|
for (Index = ChangedLCNBytes + ChangedVCNBytes + 1; Index > 0; Index--) {
|
|
dprintf( "%02x", *(TempByte - Index));
|
|
}
|
|
dprintf( "\n" );
|
|
|
|
VCN += Increment;
|
|
}
|
|
|
|
free( Buffer );
|
|
}
|
|
|
|
|
|
ULONG
|
|
ThreadListCallback(
|
|
IN PFIELD_INFO listElement,
|
|
IN PVOID Context
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Enumeration callback function for cachedrecords to check for cached file records
|
|
|
|
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
|
|
|
|
--*/
|
|
|
|
{
|
|
PDUMP_ENUM_CONTEXT dec = (PDUMP_ENUM_CONTEXT)Context;
|
|
ULONG64 ThreadAddress=listElement->address;
|
|
ULONG64 TopLevelIrp;
|
|
ULONG NtfsSig;
|
|
ULONG64 ThreadIrpContext;
|
|
int Index;
|
|
ULONG RecordSize;
|
|
ULONG64 RecordAddress;
|
|
ULONG64 FileRecordBcb;
|
|
ULONG64 FileRecord;
|
|
ULONG UnsafeSegmentNumber;
|
|
|
|
TopLevelIrp = ReadValue( ThreadAddress, NT(ETHREAD), "TopLevelIrp" );
|
|
|
|
if (TopLevelIrp) {
|
|
NtfsSig = ReadUlongValue( TopLevelIrp, SYM(TOP_LEVEL_CONTEXT), "Ntfs" );
|
|
|
|
if (NtfsSig == 0x5346544e) {
|
|
ThreadIrpContext = ReadValue( TopLevelIrp, SYM(TOP_LEVEL_CONTEXT), "ThreadIrpContext" );
|
|
if (ThreadIrpContext) {
|
|
RecordSize = GetTypeSize(SYM(IRP_FILE_RECORD_CACHE_ENTRY));
|
|
RecordAddress = ThreadIrpContext + GetOffset(SYM(IRP_CONTEXT),"FileRecordCache");
|
|
|
|
dprintf ("record: 0x%x\n", RecordAddress );
|
|
|
|
for (Index=0; Index<IRP_FILE_RECORD_MAP_CACHE_SIZE; Index++) {
|
|
|
|
FileRecord = ReadValue( RecordAddress, SYM(IRP_FILE_RECORD_CACHE_ENTRY), "FileRecord" );
|
|
FileRecordBcb = ReadValue( RecordAddress, SYM(IRP_FILE_RECORD_CACHE_ENTRY), "FileRecordBcb" );
|
|
|
|
if (FileRecord) {
|
|
UnsafeSegmentNumber = ReadUlongValue( RecordAddress, SYM(IRP_FILE_RECORD_CACHE_ENTRY), "UnsafeSegmentNumber" );
|
|
dprintf( "Thread: 0x%s FileRecord: 0x%s Bcb: 0x%s SegmentNum: 0x%x\n",
|
|
FormatValue(ThreadAddress),
|
|
FormatValue(FileRecord),
|
|
FormatValue(FileRecordBcb),
|
|
UnsafeSegmentNumber
|
|
);
|
|
}
|
|
RecordAddress += RecordSize;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
ULONG
|
|
ProcessListCallback(
|
|
IN PFIELD_INFO listElement,
|
|
IN PVOID Context
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Enumeration callback function for cachedrecords to check for cached file records
|
|
|
|
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
|
|
|
|
--*/
|
|
|
|
{
|
|
PDUMP_ENUM_CONTEXT dec = (PDUMP_ENUM_CONTEXT)Context;
|
|
ULONG64 ProcAddress=listElement->address;
|
|
ULONG64 FirstThread;
|
|
|
|
|
|
FirstThread = ReadValue( ProcAddress, NT(EPROCESS), "Pcb.ThreadListHead.Flink" );
|
|
if (FirstThread) {
|
|
ListType( NT(ETHREAD), FirstThread, 1, "Tcb.ThreadListEntry.Flink", (PVOID)dec, &ThreadListCallback );
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
DECLARE_DUMP_FUNCTION( DumpCachedRecords )
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Walk all processes and dump any which are holding filerecords cached in
|
|
irpcontexts
|
|
|
|
Arguments:
|
|
|
|
arg - none
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
|
|
{
|
|
ULONG64 FirstProcess;
|
|
DUMP_ENUM_CONTEXT dec;
|
|
|
|
INIT_DUMP();
|
|
|
|
|
|
FirstProcess = ReadValue( KdDebuggerData.PsActiveProcessHead, NT(LIST_ENTRY), "Flink" );
|
|
if (FirstProcess == 0) {
|
|
dprintf( "Unable to read _LIST_ENTRY @ %s \n", FormatValue(KdDebuggerData.PsActiveProcessHead) );
|
|
return;
|
|
}
|
|
|
|
dec.hCurrentThread = hCurrentThread;
|
|
dec.Processor = Processor;
|
|
dec.Options = Options;
|
|
|
|
ListType( NT(EPROCESS), FirstProcess, 1, "ActiveProcessLinks.Flink", (PVOID)&dec, &ProcessListCallback );
|
|
}
|
|
|
|
|
|
DECLARE_DUMP_FUNCTION( DumpHashTable )
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Dump a prefix hash table
|
|
|
|
Arguments:
|
|
|
|
arg - none
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
|
|
{
|
|
ULONG64 HashSegmentsOffset;
|
|
ULONG64 HashSegmentAddress;
|
|
ULONG64 HashSegmentPtr;
|
|
ULONG HashEntrySize;
|
|
DWORD Index;
|
|
DWORD Index2;
|
|
ULONG BytesRead;
|
|
ULONG64 NextAddr;
|
|
ULONG PtrSize;
|
|
|
|
|
|
INIT_DUMP();
|
|
|
|
dprintf( "Hash Table: 0x%s\n", FormatValue(Address) );
|
|
dprintf( "Max Buckets: 0x%x Splitpoint: 0x%x\n",
|
|
ReadUlongValue( Address, SYM(NTFS_HASH_TABLE), "MaxBucket" ),
|
|
ReadUlongValue( Address, SYM(NTFS_HASH_TABLE), "SplitPoint" ) );
|
|
|
|
HashSegmentsOffset = GetOffset(SYM(NTFS_HASH_TABLE),"HashSegments");
|
|
HashEntrySize = GetTypeSize(SYM(NTFS_HASH_ENTRY));
|
|
PtrSize = GetTypeSize(SYM(PVOID));
|
|
HashSegmentAddress = Address + HashSegmentsOffset;
|
|
|
|
for (Index=0; Index<HASH_MAX_SEGMENT_COUNT; Index++) {
|
|
HashSegmentAddress += (Index * PtrSize);
|
|
if (ReadMemory( HashSegmentAddress, &HashSegmentPtr, PtrSize, &BytesRead ) && HashSegmentPtr) {
|
|
for (Index2=0; Index2<HASH_MAX_INDEX_COUNT; Index2++) {
|
|
NextAddr = HashSegmentPtr + (Index2 * PtrSize);
|
|
while (NextAddr) {
|
|
if (Address2 == 0 || ReadValue( NextAddr, SYM(NTFS_HASH_ENTRY), "HashLcb" ) == Address2) {
|
|
dprintf( "Lcb: 0x%s Hash: 0x%x\n",
|
|
FormatValue(ReadValue( NextAddr, SYM(NTFS_HASH_ENTRY), "HashLcb" )),
|
|
ReadUlongValue( NextAddr, SYM(NTFS_HASH_ENTRY), "HashValue" ) );
|
|
}
|
|
NextAddr = ReadValue( NextAddr, SYM(NTFS_HASH_ENTRY), "NextEntry" );
|
|
if (CheckControlC()) {
|
|
return;
|
|
}
|
|
}
|
|
if (CheckControlC()) {
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
if (CheckControlC()) {
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
ULONG
|
|
FindIndexScb(
|
|
IN PFIELD_INFO ListElement,
|
|
IN PVOID Context
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Enumeration callback function to locate the index scb
|
|
|
|
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;
|
|
|
|
|
|
if (CheckControlC()) {
|
|
return TRUE;
|
|
}
|
|
|
|
if (ReadValue( Scb, SYM(SCB), "AttributeTypeCode" ) == $INDEX_ALLOCATION) {
|
|
dec->ReturnValue = Scb;
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
DECLARE_DUMP_FUNCTION( DumpFcbLcbChain )
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Dump a fcb - lcb - chain to find the bottom
|
|
|
|
Arguments:
|
|
|
|
arg - the initial fcb
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
|
|
{
|
|
ULONG64 FcbAddress = Address;
|
|
ULONG64 ScbAddress = 0;
|
|
ULONG64 LcbAddress = 0;
|
|
ULONG64 Link = 0;
|
|
DUMP_ENUM_CONTEXT dec;
|
|
ULONG64 Value;
|
|
|
|
INIT_DUMP();
|
|
|
|
|
|
do {
|
|
|
|
if (ReadValue( FcbAddress, SYM(FCB), "NodeTypeCode" ) != NTFS_NTC_FCB) {
|
|
dprintf( "Not an FCB at 0x%s\n", FormatValue(FcbAddress) );
|
|
return;
|
|
}
|
|
|
|
//
|
|
// initialize the enum context for all out enumerations
|
|
//
|
|
|
|
dec.hCurrentThread = hCurrentThread;
|
|
dec.Processor = Processor;
|
|
dec.Options = Options;
|
|
dec.ReturnValue = 0;
|
|
|
|
//
|
|
// Find the index SCB
|
|
//
|
|
|
|
Value = ReadValue( FcbAddress, SYM(FCB), "ScbQueue.Flink" );
|
|
if (Value) {
|
|
ListType( SYM(SCB), Value, TRUE, "FcbLinks.Flink", (PVOID)&dec, FindIndexScb );
|
|
if (dec.ReturnValue) {
|
|
ScbAddress = dec.ReturnValue;
|
|
}
|
|
}
|
|
|
|
if (ScbAddress == 0) {
|
|
dprintf( "unable to find index scb in fcb: 0x%s\n", FormatValue(FcbAddress) );
|
|
return;
|
|
}
|
|
|
|
dprintf( "Scb: 0x%s, NameLen: 0x%x Counts: 0x%x 0x%x\n",
|
|
FormatValue(ScbAddress),
|
|
ReadShortValue( ScbAddress, SYM(SCB), "ScbType.Index.NormalizedName.MaximumLength" ),
|
|
ReadUlongValue( ScbAddress, SYM(SCB), "CleanupCount" ),
|
|
ReadUlongValue( ScbAddress, SYM(SCB), "CloseCount" )
|
|
);
|
|
|
|
Value = ReadValue( ScbAddress, SYM(SCB), "ScbType.Index.LcbQueue.Flink" );
|
|
|
|
if (Value != (ScbAddress + GetOffset(SYM(SCB),"Index.LcbQueue.Flink"))) {
|
|
|
|
//
|
|
// Read the 1st lcb
|
|
//
|
|
|
|
LcbAddress = Value - GetOffset(SYM(LCB),"ScbLinks");
|
|
|
|
dprintf( "lcb: 0x%s Cleanup: 0x%x fcb: 0x%s\n",
|
|
FormatValue(LcbAddress),
|
|
ReadUlongValue( LcbAddress, SYM(LCB), "CleanupCount" ),
|
|
FormatValue(ReadValue( LcbAddress, SYM(LCB), "Fcb" ))
|
|
);
|
|
|
|
FcbAddress = ReadValue( LcbAddress, SYM(LCB), "Fcb" );
|
|
|
|
} else {
|
|
|
|
dprintf( "lcbqueue empty: 0x%s\n", FormatValue(ScbAddress) );
|
|
return;
|
|
}
|
|
|
|
if (CheckControlC()) {
|
|
return;
|
|
}
|
|
|
|
} while ( TRUE );
|
|
}
|
|
|
|
|
|
ULONG
|
|
EnumOverflow(
|
|
IN PFIELD_INFO ListElement,
|
|
IN PVOID Context
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Enumeration callback function to dump the overflow queue
|
|
|
|
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 IrpContext = ListElement->address;
|
|
PDUMP_ENUM_CONTEXT dec = (PDUMP_ENUM_CONTEXT)Context;
|
|
ULONG64 OriginatingIrp;
|
|
ULONG64 MdlAddress;
|
|
|
|
|
|
if (CheckControlC()) {
|
|
return TRUE;
|
|
}
|
|
|
|
OriginatingIrp = ReadValue( IrpContext, SYM(IRP_CONTEXT), "OriginatingIrp" );
|
|
if (OriginatingIrp) {
|
|
dprintf( "0x%s 0x%x ", FormatValue(OriginatingIrp), ReadValue( OriginatingIrp, SYM(IRP), "Cancel" ) );
|
|
MdlAddress = ReadValue( OriginatingIrp, SYM(IRP), "MdlAddress" );
|
|
if (MdlAddress) {
|
|
dprintf( "0x%s", FormatValue(ReadValue( MdlAddress, NT(MDL), "Process" )) );
|
|
}
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
DECLARE_DUMP_FUNCTION( DumpOverflow )
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Dump the overflow queue
|
|
|
|
Arguments:
|
|
|
|
arg - Vcb
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
|
|
{
|
|
ULONG64 VcbAddress;
|
|
ULONG64 VdoAddress;
|
|
ULONG64 Value;
|
|
DUMP_ENUM_CONTEXT dec;
|
|
|
|
INIT_DUMP();
|
|
|
|
|
|
VcbAddress = Address;
|
|
VdoAddress = VcbAddress - GetOffset(SYM(VOLUME_DEVICE_OBJECT),"Vcb");
|
|
|
|
dprintf( "Volume Device: 0x%s Vcb: 0x%s OverflowCount: 0x%x\n",
|
|
FormatValue(VdoAddress), FormatValue(VcbAddress),
|
|
ReadUlongValue( VdoAddress, SYM(VOLUME_DEVICE_OBJECT), "OverflowQueueCount" ) );
|
|
|
|
dprintf("\nIrpContext Irp Cancelled Process\n");
|
|
|
|
Value = ReadValue( VdoAddress, SYM(VOLUME_DEVICE_OBJECT), "OverflowQueue.Flink" );
|
|
|
|
if (Value && Value != VdoAddress + GetOffset(SYM(VOLUME_DEVICE_OBJECT),"OverflowQueue.Flink")) {
|
|
|
|
dec.hCurrentThread = hCurrentThread;
|
|
dec.Processor = Processor;
|
|
dec.Options = Options;
|
|
dec.ReturnValue = 0;
|
|
|
|
ListType( SYM(IRP_CONTEXT), Value, TRUE, "ListEntry.Flink", (PVOID)&dec, EnumOverflow );
|
|
}
|
|
}
|
|
|
|
|
|
DECLARE_DUMP_FUNCTION( DumpCachedRuns )
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Dumps the cached runs array
|
|
|
|
Arguments:
|
|
|
|
Address - Gives the address of the cached runs array to be dumped
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
|
|
{
|
|
ULONG64 AvailRuns;
|
|
ULONG64 MaxUsed;
|
|
ULONG64 ClusterRunSize;
|
|
int Index;
|
|
LCN Lcn;
|
|
LONGLONG Length;
|
|
ULONG64 LcnArray;
|
|
USHORT LenIndex;
|
|
ULONG64 LengthArray;
|
|
ULONG BytesRead;
|
|
USHORT WindowStart;
|
|
USHORT WindowEnd;
|
|
ULONG DelWindowIndex = 0;
|
|
ULONG64 DelArray;
|
|
ULONG64 DelWindowSize;
|
|
ULONG64 DelLengthCount;
|
|
LONGLONG PrevLength = -1;
|
|
|
|
INIT_DUMP();
|
|
|
|
dprintf( "CachedRun: %p ", Address );
|
|
|
|
AvailRuns = ReadValue( Address, SYM(NTFS_CACHED_RUNS), "Avail" );
|
|
MaxUsed = ReadValue( Address, SYM(NTFS_CACHED_RUNS), "Used" );
|
|
ClusterRunSize = GetTypeSize( SYM(NTFS_LCN_CLUSTER_RUN) );
|
|
LcnArray = ReadValue( Address, SYM(NTFS_CACHED_RUNS), "LcnArray" );
|
|
LengthArray = ReadValue( Address, SYM(NTFS_CACHED_RUNS), "LengthArray" );
|
|
DelLengthCount = ReadValue( Address, SYM(NTFS_CACHED_RUNS), "DelLengthCount" );
|
|
DelArray = ReadValue( Address, SYM(NTFS_CACHED_RUNS), "DeletedLengthWindows" );
|
|
DelWindowSize = GetTypeSize( SYM(NTFS_DELETED_RUNS) );
|
|
|
|
if (DelWindowIndex < DelLengthCount) {
|
|
|
|
WindowStart = (USHORT)ReadValue( DelArray + DelWindowSize * DelWindowIndex, SYM(NTFS_DELETED_RUNS), "StartIndex" );
|
|
WindowEnd = (USHORT)ReadValue( DelArray + DelWindowSize * DelWindowIndex, SYM(NTFS_DELETED_RUNS), "EndIndex" );
|
|
DelWindowIndex++;
|
|
}
|
|
|
|
dprintf( "Avail: 0x%I64x Used: 0x%I64x\n", AvailRuns, MaxUsed );
|
|
|
|
dprintf( "Lcns ranges sorted by length\n\n" );
|
|
|
|
for (Index=0; Index < MaxUsed; Index++) {
|
|
|
|
if (Index == WindowStart) {
|
|
|
|
dprintf( "DeleteWindow: 0x%x to 0x%x\n", WindowStart, WindowEnd );
|
|
|
|
Index = WindowEnd;
|
|
|
|
if (DelWindowIndex < DelLengthCount) {
|
|
|
|
WindowStart = (USHORT)ReadValue( DelArray + DelWindowSize * DelWindowIndex, SYM(NTFS_DELETED_RUNS), "StartIndex" );
|
|
WindowEnd = (USHORT)ReadValue( DelArray + DelWindowSize * DelWindowIndex, SYM(NTFS_DELETED_RUNS), "EndIndex" );
|
|
DelWindowIndex++;
|
|
}
|
|
continue;
|
|
}
|
|
|
|
ReadMemory( LengthArray + Index * sizeof( USHORT ), &LenIndex, sizeof( USHORT ), &BytesRead );
|
|
|
|
if (NTFS_CACHED_RUNS_DEL_INDEX != LenIndex) {
|
|
|
|
Lcn = ReadValue( LcnArray + LenIndex * (ClusterRunSize), SYM(NTFS_LCN_CLUSTER_RUN), "Lcn" );
|
|
Length = ReadValue( LcnArray + LenIndex * (ClusterRunSize), SYM(NTFS_LCN_CLUSTER_RUN), "RunLength" );
|
|
|
|
if (Length < PrevLength) {
|
|
dprintf( "WARNING: OUT OF ORDER ENTRY\n" );
|
|
}
|
|
PrevLength = Length;
|
|
|
|
dprintf( "0x%x: LcnIndex: 0x%x Lcn: 0x%I64x Length: 0x%I64x\n", Index, LenIndex, Lcn, Length );
|
|
|
|
}
|
|
|
|
if (CheckControlC()) {
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|