Файловая система NTFS, используемая в операционных системах Windows, сохраняет информацию об удаленных файлах до тех пор, пока блоки диска, на которых они находились, не будут перезаписаны новыми данными. Это позволяет восстанавливать случайно удаленные файлы при помощи различных утилит. В статье рассмотрим способы восстановления удаленных файлов в NTFS при помощи PowerShell.
Еще по теме: Восстановление NTFS используя Scrounge-NTFS Linux
Как восстановить файлы в NTFS с помощью PowerShell
Можно выделить 2 способа удаления файлов в ОС Windows:
- удаление с помощью системных инструментов del (Shift Del) или erase;
- удаление через корзину.
Способы отличаются механизмом удаления и рядом отличий во время восстановлении удаленных файлов.
Никогда не восстанавливайте удаленные файлы на тот же том, с которого они были ранее удалены. Для этого лучше использовать другой носитель.
В начале рассмотрим восстановление нерезидентных файлов, а потом поговорим про восстановление резидентных.
Восстановление удаленных файлов с использованием del или erase
Для восстановления удаленных файлов будем использовать модуль PowerShell инструмента PowerForensics. Данный модуль предлагает командлеты для NTFS и FAT. Умеет работать с системными файлами Windows. Может парсить атрибуты файлов NTFS и конвертировать метки времени представляя их в человекочитаемом виде (что необходимо в компьютерной криминалистике). Подробную информацию можно узнать из описания.
Начнем с установки модуля (PowerShell необходимо запустить от имени администратора):
1 |
Import-Module PowerForensics |
Проверим установку выполнив командлет:
1 |
Get-Command - Module PowerForensics |
Установка модуля PowerShell завершена, теперь попробуем найти все удаленные файлы. В главной файловой таблице они имеют флаг удаления 00h по смещению 16 байт от начала файловой записи.
Для создания тома F запускаем diskmgmt.msc, а после сжимаем имеющийся том и выделяем под него нового 5 Гб с размером кластера по умолчанию 4096 Кбайт). Положим туда файл, например calc.exe и попробуем удалить его через erase (что равносильно удалению через del или Shift-Del).
Теперь чтобы найти удаленный файла на томе F выполним командлет Get-ForensicsFileRecord и отфильтруем выдачу по флагу True для атрибута Deleted:
1 |
Get-ForensicFileRecord -VolumeName F: | Where-Object {$_.Deleted} |
Здесь мы видим основные файловые атрибуты и их значения, однако для восстановления нам потребуется значение файловой записи RecordNumber. После того как файл будет найден, для дальнейших действий лучше пользоваться номером файловой записи, так как имя файла может изменяться в процессе удаления (далее мы разберем этот случай).
Имея номер файловой записи, мы сможем отыскать недостающие элементы, если файл нерезидентный, и собрать его воедино по кусочкам, после чего записать содержимое в новый файл.
Для этого запишем в переменную $file_record объект файла со свойствами (атрибутами файла):
1 |
$file_record = Get-ForensicFileRecord -VolumeName F: -Index 43 |
Теперь можно обратиться к отдельному атрибуту и узнать интересующую нас информацию. Для восстановления нужно определить номер начального кластера и общее количество занимаемых файлом кластеров. Для этого в переменную $file_descriptor запишем содержимое атрибута $DATA:
1 |
$file_descriptor=$file_record.Attribute | Where-Object {$_.name -eq 'DATA'}` |
После чего можно получить значения начального кластера и количества кластеров, которые занимает наш файл. В переменную $start_cluster сохраним эти данные:
1 |
$start_cluster = $file_descriptor.DataRun | select * |
На рисунке справа видим содержимое этой переменной в консоли PowerShell, а слева — атрибут $Data с его полями для нашего удаленного файла.
Теперь дело за малым: нужно записать содержимое по «адресу» выше (номер начального кластера и количество кластеров) в восстановленный файл на томе.
Будем записывать на том С:, чтобы не затереть удаленные данные на томе F:. Можно выполнить запись при помощи командлета Invoke-ForensicDD из модуля PowerForensics или использовать WriteAllBytes из библиотеки System.IO.File:
1 |
Invoke-ForensicDD -InFile \\.\F: -Offset ($st_cl.StartCluster*4096) -BlockSize ($st_cl.ClusterLength*4096) -Count 1 -OutFile C:\calc.exe |
Здесь мы указываем в параметре InFile том и расположение файла, который будет скопирован (в нашем случае это том F и расположение удаленного файла).
В качестве смещения на диске указываем адрес начального кластера, умноженный на 4096, и количество кластеров, также умноженных на 4096, ведь размер кластера на нашем томе равен 4096 Кбайт.
После чего указываем количество файлов на диске и путь с именем файла, куда будет восстановлен наш файл.
В результате мы получаем наш рабочий калькулятор в корне тома C:\calc.exe.
Вот только есть одно но: несмотря на то что калькулятор запускается и работает без нареканий, хеш‑суммы оригинального файла (до удаления) и файла после восстановления не бьются…
Причина тому — разница в размере файла после восстановления. Размер файла до удаления равен 27 648 байт, а после восстановления — 28 672 (что при делении на 4096 дает нам 7 — те самые семь кластеров в сумме). То есть при восстановлении мы заботливо дозаписали нулями 1024 байт, это нужно и важно учитывать при получении оригинального файла.
Значения реального размера файла (RealSize=27 648) и выделенного под хранение файла пространства (AllocationSize=28 672) хранятся в атрибуте $DATA. Вся информация у нас на руках, давайте наведем красоту. Для этого, прежде чем сохранить содержимое кластеров в файл, запишем массив байтов в переменную $bytearray:
1 |
$bytearray = Invoke-ForensicDD -InFile \\.\F: -Offset ($st_cl.StartCluster*4096) -BlockSize ($st_cl.ClusterLength*4096) -Count 1 |
После чего, используя функцию WriteAllBytes системной библиотеки System.IO.File, запишем содержимое в файл, указав верхнюю границу массива для записи [0..($bytearray.Length - (1024 + 1))]:
1 |
[System.IO.File]::WriteAllBytes("C:\calc.exe",$bytearray[0..($bytearray.Length - (1024 + 1))]) |
Теперь посчитаем хеш‑суммы и сравним полученные значения.
Как и ожидалось, хеш‑суммы бьются, значит, после восстановления содержимое файла изменено не было. Если с восстановлением удаленных с использованием del (Shift-Del) или erase файлов все понятно, то что происходит в системе, когда вы перемещаете файл в корзину?
Восстановление удаленных файлов через корзину
Сразу следует отметить, что перемещение файла в корзину не равно удалению: файл удаляется после очистки корзины (хоть это и очевидно, тем не менее упомянуть об этом стоит).
После перемещения файла в корзину в директории C:\$Recycle.Bin\<User’s SID>\ создается два файла c именами, которые начинаются с $I и $R и заканчиваются оригинальным расширением перемещенного в корзину файла. Даже с отображением скрытых файлов в директории нам не удастся посмотреть на созданные после перемещения в корзину файлы.
Чтобы до них добраться, содержимое директории C:\$Recycle.Bin\<User’s SID>\ нужно переместить в специально созданную для исследования директорию (можно воспользоваться PowerShell-командлетом Copy-Item). После перемещения нам станут доступны следующие файлы:
1 |
$I<random>.original_extension |
(далее — $I) — файл с метаданными, создается, как только файл перемещается в корзину. Он используется для восстановления файла из корзины средствами Microsoft, подробнее разбор файла будет приведен ниже.
1 |
$R<random>.original_extension |
(далее — $R) — файл, который создается после перемещения в корзину. Это копия перемещенного в корзину файла, о чем говорят одинаковое содержимое и хеш‑суммы (если сравнить оригинал до удаления и перемещенный файл). Изменяется только имя файла.
Разбор содержимого популярных файлов и файловых записей, а также структур таблиц MFT, MBR, GPT и файловых атрибутов встречается в публикациях на GitHub. Однако мне не удалось найти описание файла $I с метаданными, поэтому давайте вместе разберемся, что полезного можно обнаружить в таком файле.
В роли подопытного будет по‑прежнему выступать файл calc.exe. Переместим его копию в корзину, после чего скопируем все содержимое из директории C:\$Recycle.Bin\<User’s SID>\* в папку для исследования.
Ниже представлен разбор всех полей файла $IOWX1VN.exe (был создан при перемещении калькулятора в корзину).
Здесь:
- желтый цвет — File Header, заголовок файла $I;
- синий цвет — File Size (Bytes) — размер файла;
- красный цвет — атрибут $SI ChangedTime — время удаления, точнее, перемещения файла в корзину в формате UTC;
- бирюзовый цвет — FileName Length — размер имени файла в байтах;
- пурпурный цвет — File Path — полный путь до файла, который был удален (перемещен в корзину).
У каждого пользователя своя $Recycle.Bin (корзина). Более того, на каждом томе такая корзина создается по умолчанию. Грубо говоря, корзина из тома С пробрасывается в том F и другие созданные тома.
Поэтому перед именем удаленного файла мы видим SID пользователя — зачастую это полезная информация о том, какой пользователь в системе переместил файл в корзину и выполнил удаление. Например, для файла calc.exe полное имя файла будет выглядеть так:
1 |
F:\$RECYCLE.BIN\S-1-5-21-3457051395-4168275294-665325124-1000\$ROWX1VN.exe |
или
1 |
F:\$RECYCLE.BIN\S-1-5-21-3457051395-4168275294-665325124-1000\$IOWX1VN.exe |
Кроме информации о том, кто удалил файл, мы получаем информацию о метках времени и о моменте, когда файл был перемещен в корзину. Также нам становится известен путь, по которому хранился файл до перемещения.
Теперь давайте поговорим о восстановлении файла, который был удален через корзину. По алгоритму оно похоже на восстановление файлов, удаленных с помощью del или erase, поскольку для файловой системы нет разницы между файлами, удаленными из корзины или какой‑либо другой директории. По сути, система удаляет файлы так же, как при применении утилит del или erase, только предварительно переименовав файлы в
1 2 |
$R<random>.extension $I<random>.extension |
Вероятно, у вас возник вполне логичный вопрос: какой из двух файлов восстанавливать — $I или $R? Ведь при очистке корзины удалятся оба эти файла и их записи какое‑то время будут храниться в $mft (до перезаписи другими данными).
Для восстановления удаленного файла нам нужны оба: и $R, и $I. Файл $R требуется для восстановления содержимого, а файл $I — для получения оригинального имени файла.
Единственный недостающий элемент при восстановлении — оригинальное имя, которое можно отыскать только в файле $I. Но файл $I резидентный, а это значит, что пришло время разобраться, как восстанавливать резидентные файлы.
Для начала мы также найдем ID файловой записи для файла $I:
1 2 |
Get-ForensicFileRecord -VolumeName F:| where {$_.Deleted} $file_record = Get-ForensicFileRecord -VolumeName F: -Index 44 |
После чего обратимся к атрибуту $DATA по указанному ID и запишем содержимое атрибута в массив байтов:
1 2 |
$file_descriptor=$file_record.Attribute | Where-Object {$_.name -eq 'DATA'} $Byte_Array = $file_descriptor.RawData |
В $Byte_Array хранится содержимое резидентного файла.
Структуру файла $I мы уже разобрали и помним, что байты с 0 до 26 отводятся на файловый заголовок, размер файла в байтах, атрибут $SI Changed Time и размер файлового имени. А начиная с индекса 27 до конца файла хранится полное имя файла (путь + имя). Зная эту информацию, мы можем получить недостающий элемент для восстановления нашего калькулятора.
Для этого мы декодируем значения массива с индекса 27 до конца массива в UTF8 и воспользуемся командлетом Split-Path, чтобы получить только имя файла:
1 |
$filename = Split-Path -Path ([System.Text.Encoding]::UTF8.GetString($Byte_Array[27..$Byte_Array.Length])) -Leaf |
Все данные для восстановления нерезидентного файла $ROWX1VN.exe у нас есть, и способ мы уже изучили, поэтому дело за малым. Готовый сценарий для восстановления удаленных через корзину файлов можно найти на GitHub.
Заключение
Восстановление удаленных файлов — задача довольно кропотливая и интересная. Хотя автоматизированных средств для этого предостаточно, лучше не доводить дело до потери данных. Чтобы обезопасить себя от утраты ценной информации, не забывайте создавать бэкапы и хранить их по принципу 3-2-1.
Думаю, что с полученными знаниями читателю не составит труда разработать собственную программу для автоматизации процесса восстановления.
ПОЛЕЗНЫЕ ССЫЛКИ:
- Как восстановить удаленные метаданные PDF
- Восстановление удаленных файлов Linux с PhotoRec
- Восстановление данных в Linux с помощью Foremost