![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
Как удалить файл без восстановления [D7]
nikfel © (2008-03-22 11:03:00)Подскажите, пожалуйста. Как удалить файл со всем, чтобы восстановить было нельзя. Заранее спасибо.
Riply (2008-03-25 10:03:00) [61]> [43] Riply © (25.03.08 09:52)
Несколько добавлений:
Как видно из примера для перемещения кластеров не использовался Handle файла.
MoveObjectClusters(pSourName, StuffLcn);
Это было сделано для того, чтобы показать, что "монопольное" открытие, тоже не спасает.
Перемещались кластеры "законными" методами с помощью FSCTL_MOVE_FILE
Игорь Шевченко (2008-03-25 09:52:00) [62]Riply © (24.03.08 15:09) [41]
"Я нашел, как применить здесь нестирающиеся шины из полиструктурного волокна с вырожденными аминными связями и неполными кислородными группами. Но я не знаю пока, как использовать регенерирующий реактор на субтепловых нейтронах. Миша, Мишок! Как быть с реактором?"
(с) А и Б Стругацкие
Riply (2008-03-25 09:52:00) [63]Мне не удалось воспроизвести "переезд" кластеров файла,
как прямое следствие записи в него.
Это означает только недостаточность моих знаний, но никак
не то, что данный "переезд" невозможен.
Уж не говоря о том, что не поймала сегодня - поймаю завтра :)
Повторюсь: эффект, я наблюдала и не раз.
Тогда он мне был совсем не нужен.
Я рассматривала возможности "безопасной прямой записи" данных в файл.
И то, что мне удалось зафиксировать "переезд"
ставило крест на моем способе "блокировки класеров".
Помню, расстроилась тогда :)
Зато мне удалось написать легко воспроизводимый пример,
доказывающий, что при обычной записи в файл,
никакой гарантии, что мы пишем в нужные кластеры нет :)
Я приведу только схему кода, т.к. в нем используется очень много
"самолапных" функций и классов (очень лень выдергивать все это. Sorry),
но попробую прокоментировать происходящее.
Приступим:
function ReadWippedFile(const pSourName: PUNICODE_STRING): NTSTATUS;
const
StuffExt: WideString = '.stuff';
sHelloDolly: WideString = 'Hello Dolly !!!' + sLineBreak + 'Wipped file: ';
var
SourLcn, StuffLcn: _LCN;
StuffName: UNICODE_STRING;
MFTDisk: TMFTScan;
hFileObj: THandle;
pBuffer: Pointer;
BufferSize, SourceClustersCount, StuffClustersCount: DWord;
begin
StuffLcn := -1;
SourLcn := -1;
SourceClustersCount := 4;
StuffClustersCount := SourceClustersCount * 2;
RtlInitUnicodeString(@StuffName, PWideChar(pSourName.Buffer + StuffExt));
// Создаем тестовый файл и временный файл, в который будем перемещать класеры.
// Задаем им размеры.
Result := Nt_FileCreateSized(pSourName, SourceClustersCount * BytesPerCluster, SET_SIZE_FLAG_INSTANCE, nil);
if NT_SUCCESS(Result) then Result := Nt_FileCreateSized(@StuffName, StuffClustersCount * BytesPerCluster, SET_SIZE_FLAG_INSTANCE, nil);
if NT_SUCCESS(Result) then
begin
MFTDisk := TMFTScan.Create;
try // TMFTScan - класс для работы с диском
Result := MFTDisk._Set_CallBackFunctions(pSourName, nil); // настраиваем
if Result = STATUS_SUCCESS then Result := MFTDisk.NtGetObjectRetrievalPointers(@StuffName, 0);
if Result = STATUS_SUCCESS then
begin // получили RetrievalPointers. Проверяем их пригодность как буфера для перемещения
with PRETRIEVAL_POINTERS_BUFFER(MFTDisk.IoData.pData)^ do
if ExtentCount > 0 then
with Extents[0] do
if (Lcn.QuadPart > 0) and (NextVcn.QuadPart >= SourceClustersCount)
then StuffLcn := Extents[0].Lcn.QuadPart;
if StuffLcn <= 0 then
begin
ShowMessage('Stuff file is fragmented. Try again' + sLineBreak
+ Pars_RETRIEVAL_POINTERS_BUFFER(MFTDisk.IoData.pData));
Exit;
end
else Nt_DeleteFileU(@StuffName, 0);
Result := MFTDisk.NtGetObjectRetrievalPointers(pSourName, 0);
if Result = STATUS_SUCCESS then
begin // Запоминаем исходные RetrievalPointers нашего файла и записываем их в лог
with PRETRIEVAL_POINTERS_BUFFER(MFTDisk.IoData.pData)^ do
if ExtentCount > 0 then SourLcn := Extents[0].Lcn.QuadPart;
Log_WriteStatusNT('Try to move to: ' + IntToStr(StuffLcn) + sLineBreak
+ Pars_RETRIEVAL_POINTERS_BUFFER(MFTDisk.IoData.pData), Result);
end;
// Подготовка закончена, приступаем к работе
if Result = STATUS_SUCCESS then
begin // Открываем наш файл
Result := Nt_OpenFile(pSourName, FILE_WRITE_DATA or SYNCHRONIZE, FILE_SHARE_ALX_NONE,
FILE_NON_DIRECTORY_FILE or FILE_SYNCHRONOUS_IO_NONALERT, nil, nil, hFileObj);
if Result = STATUS_SUCCESS then
try
BufferSize := SourceClustersCount * BytesPerCluster;
pBuffer := GetMemory(BufferSize);
if pBuffer <> nil then
try
Записываем в буфер приветствие для Dolly и имя файла.
FillBuffer(pBuffer, BufferSize, sHelloDolly + sLineBreakW + pSourName.Buffer);
Result := Nt_WriteFile(hFileObj, pBuffer, BufferSize, nil);
FlushFileBuffers(hFileObj);
// Записали данные в файл, приступаем к их уничтожению
NT_SUCCESS_SET_WORST(Result, Nt_SetFilePointer(hFileObj, nil, nil));
if NT_SUCCESS(Result) then
begin
FillChar(pBuffer^, BufferSize, 0); // Очистили буфер и записали первую половину файла
Result := Nt_WriteFile(hFileObj, pBuffer, BufferSize div 2, nil);
if Result = STATUS_SUCCESS then
begin
// Перемещаем кластеры нашего файла, записываем в лог новое расположение
Result := MFTDisk.MoveObjectClusters(pSourName, StuffLcn);
if NT_SUCCESS_SET_WORST(Result, MFTDisk.NtGetObjectRetrievalPointers(pSourName, 0))
then Log_WriteMessage(Pars_RETRIEVAL_POINTERS_BUFFER(MFTDisk.IoData.pData));
// и затираем вторую половину файла
NT_SUCCESS_SET_WORST(Result, Nt_WriteFile(hFileObj, IncPtr(pBuffer, BufferSize div 2), BufferSize div 2, nil));
end;
FillChar(pBuffer^, BufferSize, 0);
// читаем старые сектора нашего файла (прямое чтение)
Result := MFTDisk.ReadClustersToBuffer(pBuffer, SourLcn, SourceClustersCount);
if Result = STATUS_SUCCESS // и сохраняем их в др. файл
then Result := Nt_CreateFileData(@StuffName, pBuffer, BufferSize, nil, nil);
end;
finally
FreeMem(pBuffer);
end
else Result := STATUS_INSUFFICIENT_RESOURCES;
finally
NT_SUCCESS_SET_WORST(Result, NtClose(hFileObj));
end;
end;
end;
finally
MFTDisk.Free;
end;
end;
end;
Читаем лог:
Try to move to: 623215
ExtentCount 1
Index 0 Lcn 1778061 Count 4
The operation completed successfully
ExtentCount 1
Index 0 Lcn 623215 Count 4
The operation completed successfully
и видим, что посреди операции записи в файл, его кластеры были успешно перемещены туда,
куда мы и хотели.
Смотрим данные, полученные прямым чтением старых секторов:
H e l l o D o l l y ! ! !
W i p p e d f i l e :
\ ? ? \ I : \ Z _ S c a n T e s t D i r \ S o u r c e \ C l u s t e r e d F i l e . t x t
(Привожу только кусок, на самом деле считано все полностью). В новых кластерах, разумеется нули :)
P.S.
Операции затирания, прямого чтения и перемещения можно "тасовать" как угодно
(разумеется не нарушая логики). Результат остается тем же.
P.P.S.
Пример собирался "на коленке" так что строго не судите :)
Если возникнет необходимость - напишу нормальный (пригодный для компиляции).
Но очень лень этим заниматься. :)
Riply (2008-03-24 15:09:00) [64]> [40] guav © (24.03.08 11:42)
> Сейчас что-то не получается просто сжать и изменять, чтобы файл "переехал".
> Но явление тоже наблюдал.
Я уже написала процедуру, рекурсивно создающую дамп Run - ов всех объектов,
содержащихся в директории вместе с их именами и LCN - ми.
Осталось реализовать сравнение дампов,
и можно будет "во всеоружии" приступить к поимке переезжающих файлов :)
guav (2008-03-24 11:42:00) [65]> [39] guav © (24.03.08 11:36)
> (простой способ воспроизвести [14] - пробовать на сжатом файле).
Сейчас что-то не получается просто сжать и изменять, чтобы файл "переехал". Но явление тоже наблюдал.
guav (2008-03-24 11:36:00) [66]> [38] Игорь Шевченко © (24.03.08 11:16)
Только могут быть и другие уязвимости, не связанные с NTFS.
Ну и есть удалялки, использующие удаление путём повторной записи в файл, так они могут перезаписать не те кластеры.
(простой способ воспроизвести [14] - пробовать на сжатом файле).
Игорь Шевченко (2008-03-24 11:16:00) [67]
> Т.е. если действительно затереть их кластеры, то данные
> не будут восстановимы через логфайл
Собственно, в чем были уверены большевики. Спасибо.
guav (2008-03-24 11:00:00) [68]> [36] Игорь Шевченко © (24.03.08 09:41)
К метаданным про которые пишет Руссинович (кстати он ли ? в книге "Inside Windows NT", автор которой не Руссинович, про журналирование написано в точности то же самое, что в "Inside Windows 2000") относятся все метаданные. Включая всё, что пишется в MFT.
Данные резидентных (небольших, обычно меньше 600 байт) файлов попадают в логфайл, ссылки я уже дал.
Данные пользовательских нерезидентных файлов не попадают в логфайл, но датараны (пары логическийКластер-количествоКластеров) попадают, т.е. дают утвердительный ответ на [10] для прошлого в пределах времени цикла логфайла. Т.е. если действительно затереть их кластеры, то данные не будут восстановимы через логфайл, но если применить совет [7] к сжатому файлу, то могут быть (получится то, про что пишет Riply в [15] и никакого реального затирания кластеров не будет).
Кода не будет, потому что NDA.
Игорь Шевченко (2008-03-24 09:41:00) [69]guav © (24.03.08 02:34) [34]
Это все хорошо, но вот тот же Руссинович пишет, что журналируются метаданные, то есть, элементы каталогов и прочая..
Насчет данных самого файла - мне бы все-таки хотелось пример получить, как из перезаписанного файла на NTFS получить старые данные.
Нетрудно будет набросать ?
guav (2008-03-24 02:50:00) [70]> [33] Игорь Шевченко © (23.03.08 23:23)
> Кстати: "the NTFS file system maintains a change journal.
Ну да, это по ссылке из [31]. Change Journal не имеет (почти) отношения к Log File.
Про логфайл в MSDN мало пишут, немного есть тут http://support.microsoft.com/kb/101670
guav (2008-03-24 02:34:00) [71]> [33] Игорь Шевченко © (23.03.08 23:23)
> Я все о другом - о том, что следы в нем недолго хранятся.
> И использовать его как средство доступа к удаленной информации,
> занятие, на мой взгляд, малоперспективное.
Возражать не буду, лучше расскажу как посчитать сколько в среднем хранится записи.
Читаем в логфайле DWORD по смещению 0x40. Будет где-то между 0x20 и 0x30. Отнимаем от 0x40 прочитанное. Получится значение, на которое надо сдвинуть вправо LSN, чтобы получить номер перезаписи файла. Создаём файл и смотрим его LSN, сдвигаем его на вычисленную константу, получим число равное номеру цикла перезаписи логфайла. Теперь вычитаем из даты того файла дату логфайла, мы получаем время существования тома. Разделив это время на число циклов перезаписи, получим, сколько в среднем живёт запись логфайла. Для всего этого можно взять MFT_Scan, который by Riply :-) (LSN там назван _Usn64)
Понятно, что это время зависит от того системный ли диск, включено ли обновление времени последнего доступа, и т.п. и может получится и меньше дня и больше месяца.
> Кстати: "the NTFS file system maintains a change journal.
> When any change is made to a file or directory in a volume,
> the change journal for that volume is updated with a description
> of the change and the name of the file or directory"
>
> Насколько я понял, старых данных там не хранится...
Здесь речь скорее идёт об USN Journal ($UsnJrnl) а не о логфайле ($LogFile).
В $LogFile тарые данные хранятся для отмены незавершенной операции (в "Inside Windows 2000" это названо "undo pass"), новые хранятся для возможности повтора операции ("redo pass"). Кроме случаев, когда операция - отмена или повтор по логфайлу, для кадой операции хранятся и данные для повтора и данные для отмены.
Игорь Шевченко (2008-03-23 23:23:00) [72]guav © (23.03.08 21:04) [32]
Я все о другом - о том, что следы в нем недолго хранятся. И использовать его как средство доступа к удаленной информации, занятие, на мой взгляд, малоперспективное.
Кстати: "the NTFS file system maintains a change journal. When any change is made to a file or directory in a volume, the change journal for that volume is updated with a description of the change and the name of the file or directory"
Насколько я понял, старых данных там не хранится...
guav (2008-03-23 21:04:00) [73]> диск бы сразу был забит лог-файлом
Кстати диск не может быть забит логфайлом, размер логфайла вообще не увеличивается, он цикличен. Да, есть проблема, что логфайл может "наступить себе на хвост", но она обрабатывается.
guav (2008-03-23 21:01:00) [74]> [30] Игорь Шевченко © (23.03.08 20:44)
Именно так, и действительно в случаях вроде pagefile.sys туда ничего не попадает.
Журналирование "из любви к искусству", т.е. не нужное для работы самой ФС - это USN Journal, см. http://msdn2.microsoft.com/en-us/library/aa363801.aspx
Игорь Шевченко (2008-03-23 20:44:00) [75]guav © (23.03.08 19:37) [28]
Кстати. Насколько я понимаю, все это журналирование ведется на предмет восстановления после сбоев, а не из любви к искусству. В противном случае диск бы сразу был забит лог-файлом при достаточно интенсивной работе с файлами. Например, с pagefile.sys :))
guav (2008-03-23 19:42:00) [76]Я в [3] наверное плохо сформулировал свою точку зрения, повторюсь:
Если нужна возможность надёжно удалить файл, то об этом надо думать уже при создании файла. Перед удалением сложнее обеспечить надёжное удаление, а после обычного удаления - ещё сложнее.
guav (2008-03-23 19:37:00) [77]> [27] Игорь Шевченко © (23.03.08 19:12)
> Минуточку - там же написано, что после контрольной точки
> они как бы становятся ненужными.
Становятся ненужными - да, большинство записей становятся ненужными после контрольной точки. Но не затираются.
> Я вот честно не слышал, что в NTFS ведется хронология изменений
> файла...
И это есть, USN Log, но это опция, на ХР по дефолту выключена, и пишет только события, но не данные.
Данные действительно специально не журналируются. В логфайле журналируются метаданные, т.е. из нерезиднетных файлов туда специально пишутся только данные метафайлов.
> Впрочем, сам понимаешь, достаточно хорошенько переписать
> соседние файлы и лог забьется...
Да. Но если хорошенько переписать. И желательно знать, как переписывать, чтобы побыстрее его забить.
Я смотрел некоторые "стиралки", которые затирают неиспользованые MFT записи и свободное место тома, они таки затирают это всё, но в результате обработки ими тома в логфайле обычно появляется слишком мало записей, чтобы затереть значительную часть логфайла.
Игорь Шевченко (2008-03-23 19:12:00) [78]guav © (23.03.08 17:25) [25]
Минуточку - там же написано, что после контрольной точки они как бы становятся ненужными. Я вот честно не слышал, что в NTFS ведется хронология изменений файла...
Впрочем, сам понимаешь, достаточно хорошенько переписать соседние файлы и лог забьется...
Denis__ (2008-03-23 18:39:00) [79]самый простой способ удалить файл так, чтобы его нельзя было восстановить - просерлить жестак и залить пузырёк кислоты внутрь.А потом ещё молоточком пройтись, сверху:) (с) С.Лукьяненко.
guav (2008-03-23 17:25:00) [80]> [24] Игорь Шевченко © (23.03.08 17:00)
Ну так датараны "крупных" так же журналируются, как и данные "мелких", даже более тщательно (данные резидентных файлов в некоторых случаях не попадают в логфайл, а датараны нерезидентных - всегда попадают).