¿extrayendo información del archivo virtualbox .sav?

¿extrayendo información del archivo virtualbox .sav?

Tengo un .savarchivo de VirtualBox que quiero restaurar. Pero el problema es que sólo tengo este archivo (sin ninguna otra información sobre el archivo del disco, el tamaño de la RAM, etc.). Intenté duplicar una de mis máquinas virtuales, hice una instantánea y la reemplacé (con el nombre de archivo correcto). Y al restaurar el estado, VirtualBox arrojó un error

No se pudo cargar la unidad 'mm' (VERR_SSM_LOAD_MEMORY_SIZE_MISMATCH)

Como no sé el tamaño de la memoria, no puedo seguir adelante.

Después de buscar en Google, encuentro un archivo de instantánea que contiene toda la información y configuración de una máquina virtual. ¿Existe alguna forma posible de extraer información de un .savarchivo para poder obtener la configuración correcta?

Respuesta1

Lo siguiente se relaciona con la versión más reciente de VirtualBox al momento de escribir este artículo (4.3). No puedo hablar de versiones anteriores.

Un SAVarchivo se compone de units. Si abre su SAVarchivo en un editor hexadecimal, puede navegar a través de las unidades buscando la siguiente cadena hexadecimal:

0A 55 6E 69 74 0A 00 00

Esta es la palabra Unitcon algunos otros caracteres a su alrededor. 0x24 (36) bytes después del hit, verá algunos caracteres ASCII. Por ejemplo, el primero probablemente será: SSM. Este es el descriptor de la unidad, en este caso el "Administrador de estado guardado".

Quiere encontrar la mmunidad (Administrador de memoria). Para mí, siempre ha sido la tercera unidad en el archivo SAV, por lo que el tercer resultado al buscar:

En hexadecimal:

0A 55 6E 69 74 0A 00 00 52 01 00 00 00 00 00 00 7C 36 11 91 CE B0 E2
CE 02 00 00 00 01 00 00 00 FF FF FF FF 00 00 00 00 03 00 00 00 6D 6D
00 92 10 1E 00 08 00 00 00 00 00 00 00 00 80 00 00 00 00 91 0E 01 00
38 7E D4 06 22 00 00 00 00 00 00 00

Como puede ver, los primeros 8 bytes son el unitencabezado. Luego, 0x24 (36) bytes más tarde vemos 6D 6D 00cuál es mm\0. Omita tres bytes ( 92 10 1E), luego tendrá un uint16 (little endian), que es la cantidad de memoria del sistema en el momento en que se tomó la instantánea. En mi ejemplo: 00 08= 0x800= 2048= 2GB.

Respuesta2

Puedes intentar ejecutar elvboxmanage adopta el estado, que, según la documentación, intentará cambiar la VM para adjuntar la instantánea actual al estado de guardado propuesto.

Si no funciona, parsiya hizo un blog interesante sobre cómo analizar el estado de SAV que se puede encontrar aquí:blog parsia

Según su blog, el estado SAVE se describe enSSM.cpp

La nueva información que encontré se basa en SSMFILEHDRV12 (más reciente que parsiya). La unidad de RTGCPHYS está en GIM_HV_PAGE_SIZE (4096). Es más una unidad y generalmente es 08 * 4096 si entendí correctamente. De hecho, hay otra unidad para los datos creados más adelante.

Si entendí correctamente, la lógica del código SSM.cpp como se explicó al principio es realizar el estado de guardado en vivo. Es decir, se desconoce el tamaño total. Por lo tanto, podrían registrarse varias unidades de memoria. Si solo hay una unidad de memoria sin procesar, entonces sí, podría deducir el tamaño de la VM. El kilometraje varía

Extracto del principio del archivo.

 * The live snapshots feature (LS) is similar to teleportation (TP) and was a
 * natural first step when implementing TP.  The main differences between LS and
 * TP are that after a live snapshot we will have a saved state file, disk image
 * snapshots, and the VM will still be running.
 *  * Compared to normal saved stated and snapshots, the difference is in that the
 * VM is running while we do most of the saving.  Prior to LS, there was only
 * one round of callbacks during saving and the VM was paused during it.  With
 * LS there are 1 or more passes while the VM is still running and a final one
 * after it has been paused.  The runtime passes are executed on a dedicated
 * thread running at at the same priority as the EMTs so that the saving doesn't
 * starve or lose in scheduling questions (note: not implemented yet). The final
 * pass is done on EMT(0).

 * The saved state units each starts with a variable sized header
 * (SSMFILEUNITHDRV2) that contains the name, instance and pass.  The data
 * follows the header and is encoded as records with a 2-8 byte record header
 * indicating the type, flags and size.  The first byte in the record header
 * indicates the type and flags:
 *  *   - bits 0..3: Record type:
 *       - type 0: Invalid.
 *       - type 1: Terminator with CRC-32 and unit size.
 *       - type 2: Raw data record.
 *       - type 3: Raw data compressed by LZF. The data is prefixed by a 8-bit
 *                 field containing the length of the uncompressed data given in
 *                 1KB units.
 *       - type 4: Zero data. The record header is followed by a 8-bit field
 *                 counting the length of the zero data given in 1KB units.
 *       - type 5: Named data - length prefixed name followed by the data. This
 *                 type is not implemented yet as we're missing the API part, so
 *                 the type assignment is tentative.
 *       - types 6 thru 15 are current undefined.
 *   - bit 4: Important (set), can be skipped (clear).
 *   - bit 5: Undefined flag, must be zero.
 *   - bit 6: Undefined flag, must be zero.
 *   - bit 7: "magic" bit, always set.  
 /**
 * Writes a record header for the specified amount of data.
 *
 * @returns VBox status code. Sets pSSM->rc on failure.
 * @param   pSSM            The saved state handle
 * @param   cb              The amount of data.
 * @param   u8TypeAndFlags  The record type and flags.
 */
static int ssmR3DataWriteRecHdr(PSSMHANDLE pSSM, size_t cb, uint8_t u8TypeAndFlags)
{
    size_t  cbHdr;
    uint8_t abHdr[8];
    abHdr[0] = u8TypeAndFlags;
    if (cb < 0x80)
    {
        cbHdr = 2;
        abHdr[1] = (uint8_t)cb;
    }
    else if (cb < 0x00000800)
    {
        cbHdr = 3;
        abHdr[1] = (uint8_t)(0xc0 | (cb >> 6));
        abHdr[2] = (uint8_t)(0x80 | (cb & 0x3f));
    }
    else if (cb < 0x00010000)
    {
        cbHdr = 4;
        abHdr[1] = (uint8_t)(0xe0 | (cb >> 12));
        abHdr[2] = (uint8_t)(0x80 | ((cb >> 6) & 0x3f));
        abHdr[3] = (uint8_t)(0x80 | (cb & 0x3f));
    }
    else if (cb < 0x00200000)
    {
        cbHdr = 5;
        abHdr[1] = (uint8_t)(0xf0 |  (cb >> 18));
        abHdr[2] = (uint8_t)(0x80 | ((cb >> 12) & 0x3f));
        abHdr[3] = (uint8_t)(0x80 | ((cb >>  6) & 0x3f));
        abHdr[4] = (uint8_t)(0x80 |  (cb        & 0x3f));
    }
    else if (cb < 0x04000000)
    {
        cbHdr = 6;
        abHdr[1] = (uint8_t)(0xf8 |  (cb >> 24));
        abHdr[2] = (uint8_t)(0x80 | ((cb >> 18) & 0x3f));
        abHdr[3] = (uint8_t)(0x80 | ((cb >> 12) & 0x3f));
        abHdr[4] = (uint8_t)(0x80 | ((cb >>  6) & 0x3f));
        abHdr[5] = (uint8_t)(0x80 |  (cb        & 0x3f));
    }
    else if (cb <= 0x7fffffff)
    {
        cbHdr = 7;
        abHdr[1] = (uint8_t)(0xfc |  (cb >> 30));
        abHdr[2] = (uint8_t)(0x80 | ((cb >> 24) & 0x3f));
        abHdr[3] = (uint8_t)(0x80 | ((cb >> 18) & 0x3f));
        abHdr[4] = (uint8_t)(0x80 | ((cb >> 12) & 0x3f));
        abHdr[5] = (uint8_t)(0x80 | ((cb >>  6) & 0x3f));
        abHdr[6] = (uint8_t)(0x80 | (cb & 0x3f));
    }
    else
        AssertLogRelMsgFailedReturn(("cb=%#x\n", cb), pSSM->rc = VERR_SSM_MEM_TOO_BIG);

    Log3(("ssmR3DataWriteRecHdr: %08llx|%08llx/%08x: Type=%02x fImportant=%RTbool cbHdr=%u\n",
          ssmR3StrmTell(&pSSM->Strm) + cbHdr, pSSM->offUnit + cbHdr, cb, u8TypeAndFlags & SSM_REC_TYPE_MASK, !!(u8TypeAndFlags & SSM_REC_FLAGS_IMPORTANT), cbHdr));

    return ssmR3DataWriteRaw(pSSM, &abHdr[0], cbHdr);
}

También notó, como Bridgey, que las unidades comienzan con ascii "Unit", pero también que la última unidad termina con "TheEnd".

Analizó parte de la estructura del archivo SAV basándose en la estructura de la UNIDAD descrita en SSMInternal.h aquí:encabezado de código abierto de virtualbox

información relacionada