From 4fa87993b758986b4fe99cdfecda62a6f54c2138 Mon Sep 17 00:00:00 2001 From: Natalia Portillo Date: Mon, 10 Jul 2017 22:47:17 +0100 Subject: [PATCH] Use .NET marshalling, corrects alignment. Use volume size from SuperBlock. HPFS does not use clusters but individual sectors. Detect and hash boot code of BPB sector. Show NT flags, they're set by NT 3.x. Do not show integrity check date if it never happened. --- DiscImageChef.Filesystems/HPFS.cs | 136 +++++++++++++----------------- 1 file changed, 57 insertions(+), 79 deletions(-) diff --git a/DiscImageChef.Filesystems/HPFS.cs b/DiscImageChef.Filesystems/HPFS.cs index 834aead27..236562c17 100644 --- a/DiscImageChef.Filesystems/HPFS.cs +++ b/DiscImageChef.Filesystems/HPFS.cs @@ -33,6 +33,8 @@ using System; using System.Text; using System.Collections.Generic; +using System.Runtime.InteropServices; +using DiscImageChef.Checksums; namespace DiscImageChef.Filesystems { @@ -90,71 +92,22 @@ namespace DiscImageChef.Filesystems byte[] hpfs_sb_sector = imagePlugin.ReadSector(16 + partitionStart); // Seek to superblock, on logical sector 16 byte[] hpfs_sp_sector = imagePlugin.ReadSector(17 + partitionStart); // Seek to spareblock, on logical sector 17 - hpfs_bpb.jmp1 = hpfs_bpb_sector[0x000]; - hpfs_bpb.jmp2 = BitConverter.ToUInt16(hpfs_bpb_sector, 0x001); - Array.Copy(hpfs_bpb_sector, 0x003, oem_name, 0, 8); - hpfs_bpb.OEMName = StringHandlers.CToString(oem_name); - hpfs_bpb.bps = BitConverter.ToUInt16(hpfs_bpb_sector, 0x00B); - hpfs_bpb.spc = hpfs_bpb_sector[0x00D]; - hpfs_bpb.rsectors = BitConverter.ToUInt16(hpfs_bpb_sector, 0x00E); - hpfs_bpb.fats_no = hpfs_bpb_sector[0x010]; - hpfs_bpb.root_ent = BitConverter.ToUInt16(hpfs_bpb_sector, 0x011); - hpfs_bpb.sectors = BitConverter.ToUInt16(hpfs_bpb_sector, 0x013); - hpfs_bpb.media = hpfs_bpb_sector[0x015]; - hpfs_bpb.spfat = BitConverter.ToUInt16(hpfs_bpb_sector, 0x016); - hpfs_bpb.sptrk = BitConverter.ToUInt16(hpfs_bpb_sector, 0x018); - hpfs_bpb.heads = BitConverter.ToUInt16(hpfs_bpb_sector, 0x01A); - hpfs_bpb.hsectors = BitConverter.ToUInt32(hpfs_bpb_sector, 0x01C); - hpfs_bpb.big_sectors = BitConverter.ToUInt32(hpfs_bpb_sector, 0x024); - hpfs_bpb.drive_no = hpfs_bpb_sector[0x028]; - hpfs_bpb.nt_flags = hpfs_bpb_sector[0x029]; - hpfs_bpb.signature = hpfs_bpb_sector[0x02A]; - hpfs_bpb.serial_no = BitConverter.ToUInt32(hpfs_bpb_sector, 0x02B); - Array.Copy(hpfs_bpb_sector, 0x02F, volume_name, 0, 11); - hpfs_bpb.volume_label = StringHandlers.CToString(volume_name, CurrentEncoding); - Array.Copy(hpfs_bpb_sector, 0x03A, oem_name, 0, 8); - hpfs_bpb.fs_type = StringHandlers.CToString(oem_name, CurrentEncoding); + IntPtr bpbPtr = Marshal.AllocHGlobal(512); + Marshal.Copy(hpfs_bpb_sector, 0, bpbPtr, 512); + hpfs_bpb = (HPFS_BIOSParameterBlock)Marshal.PtrToStructure(bpbPtr, typeof(HPFS_BIOSParameterBlock)); + Marshal.FreeHGlobal(bpbPtr); - hpfs_sb.magic1 = BitConverter.ToUInt32(hpfs_sb_sector, 0x000); - hpfs_sb.magic2 = BitConverter.ToUInt32(hpfs_sb_sector, 0x004); - hpfs_sb.version = hpfs_sb_sector[0x008]; - hpfs_sb.func_version = hpfs_sb_sector[0x009]; - hpfs_sb.dummy = BitConverter.ToUInt16(hpfs_sb_sector, 0x00A); - hpfs_sb.root_fnode = BitConverter.ToUInt32(hpfs_sb_sector, 0x00C); - hpfs_sb.sectors = BitConverter.ToUInt32(hpfs_sb_sector, 0x010); - hpfs_sb.badblocks = BitConverter.ToUInt32(hpfs_sb_sector, 0x014); - hpfs_sb.bitmap_lsn = BitConverter.ToUInt32(hpfs_sb_sector, 0x018); - hpfs_sb.zero1 = BitConverter.ToUInt32(hpfs_sb_sector, 0x01C); - hpfs_sb.badblock_lsn = BitConverter.ToUInt32(hpfs_sb_sector, 0x020); - hpfs_sb.zero2 = BitConverter.ToUInt32(hpfs_sb_sector, 0x024); - hpfs_sb.last_chkdsk = BitConverter.ToInt32(hpfs_sb_sector, 0x028); - hpfs_sb.last_optim = BitConverter.ToInt32(hpfs_sb_sector, 0x02C); - hpfs_sb.dband_sectors = BitConverter.ToUInt32(hpfs_sb_sector, 0x030); - hpfs_sb.dband_start = BitConverter.ToUInt32(hpfs_sb_sector, 0x034); - hpfs_sb.dband_last = BitConverter.ToUInt32(hpfs_sb_sector, 0x038); - hpfs_sb.dband_bitmap = BitConverter.ToUInt32(hpfs_sb_sector, 0x03C); - hpfs_sb.zero3 = BitConverter.ToUInt64(hpfs_sb_sector, 0x040); - hpfs_sb.zero4 = BitConverter.ToUInt64(hpfs_sb_sector, 0x048); - hpfs_sb.zero5 = BitConverter.ToUInt64(hpfs_sb_sector, 0x04C); - hpfs_sb.zero6 = BitConverter.ToUInt64(hpfs_sb_sector, 0x050); - hpfs_sb.acl_start = BitConverter.ToUInt32(hpfs_sb_sector, 0x058); + IntPtr sbPtr = Marshal.AllocHGlobal(512); + Marshal.Copy(hpfs_sb_sector, 0, sbPtr, 512); + hpfs_sb = (HPFS_SuperBlock)Marshal.PtrToStructure(sbPtr, typeof(HPFS_SuperBlock)); + Marshal.FreeHGlobal(sbPtr); - hpfs_sp.magic1 = BitConverter.ToUInt32(hpfs_sp_sector, 0x000); - hpfs_sp.magic2 = BitConverter.ToUInt32(hpfs_sp_sector, 0x004); - hpfs_sp.flags1 = hpfs_sp_sector[0x008]; - hpfs_sp.flags2 = hpfs_sp_sector[0x009]; - hpfs_sp.dummy = BitConverter.ToUInt16(hpfs_sp_sector, 0x00A); - hpfs_sp.hotfix_start = BitConverter.ToUInt32(hpfs_sp_sector, 0x00C); - hpfs_sp.hotfix_used = BitConverter.ToUInt32(hpfs_sp_sector, 0x010); - hpfs_sp.hotfix_entries = BitConverter.ToUInt32(hpfs_sp_sector, 0x014); - hpfs_sp.spare_dnodes_free = BitConverter.ToUInt32(hpfs_sp_sector, 0x018); - hpfs_sp.spare_dnodes = BitConverter.ToUInt32(hpfs_sp_sector, 0x01C); - hpfs_sp.codepage_lsn = BitConverter.ToUInt32(hpfs_sp_sector, 0x020); - hpfs_sp.codepages = BitConverter.ToUInt32(hpfs_sp_sector, 0x024); - hpfs_sp.sb_crc32 = BitConverter.ToUInt32(hpfs_sp_sector, 0x028); - hpfs_sp.sp_crc32 = BitConverter.ToUInt32(hpfs_sp_sector, 0x02C); + IntPtr spPtr = Marshal.AllocHGlobal(512); + Marshal.Copy(hpfs_sp_sector, 0, spPtr, 512); + hpfs_sp = (HPFS_SpareBlock)Marshal.PtrToStructure(spPtr, typeof(HPFS_SpareBlock)); + Marshal.FreeHGlobal(spPtr); - if(hpfs_bpb.fs_type != "HPFS " || + if(StringHandlers.CToString(hpfs_bpb.fs_type) != "HPFS " || hpfs_sb.magic1 != 0xF995E849 || hpfs_sb.magic2 != 0xFA53E9C5 || hpfs_sp.magic1 != 0xF9911849 || hpfs_sp.magic2 != 0xFA5229C5) { @@ -166,9 +119,9 @@ namespace DiscImageChef.Filesystems sb.AppendFormat("Spareblock magic2: 0x{0:X8} (Should be 0xFA5229C5)", hpfs_sp.magic2).AppendLine(); } - sb.AppendFormat("OEM name: {0}", hpfs_bpb.OEMName).AppendLine(); + sb.AppendFormat("OEM name: {0}", StringHandlers.CToString(hpfs_bpb.oem_name)).AppendLine(); sb.AppendFormat("{0} bytes per sector", hpfs_bpb.bps).AppendLine(); - sb.AppendFormat("{0} sectors per cluster", hpfs_bpb.spc).AppendLine(); + // sb.AppendFormat("{0} sectors per cluster", hpfs_bpb.spc).AppendLine(); // sb.AppendFormat("{0} reserved sectors", hpfs_bpb.rsectors).AppendLine(); // sb.AppendFormat("{0} FATs", hpfs_bpb.fats_no).AppendLine(); // sb.AppendFormat("{0} entries on root directory", hpfs_bpb.root_ent).AppendLine(); @@ -178,12 +131,13 @@ namespace DiscImageChef.Filesystems // sb.AppendFormat("{0} sectors per track", hpfs_bpb.sptrk).AppendLine(); // sb.AppendFormat("{0} heads", hpfs_bpb.heads).AppendLine(); sb.AppendFormat("{0} sectors hidden before BPB", hpfs_bpb.hsectors).AppendLine(); - sb.AppendFormat("{0} sectors on volume ({1} bytes)", hpfs_bpb.big_sectors, hpfs_bpb.big_sectors * hpfs_bpb.bps).AppendLine(); + sb.AppendFormat("{0} sectors on volume ({1} bytes)", hpfs_sb.sectors, hpfs_sb.sectors * hpfs_bpb.bps).AppendLine(); + // sb.AppendFormat("{0} sectors on volume ({1} bytes)", hpfs_bpb.big_sectors, hpfs_bpb.big_sectors * hpfs_bpb.bps).AppendLine(); sb.AppendFormat("BIOS Drive Number: 0x{0:X2}", hpfs_bpb.drive_no).AppendLine(); - // sb.AppendFormat("NT Flags: 0x{0:X2}", hpfs_bpb.nt_flags).AppendLine(); + sb.AppendFormat("NT Flags: 0x{0:X2}", hpfs_bpb.nt_flags).AppendLine(); sb.AppendFormat("Signature: 0x{0:X2}", hpfs_bpb.signature).AppendLine(); sb.AppendFormat("Serial number: 0x{0:X8}", hpfs_bpb.serial_no).AppendLine(); - sb.AppendFormat("Volume label: {0}", hpfs_bpb.volume_label).AppendLine(); + sb.AppendFormat("Volume label: {0}", StringHandlers.CToString(hpfs_bpb.volume_label, CurrentEncoding)).AppendLine(); // sb.AppendFormat("Filesystem type: \"{0}\"", hpfs_bpb.fs_type).AppendLine(); DateTime last_chk = DateHandlers.UNIXToDateTime(hpfs_sb.last_chkdsk); @@ -192,11 +146,13 @@ namespace DiscImageChef.Filesystems sb.AppendFormat("HPFS version: {0}", hpfs_sb.version).AppendLine(); sb.AppendFormat("Functional version: {0}", hpfs_sb.func_version).AppendLine(); sb.AppendFormat("Sector of root directory FNode: {0}", hpfs_sb.root_fnode).AppendLine(); - // sb.AppendFormat("{0} sectors on volume", hpfs_sb.sectors).AppendLine(); sb.AppendFormat("{0} sectors are marked bad", hpfs_sb.badblocks).AppendLine(); sb.AppendFormat("Sector of free space bitmaps: {0}", hpfs_sb.bitmap_lsn).AppendLine(); sb.AppendFormat("Sector of bad blocks list: {0}", hpfs_sb.badblock_lsn).AppendLine(); - sb.AppendFormat("Date of last integrity check: {0}", last_chk).AppendLine(); + if(hpfs_sb.last_chkdsk > 0) + sb.AppendFormat("Date of last integrity check: {0}", last_chk).AppendLine(); + else + sb.AppendLine("Filesystem integrity has never been checked"); if(hpfs_sb.last_optim > 0) sb.AppendFormat("Date of last optimization {0}", last_optim).AppendLine(); else @@ -254,13 +210,25 @@ namespace DiscImageChef.Filesystems sb.AppendLine("Unknown flag 0x80 on flags2 is active"); xmlFSType = new Schemas.FileSystemType(); + + // Theoretically everything from BPB to SB is boot code, should I hash everything or only the sector loaded by BIOS itself? + if(hpfs_bpb.jump[0] == 0xEB && hpfs_bpb.jump[1] > 0x3C && hpfs_bpb.jump[1] < 0x80 && hpfs_bpb.signature2 == 0xAA55) + { + xmlFSType.Bootable = true; + SHA1Context sha1Ctx = new SHA1Context(); + sha1Ctx.Init(); + string bootChk = sha1Ctx.Data(hpfs_bpb.boot_code, out byte[] sha1_out); + sb.AppendLine("Volume is bootable"); + sb.AppendFormat("Boot code's SHA1: {0}", bootChk).AppendLine(); + } + xmlFSType.Dirty |= (hpfs_sp.flags1 & 0x01) == 0x01; - xmlFSType.Clusters = hpfs_bpb.big_sectors / hpfs_bpb.spc; - xmlFSType.ClusterSize = hpfs_bpb.bps * hpfs_bpb.spc; + xmlFSType.Clusters = hpfs_sb.sectors; + xmlFSType.ClusterSize = hpfs_bpb.bps; xmlFSType.Type = "HPFS"; - xmlFSType.VolumeName = hpfs_bpb.volume_label; + xmlFSType.VolumeName = StringHandlers.CToString(hpfs_bpb.volume_label, CurrentEncoding); xmlFSType.VolumeSerial = string.Format("{0:X8}", hpfs_bpb.serial_no); - xmlFSType.SystemIdentifier = hpfs_bpb.OEMName; + xmlFSType.SystemIdentifier = StringHandlers.CToString(hpfs_bpb.oem_name); information = sb.ToString(); } @@ -268,14 +236,15 @@ namespace DiscImageChef.Filesystems /// /// BIOS Parameter Block, at sector 0 /// + [StructLayout(LayoutKind.Sequential, Pack = 1)] struct HPFS_BIOSParameterBlock { /// 0x000, Jump to boot code - public byte jmp1; - /// 0x001, ...; - public ushort jmp2; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)] + public byte[] jump; /// 0x003, OEM Name, 8 bytes, space-padded - public string OEMName; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] + public byte[] oem_name; /// 0x00B, Bytes per sector public ushort bps; /// 0x00D, Sectors per cluster @@ -309,14 +278,22 @@ namespace DiscImageChef.Filesystems /// 0x02B, Volume serial number public uint serial_no; /// 0x02F, Volume label, 11 bytes, space-padded - public string volume_label; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 11)] + public byte[] volume_label; /// 0x03A, Filesystem type, 8 bytes, space-padded ("HPFS ") - public string fs_type; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] + public byte[] fs_type; + /// Boot code. + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 448)] + public byte[] boot_code; + /// 0x1FE, 0xAA55 + public ushort signature2; } /// /// HPFS superblock at sector 16 /// + [StructLayout(LayoutKind.Sequential, Pack = 1)] struct HPFS_SuperBlock { /// 0x000, 0xF995E849 @@ -370,6 +347,7 @@ namespace DiscImageChef.Filesystems /// /// HPFS spareblock at sector 17 /// + [StructLayout(LayoutKind.Sequential, Pack = 1)] struct HPFS_SpareBlock { /// 0x000, 0xF9911849