[ Content | View menu ]

Извлечение данных из виртуальных дисков VirtualBox

Опубликовано 21.07.2010

Однажды глубокой ночью мне позарез понадобилось вытащить из остановленной виртуальной машины Virtualbox, находящейся на моем рабочем компьютере, один файлик. Удаленно запустить виртуальную машину и тем более подключиться к ней не получилось, поэтому я решил попробовать вытащить нужный раздел из vdi и смонтировать его. Ситуация немного осложнялась тем, что виртуальный жесткий диск хоть и содержал всего один корневой раздел, но был динамически расширяющимся, а это значит, что блоки файловой системы располагались в хронологическом порядке, а не в том, который ожидает драйвер файловой системы.

К счастью, можно легко преобразовать vdi из динамического формата в статический с помощью многоцелевой утилиты vboxmanage, входящей в состав пакета virtualbox:

vboxmanage clonehd --variant static debian.vdi temp.vdi

Теперь у нас есть файл temp.vdi, внутри которого где-то присутствует образ искомой файловой системы; для ее корректного извлечения нужно вычислить смещение образа относительно начала файла. В половине найденных по запросу «mount vdi linux» статей рекомендуется использовать для этих целей утилиту vditool, предназначенную на самом деле для внутреннего тестирования функциональности виртуальных дисков в VirtualBox. Раньше бинарник vditool можно было отдельно скачать с сайта virtualbox.org, но теперь его там по понятным причинам нет (желающие могут скомпилировать его самостоятельно: vditool.cpp)

Мы, как всегда, пойдем другим путем и воспользуемся подручными средствами. Первые 512 байт нашего vdi-файла — его заголовок, в котором можно разобраться, воспользовавшись, например, этим мануалом или непосредственно описанием структуры заголовка vdi в исходниках VirtualBox. Из этих источников следует, что образ размечен следующим образом:
512 байт: заголовок
4 * N + X: карта мегабайтных блоков, здесь N ­— количество мегабайт в виртуальном жестком диске, а X — выравнивание получившегося числа до ближайшей верхней 512-байтной границы
512 + 4*N + выравнивание: смещение данных

Зная точный размер виртуального диска, можно легко вычислить смещение вручную:

$ vboxmanage showhdinfo f8e0de05-1419-405d-92d9-8358dc1e6bec
VirtualBox Command Line Management Interface Version 3.0.8_OSE
(C) 2005-2009 Sun Microsystems, Inc.
All rights reserved.

UUID:                 f8e0de05-1419-405d-92d9-8358dc1e6bec
Accessible:           yes
Description:
Logical size:         4095 MBytes
Current size on disk: 2637 MBytes
Type:                 normal (base)
Storage format:       VDI
In use by VMs:        debian (UUID: f1f8221a-6542-4dfe-9062-5397f429da4b)
Location:             /home/bvk/.VirtualBox/HardDisks/debian.vdi

(UUID нужного диска можно узнать из вывода команды vboxmanage list hhds). Здесь выравненное до 512 значение размера карты блоков равно 16384, а смещение данных — 16896.
А можно и вытащить смещение непосредственно из заголовка vdi. Например, вот начало моего четырёхгигового виртуального диска:

$ head -c 512 temp.vdi |hexdump  -C
00000000  3c 3c 3c 20 53 75 6e 20  56 69 72 74 75 61 6c 42  |< << Sun VirtualB|
00000010  6f 78 20 44 69 73 6b 20  49 6d 61 67 65 20 3e 3e  |ox Disk Image >>|
00000020  3e 0a 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |>...............|
00000030  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00000040  7f 10 da be 01 00 01 00  80 01 00 00 02 00 00 00  |................|
00000050  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
*
00000150  00 00 00 00 00 02 00 00  00 42 00 00 00 00 00 00  |.........B......|
00000160  00 00 00 00 00 00 00 00  00 02 00 00 00 00 00 00  |................|
00000170  00 00 f0 ff 00 00 00 00  00 00 10 00 00 00 00 00  |................|
00000180  ff 0f 00 00 ff 0f 00 00  db fa c4 c9 fd 13 ea 49  |...............I|
00000190  9e ae 4e 47 43 3f a0 3c  46 37 6c be e6 fd 02 40  |..NGC?.<f7l ....@|
000001a0  a7 63 44 3f 6e 3f 26 d8  00 00 00 00 00 00 00 00  |.cD?n?&.........|
000001b0  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
000001c0  00 00 00 00 00 00 00 00  0a 02 00 00 ff 00 00 00  |................|
000001d0  3f 00 00 00 00 02 00 00  00 00 00 00 00 00 00 00  |?...............|
000001e0  00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
*
00000200

Жирным шрифтом выделены необходимые четыре байта offsetData по смещению 0×0158. Можно искать их визуально, помня о little-endian-порядке байт (в этом случае искомое значение равно 0×00004200), а можно воспользоваться простенькой командой:

$ head -c 348 temp.vdi |tail -c 4|perl -ne 'print unpack("L",$_),"\n"'
16896

В любом случае, лишний раз перепроверить себя никогда не помешает.

Посмотрим, что находится по этому смещению. Сразу можно предположить, что там располагается начало образа жесткого диска, из этого следует, что первые 512 байт содержат mbr. Проверим:

$ dd if=temp.vdi bs=512 count=1 skip=$((16896/512))|file -
1+0 records in
1+0 records out
512 bytes (512 B) copied, 3.9397e-05 s, 13.0 MB/s
/dev/stdin: x86 boot sector; partition 1: ID=0x83, active, starthead 1,
startsector 63, 7903917 sectors; partition 2: ID=0x5, starthead 0, startsector
7903980, 481950 sectors, code offset 0x4c

Жесткий диск содержит 2 раздела: основной размером 3859 мегабайт, начинающийся с 63 сектора (1 сектор — 512 байт), и расширенный 235 мегабайт, отведенный установщиком Debian под swap (вот это сюрприз на виртуалке). Для очистки совести проверяем заголовок первого раздела:

$ dd if=temp.vdi bs=512 count=3 skip=$((16896/512+63))|file -
3+0 records in
3+0 records out
1536 bytes (1.5 kB) copied, 4.7716e-05 s, 32.2 MB/s
/dev/stdin: Linux rev 1.0 ext3 filesystem data,
UUID=5ac94027-bf6e-43bc-9c3e-8a7830fe4ff8 (needs journal recovery) (large files)

То, что надо! Осталось смонтировать. Несколько лет назад пришлось бы дополнительно извлекать все 7903917 секторов в отдельный файл и монтировать его, но сейчас можно просто указать смещение от начала файла как опцию mount (оставшиеся расширенный раздел и swap внутри него будут проигнорированы):

$ sudo mount -o loop,offset=$((16896+63*512)) temp.vdi mnt
$ ls mnt/
bin   cdrom  etc   initrd.img      lib         media  opt   root  selinux  sys  usr  vmlinuz
boot  dev    home  initrd.img.old  lost+found  mnt    proc  sbin  srv      tmp  var  vmlinuz.old

Задача решена, все свободны.

«
»

7 комментариев

Write a comment - TrackBack - RSS Comments

  1. Comment by kolebas:

    а vdfuse не используете?

    21.07.2010 @ 21:32
  2. Comment by bappoy:

    спасибо, посмотрю
    интереснее же самому разобраться

    21.07.2010 @ 21:42
  3. Comment by yuri:

    А что же не получилось с запуском и подключением к машине?

    VBoxManage -q startvm centos –type headless

    И потом по ssh.

    Или если VirtualBox не OSE, то

    VBoxManage -q startvm centos –type vrdp

    а потом rdesktop localhost

    22.07.2010 @ 07:26
  4. Comment by bappoy:

    не осилил в три часа ночи :) входящий ssh не был настроен, а поскольку virtualbox у меня ose, то фича «vrdp» там отсутствует

    22.07.2010 @ 10:28
  5. Comment by bioex:

    «Жирным цветом»? ;)

    22.07.2010 @ 14:08
  6. Comment by DarkHobbit:

    По приведённой ссылке vditool.cpp тоже уже нет. Надо либо лезть в предыдущую ревизию
    http://www.virtualbox.org/browser/trunk/src/VBox/Devices/Storage/testcase/vditool.cpp?rev=33000
    копировать текст и вручную чистить номера строк, либо svn-ом качать trunk и трясти svn merge-м (каюсь, я пошёл по первому пути, хоть это и не unix way).

    09.04.2011 @ 21:20
  7. Comment by Aлекксандр:

    Застрял вот на этом шаге vboxmanage clonehd –variant static debian.vdi

    C:\Program Files\Programs\Virtualbox>vboxmanage clonehd –variant static «d:\Win
    dows XP.vdi» «c:\temp.vdi»
    VBoxManage.exe: error: Could not get the storage format of the medium ‘d:\Windows XP.vdi’ (VERR_NOT_SUPPORTED)
    VBoxManage.exe: error: Details: code VBOX_E_IPRT_ERROR (0×80bb0005), component Medium, interface IMedium, callee IUnknown
    Context: «OpenMedium(Bstr(pszFilenameOrUuid).raw(), enmDevType, AccessMode_ReadWrite, fForceNewUuidOnOpen, pMedium.asOutParam())» at line 210 of file VBoxManage
    Disk.cpp

    Как решить это? Вообще началось все с того что перестала открываться виртуальная машина, выдает ошибку verr_VD_VDI_invalid_header .

    Помогите пожалуйста восстановить. На виртуальной машине очень много данных необходимых по работе.

    27.01.2012 @ 07:33
Write comment

Я не робот.