Как восстановить данные с флешки при помощи инструментов Linux.

Как восстановить данные с флешки при помощи инструментов Linux.

Сбой с данными всегда проблема. Но если это критически важные данные которые находятся как всегда на флешке, это вдвое большая проблема. Сегодня мы рассмотрим не типичный случай восстановления данных с такого носителя. Как восстановить данные с флешки при помощи инструментов Linux таких как TestDisk, PhotoRec мы рассмотрим в данной статье.

Как восстановить данные с флешки при помощи инструментов Linux.

Недавно ко мне пришел товарищ с фразой: «У меня флешка сломалась, можешь посмотреть? В принципе, если не получится, то и ладно, но там есть несколько файлов, копий которых нет».

Я, конечно, флешку взял и обещал посмотреть, что можно сделать. Грех не помочь другу! Входные данные были такие: «винда перестала видеть флешку». Других внятных объяснений произошедшего я не добился.

 

И вот, когда выдалось немного свободного времени, настала пора попробовать восстановить какие-то данные с флешки.

В этой статье рассматривается восстановление флешек в среде Linux. В Windows тоже можно восстанавливать данные: есть разные утилиты и проприетарные продукты (например, R-Studio), но это тема для отдельных статей.

Первым делом, подключив флешку к ноуту с Linux, я убедился, что аппаратная часть девайса жива, а повреждены именно данные на ней.

Второе, что я сделал, — снял образ.

 

Техника безопасности: снимаем образ

Самая важная часть в восстановлении данных — не угробить своими действиями еще больше данных. Все описываемые в статье действия производились исключительно с образом флешки. Снять образ можно следующими командами (тебе, конечно, надо указать путь к своему устройству):

$ dd if=/dev/sdc of=flash.img bs=512

Как вариант, можно использовать команду ddrescue:

$ ddrescue /dev/sdc flash.img /tmp/flash.log

Лично я предпочитаю второй способ, поскольку ddrescue пытается считать данные в несколько проходов, а также (если ты дал команду писать лог) прервать чтение и продолжить с места остановки. Плюс к этому утилита дает красивый отчет о том, сколько данных считалось, а сколько нет, и оценку времени до конца съема образа.

Кроме того, имеет смысл работать с копией образа. Вдруг ты его испортишь, и не факт, что получится еще раз снять образ с флешки, если она умирает из-за аппаратных проблем. Для частичных копий образа и восстановления испорченных частей к начальному состоянию рекомендую пользоваться тем же всемогущим dd.

$ ddrescue flash.img backup_part.img bs=10M count=1
$ ddrescue backup_part.img flash.img conv=notrunc

Параметр notrunc нужен для того, чтобы dd не обрезала файл-назначение, когда закончатся данные в файле-источнике.

Сняв образ флешки, я взглянул на содержимое. Увиденное несколько меня удивило.

$ hexdump -C flash.img|less

00000000 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |…………….| * 00400000 01 76 0a 00 02 76 0a 00 03 76 0a 00 04 76 0a 00 |.v…v…v…v..| 00400010 05 76 0a 00 06 76 0a 00 07 76 0a 00 08 76 0a 00 |.v…v…v…v..| 00400020 09 76 0a 00 0a 76 0a 00 0b 76 0a 00 0c 76 0a 00 |.v…v…v…v..| 00400030 0d 76 0a 00 0e 76 0a 00 0f 76 0a 00 10 76 0a 00 |.v…v…v…v..| 00400040 11 76 0a 00 12 76 0a 00 13 76 0a 00 14 76 0a 00 |.v…v…v…v..| …

В образе первые 4 Мбайт данных были забиты 0xFF. Поврежден блок флеш-памяти? Чья-то попытка стереть данные? Сбой какого-то приложения? Почему затерта область — неважно. Главное, что у нас нет ни таблицы разделов, ни структуры файловой системы… Хотя если приглядеться, то видна закономерность. Перед нами последовательность увеличивающихся на единицу 32-битных чисел (в формате LittleEndian): 0x000a7601, 0x000a7602, 0x000a7603… Следовательно, у нас на флешке, скорее всего, была файловая система FAT32.

Что ж, попробуем восстановить данные. Для начала возьмем утилиту TestDisk.

 

TestDisk

TestDisk — не просто утилита, а мощный комбайн по восстановлению данных.

 

О TestDisk

TestDisk разработан Кристофом Гренье и распространяется по лицензии GPL v2. Эта утилита предназначена в первую очередь для восстановления потерянных разделов на носителях информации, а также для восстановления загрузочного сектора.

TestDisk может:

  • исправлять таблицу разделов, восстанавливать удаленные разделы;
  • восстанавливать загрузочный сектор FAT32 из резервной копии;
  • перестраивать (реконструировать) загрузочный сектор FAT12/FAT16/FAT32;
  • исправлять таблицу FAT;
  • перестраивать (реконструировать) загрузочный сектор NTFS;
  • восстанавливать загрузочный сектор NTFS из резервной копии;
  • восстанавливать MFT;
  • определять резервный SuperBlock ext2/ext3/ext4;
  • восстанавливать удаленные файлы на файловых системах FAT, NTFS и ext2;
  • копировать файлы с удаленных разделов FAT, NTFS и ext2/ext3/ext4.

Запускаем TestDisk такой командой:

$ testdisk flash.img

Видим меню.

Стартовый экран TestDisk
Стартовый экран TestDisk

Выбираем пункты меню Procced → Intel → Analyse и получим следующее.

Выбор типа разметки
Выбор типа разметки
Выбор типа разметки
Выбор опций
Таблица разделов
Таблица разделов
Еще одна таблица разделов
Еще одна таблица разделов

Видим, что TestDisk не нашел таблицы разделов. Ожидаемо, ведь она затерта. Попробуем ее восстановить с использованием «быстрого поиска» разделов на диске. Выбираем пункт Quick Search.

Все еще без таблицы разделов
Все еще без таблицы разделов

TestDisk ничего не нашел, но и это ожидаемо, ведь раздел FAT32 тоже поврежден. TestDisk теперь предлагает нам прописать разделы вручную, но мы не знаем, что где лежало. Поэтому пока отложим эту утилиту в сторону. Для выхода достаточно несколько раз нажать кнопку q.

Что ж, возьмем тогда на вооружение другое изобретение того же автора — PhotoRec.

 

PhotoRec

PhotoRec — это программа для восстановления утерянных (удаленных) файлов. Изначально она разрабатывалась для восстановления изображений из памяти цифровых камер, отсюда и название — PHOTO RECovery. Со временем она обросла функциями восстановления и других типов данных, но название осталось.

 

О PhotoRec

PhotoRec ищет известные заголовки файлов. Если нет фрагментации, которая часто бывает, он может восстановить весь файл. PhotoRec распознает многочисленные форматы файлов, включая ZIP, Office, PDF, HTML, JPEG и другие форматы графических файлов. Полный список форматов, поддерживаемых PhotoRec содержит более 390 расширений (около 225 семейств форматов).

Если данные не фрагментированы, восстановленный файл должен быть идентичного размера или больше, чем исходный файл. В некоторых случаях PhotoRec может узнать оригинальный размер файла из заголовка, так что восстановленный файл усекается до необходимого размера. Однако, если восстановленный файл заканчивается раньше, чем указывает его заголовок, он отбрасывается. Некоторые файлы, такие как MP3, представляют собой поток данных. В этом случае PhotoRec анализирует полученные данные, а затем останавливает восстановление, когда поток завершается.

Натравим эту утилитку на наш образ флешки и посмотрим, что получится.

$ photorec flash.img
Стартовый экран PhotoRec
Стартовый экран PhotoRec

Видим уже знакомый интерфейс, выбираем Proceed → Search → Other, указываем папку, куда сохранять (лучше ее создать заранее), жмем кнопку c. И ждем.

Выбор раздела
Выбор раздела
Выбор типа файловой структуры
Выбор типа файловой структуры
Выбор папки назначения
Выбор папки назначения
Процесс восстановления
Процесс восстановления

В итоге получаем несколько папок с тысячами файлов в них.

Куча сохраненных файлов
Куча сохраненных файлов

Беглый осмотр показал, что какие-то файлы восстановились: и документы, и картинки, и исходники. Но нет ни имен файлов, ни даты их создания, ни структуры папок. Кроме того, как оказалось, на флешке была какая-то документация в виде страничек HTML с кучей мелких картинок. В связи с чем поиск ценных файлов занял бы не один час…

Да и, как указано на врезке, фрагментированные файлы или не восстановились, или повреждены (обрезаны).

Видимо, придется напрячь все свои силы и руками восстановить структуру FAT32.

 

Чиним FAT32

Для восстановления структуры FAT32 надо внимательно почитать документацию, вычислить значения ключевых параметров, а затем внести их в загрузочную запись FAT32. Кратко суть структуры FAT32 изображена на рисунке.

Сюда входит загрузочный сектор, структура FSInfo, две копии таблиц FAT и область данных. Загрузочный сектор (он же BPB — Boot Parameter Block) содержит основные данные, которые описывают характеристики раздела, и код загрузчика.

В таблице FAT хранятся записи номеров следующих кластеров цепочки файла/директории, признак последнего кластера в цепочке (значение 0xFFFFFFFF) или признак свободного кластера (значение 0). Область данных начинается с корневой директории, содержимое дальнейшей области зависит от данных в записях корневой директории и соответствующих цепочках таблицы FAT. Более подробное описание файловой системы смотри по ссылкам, приведенным во врезке.

Для удобной работы с образом нам потребуется Hex-редактор. Лично мне очень нравится редактор 010 Editor. Он позволяет задавать шаблоны структуры на C-подобном языке и подсвечивать поля структуры в редакторе.

Откроем в нем наш образ флешки.

 

Ищем смещения

Начнем с того, что нам надо вычислить адреса, с которых начинаются раздел FAT32 и первая копия таблицы FAT.

Сначала поймем, повреждена у нас первая копия FAT или обе. Из документации мы знаем, что таблица FAT начинается с последовательности F8 FF FF FF (число 0xFFFFFFF8 в Little Endian). Поищем ее.

Поиск сигнатуры
Поиск сигнатуры

Нам повезло — такая сигнатура нашлась. Значит, повреждена только первая копия таблицы FAT и мы можем скопировать данные второй таблицы в первую. Конечно, стоит помнить, что если флешка была отключена внезапно, то вторая копия может не полностью совпадать с первой (в нее просто не успели сохраниться изменения). Но все же мы сможем восстановить больше данных, чем при помощи только PhotoRec. Как минимум получим дополнительно имена файлов, даты их создания, корректные цепочки для фрагментированных файлов и даже структуру директорий.

Смотрим адрес — 0x8AE400. Это адрес начала второй копии таблицы. Теперь надо вычислить длину самой таблицы. Можно, конечно, руками полистать дамп, пока не заметим данные корневой директории. Но есть вариант попроще. Поскольку это две копии, то и запись, с которой начинается кусок первой копии таблицы, должна быть и во второй копии. А разница между ними и будет размером!

Поищем последовательность 01 76 0A 00, которую мы видели вначале, когда воспользовались hexdump. Быстро начинают находиться варианты. Остановим поиск нажатием ESC — нас интересуют первые два вхождения.

Первое вхождение последовательности
Первое вхождение последовательности

Первое вхождение (адрес 0x400000) — первая уцелевшая запись в первой копии FAT. Перед ней затертое пространство.

Второе вхождение последовательности
Второе вхождение последовательности

Второе вхождение (по адресу 0xB4BC00) — эта же запись во второй копии FAT. Перед ней мы видим сохранившиеся данные цепочек.

Вычислим размер таблицы FAT: 0xB4BC00 – 0x400000 = 0x74BC00 байт. Следовательно, если вычтем этот размер из адреса начала второй копии таблицы, то получим адрес начала первой копии: 0x8AE400 – 0x74BC00 = 0x162800.

Итак, у нас есть смещение начала таблиц FAT. Теперь надо найти адрес начала раздела. Согласно данным в спецификациях и статьях, приведенных во врезке, обычно первая копия таблицы начинается с 32-го сектора. Сектора, напомню, по 512 байт, значит, начало раздела должно находиться по адресу 0x162800 – 32 * 512 = 0x15E800.

Кстати, зная размеры таблиц и смещения их начала, можем найти адрес начала корневой директории.

Смещение корневой директории равно 0x15E800 + 32 * 512 + 2 * 0x74BC00 = 0xFFA000. И начинается она записью Transcend, что, очевидно, является меткой раздела.

Отлично. Смещения таблиц, корневой директории и адрес начала раздела знаем, осталось придумать, что записать в загрузочную запись. Можно сидеть и читать спецификации, высчитывая каждое значение. А я предлагаю сделать ход конем! Создаем пустой файл размером с раздел. Далее мы его форматируем в FAT32. Затем копируем первые 32 сектора в наш образ — и готово! 🙂

Попробуем воплотить этот план в жизнь.

 

Создаем загрузочную запись

Для начала определим размер раздела.

$ ls -la flash.img -rw-r—r— 1 user users 15676211200 сен 5 13:36 flash.img

Размер раздела равен равен размеру флешки минус смещение раздела. Получается 15 676 211 200 – 0x15E800 = 15 674 775 552 байта.

Чтобы не занимать кучу места на диске нашим пустым образом, воспользуемся фишкой файловой системы ext2 — разреженными файлами.

$ dd if=/dev/zero of=test.img bs=1 seek=15674775552 count=0
$ mkfs.vfat -f 2 -F32 -n TEST test.img

Откроем файл в 010 Editor. И воспользуемся шаблоном Drive (возможно, его потребуется установить, см. меню Templates Repository). Если появится окошко с предупреждением о долгой работе, соглашаемся на продолжение работы скрипта.

Смотрим сгенерированный образ
Смотрим сгенерированный образ
Разбор полей образа
Разбор полей образа
Разбор полей BPB
Разбор полей BPB

Прекрасно! Теперь у нас есть заполненные структуры загрузочного сектора. Надо бы их перенести в наш образ.

Выделяем мышкой структуру FAT_BOOTSECTOR в окне Templates Results, автоматически выделится диапазон данных, скопируем их в буфер (щелкнуть правой кнопкой мыши в окне данных и выбрать пункт Copy).

 

Собираем чудовище Франкенштейна

Для сборки образа вставим сгенерированный загрузочный сектор и скопируем вторую копию FAT поверх первой.

Начнем с вставки загрузочного сектора. Он у нас уже в ОЗУ. Перейдем на вычисленный адрес 0x15E800 и вставим данные из буфера.

Вставленные данные
Вставленные данные

Выясняется, что после сектора идут байты 0xFF, а в сгенерированном образе после этого сектора есть еще данные.

Сгенерированный образ
Сгенерированный образ

Непорядок. После первого сектора ведь идет структура FSInfo! Да и по смещению 0xC00 находится копия загрузочного сектора (на случай его повреждения). Нет, лучше скопируем все 32 сектора (0x4000 байт). Кстати, заодно убедились, что в образе, сгенерированном mkfs, по смещению 0x4000 будет последовательность F8 FF FF FF. После вставки в наш образ мы оказались по адресу 0x162800, который ранее и рассчитали. Пока все совпадает.

Теперь нам надо скопировать вторую копию FAT поверх первой. Выделяем участок длиной 0x74BC00 с адреса 0x8AE400, копируем его и вставляем по адресу 0x162800. Для выделения участка удобно воспользоваться фичей Select Range (Ctrl + Shift + A) — просто введем в поля адрес и размер.

Корневая директория
Корневая директория

После вставки оказались в начале корневой директории. Пока все сходится.

Теперь нам бы смонтировать этот раздел и посмотреть, что удастся с него считать.

 

Читаем данные

Для монтирования файловой системы выполним следующие команды.

$ mkdir mnt $ sudo mount -oro,offset=1435648 flash.img mnt/ $ ls mnt/ ls: невозможно получить доступ к ‘mnt/28-02-~1’: Ошибка ввода/вывода ls: невозможно получить доступ к ‘mnt/map_n’: Ошибка ввода/вывода 10_10_2016 2019.07.13 28-02-~1 BOOTEX.LOG ……

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

$ ls -la mnt/ … d????????? ? ? ? ? ? map_n …

Очень странно. Да и просмотр содержимого директорий дает понять, что где-то закралась ошибка.

$ ls mnt/some_dir/ ls: невозможно получить доступ к ‘mnt/some_dir/%PDF-1.4.’$’\n»%╨’: Ошибка ввода/вывода ls: чтение каталога ‘mnt/some_dir/’: Ошибка ввода/вывода

Имя файла совпадает с заголовком PDF. Похоже, кластер, на который указывает запись для этой директории, содержит PDF.

Волшебства не произошло, придется разбираться, в чем косяк. Но перед этим немного упростим себе жизнь и создадим таблицу разделов. Забегая вперед, скажу, что шаблон Drive в редакторе 010 Editor вроде бы шибко умный, но начать разбор с определенного смещения не может, только с начала файла.

Для создания таблицы разделов воспользуемся утилитой fdisk. Создадим один раздел, начинающийся с сектора номер 2804. Смещение нестандартное (по умолчанию — 2048), возможно, что на флешке было два раздела, первый был маленький и погиб целиком. Но это уже неважно. Сам сектор вычисляется легко — просто делим начало смещения раздела на размер сектора (0x15E800/512 = 2804).

Вывод fdisk
Вывод fdisk

Обращаю внимание, что fdisk определил наличие по этому смещению раздела с FAT32 (vfat) и спросил, не удалить ли. Кроме того, не забываем поменять тип раздела на W95 FAT32 (LBA) (код 0c).

 

Работа над ошибками

Поиск ошибки занял у меня где-то час, в течение которого я активно курил спецификации и сверял значения в структурах, разобранных шаблоном Drive в 010 Editor. Вкратце опишу свои поиски.

Скриншот полей BPB
Скриншот полей BPB

Сначала я заметил, что корневая директория расположена по адресу 0xFFA800, а не по адресу 0xFFA000.

Я подумал, что неверно определен размер кластера. Утилита mkfs создала кластеры по 16 секторов, а секторы по 512 байт (см. на скриншоте поля BytesPerSector и SectorsPerCluster). Сначала я попробовал поиграть значениями этих параметров, каждый раз перемонтируя образ.

 

Loop

Поскольку в образе есть таблица разделов, можно не запускать каждый раз mount со всеми параметрами (-oro,offset=1435648 flash.img mnt/). Вместо этого можно подключить loop-устройство и попросить ядро считать таблицу разделов с него.

$ sudo losetup -f flash.img
$ sudo partprobe /dev/loop0

Или можно еще проще (читай man losetup):

$ sudo losetup -f -P flash.img

Далее можем монтировать и перемонтировать раздел сколько угодно.

$ sudo mount -oro /dev/loop0p1 mnt/
$ sudo umount mnt/

После каждой правки не надо заново подключать loop-устройство, смещение раздела в образе у нас не меняется.

Ничего путного из этого не вышло. Становилось только хуже.

Через некоторое время я понял, что и вторая копия таблицы начинается не там, где надо.

И тут я обратил внимание на поле SectorsPerFat32 (на скриншоте). Это поле описывает размер таблицы FAT в секторах. Его значение равно 0x3A60, а должно оно быть 0x74BC00/512 = 0x3A5E. Разница в два сектора на каждую копию таблицы FAT как раз дает нам 2 * 2 * 0x200 = 0x800 байт разницы между правильным смещением корневой директории и имеющимся у нас ошибочным.

Правим его (прямо в окне структуры, что очень удобно), сохраняем изменения и проверяем.

$ sudo mount -oro /dev/loop0p1 mnt/
$ ls mnt/

Отлично! Ошибки пропали! Все файлы и папки читаются. Структура похожа на корректную.

Натравив на образ fsck, все равно видим ворох ошибок. Однако первое, что бросается в глаза, — это несоответствие загрузочных записей.

$ sudo fsck.vfat -n /dev/loop0p1 fsck.fat 4.1 (2017-01-24) There are differences between boot sector and its backup. This is mostly harmless. Differences: (offset:original/backup) 36:5e/60 Not automatically fixing this. FATs differ but appear to be intact. Using first FAT. ….

Обращаю внимание, параметр -n у fsck говорит, что правки вносить не надо.

Что ж, исправим и вторую копию. К сожалению, шаблон 010 Editor не разбирает вторую копию загрузочного сектора, поэтому сами найдем нужный байт и поправим его. Его легко найти — смещение 0x24 от начала сектора, в нашем случае 0x15F424, меняем 0x60 на 0x5E.

Запускаем еще раз fsck.

Странно, но fsck выдает ошибки и говорит, что копии таблиц FAT не совпадают (хотя мы же их копировали), и жалуется на длины файлов. Возможно, повлияли предыдущие монтирования или что-то еще.

Я восстановил из бэкапа (ты же прочел врезку о технике безопасности?) оригинальный образ флешки и заново прошел этапы копирования таблиц, загрузочного сектора (с правкой поля SectorsPerFat32) и его копии. Повторный запуск fsck меня порадовал.

$ sudo fsck.vfat -n /dev/loop0p1 fsck.fat 4.1 (2017-01-24) Free cluster summary wrong (1911553 vs. really 899251) Auto-correcting. Leaving filesystem unchanged. /dev/loop0p1: 32183 files, 1012304/1911555 clusters

Что, в принципе, логично, так как значения в полях структуры FSInfo мы не пересчитывали. Можно, кстати, запустить fsck без параметра -n, чтобы исправить эти мелкие косячки. После чего взять новую флешку на 16 Гбайт, залить на нее исправленный образ и вернуть ее товарищу. Пусть удивится, а ты в его глазах вырастешь из просто «тыжпрограммиста» в гуру. 🙂

 

Выводы

В заключение, думаю, стоит отметить, что если с ходу утилиты TestDisk и PhotoRec не дают хороших результатов, то не стоит отчаиваться и надо попробовать восстановить данные с флешки с использованием головы и прямых рук. В итоге всей работы, которая суммарно заняла около двух часов, мы восстановили фактически все данные с «умершей» флешки, включая структуру директорий и всю метаинформацию.

Кроме того, крайне рекомендую делать бэкапы как можно чаще. Как образов, с которыми работаешь при восстановлении, так и важных данных на своих собственных флешках, чтобы не приходилось их восстанавливать. Ведь, как известно, люди делятся на две категории: на тех, кто еще не делает бэкапы, и на тех, кто уже их делает.

Click to rate this post!
[Total: 0 Average: 0]

Специалист в области кибер-безопасности. Работал в ведущих компаниях занимающихся защитой и аналитикой компьютерных угроз. Цель данного блога - простым языком рассказать о сложных моментах защиты IT инфраструктур и сетей.

Leave a reply:

Your email address will not be published.