k47.cz  — každý den dokud se vám to nezačne líbit
výběr foto Praha povídky kultura
TECH ▞▞ kolo | twitter RSS
««« »»»

Ve střevech mrtvých NTFS disků

28. 12. 2018 — k47 (♪)

Jak jsem tady už psal, stal jsem se opa­t­rov­ní­kem a kří­si­te­lem jed­noho mrt­vého disku. Ná­sle­du­jící řádky před­sta­vují de­tailní zá­pisky z pouti za ob­no­vou dat.

Jako první krok jsem vy­tvo­řil obraz disku, pro­tože snažit se ob­no­vit data ze za­ří­zení, které vám umírá pod rukama, je méně než ide­ální. Hlavní je z trosek za­chrá­nit co nej­více bajtů a starou ro­tu­jící rez ne­na­má­hat víc, než je nutné. Jsou na to extra pro­gramy jako ddrescue, ale kla­sické dd if=/dev/sdf of=disk.img fun­go­valo na vý­bor­nou.

Co dál? Zkusil jsem obraz disku při­po­jit, nic, nejde o va­lidní sou­bo­rový systém (FS). Vy­tvo­řil jsem dump celého disku ne jen NTFS oddílu a mount při­po­juje právě jen oddíly (V tom spo­čívá rozdíl mezi /dev/sdf/dev/sdf1). He­xe­di­to­rem jsem z GPT bloku vyčetl, že NTFS oddíl začíná na adrese 0x100000. Když jsem pak tuto hod­notu předal mountu, ten roz­po­znal NTFS, jen hlásil že je po­ško­zený a od­mí­tal ho při­po­jit. Ná­sle­do­vala další dů­kladná várka go­o­glení (tedy duc­kduc­kgo­o­vání), další pro­gramy, které by měly opra­vit FS do kon­zis­tent­ního stavu (testdisk), ale nic. Stále FS nelze při­po­jit. Dostal jsem se tedy do stavu, kdy se mi disku válelo 300GB dat, je­jichž formát byl dobře znám a zdo­ku­men­to­ván, ale byly po­ško­zené způ­so­bem, který je zne­mož­ňo­val jed­no­duše číst stan­dardní cestou. Co dál?

Nor­mální člověk by po­kr­čil rameny a pro­hlá­sil, že si neumí po­ra­dit, ale to není víc než po­ra­že­necké vý­mluvy. Nic pro mě. Já pre­fe­ruji stu­pidní řešení, když to povede k dobré his­torce (a zápisu na k47čce, což je více méně jedno a to samé). Proto nastal čas na plán B, dra­ma­tický a ra­di­kální, přeně v duchu vzá­jem­ného pohybu hory a mo­ha­meda.

Pro­tože jsem ne­na­šel žádnou uti­litu pro obnovu dat, jed­no­duše jsem si napsal vlastní. Ne­hle­dal jsem příliš dů­kladně a ani to nebylo úplně jed­no­du­ché2 , ale co, teď už je pozdě něco měnit. Vý­sled­kem je pro­gram, který projde obsah disku, de­kó­duje ho, zjistí, kde se ve změti bytů na­chá­zejí data sou­borů a zko­pí­ruje je ven do či­telné podoby. Bylo k tomu třeba hodně duc­kduc­kgo­o­vání, do­ku­men­tace da­to­vých struk­tur NTFS, hodně pokusů a ještě více omylů, ale na­ko­nec jsem uspěl.

NTFS je, pokud já i pů­vodní ma­ji­tel(ka) disku ig­no­ru­jeme všechny jeho po­kro­čilé funkce, celkem jed­no­du­chý. Všechny sou­bory jsou vy­jme­no­vané v ta­bulce MFT (master file table), každá po­ložka má 1kB a začíná ma­gic­kým strin­gem FILE0. Když zjis­tím, kde se MFT na­chází, stačí číst 1kB bloky a de­kó­do­vat je. Jejich obsah je tvo­řený hla­vič­kou a se­zna­mem atri­butů pro­měnné délky. Z hla­vičky MFT zá­znamu zjis­tím adresu, kde atri­buty za­čí­nají a pak v nich musím najít dva: Jméno (iden­ti­fi­ko­vané pre­fi­xem 0x30) a obsah sou­boru (prefix 0x80). Není to zas tak jed­no­du­ché – atri­buty mohou být re­zi­dentní (jsou pří­tomné v MFT zá­znamu, jen pokud se vejdou do 1kB pro­storu) a ne­re­zi­dentní (od­ka­zují na bloky disku, kde leží jejich obsah). Jméno musí být re­zi­dentní, ale obsah může mít obě podoby. Krátké sou­bory se tedy mohou celé na­chá­zet v MFT zá­znamu, dlouhé jsou pak od­ka­zo­vané přes tzv. clus­ter chain – kom­pri­mo­vaný seznam dvojic číslo clus­teru (FS je ad­re­so­vaný v clus­te­rech (4kB), ne v blo­cích (512B)) a počet za­bra­ných clus­terů. Je tedy nutné najít všechny tyto frag­menty a zko­pí­ro­vat je ve správ­ném pořadí.

Do hry ještě vstu­pují po­div­nosti Win­dows a vy­chy­távky NTFS. Soubor nemá jen jedno jméno, ale dvě—dlouhé jméno a krátké 8.3 (data jsou ulo­ženy jako litle-endian a texty jsou v LE UTF-16). Navíc sou­bory můžou mít ně­ko­lik stre­amů, kdy jedno jméno od­ka­zuje na ně­ko­lik sou­borů, z nichž jeden je ten hlavní a ostatní jsou skryté, ob­vykle ne­vi­di­telné. Tato funk­ci­o­na­lita se po­u­žívá jen okra­jově (sou­bory sta­žené z in­ter­netu jsou tímto způ­so­bem ozna­čené a win­dows varují při jejich spuš­tění), ale je třeba z nimi po­čí­tat při zá­chraně dat.3

Při obnově jsem zjis­til, že se z ne­zná­mého důvodu určité sou­bory vy­sky­to­valy v MFT ně­ko­li­krát. Možná že šlo o pře­su­nuté (nebo zko­pí­ro­vané a pak smaz­néú sou­bory), kdy pů­vodní záznam zůstal a přibyl nový. Možná, ne­zjiš­ťo­val jsem to. Data jsem vy­ko­pí­ro­val ven, pak je de­du­pli­ko­val a vy­há­zel sou­bory plné nul. Někdy jen díky těmto zá­had­ným du­pli­ká­tům soubor přežil apo­ka­ly­psu. Už tak jsem na akci obnovy strá­vil víc času, než by bylo ro­zumné a ne­chtěl jsem stu­do­vat každý detail a za­pekli­tost sou­bo­ro­vého sys­tému z roku 1993 (který se micro­soft víc než jednou snažil na­hra­dit něčím no­věj­ším).

Ale i tak jsem se toho do­zvě­děl víc, než jsem kdy doufal, že se dozvím a jedno je jisté – sou­bo­rové sys­témy jsou velice za­jí­mavé. Jde o kri­tic­kou kom­po­nentu. Když se něco pokazí v ovla­dači gra­fiky, re­star­tu­jte po­čí­tač a všechno je za­po­me­nuto, ale FS musí fun­go­vat, pro­tože jinak dojde ke ztrátě dat. A co víc, musí fun­go­vat za všech okol­ností, když vy­padne elektřina, ha­va­ruje systém, dojde ke spon­tán­nímu pře­ho­zení bitu nebo k chybám v umí­ra­jí­cím hard­ware. Do toho musíte za­po­čí­tat zpět­nou i do­před­nou kom­pa­ti­bi­litu a s tím sou­vi­se­jící roz­ši­ři­tel­nost a další po­ža­davky na mo­derní FS jako jsou kon­t­rolní součty, za­bu­do­vaný RAID, sna­pshoty, kom­prese, šif­ro­vání, de­du­pli­kace a nároky na vy­so­kou efek­ti­vitu na mnoha ka­te­go­ri­ích disků a máte před sebou ky­klop­ský pro­jekt. Ne na­darmo se říká, že k vývoji FS je třeba 100 člo­vě­ko­let, než do­sáhne po­u­ži­tel­ného stavu.

Abych to zkrá­til: Ope­race pro­běhla úspěšně. Po ně­ko­lika dnech hac­ko­vání se mi po­da­řilo ob­no­vit víc jak 50% disku, zbytek byl ne­či­telný a/nebo plný nul. Hlavní však byla cesta, která za tím vý­sled­kem vedla a všechno to, co jsem se naučil.

Navíc jsem získal jednu za­dlu­že­nou duši. Můžu se u ní ukázat ve tři ráno a po­ža­do­vat spo­lu­práci při li­kvi­daci mrt­voly. Dávám tomu tak 30%, že toho v příš­tím roce vy­u­žiji.


  1. Po in­ci­dentu jsem se začal za­jí­mat, jak jsou or­ga­ni­zo­vané další sou­bo­rové sys­témy a po­dí­val se na vnitř­nosti ext4. Ten také není příliš kom­pli­ko­vaný a bylo by snadné napsat uti­litu, která z něj vytahá data. Ale pro­tože jde o li­nu­xo­vou stá­lici a jeden z prv­ních sou­bo­ro­vých sys­témů na této plat­formě (jako ext v roce 1992), do­vo­lil bych si ti­po­vat, že tyto již exis­tují, jsou efek­tivní a při­pra­veny k po­u­žití v re­po­zi­tá­řích. Z do­ku­men­tace jde také jasně vidět, jak se byl v prů­běhu let po­stupně vy­lep­šo­ván a funkce se vršily jedna na druhou při za­cho­vání zpětné kom­pa­ti­bi­lity for­mátu dat. Na­pří­klad kon­t­rolní součty jsou po­divně roz­dě­lené. Na za­čátku inode se na­chází prv­ních 16 bitů a někdy poz­ději dal­ších 16 bitů, tato ne­spo­ji­tost je oči­vidně dů­sle­dek his­to­ric­kého vývoje.
  2. Kdyby Java umož­ňo­vala mmap sou­boru vět­šího než 2GB, bylo by to o něco jed­no­dušší.
  3. Ne­dávno jsem se do­zvě­děl, že je to běžné i v uni­xo­vém světě jako roz­ší­řené atri­buty.
píše k47 & hosté, ascii@k47.cz