#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 } 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; }