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