Top.Mail.Ru
Мастера DELPHI, Delphi programming community Титульная страница Поиск, карта сайта Написать письмо 
| Новости | Поиск | FAQ | Статьи | Книги | Новости VCL |
| Форумы ЧАТ | Орешник | KOL и MCK |
Форумы -» Основная («Начинающим»)/ Базы / WinAPI / Компоненты / Сети / Media / Игры / Corba и COM / KOL / FreePascal / .Net / Прочее / RSDN.ORG

« предыдущая ветвь | форум | следующая ветвь »

Как удалить файл без восстановления [D7]


Страницы:   1 2 3 4 5 6

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


Страницы:   1 2 3 4 5 6

Наверх

Титульная страница Поиск, карта сайта Написать письмо