L2V: Making Logical Volume Image Bootable as Physical

Discussions about using Windows guests in VirtualBox.
Post Reply
alleoma
Posts: 2
Joined: 31. Mar 2014, 00:29

L2V: Making Logical Volume Image Bootable as Physical

Post by alleoma »

I've got lots of very old PCs at work, with Windows XP installed on them. Most of them formatted as fashionable in their heyday: one moderate size primary bootable system partition, plus some more much larger partitions - for data.

These Windows XP installations (mostly OEM) have to be backed up before migration to another OS (fiscal requirement), and allow their re-imaging onto respective PCs at any moment (at least, in principle), with their MS activation status preserved. I didn't want to preserve the data partitions (waste of storage), but wanted to be able to run any of the bootable partition images within a VirtualBox VM (to alleviate the OS migration to our users, and to spare re-imaging for the purposes of annual software assets inventory).

Having uncertain results with P2V and cloning products, I decided to stick with the most straightforward tools only (which made me a bit "Linux-biased", as some put it here, in the forums). While dd can image a bootable system logical volume, the latter won't boot in a VM. For that, it needs to be made 'physical', which means prepending a suitable MBR to it + some corrections.

As I've found no definitive howto on converting a bootable logical volume image into a virtual equivalent of bootable physical volume image, after some digging of known facts and experimenting, I've compiled for myself this "L2V" howto.

Sharing.

************************************************************************************

How to make a bootable VM from a dd image made of a logical volume (not entire disk)

[a Windows XP on an NTFS boot partition experience]

************************************************************************************


You'll want to boot off some Linux Live USB/CD (I've experimented with Fedora 20, KDE version), to make everything described below.


1. Supplying Windows with other drivers, except the actually installed.

However, first off, we need to supply Windows XP with additional drivers, to enable it to boot in on a different (now, virtual) hardware (esp., HDD). Make sure you have something like i386 drivers repository on your Windows system drive, and run the MergeIDE script. It will copy the drivers and put necessary information on them into the system registry.


2. Getting principal partition information

Now, we boot into Linux. As it is live, we may count on our source drive to be something like /dev/sda. Let's grab and save into a file a principal partition information on it (we'll need it later, when correcting the partition table).

# fdisk -lu /dev/sda

Disk /dev/loop1: 74.5 GiB, 80026402816 bytes, 156301568 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: dos
Disk identifier: 0x9cf5c497

Device Boot Start End Blocks Id System
/dev/loop1p1 31214295 156296384 62541045 f W95 Ext'd (LBA)
/dev/loop1p2 63 176714 88326 de Dell Utility
/dev/loop1p3 * 176715 31214294 15518790 7 HPFS/NTFS/exFAT
/dev/loop1p5 31214358 156296384 62541013+ 7 HPFS/NTFS/exFAT

Partition table entries are not in disk order.

# fdisk -lu /dev/sda > ./part.txt


3. Making dd image file(s).

A must to remember, you'll be always better off with a copy of the MBR (or expect no easy getting a bootable image). Make sure you've read http://en.wikipedia.org/wiki/Dd_(Unix) on general dd options.

[obligatory] # dd if=/dev/sda of=./mbr.img bs=512 count=1

This will give you the parition table records, with partition(s) offsets and sizes.

Next, what's the best if you have room for it, make an image of the whole harddrive (no number appended to the device name). With this stored intact (highly recommended), you'll be able to restore your source machine to an original state, if needed. Also, it helps troubleshooting any further logical-to-physical volume conversion. Large bs gives higher copy speed.

[recommended] # dd if=/dev/sda of=./disk.img bs=8M conv=sync,notrunc,noerror

Now, let's image any logical volumes we may need. The bootable one(s) are what we need anyway, to make a VM. The other ones we may either image, or just copy files, no matter, as we don't boot off them. Logical volumes bear a number appended to a device name (!).

[obligatory] # dd if=/dev/sda1 of=./part1.img bs=8M conv=sync,notrunc,noerror


4. Making a bootable 'physical' image from a 'logical' one.

Harddrives (unlike, supposedly, USB flash or floppy disks) do not boot out of the active partition's boot sector directly. They need a Master Boot Record (MBR), which would properly refer that bootable part of the bootable partition. MBR is not part of logical volume images.

Hence, we need to prepend a correct MBR (including a correct drive partition table, referencing a correct offset to our logical volume image, showing correct sizes, etc.) to our logical volume image. Let's use the original drive's MBR as a template.

# cp mbr.img boot.img

(if you don't have a good HEX [disk] editor capable of dealing with large files, you may try making all necessary corrections to the partition table in boot.img here, with mc or whatever, before appending the logical volume to it, and hope to have made no errors; you won't edit the partition's start offset in the NTFS BPB - see 6.1 below, but, hopefully, it may work even without it, which would be much better from the forensical point of view).

# dd if=./part1.img of=./boot.img bs=32M seek=512 oflag=seek_bytes conv=notrunc,nocreat

It means: copy 512B of MBR to a new file boot.img; append the logical volume image to it (for there's no way to prepend). You may risk optimizing this step with respect to disk room, making a dd copy of /dev/sda1 directly into mbr.img above.

Note: large bs lends speed, "seek" means offset in the output file (the end of it, effectively), "oflag=seek_bytes" is important (or it will not seek 512B, but 512*32M here, bs-fold), without "notrunc" it will truncate the boot.img past part1.img (if the boot.img were large, or already contained other partitions further than part1.img), "nocreat" means do not delete boot.img before copying into it (without it, it will pad the first 512B in this example with zeros).


5. Preparing the MBR partition table in boot.img

The more comfortable way of making the necessary corrections to the partition table is to use some good HEX editor, capable of dealing with large files, like our images.

wxHexEditor has been a tool of choice for me (http://sourceforge.net/projects/wxhexeditor/).

Let us note the bootable partition in our fdisk-saved information - the one marked with asterisk. The size should also match what you know ("blocks" means here "two sectors", so multiply it by two, and that will make the partition size in KB). ID should be 7 for NTFS (there are other partition identifiers for other filesystems).

Now, having identified the partition, notice the starting offset of it, on the disk: 176715 sectors in this example. On the whole disk image (disk.img), you may go to offset 176715 (offset) * 512 (sector size in bytes) bytes and see our logical volume's start. The same (for NTFS) you should see at the very start of the logical volume image file (part1.img), and at offset 512 bytes in our boot.img (just after the MBR, the so called BIOS Parameter Block (BPB) for an NTFS volume):

000000512 EB 52 90 4E 54 46 53 20 20 20 20 00 02 08 00 00 >> "ëRNTFS "

--------------------------------------------------------

The Master Boot Record contains four partition entries:

Offset Description Size
000h Executable Code (Boots Computer) 446 Bytes
1BEh 1st Partition Entry (See Next Table) 16 Bytes
1CEh 2nd Partition Entry 16 Bytes
1DEh 3rd Partition Entry 16 Bytes
1EEh 4th Partition Entry 16 Bytes
1FEh Boot Record Signature (55h AAh) 2 Bytes

That is:

Partition 1, offset 0x01BE (446)
Partition 2, offset 0x01CE (462)
Partition 3, offset 0x01DE (478)
Partition 4, offset 0x01EE (494)

--------------------------------------------------------

Now, in the HEX editor, we should identify our partition entry. It's characteristic will be, first, 80H as the first byte of respective entry, as it's bootable. Non-bootable entries have zero as the first byte.

--------------------------------------------------------

Partition Entries within MBR:

Offset Description Size
00h Current State of Partition
(00h=Inactive, 80h=Active) 1 Byte
01h Beginning of Partition - Head 1 Byte
02h Beginning of Partition -
Cylinder/Sector (See Below) 1 Word
04h Type of Partition (See List Below) 1 Byte
05h End of Partition - Head 1 Byte
06h End of Partition - Cylinder/Sector 1 Word
08h Number of the First Sector in the
Partition (offset from disk start) 1 Double Word
0Ch Number of Sectors in the Partition 1 Double Word

--------------------------------------------------------

Next, note the number (which is the Logical Block Addressing, or LBA offset on the disk) at offset 08h from the start of the respective partition entry (the wxHexEditor will show you also as 32-bit decimal) - it should be equal to the start value from the fdisk-saved information (176715, in our example). Also, you may check the size of partition.

[ Note: Intel PCs are based on the little-endian architecture with an actual reversed byte order for multi-byte number representations. So the LBA sector offset number like 01 38 8b 3b is stored as 3b 8b 38 01. Mind it when using a calculator to convert from hex to dec and back (!) ].

Now that we've identified the partition entry to be corrected, copy 16 bytes of our partition entry to the first partition entry (offset 446), and zero the rest three entries. Don't occasionally delete "55 AA" end-of-MBR marker (!).



6. Adjusting the MBR partition table entry in boot.img


6.1. Partition start offset (LBA)

As we have put the logical volume partition right after the MBR (offset 512, or 1 sector), we should change the number at offset 08h respectively: 01 00 00 00 (reversed order, double word).

Despite that Microsoft insists that BIOS Parameter Block (BPB) for NTFS volumes (this is what an NTFS volume starts with - the first sector of our part1.img, and the sector at offset 512B in our boot.img) the "4 bytes" are "not used or checked by NTFS" at offset "0x1Ch" from the BPB start (http://technet.microsoft.com/en-us/libr ... 10%29.aspx), here we are most likely to find another copy of this partition's LBA offset number (176715, in our example), which was present at offset 08h from the start of the respective partition entry in MBR.

So, just in case, here, at disk offset 512B (logical volume start offset) + 0x1Ch (this number offset), we will also repeat what we have just put into the MBR partition entry: 01 00 00 00 (reversed order, double word).


6.2. Partition start offset (CHS)

Setting the partition start offset in terms of Head/Cylinder/Sector is more tricky. Here, bearing in mind that we have our partition at the offset of 1 sector, we might think that it should be something like "00 01 00" at offset 01h of the MBR partition entry, which means 0 head/0 cylinder/1 sector (the second byte is lower in the little-endian word 01 00 for cylinder/sector, where, at that, cylinder gets 10 higher bits, and sector 5 lower).

Nope!

It will work only when you put there "00 02 00" (that is, plus 1 to what's expected).

That's because sectors seem to be numbered 1-63 (!). And despite the statements that modern OSes/BIOSes don't use the CHS information, but just the LBA, Windows XP does, and will not boot if this value is incorrect.


6.3. Partition size

This should be correct as is. However, mind that the size shown for the boot.img (mount it with "# losetup -f -r ./boot.img", which is find an available loop device node (like /dev/loop0), and mount read-only, then do fdisk -lu /dev/loop0 - see an example output below) as a whole does not correlate well with the size shown as "End" sector of the partition.

It is the latter number ("End" value of fdisk information) should appear at offset 0Ch from the start of the MBR partition entry ("8C 98 D9 01" or 31037580, in my case). Check it.

And, surprise, it is 1 sector less in the BPB of the NTFS volume ("8B 98 D9 01" or 31037579, in my case), at offset 0x28 from the beginning of it. Check it.

***************************************************
With this, partition manipulations are over. Hooray.


7. Adjusting partition number in boot.ini

It will not boot, however, if the logical volume we used to produce our bootable "physical" volume image were not the same number as originally. Remember, we have moved the partition entry in MBR. There might also be other partitions, which counted on the source machine within the context of the whole disk.

Now, we'll have to mount our boot.img locally.

# losetup -f ./boot.img
# losetup
NAME SIZELIMIT OFFSET AUTOCLEAR RO BACK-FILE
/dev/loop0 0 0 1 0 /path/to/boot.img

Then, we could mount the NTFS partition from it.

# fdisk -lu /dev/loop0
Disk /dev/loop0: 14.8 GiB, 15891304448 bytes, 31037704 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: dos
Disk identifier: 0x9cf5c497

Device Boot Start End Blocks Id System
/dev/loop0p1 * 1 31037580 15518790 7 HPFS/NTFS/exFAT


Mind the start offset of 1 sector (=512B). Just to confirm. Now, we can mount this partition from the "disk" image file we've produced, at the 512B offset.

# losetup -f -o 512 ./boot.img
# losetup
NAME SIZELIMIT OFFSET AUTOCLEAR RO BACK-FILE
/dev/loop0 0 512 0 0 /path/to/boot.img

And mount it as NTFS:

#mount /dev/loop0 /path/to/mounpoint

Alternatively, you may use kpartx -av /dev/loop0, which will produce /dev/mapper/loop0p1 et al. mapping for all valid partitions within boot.img

Now, as we have access to boot.ini file, change the partition number accordingly, bearing in mind that, apparently, the only partition in boot.img is number 1, not zero:

[boot loader]
timeout=30
default=multi(0)disk(0)rdisk(0)partition(1)\WINDOWS
[operating systems]
multi(0)disk(0)rdisk(0)partition(1)\WINDOWS="Microsoft Windows XP Professional" /noexecute=optin /fastdetect


8. Starting the boot.img with VM

I'd recommend storing boot.img intact, using copies of it, or shapshots. And go-go, as simple like this:

# qemu-system-i386 -snapshot -m 512 ./boot.img

Getting it onto VirtualBox is possible with creating an external VMDK descriptor file for boot.img (possible only with loop-mounted image, i.e. block device):

# VBoxManage internalcommands createrawvmdk -filename boot.vmdk -rawdisk /dev/loop0


9. Getting around with Windows activation

With some Windows releases, you can expect an offer to activate it after porting an installation into VM.

As a first counter-measure, press F8 repeatedly on boot, choose Safe Mode with Command Prompt, and execute "rundll32.exe syssetup,SetupOobeBnk", which will give you 30 more days. You can repeat it 3 more times prior to another 30 days period expiration.

**********
That's it.
Post Reply