wyodrębnianie informacji z pliku .sav wirtualnej skrzynki?

1

mam .sav plik VirtualBox, który chcę przywrócić. Ale problem polega na tym, że mam tylko ten plik (bez żadnych innych informacji o wielkości pliku dyskowego i pamięci RAM itd.). Próbowałem zduplikować jedną z moich maszyn wirtualnych, utworzyć migawkę i zastąpić migawkę (z właściwą nazwą pliku). A podczas przywracania stanu VirtualBox zgłosił błąd

Nie można załadować jednostki „mm” (VERR_SSM_LOAD_MEMORY_SIZE_MISMATCH)

Ponieważ nie znam rozmiaru pamięci, nie mogę przejść dalej.

Po googlu znajduję plik migawki zawierający wszystkie informacje i konfigurację maszyny wirtualnej. Czy jest jakiś możliwy sposób na wyodrębnienie informacji z .sav plik, dzięki czemu mogę uzyskać odpowiednią konfigurację?

JACK M
źródło

Odpowiedzi:

4

Poniższe odnosi się do najnowszej wersji VirtualBox w momencie pisania (4.3). Nie mogę mówić za starsze wersje.

ZA SAV plik składa się z units. Jeśli otworzysz swój SAV w edytorze szesnastkowym możesz poruszać się po jednostkach, szukając następującego ciągu szesnastkowego:

0A 55 6E 69 74 0A 00 00

To jest słowo Unit z kilkoma innymi postaciami wokół niego. 0x24 (36) bajtów po trafieniu, zobaczysz kilka znaków ASCII. Na przykład pierwszym będzie prawdopodobnie: SSM. Jest to deskryptor jednostki, w tym przypadku „Saved State Manager”.

Chcesz znaleźć mm (Menedżer pamięci). Dla mnie zawsze była to trzecia jednostka w pliku SAV - więc trzeci wynik podczas wyszukiwania:

Na heksie:

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

Jak widać, pierwsze 8 bajtów to unit nagłówek. Następnie widzimy 0x24 (36) bajtów później 6D 6D 00 który jest mm\0. Pomiń trzy bajty ( 92 10 1E ) a następnie masz uint16 (mały endian), który jest ilością pamięci systemowej w czasie wykonywania migawki. W moim przykładzie: 00 08 = 0x800 = 2048 = 2GB.

Bridgey
źródło
0

Możesz spróbować wykonać vboxmanage przyjmuje stan , który zgodnie z dokumentacją będzie próbował zmienić maszynę wirtualną, aby dołączyć bieżącą migawkę do proponowanego stanu składowania.

Jeśli to się nie uda, parsiya zamieściła interesujący blog o analizowaniu stanu SAV, który można znaleźć tutaj: blog parsiya

Zgodnie z jego blogiem, stan SAVE jest opisany w SSM.cpp

Nowe informacje, które znalazłem, oparte są na SSMFILEHDRV12 (nowszym niż parsiya) Jednostka RTGCPHYS znajduje się w GIM_HV_PAGE_SIZE (4096). Jest to bardziej jednostka i ogólnie 08 * 4096, jeśli dobrze zrozumiałem. W rzeczywistości istnieje jeszcze inna jednostka do tworzenia danych

Jeśli dobrze zrozumiałem, logika kodu SSM.cpp, jak wyjaśniono na początku, to wykonanie stanu zapisywania na żywo. IE całkowity rozmiar nie jest znany. Może więc być zarejestrowanych wiele jednostek pamięci. Jeśli istnieje tylko jedna jednostka pamięci surowej, to tak, można wywnioskować wielkość maszyny wirtualnej. Przebieg zmienia się

Wyciąg z początku pliku

 * 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);
}

Zauważył także, podobnie jak Bridgey, że Jednostki zaczynają się od ascii „Jednostki”, ale także, że ostatnia jednostka kończy się „TheEnd”

Parsował część struktury pliku SAV na podstawie struktury JEDNOSTKI opisanej w SSMInternal.h tutaj: nagłówek opensource wirtualnego

sysarchitek
źródło