![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
Как удалить файл без восстановления [D7]
nikfel © (2008-03-22 11:03:00)Подскажите, пожалуйста. Как удалить файл со всем, чтобы восстановить было нельзя. Заранее спасибо.
Riply (2008-03-26 23:18:00) [41]> [63] Игорь Шевченко © (26.03.08 23:03)
> Я пишусь так: Schevchenko
Sorry
> Насчет спортивности - гораздо проще скопировать файл перед его затиранием. Не надо с кластерами возиться.
Перед затиранием я ничего не делаю.
> Я вроде написал свои условия.
Я поняла так, что "В параллель с файлом ты можешь делать все, что угодно"
>А у тебя получается, что ты копируешь кластеры, параллельно затираешь файл, а потом из скопированных читаешь.
Нет, не так получается, а вот как: я вынуждаю функцию затирать не те кластеры, где располагался файл,
а новые, совершенно другие. Что она с успехом и делает :)
И считываю я не из "скопированных класеров" а из "старых", которые в результате
остались на диске безхозными и не затертыми. :)
> Неспортивно.
Подаю жалобу на перерассмотрение вердикта :)
Игорь Шевченко (2008-03-26 23:03:00) [42]
> WipeFileByShevchenko
Я пишусь так: Schevchenko
Насчет спортивности - гораздо проще скопировать файл перед его затиранием. Не надо с кластерами возиться.
Я вроде написал свои условия. А у тебя получается, что ты копируешь кластеры, параллельно затираешь файл, а потом из скопированных читаешь.
Неспортивно.
Riply (2008-03-26 22:04:00) [43]Вроде, удалось добиться нужного результата.
Опишу как я действовла, чтобы получить вердикт: спортивно или нет.
Если да и потребуется код, пригодный для компиляции, - буду писать,
если нет, то учту замечания и буду думать дальше :)
Все происходит на NTFS диске (не виртуальном).
Есть исходный файл, в котором хранятся наши секретные данные
SourName = 'BaseDataFile.txt' размером DataSize = 7786 Byte.
Подготовка:
Копируем SourName в VictimName - этот файл будем затирать.
Создаем файл StuffName с размером ROUND_UP(DataSize, BytesPerCluster).
Затираем его нулями :)
Проверяем что он не фрагментирован и получаем "номер" его первого кластера StuffLcn.
Это временный файл, в чьи кластеры мы будем премещать подопытного.
Пишем две процедуры:
Первая устанавливает hEvent, сигнализирующий, что мы готовы к работе
и переходит к ожиданию открытия нового Handle - а.
Мы расчитываем, что он будет открыт
процедурой затирания от Игоря: WipeFileByShevchenko
function WaitCreateHandle(hEvent: THandle): NTSTATUS;
var
OldHandleCount, HandleCount: DWord;
//....
begin
Result := NtQueryInformationProcess(GetCurrentProcess, ProcessHandleCount,
@OldHandleCount, SizeOf(DWord), nil);
if SetEvent(hEvent) then
while NT_SUCCESS(Result) do
begin
Result := NtQueryInformationProcess(GetCurrentProcess, ProcessHandleCount,
@HandleCount, SizeOf(DWord), nil);
if HandleCount = Succ(OldHandleCount) then Exit;
//....
end
//....
end;
Вторая процедура у нас и будет заниматься перемещением и чтением.
Она будет работать внутри дополнительной нити.
Выглядит она примерно так:
function MoveAndReadWippedFile(const pVictim, pRestore: PUNICODE_STRING; hEvent: THandle; const VictimSize: DWord): NTSTATUS;
var
StuffName: UNICODE_STRING;
begin
//....
Result := Nt_DeleteFileU(@StuffName, 0); // уничтожаем файл - контейнер кластеров.
if Result = STATUS_SUCCESS then
begin
// сигнализируем, что готовы к работе и ждем открытия подопытного файла процедурой затирания
Result := WaitCreateHandle(hEvent);
if NT_SUCCESS(Result) then
begin // Дождались, начинаем работу. (т.е. затиралка уже открыла файл и вовсю его трет. :))
Result := MoveObjectClusters(pVictim, StuffLcn);
// MoveObjectClusters - открывает файл pVictim,
// получает его RETRIEVAL_POINTERS_BUFFER
// после чего, перемещает его кластеры в подготовленные нами кластеры StuffName
// закрывает файл
ReadRetPointersToFile(IoData.pData, pRestore, VictimSize);
// Считывает кластеры из старого расположения нашего подопытного (прямое чтение)
// и сохраняет данные в файл pRestore
end;
//....
end;
Процедура нити:
function MoveClusters(pParams: Pointer): integer;
begin
Result := 0;
with PMoveParams(pParams)^ do
try
MoveStatus := MoveAndReadWippedFile(@VictimName, @RestoreName, hMoveEvent, VictimSize)
finally
SetEvent(hMoveEvent);
end;
end;
Ну и вызов всего этого безобразия:
hMoveEvent := CreateEvent(nil, False, False, nil);
if hMoveEvent <> 0 then
try
hThread := BeginThread(nil, 0, MoveClusters, @MoveParams, 0, ThreadID);
if hThread <> 0 then
try // Ждем сигнала готовности
if WaitForSingleObject(MoveParams.hMoveEvent, 100000) = WAIT_OBJECT_0 then
with MoveParams do
begin
// Вызываем затирающую процедуру
WipeFileByShevchenko(VictimName.Buffer);
Уфф. Вроде ничего не упустила.
Несколько тестов показали, что
при данных условиях, "затертые" данные восстанавливаются полностью.
P.S.
Понимаю некузявость кода. Он приведен толко как схема действий
для получения вердикта о спортивности поведения :)
Игорь Шевченко (2008-03-26 12:01:00) [44]
> Могу ли я в середине цикла
>
> for I := 0 to (FileSize div SizeOf(Buffer)) - 1 do
> if not WriteFile(AFile, Buffer, SizeOf(Buffer), Worker,
> nil)
> or (Worker <> SizeOf(Buffer)) then
> raise Exception.Create('Write failed');
>
> вызвать из него свою процедуру ?
Нет, не можешь.
> Здесь надо симитировать, что в этот момент времени
> другой процесс(поток), например, с более высоким приоритетом,
>
> производит "перемещение" кластеров нашего файла в кластеры
> с "номерами" 1000 и 1001
> NtFsControlFile(..., FSCTL_MOVE_FILE, ...)
Ну сделай файл на 1 гигабайт и запусти другой процесс параллельно.
Идея в том, чтобы получить данные затертого файла. Код затирания я привел, и вмешиваться в него не надо. Если без хитростей с перемещением не получится, то и браться не стоит :)
Riply (2008-03-26 10:54:00) [45]> [55] Игорь Шевченко © (25.03.08 13:20)
> В параллель с файлом ты можешь делать все, что угодно.
Могу ли я в середине цикла
for I := 0 to (FileSize div SizeOf(Buffer)) - 1 do
if not WriteFile(AFile, Buffer, SizeOf(Buffer), Worker, nil)
or (Worker <> SizeOf(Buffer)) then
raise Exception.Create('Write failed');
вызвать из него свою процедуру ?
Идея, примерно, такая:
Для удобства, считаем, что на каждом шаге затирается один кластер.
Пусть исходно файл занимал кластеры с "номерами" 0 и 1.
Допустим, у нас в цикле только два шага.
Проходим первый шаг (как бы запись в класер 0).
Здесь надо симитировать, что в этот момент времени
другой процесс(поток), например, с более высоким приоритетом,
производит "перемещение" кластеров нашего файла в кластеры с "номерами" 1000 и 1001
NtFsControlFile(..., FSCTL_MOVE_FILE, ...)
Проходим второй шаг цикла (как бы запись в класер ??? ).
Завершили затирание.
Встает такой вопрос:
В какие кластеры реально велась запись ?
0, 1 или 1000, 1001 ? А может в 0, 1001 ?
Инфомация может считаться "уничтоженной без возможности восстановления"
только в двух случаях:
1. Запись велась в 0, 1 и они (уже затертые) переместились в 1000 и 1001.
2. Запись велась во все четыре кластера.
Пример, который я приводила показывает, что в общем случае это не первый и не второй варианты.
Да и не логичные они какие-то :)
Во всех остальны случаях информация уничтожена не полностью - т.е. не уничтожена :)
Я спрашиваю о "добавлении" вызова функции в процедуру затирания,
т.к. довольно сложно из другого процесса(потока) без синхронизации поймать нужный момент :)
Можно, конечно определять "момент такой" с помощью перехвата, но это уж очень некузяво :)
Самый простой способ - сразу вызывать NtFsControlFile, как впрочем я и делала :)
WipeInfo (2008-03-25 14:38:00) [46]Удалено модератором
Примечание: Offtopic
Riply (2008-03-25 13:36:00) [47]> [57] Игорь Шевченко © (25.03.08 13:32)
> После этого ты любым тебе доступным инструментом восстановишь
> содержимое этого файла
Может не обязательно полное содержимое, а хотя бы один сектор (ну или кластер) ?
> Время разумеется не ограничено :)
Ну а после этого уточнения, я полностью согласная :)
Игорь Шевченко (2008-03-25 13:32:00) [48]Riply © (25.03.08 13:28) [56]
Тебе надо сделать
> После этого ты любым тебе доступным инструментом восстановишь
> содержимое этого файла
Время разумеется не ограничено :)
Riply (2008-03-25 13:28:00) [49]> [54] Игорь Шевченко © (25.03.08 13:17)
> Договорились ?
Т.е. мне надо найти условия, при которых данное затирание
будет работать не сто процентно.
Причем такие, что сбой в затирании был воспроизводим
при разумном числе попыток ?
Если я правильно поняла и мне дается время, то согласна :)
Игорь Шевченко (2008-03-25 13:20:00) [50]В дополнение к [54]
В параллель с файлом ты можешь делать все, что угодно. Но принцип такой, что после окончания всех процессов с файлом, ты, имея диск с NTFS, пытаешь восстановить. Разумеется, способ, когда ты заранее скопируешь кластеры, занимаемые файлом до его затирания, а потом перепишешь файл в другое место каким-либо способом, хотя бы и влэндишным, считается неспортивным.
Да, разумеется ход процесса восстановления надо в студию, чтобы пример был воспроизводимым.
Игорь Шевченко (2008-03-25 13:17:00) [51]Давай сделаем проще:
Ты создашь файл, стандартным образом, скопируешь файл с исходным текстов какого-нибудь твоего примера, килобайт на 10 в файл с именем a.txt.
После этого ты его аккуратно откроешь на запись, и пропишешь от начала до конца нулями или произвольным символом.
var
AFile: HFILE;
FileSize, Worker: Cardinal;
I: Integer;
Buffer: array[0..1023] of char;
begin
FillChar(Buffer, SizeOf(Buffer), 65);
AFile := CreateFile('a.txt', GENERIC_READ or GENERIC_WRITE,
FILE_SHARE_READ, nil, OPEN_EXISTING, 0, 0);
Win32Check(AFile <> INVALID_HANDLE_VALUE);
try
FileSize := GetFileSize(AFile, @Worker);
if Worker <> 0 then
raise Exception.Create('File too large to test');
for I := 0 to (FileSize div SizeOf(Buffer)) - 1 do
if not WriteFile(AFile, Buffer, SizeOf(Buffer), Worker, nil)
or (Worker <> SizeOf(Buffer)) then
raise Exception.Create('Write failed');
if FileSize mod SizeOf(Buffer) <> 0 then
if not WriteFile(AFile, Buffer, FileSize mod SizeOf(Buffer), Worker,
nil) or (Worker <> FileSize mod SizeOf(Buffer)) then
raise Exception.Create('Write failed');
finally
CloseHandle(AFile);
end;
end;
После этого ты любым тебе доступным инструментом восстановишь содержимое этого файла :)
Потом то же самое с сжатым файлом и с разреженным.
Договорились ?
Riply (2008-03-25 13:14:00) [52]> [52] Игорь Шевченко © (25.03.08 13:03)
> Воспроизводи. До тех пор, пока не воспроизвела, считается за глюк инструмента.
"Ох не легкая это работа, из болота тащить бегемота." (с)
Что ж делать, буду пытаться. Но требуется время (кроме удовольствия, еще, к сожалению, и работа существует :)
> В примере ты его параллельно дварковала, причем влэндишным способом.
:)
Дык дваркование из примера можно убрать и поместить
в другой порцесс. Просто так было легче совместить его с записью в файл :)
Игорь Шевченко (2008-03-25 13:03:00) [53]Riply © (25.03.08 12:14) [51]
> Ведь не случайно эффект я наблюдала на фрагментированных
> файлах.
Воспроизводи. До тех пор, пока не воспроизвела, считается за глюк инструмента.
> В примере я специально использовала стандартный файл, даже
> не фрагментированный,
> что бы показать, что и в этом случае запись может происходить
> "не туда".
В примере ты его параллельно дварковала, причем влэндишным способом.
Riply (2008-03-25 12:14:00) [54]> [50] Игорь Шевченко © (25.03.08 11:59)
> Riply © (25.03.08 10:52) [48]
> Ошибка в том, что при обычной записи в файл (несжатый)
> его кластеры автомагически не перемещаются. Ибо незачем.
К "несжатый" надо еще добавить "неразраженный", и очень вероятно "не фрагментированный" :)
Ведь не случайно эффект я наблюдала на фрагментированных файлах.
Насчет "незачем", я бы не была столь категорична, ибо пути системы неисповедимы. :)
Это относиться и к сторонним программам, установленным на компьютер.
И если кто угодно из них имеет возможность переместить наш файл, когда мы в него пишем,
то какая здесь может быть гарантия ?
В примере я специально использовала стандартный файл, даже не фрагментированный,
что бы показать, что и в этом случае запись может происходить "не туда".
Игорь Шевченко (2008-03-25 11:59:00) [55]Riply © (25.03.08 10:52) [48]
Ошибка в том, что при обычной записи в файл (несжатый) его кластеры автомагически не перемещаются. Ибо незачем.
guav (2008-03-25 11:57:00) [56]> [45] WipeInfo (25.03.08 10:09)
> Eraser
Вот кстати эту тулзу смотрел (код открыт).
На NTFS она логфайл не чистит, а на FAT имеются ошибки, которые моут привести к проче данных.
Riply (2008-03-25 10:52:00) [57]> [46] Игорь Шевченко © (25.03.08 10:26)
Ну нельзя же так издеваться над софорумчанкой :)
В чем эта чертова ошибка ?
Riply (2008-03-25 10:32:00) [58]> [46] Игорь Шевченко © (25.03.08 10:26)
> Вот же. А ошибку в примере ты уже нашла ?
Ну вот. Как всегда :(
Пол ночи писала это дело, уже голова плохо соображает.
И где она (ошибка) ?
Игорь Шевченко (2008-03-25 10:26:00) [59]
> Зато мне удалось написать легко воспроизводимый пример,
> доказывающий, что при обычной записи в файл,
> никакой гарантии, что мы пишем в нужные кластеры нет
Вот же. А ошибку в примере ты уже нашла ?
WipeInfo (2008-03-25 10:09:00) [60]Eraser
WipeInfo