Все диски на маках шифруются секретным ключом - Volume Encryption Key (VEK). Ключ этот сам хранится в зашифрованном виде несколько раз - по одному разу на каждого пользователя. Для того, чтобы получить ключ расшифровки содержимого диска, нужно знать пароль любого из пользователей. Пароль хешируется по определённому алгоритму, из чего получается так называемый Key Encryption Key (KEK). Этим ключом уже можно попробовать расшифровать сам VEK. Когда шифруют VEK, к нему в конец приписывают определённую последовательность: 0xA6A6A6A6A6A6A6A6. Если результат расшифровки заканчивается так, значит пароль правильный. Когда пользователь меняет пароль или добавляется новый пользователь, ключ шифрования остаётся старый, но его нужно зашифровать при помощи нового обновлённого KEK.
Пароль от ноутбука - это глубоко личная информация, так что спрашивать я его не стал. Вместо этого я (вместе с Gemini) написал скрипт на питоне, который дублировал логику расшифровки VEK и отправил его другу. Скрипт содержал в себе все необходимые входные данные, которые я прочитал с диска: зашифрованный VEK, соль и число итераций хеширования пароля. Сам образ диска отправлять не пришлось.
Друг запустил этот скрипт у себя, ввёл пароль и отправил расшифрованный VEK мне. Мне осталось только заменить логику запрашивания пароля в драйвере, чтобы она сразу выдавала ключ расшифровки диска. Драйвер смог работать дальше...
Ищем заветный email
После всех манипуляций, драйвер смог успешно отработать и смонтировать образ без ошибок. Я мог перемещаться по директориям и смотреть, какие файлы в них находились. Было ощущение, что успех совсем близок. Однако, почти любая попытка прочитать какой-либо файл, приводил к ошибке.
Если знать, по какому offset-у лежит нужный мне файл, то можно было бы ещё раз запустить ddrescue на ноутбуке, и тогда этот файл можно было бы извлечь. Но на диске были тысячи писем, и я понятия не имел, какой из файлов нужный.
Усовершенствуем старый трюк: добавим логирование в код драйвера, который пытается открыть файл на чтение. Каждый раз, когда драйвер открывает какой-либо файл, я узнаю его адрес. Осталось запустить grep из корневой директории с письмами и собрать получившиеся логи. grep пробует открыть все файлы во всём под-дереве, так что я так получил адреса всех писем. После дедупликации получилось ~6000 офсетов.
Я разбил полученные адреса на группы по 1000 и написал 6 скриптов следующего вида:
ddrescue -i 25890078720 -s 65536 /dev/sda2 dump-part2.img dump-part2.log &&
ddrescue -i 119821115392 -s 65536 /dev/sda2 dump-part2.img dump-part2.log &&
ddrescue -i 112831520768 -s 65536 /dev/sda2 dump-part2.img dump-part2.log &&
... 1000 таких командКаждая из команд заставляет ddrescue скопировать 64 кб данных по заданному офсету.
К моему удивлению, такой подход сработал очень хорошо, и диск за всё время перегрелся всего один раз.
Мне тогда лишь осталось скопировать полученные файлы с образа и отправить их другу на проверку. Письмо нашлось, клиент остался доволен (хоть письмо в результате оказалось и не нужно 😐).