Skip to content

Commit

Permalink
Merge pull request #12 from tuxuser/for_emoose
Browse files Browse the repository at this point in the history
Filesystem extraction (fixed disks, to raw or vhd), Xvd mount arguments
  • Loading branch information
emoose authored Mar 20, 2019
2 parents c376b9a + 28f7698 commit f95e041
Show file tree
Hide file tree
Showing 12 changed files with 460 additions and 192 deletions.
32 changes: 28 additions & 4 deletions LibXboxOne/Shared.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,32 @@ namespace LibXboxOne
public class Natives
{
[DllImport("xsapi.dll", SetLastError = true)]
public static extern uint XvdMount(IntPtr unk1,
public static extern uint XvdMount(out IntPtr hDiskHandle,
out int mountedDiskNum,
IntPtr hXvdHandle,
[MarshalAs(UnmanagedType.LPWStr)] string pszXvdPath,
long unk2,
long unk3,
int unk4);
long unknown,
[MarshalAs(UnmanagedType.LPWStr)] string pszMountPoint,
int mountFlags);

[DllImport("xsapi.dll", SetLastError = true)]
public static extern uint XvdMountContentType(out IntPtr hDiskHandle,
out int mountedDiskNum,
IntPtr hXvdHandle,
[MarshalAs(UnmanagedType.LPWStr)] string pszXvdPath,
long xvdContentType,
long unknown,
[MarshalAs(UnmanagedType.LPWStr)] string pszMountPoint,
int mountFlags);

[DllImport("xsapi.dll", SetLastError = true)]
public static extern uint XvdVmMount(out IntPtr hDiskHandle,
IntPtr hXvdHandle,
long vmNumber,
[MarshalAs(UnmanagedType.LPWStr)] string pszXvdPath,
long unknown,
[MarshalAs(UnmanagedType.LPWStr)] string pszMountPoint,
int mountFlags);

[DllImport("xsapi.dll", SetLastError = true)]
public static extern uint XvdUnmountDiskNumber(IntPtr hXvdHandle,
Expand All @@ -25,6 +44,11 @@ public static extern uint XvdUnmountDiskNumber(IntPtr hXvdHandle,
public static extern uint XvdUnmountFile(IntPtr hXvdHandle,
[MarshalAs(UnmanagedType.LPWStr)] string pszXvdPath);

[DllImport("xsapi.dll", SetLastError = true)]
public static extern uint XvdVmUnmountFile(IntPtr hXvdHandle,
long vmId,
[MarshalAs(UnmanagedType.LPWStr)] string pszXvdPath);

[DllImport("xsapi.dll", SetLastError = true)]
public static extern uint XvdOpenAdapter(out IntPtr phXvdHandle);

Expand Down
9 changes: 3 additions & 6 deletions LibXboxOne/VHD/VHDFile.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,20 +23,17 @@ public VhdFile(string fileName)
public void Create(VhdDiskType diskType, ulong driveSize)
{
Header = new VhdFooter();
Header.InitDefaults();
Header.OriginalSize = driveSize.EndianSwap();
Header.CurrentSize = driveSize.EndianSwap();

DynamicDiskHeader = new VhdDynamicDiskHeader();
DynamicDiskHeader.InitDefaults();
DynamicDiskHeader = VhdDynamicDiskHeader.Create(driveSize);

var batEntryCount = (uint)(driveSize/DynamicDiskHeader.BlockSize.EndianSwap());
uint batEntryCount = DynamicDiskHeader.MaxTableEntries.EndianSwap();
BlockAllocationTable = new uint[(int) batEntryCount];

for (uint i = 0; i < batEntryCount; i++)
BlockAllocationTable[i] = 0xFFFFFFFF;

DynamicDiskHeader.MaxTableEntries = batEntryCount.EndianSwap();

Header.FixChecksum();
DynamicDiskHeader.FixChecksum();
}
Expand Down
11 changes: 11 additions & 0 deletions LibXboxOne/VHD/VhdDiskGeometry.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
using System;

namespace LibXboxOne.Vhd
{
public struct VhdDiskGeometry
{
public ushort Cylinder;
public byte Heads;
public byte SectorsPerCylinder;
}
}
41 changes: 28 additions & 13 deletions LibXboxOne/VHD/VhdDynamicDiskHeader.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,25 +33,40 @@ public struct VhdDynamicDiskHeader

/* END = 0x400 */

static uint VHD_DYN_HEADER_VERSION => 0x00010000;
static uint VHD_STANDARD_BLOCK_SIZE => 0x00200000;

public static char[] GetHeaderCookie()
{
return new char[]{'c','x','s','p','a','r','s','e'};
}

public void InitDefaults()
static VhdDynamicDiskHeader CreateWithDefaultValues()
{
return new VhdDynamicDiskHeader()
{
Cookie = GetHeaderCookie(), // cxsparse
DataOffset = 0xFFFFFFFFFFFFFFFF, // Currently unused, 0xFFFFFFFFFFFFFFFF
TableOffset = ((ulong)0x600).EndianSwap(), // Vhd footer + dynamic disk header length
HeaderVersion = VHD_DYN_HEADER_VERSION.EndianSwap(),
MaxTableEntries = 0,
BlockSize = VHD_STANDARD_BLOCK_SIZE.EndianSwap(),
ParentUuid = new byte[0x10],
ParentTimeStamp = 0x0,
ParentUnicodeName = new byte[0x200],
ParentLocatorEntries = new VhdParentLocatorEntry[8],
Checksum = 0,
Reserved2 = new byte[0x100]
};
}

public static VhdDynamicDiskHeader Create(ulong driveSize)
{
Cookie = GetHeaderCookie(); // cxsparse
DataOffset = 0xFFFFFFFFFFFFFFFF; // Currently unused, 0xFFFFFFFFFFFFFFFF
TableOffset = ((ulong) 0x600).EndianSwap();
HeaderVersion = 0x100;
MaxTableEntries = 0;
BlockSize = 0x00200000;
Checksum = 0x6FF4FFFF;
ParentUuid = new byte[0x10];
ParentTimeStamp = 0x0;
ParentUnicodeName = new byte[0x200];
ParentLocatorEntries = new VhdParentLocatorEntry[8];
Reserved2 = new byte[0x100];
uint tableEntries = (uint)((driveSize + VHD_STANDARD_BLOCK_SIZE - 1) / VHD_STANDARD_BLOCK_SIZE);

var dynHeader = CreateWithDefaultValues();
dynHeader.MaxTableEntries = tableEntries.EndianSwap();
return dynHeader;
}

internal static uint CalculateChecksum(VhdDynamicDiskHeader data)
Expand Down
64 changes: 44 additions & 20 deletions LibXboxOne/VHD/VhdFooter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ public struct VhdFooter
{
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x8)]
/* 0x0 */ public char[] Cookie;
/* 0x8 */ public VhdDiskFeatures Features;
/* 0x8 */ public uint Features;
/* 0xC */ public uint FileFormatVersion;
/* 0x10 */ public ulong DataOffset;
/* 0x18 */ public uint TimeStamp;
Expand All @@ -20,8 +20,8 @@ public struct VhdFooter
/* 0x24 */ public byte[] CreatorHostOS;
/* 0x28 */ public ulong OriginalSize;
/* 0x30 */ public ulong CurrentSize;
/* 0x38 */ public uint DiskGeometry;
/* 0x3C */ public VhdDiskType DiskType;
/* 0x38 */ public VhdDiskGeometry DiskGeometry;
/* 0x3C */ public uint DiskType;
/* 0x40 */ public uint Checksum;

[MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x10)]
Expand All @@ -32,29 +32,53 @@ public struct VhdFooter
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 0x1AB)]
/* 0x55 */ public byte[] Reserved;

static uint VHD_FILEFORMAT_VERSION => 0x00010000;
static uint VHD_CREATOR_VERSION => 0x000A0000;

public static char[] GetHeaderCookie()
{
return new char[]{'c','o','n','e','c','t','i','x'};
}

public void InitDefaults()
static VhdFooter CreateWithDefaultValues(ulong driveSize, byte[] uniqueId)
{
return new VhdFooter()
{
Cookie = GetHeaderCookie(), // conectix
Features = ((uint)VhdDiskFeatures.Reserved).EndianSwap(),
FileFormatVersion = VHD_FILEFORMAT_VERSION.EndianSwap(),
TimeStamp = VhdUtils.GetTimestamp(DateTime.UtcNow).EndianSwap(),
CreatorApp = VhdCreatorApplication.WindowsDiskMngmt,
CreatorVersion = VHD_CREATOR_VERSION.EndianSwap(),
CreatorHostOS = VhdCreatorHostOs.Windows,
OriginalSize = driveSize.EndianSwap(),
CurrentSize = driveSize.EndianSwap(),
DiskGeometry = VhdUtils.CalculateDiskGeometry(driveSize),
Checksum = 0x0,
UniqueId = uniqueId,
SavedState = 0,
Reserved = new byte[0x1AB]
};
}

public static VhdFooter CreateForFixedDisk(ulong driveSize, byte[] uniqueId)
{
Cookie = GetHeaderCookie(); // conectix
Features = VhdDiskFeatures.None;
FileFormatVersion = 0x00010000;
DataOffset = 0xffffffffffffffff; // Fixed disk: 0xffffffffffffffff, Others: Real value
TimeStamp = 0x0;
CreatorApp = VhdCreatorApplication.WindowsDiskMngmt;
CreatorVersion = 0x03000600;
CreatorHostOS = VhdCreatorHostOs.Windows;
OriginalSize = 0x40000000;
CurrentSize = 0x40000000;
DiskGeometry = 0x2008;
DiskType = VhdDiskType.None;
Checksum = 0x0;
UniqueId = new byte[0x10];
SavedState = 0;
Reserved = new byte[0x1AB];
var footer = CreateWithDefaultValues(driveSize, uniqueId);
footer.DiskType = ((uint)VhdDiskType.Fixed).EndianSwap();
footer.DataOffset = 0xffffffffffffffff;

footer.FixChecksum();
return footer;
}

public static VhdFooter CreateForDynamicDisk(ulong driveSize, byte[] uniqueId)
{
var footer = CreateWithDefaultValues(driveSize, uniqueId);
footer.DiskType = ((uint)VhdDiskType.Dynamic).EndianSwap();
footer.DataOffset = ((ulong)0x200).EndianSwap(); // Offset of dynamic disk header (size of footer)

footer.FixChecksum();
return footer;
}

internal static uint CalculateChecksum(VhdFooter data)
Expand Down
66 changes: 66 additions & 0 deletions LibXboxOne/VHD/VhdUtils.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
using System;

namespace LibXboxOne.Vhd
{
public static class VhdUtils
{
const uint VHD_SECTOR_LENGTH = 512;
static readonly DateTime VhdEpoch = new DateTime(2000, 1, 1, 1, 0, 0, DateTimeKind.Utc);
public static uint GetTimestamp(DateTime dateTime)
{
return (uint)dateTime.Subtract(VhdEpoch).TotalSeconds;
}

// Source: https://github.com/ctatoiu/PS-Azure/blob/master/src/ServiceManagement/Compute/VhdManagement/Model/DiskGeometry.cs
public static VhdDiskGeometry CalculateDiskGeometry(ulong driveSize)
{
long totalSectors = (long)(driveSize / VHD_SECTOR_LENGTH);
if (totalSectors > 65535 * 16 * 255)
{
totalSectors = 65535 * 16 * 255;
}

int sectorsPerTrack;
int heads;
long cylinderTimesHeads;
if (totalSectors >= 65535 * 16 * 63)
{
sectorsPerTrack = 255;
heads = 16;
cylinderTimesHeads = totalSectors / sectorsPerTrack;
}
else
{
sectorsPerTrack = 17;
cylinderTimesHeads = totalSectors / sectorsPerTrack;

heads = (int)((cylinderTimesHeads + 1023) / 1024);

if (heads < 4)
{
heads = 4;
}
if (cylinderTimesHeads >= (heads * 1024) || heads > 16)
{
sectorsPerTrack = 31;
heads = 16;
cylinderTimesHeads = totalSectors / sectorsPerTrack;
}
if (cylinderTimesHeads >= (heads * 1024))
{
sectorsPerTrack = 63;
heads = 16;
cylinderTimesHeads = totalSectors / sectorsPerTrack;
}
}
long cylinders = cylinderTimesHeads / heads;

return new VhdDiskGeometry()
{
Cylinder = (ushort)cylinders,
Heads = (byte)heads,
SectorsPerCylinder = (byte)sectorsPerTrack
};
}
}
}
Loading

0 comments on commit f95e041

Please sign in to comment.