Конференция "WinAPI" » Как удалить файл без восстановления [D7]
 
  • Riply © (26.03.08 10:54) [60]
    > [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, как впрочем я и делала :)
  • Игорь Шевченко © (26.03.08 12:01) [61]

    > Могу ли я в середине цикла
    >
    > 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 © (26.03.08 22:04) [62]
    Вроде, удалось добиться нужного результата.
    Опишу как я действовла, чтобы получить вердикт: спортивно или нет.
    Если да и потребуется код, пригодный для компиляции, - буду писать,
    если нет, то учту замечания и буду думать дальше :)

    Все происходит на 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.
    Понимаю некузявость кода. Он приведен толко как схема действий
    для получения вердикта о спортивности поведения :)
  • Игорь Шевченко © (26.03.08 23:03) [63]

    > WipeFileByShevchenko


    Я пишусь так: Schevchenko

    Насчет спортивности - гораздо проще скопировать файл перед его затиранием. Не надо с кластерами возиться.

    Я вроде написал свои условия. А у тебя получается, что ты копируешь кластеры, параллельно затираешь файл, а потом из скопированных читаешь.

    Неспортивно.
  • Riply © (26.03.08 23:18) [64]
    > [63] Игорь Шевченко ©   (26.03.08 23:03)
    > Я пишусь так: Schevchenko

    Sorry

    > Насчет спортивности - гораздо проще скопировать файл перед его затиранием. Не надо с кластерами возиться.

    Перед затиранием я ничего не делаю.

    > Я вроде написал свои условия.

    Я поняла так, что "В параллель с файлом ты можешь делать все, что угодно"

    >А у тебя получается, что ты копируешь кластеры, параллельно затираешь файл, а потом из скопированных читаешь.

    Нет, не так получается, а вот как: я вынуждаю функцию затирать не те кластеры, где располагался файл,
    а новые, совершенно другие. Что она с успехом и делает :)
    И считываю я не из "скопированных класеров" а из "старых", которые в результате
    остались на диске безхозными и не затертыми. :)

    > Неспортивно.
    Подаю жалобу на перерассмотрение вердикта :)
  • Игорь Шевченко © (27.03.08 00:26) [65]

    > Нет, не так получается, а вот как: я вынуждаю функцию затирать
    > не те кластеры, где располагался файл,
    > а новые, совершенно другие. Что она с успехом и делает :
    > )
    > И считываю я не из "скопированных класеров" а из "старых",
    >  которые в результате
    > остались на диске безхозными и не затертыми. :)


    Ну я говорю, проще скопировать файл перед затиранием. Неспортивно.
    Под "делать все, что хочешь", я, разумеется не имел в виду создание копии незатертых данных.
  • Riply © (27.03.08 01:14) [66]
    >  [65] Игорь Шевченко ©   (27.03.08 00:26)
    Еще раз попробую снять обвинение в неспортивом поведении :)

    > Под "делать все, что хочешь", я, разумеется не имел в виду создание копии незатертых данных.

    О какой копии идет речь ? Пока не начался цикл затирания, я даже файл не открываю.
    Только после этого получаю Pointers даю команду на перемещение.
    К этому времени в цикле уже обработана чать данных.
    Было бы нелогично предполагать, что система будет перемещать старые(уже никому не нужные данные),
    чтобы потом их затирать. Она просто скинет уже обработанные данные в новое место и продолжит запись
    в новые кластеры. (Мой первый пример подтверждает это предположение)
    Так что копии, в данном случае, не создается, а только переопределяется место записи. (Это надеюсь спортивно ? :)
    Здесь, конечно, мне попалась облегченная задача.
    Если бы буфер для затирания был не 1024, а равен кластеру,
    еще лучше "объединению" кластеров (обычно это 16 кластеров), то было бы сложнее, но не безнадежно :)
    Трудности возникли бы и с большими файлами.
    Но мы же искали не способ затирания, а контрпример.
    И с этой задачей, как мне кажется, нам удалось справиться.
    Во всяком случае показано, что при обычной записи в файл,
    не является фактом ведение записи именно в те кластеры где этот файл располагался.
  • Игорь Шевченко © (27.03.08 01:33) [67]
    Riply ©   (27.03.08 01:14) [66]


    > Во всяком случае показано, что при обычной записи в файл,
    >  
    > не является фактом ведение записи именно в те кластеры где
    > этот файл располагался.


    Да, если при этом работает дефрагментатор, то тоже не является фактом.
    Только я, убей бог, не понимаю, что это значит ?
    Если параллельно с записью происходит копирование файла, то тоже не факт, что копия будет идентична оригиналу.

    И что из этого следует ? Что не надо затирать файлы, когда их одновременно копируют ? Что система может произвольно при записи перераспределить кластеры файла ?

    Нет, их перераспределит ТВОЙ ПРОЦЕСС или процесс дефрагментатора, но никак не система сама собой.

    Если ты добьешься того, что при отсутствии параллельных процессов, перемещающих кластеры файла, система будет их перераспределять при записи того же файла по месту, тогда пост о том, что "кластеры могут меняться" будет считаться действительным.

    Этак каждый гражданин себе веревок настрижет, польт не напасешься.
  • Riply © (27.03.08 02:10) [68]
    > [67] Игорь Шевченко ©   (27.03.08 01:33)
    > Да, если при этом работает дефрагментатор, то тоже не является фактом.
    > Только я, убей бог, не понимаю, что это значит ?

    Это означает то, что ответ "записать в файл нули" на вопрос
    "Как удалить файл со всем, чтобы восстановить было нельзя?"
    является не совсем корректным. Только и всего :)

    > Что система может произвольно при записи перераспределить кластеры файла ?
    > Нет, их перераспределит ТВОЙ ПРОЦЕСС или процесс дефрагментатора, но никак не система сама собой.
    К сожалению, я не знаю как поведет себя система. Ибо неисповедима :)
    Вдруг она решит, что при записи именно в такой то файл, ей удобнее работать так-то и так-то. Черт ее знает :)

    > Если ты добьешься того, что при отсутствии параллельных процессов, перемещающих кластеры файла,
    > система будет их перераспределять при записи того же файла по месту,
    > тогда пост о том, что "кластеры могут меняться" будет считаться действительным.

    В такой постановке, это довольно не просто.
    Этим процессом может оказаться драйвер, какого нибудь супер-пупер виртуального диска.
    Но я буду иметь это ввиду и постоянно следить не имело ли это место.
    Благо работаю то с файловой системой.

    P.S.
    Я могу не знать, ошибаться, не понимать чего-то, но никак не передергивать или подтасовывать факты.

    P.P.S.
    И вообще, у меня очень спортивное поведение.
    Решила объявить это сама, а то вдруг кто не догадается :)
  • Игорь Шевченко © (27.03.08 09:46) [69]
    Riply ©   (27.03.08 02:10) [68]


    > К сожалению, я не знаю как поведет себя система. Ибо неисповедима
    > :)


    Система вполне исповедима бо написана согласно детерминированным алгоритмам.

    Я напомню из поста [14]

    "Я воспроизводила, примерно, такое:
    Создавала файл, например, занимающий восемь кластеров с "номерами":
    0..3,  128...131.
    И после "обычной" записи в него его картинка становилась: 0..7.
    Я не утверждаю, что это происходит всегда,
    но в моих тестах это повторилось несколько раз."

    У меня небольшой вопрос, что значит "обычной" записи в твоих словах ?
    С параллельно работающим дефрагментатором или иной перемещалкой кластеров ?


    > В такой постановке, это довольно не просто.
    > Этим процессом может оказаться драйвер, какого нибудь супер-
    > пупер виртуального диска.
    > Но я буду иметь это ввиду и постоянно следить не имело ли
    > это место.
    > Благо работаю то с файловой системой.


    Обычный диск, на нем обычная система NTFS, параллельно не запущено пермещающих кластеры процессов. Возможна ли ситуация, когда при записи файла (не сжатого, не разреженного) по месту, его распределение кластеров поменяется ?
  • Riply © (27.03.08 10:00) [70]
    > [69] Игорь Шевченко ©   (27.03.08 09:46)
    > У меня небольшой вопрос, что значит "обычной" записи в твоих словах ?
    > С параллельно работающим дефрагментатором или иной перемещалкой кластеров ?

    Игорь, к сожалению, я не могу дать четкого ответа.
    В то время мне и голову не приходило, что кто-то кроме системы может это делать.
    Едиственное, что могу сказать: дефрагментатор точно не был запущен :)
    Насчет других "перемещалок кластеров" не уверена.
    Например, я не знаю как работает "DAEMON Tools". (тогда он у меня стоял).
    Что было еще не помню. "Norton Unerase" может ?

    Соответственно не могу дать однозначного ответа и на это вопрос:
    > Обычный диск, на нем обычная система NTFS, параллельно не запущено пермещающих кластеры процессов.
    > Возможна ли ситуация, когда при записи файла (не сжатого, не разреженного)
    > по месту, его распределение кластеров поменяется ?

    Единственное, что могу утверждать, что "переезд" во время записи возможен.
    А кто тому виной ... ответить не готова.   (Пока :)

    P.S.
    Есть один вариант теста... Надо хорошенько его обдумать.
    Может он и поможет нам докапаться ло истины :)
  • Игорь Шевченко © (27.03.08 10:14) [71]

    > Единственное, что могу утверждать, что "переезд" во время
    > записи возможен.


    Пример в студию
  • Riply © (27.03.08 10:19) [72]
    >  [71] Игорь Шевченко ©   (27.03.08 10:14)
    > Пример в студию

    Тот, который я описывала выше ?
    Мне понадобится время для написания кода, пригодного к компиляции.
  • clickmaker © (27.03.08 10:37) [73]
    а о чем речь вообще?
    что нельзя так затереть файл, чтобы не было возможности восстановить?
  • Riply © (27.03.08 11:01) [74]
    > [70] Riply ©   (27.03.08 10:00)
    > Единственное, что могу утверждать, что "переезд" во время записи возможен.

    Чуть подумав, изменю формулировку:
    "возможен "переезд" во время работы цикла while Condition do WriteFile"
    Ибо именно это происходит в моем примере.
  • Riply © (27.03.08 11:03) [75]
    > [73] clickmaker ©   (27.03.08 10:37)
    > а о чем речь вообще?
    > что нельзя так затереть файл, чтобы не было возможности восстановить?

    Обо всем понемножку. И об этом, в том числе :)
    Точнее не "нельзя", а очень сложно :)
  • clickmaker © (27.03.08 11:18) [76]

    > [75] Riply ©   (27.03.08 11:03)

    ну так, и документ, скормленный шредеру, тоже можно восстановить при желании )
    только кому это интересно, кроме налоговой и ГРУ? )
  • Riply © (27.03.08 11:24) [77]
    > [76] clickmaker ©   (27.03.08 11:18)
    > ну так, и документ, скормленный шредеру, тоже можно восстановить при желании )
    > только кому это интересно, кроме налоговой и ГРУ? )

    Ну... например, возможно, автор этой ветки, полагает, что за его данными может
    охотиться одна из этих благославенных организаций :)
  • Игорь Шевченко © (27.03.08 11:39) [78]
    Riply ©   (27.03.08 10:19) [72]

    Пример в студию, когда при обычной записи и при отсутствие процесса, перемещающего кластеры, распределение кластеров может измениться при перезаписи по месту несжатого и неразреженного файла.
  • Riply © (27.03.08 11:47) [79]
    > [78] Игорь Шевченко ©   (27.03.08 11:39)
    > Пример в студию, когда при обычной записи и при отсутствие процесса, перемещающего кластеры,
    > распределение кластеров может измениться при перезаписи по месту несжатого и неразреженного файла.

    Игорь, так я же в том утверждении написала: "А кто тому виной ... ответить не готова."
    Я имела ввиду, что не знаю кто перемещал "процесс, перемещающий кластеры" или система.
    Sorry, если непонятно выразилась.
 
Конференция "WinAPI" » Как удалить файл без восстановления [D7]
Есть новые Нет новых   [134433   +22][b:0][p:0.001]