windows-nt/Source/XPSP1/NT/base/fs/utils/diskedit/crack.cxx
2020-09-26 16:20:57 +08:00

476 lines
14 KiB
C++

#include "ulib.hxx"
#include "drive.hxx"
#include "ifssys.hxx"
#include "ntfssa.hxx"
#include "frs.hxx"
#include "attrib.hxx"
#include "mftfile.hxx"
#include "bitfrs.hxx"
#include "ntfsbit.hxx"
#include "upfile.hxx"
#include "upcase.hxx"
#include "rfatsa.hxx"
#include "rcache.hxx"
#include "hmem.hxx"
#include "recordpg.hxx"
#include "crack.hxx"
#include "diskedit.h"
extern "C" {
#include <stdio.h>
}
extern PLOG_IO_DP_DRIVE Drive;
TCHAR Path[MAX_PATH];
VOID
CrackNtfsPath(
IN HWND WindowHandle
)
{
DSTRING path;
NTFS_SA ntfssa;
MESSAGE msg;
NTFS_MFT_FILE mft;
NTFS_BITMAP_FILE bitmap_file;
NTFS_ATTRIBUTE bitmap_attribute;
NTFS_BITMAP volume_bitmap;
NTFS_UPCASE_FILE upcase_file;
NTFS_ATTRIBUTE upcase_attribute;
NTFS_UPCASE_TABLE upcase_table;
NTFS_FILE_RECORD_SEGMENT file_record;
BOOLEAN error;
BOOLEAN system_file;
ULONG file_number;
TCHAR buf[100];
if (!path.Initialize(Path)) {
wsprintf(buf, TEXT("Out of memory"));
MessageBox(WindowHandle, buf, TEXT("DiskEdit"), MB_OK|MB_ICONEXCLAMATION);
return;
}
if (!Drive ||
!ntfssa.Initialize(Drive, &msg) ||
!ntfssa.Read() ||
!mft.Initialize(Drive, ntfssa.QueryMftStartingLcn(),
ntfssa.QueryClusterFactor(),
ntfssa.QueryFrsSize(),
ntfssa.QueryVolumeSectors(), NULL, NULL) ||
!mft.Read() ||
!bitmap_file.Initialize(mft.GetMasterFileTable()) ||
!bitmap_file.Read() ||
!bitmap_file.QueryAttribute(&bitmap_attribute, &error, $DATA) ||
!volume_bitmap.Initialize(ntfssa.QueryVolumeSectors() /
(ULONG) ntfssa.QueryClusterFactor(), FALSE, NULL, 0) ||
!volume_bitmap.Read(&bitmap_attribute) ||
!upcase_file.Initialize(mft.GetMasterFileTable()) ||
!upcase_file.Read() ||
!upcase_file.QueryAttribute(&upcase_attribute, &error, $DATA) ||
!upcase_table.Initialize(&upcase_attribute) ||
!mft.Initialize(Drive, ntfssa.QueryMftStartingLcn(),
ntfssa.QueryClusterFactor(),
ntfssa.QueryFrsSize(),
ntfssa.QueryVolumeSectors(),
&volume_bitmap,
&upcase_table) ||
!mft.Read()) {
swprintf(buf, TEXT("Could not init NTFS data structures"));
MessageBox(WindowHandle, buf, TEXT("DiskEdit"), MB_OK|MB_ICONEXCLAMATION);
return;
}
if (!ntfssa.QueryFrsFromPath(&path, mft.GetMasterFileTable(),
&volume_bitmap, &file_record, &system_file, &error)) {
wsprintf(buf, TEXT("File not found."));
MessageBox(WindowHandle, buf, TEXT("DiskEdit"), MB_OK|MB_ICONINFORMATION);
return;
}
file_number = file_record.QueryFileNumber().GetLowPart();
wsprintf(buf, TEXT("The given path points to file record 0x%X"), file_number);
MessageBox(WindowHandle, buf, TEXT("Path Image"), MB_OK);
}
BOOLEAN
BacktrackFrs(
IN VCN FileNumber,
IN OUT PNTFS_MASTER_FILE_TABLE Mft,
OUT PWCHAR PathBuffer,
IN ULONG BufferLength,
OUT PULONG PathLength
)
/*++
Routine Description:
This function finds a path from the root to a given FRS.
Arguments:
FileNumber -- Supplies the file number of the target FRS.
Mft -- Supplies the volume's Master File Table.
PathBuffer -- Receives a path to the FRS.
BufferLength -- Supplies the length (in characters) of
the client's buffer.
PathLength -- Receives the length (in characters) of
the path.
Return Value:
TRUE upon successful completion. The returned path may
not be NULL-terminated.
--*/
{
NTFS_FILE_RECORD_SEGMENT CurrentFrs;
NTFS_ATTRIBUTE FileNameAttribute;
VCN ParentFileNumber;
PCFILE_NAME FileName;
ULONG i;
BOOLEAN Error;
if( FileNumber == ROOT_FILE_NAME_INDEX_NUMBER ) {
// This is the root; return a NULL path.
//
*PathLength = 0;
return TRUE;
}
// Initialize the FRS and extract a name (any name will do).
//
if( !CurrentFrs.Initialize( FileNumber, Mft ) ||
!CurrentFrs.Read() ||
!CurrentFrs.QueryAttribute( &FileNameAttribute, &Error, $FILE_NAME ) ||
!FileNameAttribute.IsResident() ) {
return FALSE;
}
FileName = (PCFILE_NAME)FileNameAttribute.GetResidentValue();
ParentFileNumber.Set( FileName->ParentDirectory.LowPart,
(LONG)FileName->ParentDirectory.HighPart );
// Now recurse into this file's parent.
//
if( !BacktrackFrs( ParentFileNumber,
Mft,
PathBuffer,
BufferLength,
PathLength ) ) {
return FALSE;
}
// Add this file's name to the path.
//
if( *PathLength + FileName->FileNameLength + 1 > BufferLength ) {
// Buffer is too small.
//
return FALSE;
}
PathBuffer[*PathLength] = '\\';
for( i = 0; i < FileName->FileNameLength; i++ ) {
PathBuffer[*PathLength+1+i] = FileName->FileName[i];
}
*PathLength += 1 + FileName->FileNameLength;
return TRUE;
}
BOOLEAN
BacktrackFrsFromScratch(
IN HWND WindowHandle,
IN VCN FileNumber
)
/*++
Routine Description:
This function finds a path from the root to a given
FRS; it sets up the MFT and its helper objects as
needed.
Arguments:
WindowHandle -- Supplies a handle to the parent window.
FileNumber -- Supplies the file number of the target FRS.
Return Value:
TRUE upon successful completion. The returned path may
not be NULL-terminated.
--*/
{
WCHAR WPath[MAX_PATH];
NTFS_SA ntfssa;
MESSAGE msg;
NTFS_MFT_FILE mft;
NTFS_BITMAP_FILE bitmap_file;
NTFS_ATTRIBUTE bitmap_attribute;
NTFS_BITMAP volume_bitmap;
NTFS_UPCASE_FILE upcase_file;
NTFS_ATTRIBUTE upcase_attribute;
NTFS_UPCASE_TABLE upcase_table;
BOOLEAN error;
ULONG BufferLength, PathLength, i;
BufferLength = sizeof(WPath);
if (!Drive ||
!ntfssa.Initialize(Drive, &msg) ||
!ntfssa.Read() ||
!mft.Initialize(Drive, ntfssa.QueryMftStartingLcn(),
ntfssa.QueryClusterFactor(),
ntfssa.QueryFrsSize(),
ntfssa.QueryVolumeSectors(), NULL, NULL) ||
!mft.Read() ||
!bitmap_file.Initialize(mft.GetMasterFileTable()) ||
!bitmap_file.Read() ||
!bitmap_file.QueryAttribute(&bitmap_attribute, &error, $DATA) ||
!volume_bitmap.Initialize(Drive->QuerySectors()/
(ULONG) ntfssa.QueryClusterFactor(), FALSE, NULL, 0) ||
!volume_bitmap.Read(&bitmap_attribute) ||
!upcase_file.Initialize(mft.GetMasterFileTable()) ||
!upcase_file.Read() ||
!upcase_file.QueryAttribute(&upcase_attribute, &error, $DATA) ||
!upcase_table.Initialize(&upcase_attribute) ||
!mft.Initialize(Drive, ntfssa.QueryMftStartingLcn(),
ntfssa.QueryClusterFactor(),
ntfssa.QueryFrsSize(),
ntfssa.QueryVolumeSectors(),
&volume_bitmap,
&upcase_table) ||
!mft.Read() ||
!bitmap_file.Initialize(mft.GetMasterFileTable()) ||
!bitmap_file.Read() ||
!bitmap_file.QueryAttribute(&bitmap_attribute, &error, $DATA) ||
!volume_bitmap.Initialize(Drive->QuerySectors()/
(ULONG) ntfssa.QueryClusterFactor(), FALSE, NULL, 0) ||
!volume_bitmap.Read(&bitmap_attribute) ||
!upcase_file.Initialize(mft.GetMasterFileTable()) ||
!upcase_file.Read() ||
!upcase_file.QueryAttribute(&upcase_attribute, &error, $DATA) ||
!upcase_table.Initialize(&upcase_attribute) ||
!BacktrackFrs( FileNumber, mft.GetMasterFileTable(), WPath,
BufferLength, &PathLength ) ) {
return FALSE;
}
MessageBox(WindowHandle, WPath, TEXT("Path Image"), MB_OK);
return TRUE;
}
VOID
CrackFatPath(
IN HWND WindowHandle
)
{
DSTRING path;
REAL_FAT_SA fatsa;
MESSAGE msg;
ULONG cluster_number;
TCHAR buf[100];
if (!path.Initialize(Path) ||
!Drive ||
!fatsa.Initialize(Drive, &msg) ||
!fatsa.FAT_SA::Read()) {
return;
}
cluster_number = fatsa.QueryFileStartingCluster(&path);
wsprintf(buf, TEXT("The given path points to cluster 0x%X"), cluster_number);
MessageBox(WindowHandle, buf, TEXT("Path Image"), MB_OK);
}
VOID
CrackLsn(
IN HWND WindowHandle
)
{
extern LSN Lsn;
TCHAR buf[100];
LONGLONG FileOffset;
(void)GetLogPageSize(Drive);
LfsTruncateLsnToLogPage(Drive, Lsn, &FileOffset);
wsprintf(buf, TEXT("page at %x, offset %x, seq %x"), (ULONG)FileOffset,
LfsLsnToPageOffset(Drive, Lsn) , LfsLsnToSeqNumber(Drive, Lsn));
MessageBox(WindowHandle, buf, TEXT("LSN"), MB_OK);
}
//
// CrackNextLsn -- given an LSN in the Lsn variable, find the
// LSN following that one in the log file. This involves
// reading the log record for the given lsn to find it's
// size, and figuring the page and offset of the following
// lsn from that.
//
BOOLEAN
CrackNextLsn(
IN HWND WindowHandle
)
{
extern LSN Lsn;
TCHAR buf[100];
NTFS_SA ntfssa;
NTFS_MFT_FILE mft;
ULONG PageOffset;
LONGLONG FileOffset;
MESSAGE msg;
BOOLEAN error;
NTFS_FILE_RECORD_SEGMENT frs;
NTFS_ATTRIBUTE attrib;
LFS_RECORD_HEADER RecordHeader;
ULONG bytes_read;
ULONG RecordLength;
ULONG PageSize;
ULONGLONG NextLsn;
ULONG SeqNumber;
if (0 == (PageSize = GetLogPageSize(Drive))) {
return FALSE;
}
if (!Drive)
return FALSE;
if (!ntfssa.Initialize(Drive, &msg))
return FALSE;
if (!ntfssa.Read())
return FALSE;
if (!mft.Initialize(Drive, ntfssa.QueryMftStartingLcn(),
ntfssa.QueryClusterFactor(), ntfssa.QueryFrsSize(),
ntfssa.QueryVolumeSectors(), NULL, NULL))
return FALSE;
if (!mft.Read())
return FALSE;
if (!frs.Initialize((VCN)LOG_FILE_NUMBER, &mft))
return FALSE;
if (!frs.Read())
return FALSE;
if (!frs.QueryAttribute(&attrib, &error, $DATA, NULL)) {
return FALSE;
}
LfsTruncateLsnToLogPage(Drive, Lsn, &FileOffset);
PageOffset = LfsLsnToPageOffset(Drive, Lsn);
SeqNumber = (ULONG)LfsLsnToSeqNumber(Drive, Lsn);
if (!attrib.Read((PVOID)&RecordHeader, ULONG(PageOffset | FileOffset),
LFS_RECORD_HEADER_SIZE, &bytes_read))
return FALSE;
if (bytes_read != LFS_RECORD_HEADER_SIZE) {
return FALSE;
}
RecordLength = LFS_RECORD_HEADER_SIZE + RecordHeader.ClientDataLength;
if (PageOffset + RecordLength < PageSize &&
PageSize - (PageOffset + RecordLength) >= LFS_RECORD_HEADER_SIZE) {
//
// the current record ends on this page, and the next record begins
// immediately after
//
PageOffset += RecordLength;
} else if (PageSize - (PageOffset+RecordLength) < LFS_RECORD_HEADER_SIZE) {
//
// The next record header will not fit on this page... it
// will begin on the next page immediately following the page
// header
//
FileOffset += PageSize;
PageOffset = LFS_PACKED_RECORD_PAGE_HEADER_SIZE;
} else {
//
// the next log record starts on a following page
//
ULONG left;
ULONG page_capacity;
left = PageSize - (PageOffset + RecordLength);
page_capacity = PageSize - LFS_PACKED_RECORD_PAGE_HEADER_SIZE;
PageOffset += (left / page_capacity + 1) * PageSize;
FileOffset = left % page_capacity + LFS_PACKED_RECORD_PAGE_HEADER_SIZE;
}
// create lsn from FileOffset + PageOffset
NextLsn = LfsFileOffsetToLsn(Drive, FileOffset | PageOffset, SeqNumber);
wsprintf(buf, TEXT("Next LSN %x:%x, at %x + %x"), ((PLSN)&NextLsn)->HighPart,
((PLSN)&NextLsn)->LowPart, (ULONG)FileOffset, (ULONG)PageOffset);
MessageBox(WindowHandle, buf, TEXT("LSN"), MB_OK);
return TRUE;
}
struct {
ULONG Code;
PTCHAR Name;
} TypeCodeNameTab[] = {
{ $UNUSED, TEXT("$UNUSED") },
{ $STANDARD_INFORMATION, TEXT("$STANDARD_INFORMATION") },
{ $ATTRIBUTE_LIST, TEXT("$ATTRIBUTE_LIST") },
{ $FILE_NAME, TEXT("$FILE_NAME") },
{ $OBJECT_ID, TEXT("$OBJECT_ID") },
{ $SECURITY_DESCRIPTOR, TEXT("$SECURITY_DESCRIPTOR") },
{ $VOLUME_NAME, TEXT("$VOLUME_NAME") },
{ $VOLUME_INFORMATION, TEXT("$VOLUME_INFORMATION") },
{ $DATA, TEXT("$DATA") },
{ $INDEX_ROOT, TEXT("$INDEX_ROOT") },
{ $INDEX_ALLOCATION, TEXT("$INDEX_ALLOCATION") },
{ $BITMAP, TEXT("$BITMAP") },
{ $SYMBOLIC_LINK, TEXT("$SYMBOLIC_LINK") },
{ $EA_INFORMATION, TEXT("$EA_INFORMATION") },
{ $EA_DATA, TEXT("$EA_DATA") },
{ $END, TEXT("$END") }
};
PTCHAR
GetNtfsAttributeTypeCodeName(
IN ULONG Code
)
{
for (INT i = 0; $END != TypeCodeNameTab[i].Code; ++i) {
if (Code == TypeCodeNameTab[i].Code) {
return TypeCodeNameTab[i].Name;
}
}
return NULL;
}