xls visszaállítás és Excel-borítás

Tegnap volt egy "alkalmazásrétegből megborul a gép" sztori, nálam "csak" egy kékhalál lett, de gondoltam leírom (és egyben archiválok egy xls visszaállítási metódust): eltűnt egy xls fájl (véletlen törlés, programhiba, akármi, nem tudni, a lényeg, hogy eltűnt). A szokásos testdisk, photorec, GetDataback körök hatástalanok voltak, jött a "taknyolós megoldás". Az xls-ben szerencsére volt egy elég jellegzetes string (a példa kedvéért legyen "cikkturkáló"), ami azt jelenti, hogy valahol benne van az ASCII "cikkturk" kifejezés [ha valaki tudja, hogy milyen kódolást használ az Excel az ékezetes karakterekre, ne tartsa magában, valami multibyte, de nem UTF-8], így:


foo@bar:~# grep -oba cikkturk /dev/sda2 --null-bytes
4235423423: cikkturk
4235645334: cikkturk
5687291311: cikkturk

Fogva a kapott offseteket dd-vel kicsit kezelhetőbb darabkákat tudunk kimásolni:


foo@bar:~# dd if=/dev/sda2 of=segment.dd bs=1M count=2 skip=$(expr 4235423423 / 1024 / 1024)

(két megás darab a legközelebbi, az offset "alatt" levő megabyte határtól)

Ebben már kényelmesebben tudjuk keresgetni a bináris office fájlok magic byte-jait: d0 cf 11 e0 a1 b1 a1 e1 (most esik le, hogy docfile... :) )


foo@bar:~# hexdump -v segment.dd | grep "cfd0 e011"
0036ebf cfd0 e011 b1a1 e11a 0000 0000 0000 0000

Az offsetet decimálisba alakítva (a példában 224959) már csak egy dd van hátra:


foo@bar:~# dd if=/dev/segment.dd of=restored.xls bs=1 count=128K skip=224959

És van egy restored.xls fájlunk. A 128 kilobyte-os fájlméretet hasraütésszerűen választottam, elvileg 512 byte-onként IDŐNKÉNT van egy pár byte-os magic number az xls-ekben ill. olvastam, mintha lenne a fájl végén is jelölő, de utóbbit nem láttam egyik tesztfájlon sem, előbbivel meg nem akartam szórakozni.

És akkor a megborulás: az egyik így visszaállított fájlt (több találat is volt a lemezen) Excelben megnyitva megnyílt, egészen az utolsó munkalap kiválasztásáig, amikor is kb. ~10 perc homokórázás (ami alatt azt értem, hogy a kurzort se lehetett mozdítani) után egy kellemes kékhalál fogadott. LibreOffice-ban gond nélkül megnyílt...

------------------
Szerk.: 2016. 10. 14.

Ma docx-el futottam egy kört, photorec csak egy korábbi példányt talált meg, úgyhogy jött a dd+grep+hexdump :)


#!/bin/bash
IMAGE="Pendrive.img"
mkdir scratch
mkdir recup
rm recup/* scratch/*
for offset in $(grep -oba "word/media/image5.png" $IMAGE | cut -d":" -f1); do
	dd if=$IMAGE of=scratch/$offset.dd bs=1M count=6 skip=$(expr $offset / 1024 / 1024) > /dev/null 2>&1
	start=$(hexdump -v scratch/$offset.dd | grep "4b50 0403" | cut -d" " -f1 | head -n 1)
	skip=$(perl -le "print hex('$start')")
	dd if=scratch/$offset.dd of=scratch/$offset-corrected.dd bs=1 skip=$skip > /dev/null 2>&1
	end=$(hexdump -v scratch/$offset-corrected.dd | grep "0000 0000" | cut -d" " -f1 | tail -n 1)
	count=$(perl -le "print hex('$end') + 21")
	echo "Skipping $skip bytes and extracting $count bytes"
	dd if=scratch/$offset-corrected.dd of=recup/restored-$offset.docx bs=1 count=$count > /dev/null 2>&1
done

Mint látszik, olyan doksit kerestem, amiben az ötödik kép png formátumú (word/document.xml-el a grep-ben minden doksit keres) és pár megás (6 megás darabot vágok ki elsőre, a keresett fájl olyan 2.8-3.2 között volt)...
Kis magyarázat: a 4b50 0403 a standard ZIP fejléc (local file header), kis szerencsével két null byte-ra végződik a zip (nem találtam rá pontos utalást, de ami docx-et/zip-et kipróbáltam, az így csinálta :) ), a többi csak másolgatás össze vissza (byte-onként dd FTW, tetű lassú) meg offset keresgetés... A recup-ba dobálja be a kinyert docx fájlokat, a scratchbe dobálja az ideiglenes fájlokat.

BlackY

Hozzászólások

Szép munka.

Ami a kékhalált illeti, gondolom, elfogyott a RAM, bár azt illene ellenőriznie a kernelnek, és kivágni a renitens foglalót. Lehet, azt hitte, más miatt fogyott el a RAM, és az OOM Killer azt a rendszerkomponenst ölte meg?

tr '[:lower:]' '[:upper:]' <<<locsemege
LOCSEMEGE

Részben én is a memóriára gyanakszom (egy talán 2 giga ramos virtuális gépben néztem, minimális swappel), de attól még nem lenne szabad random alkalmazásnak megfektetni a rendszert. A memória szerintem inkább csak valami limit volt, aminél tényleg kinyírta az Excel-t a kernel, ami közben már valami nagyon csúnyát csinált (szaggatva ugyan, de 100% erőforrás használat mellett is azért az egér mozgására szokott reagálni a Win)

BlackY
--
"en is amikor bejovok dolgozni, nem egy pc-t [..] kapcsolok be, hanem a mainframe-et..." (sj)

Nem UTF-16? (Csak tipp, nem tudom.)

Én már kezdem elveszteni a fonalat, de jogos, az is van benne :)
Belenéztem a PHPExcel kódjába, ott találtam egy hivatkozást, amit OpenOffice-os doksik is megerősítettek, hogy a BIFF8 doksik (Excel 8.0-tól) mind UTF-16LE-k legfeljebb a 0 felső byte-okat levágják. Viszont most látom, hogy a file a kimenetében szépen kiírja a használt kódlapot (1250), vagyis tegnap benéztem a multibyte-ot (és ránézve 1250-el stimmeltek az ékezetek). A legjobb tippem, hogy ez egy BIFF5-BIFF8 compound doksi (passz, hogy mi az, OOo doksiban szerepel :) ), ezért van benne a legacy kódlapos stream is...

BlackY
--
"en is amikor bejovok dolgozni, nem egy pc-t [..] kapcsolok be, hanem a mainframe-et..." (sj)