Хакота

written on Thursday, March 21, 2013

Вчера применил адский уровень красноглазости - доставал убитый файл через отладчик. Дело было так: качаю себе большой длинный файл через торренты на фиговом интернете (от отсутствия оптики на острове я страдаю и ностальгирую). Скачал. Тут рука промахивается в истории команд и вместо открытия файла в мплеере я резко грохаю его через rm. Упс.

Можно конечно перескачать, но это долго, я уже настроился посмотреть эту серию. И обидно. Но я-то в курсе, как в юниксах работают файловые системы и знаю, что пока торрент-клиент открыт, файл еще никуда не делся.

Был бы линукс - скопировал бы через /proc/$pid/fd/$n. Но увы, это злобная макось и /proc тут нету. Зато есть lsof и gdb.

GDB

Цепляюсь к процессу торрент-клиента через gdb -p pid, смотрю номер дескриптора, соответствующего удаленному файлу черещ lsof:

Transmiss 45382 muromec 28r REG 1,2 635760707 66811886 блаблабла.mkv

Ну окей, файл еще живой, надо всего-то сделать хардлинк. Идут в гуглу и стековерфлоу искать, как делаются хардлинки на файловый дескриптор.

А никак. Ну или я тупой и не нашел. link() хочет два пути и все.

Параллельно узнал, что в линуксе больше нет рута, все на capabilities переделали.

Code inject

Через gdb можно нагло залезть в память процесса и подергать функции. Поскольку выполнение программы остановлено, то она даже не упадет до тех пор, пока отладчик ее не отпустит.

И так, у меня есть номер дескриптора и возможность дергать функции. Дальше все нудно. Делаем копию файлового дескриптора, ставим позицию в файле на 0 и начинаем read-write loop (лог gdb записан приблизительно и по памяти):

(gdb) print (int)dup(28)
$1 = 30
(gdb) print lseek(30, 0,)
$2 = 0
(gdb) print (long)malloc(0x3200000)
$3 = 4389474304
(gdb) print (int)open("copy.mkv", 0x202)
$4 = 31
(gdb) print (int)read(30, 4389474304, 0x3200000)
$5 = 52428800
(gdb) print (int)write(31, 4389474304, 0x3200000)
$6 = 52428800

Ну и так далее. Иногда оно почему-то ловило SIGPIPE и приходилось ручками ставить правильный offset через lseek(), потомучто я не понимал, в какой момент и зачем этот сигнал прилетел.

В конце этого действа я дернул close() и пошел смотреть восстановленный файл. Только выставил на него нормальные пермишшены и все.

This entry was tagged hack and unix