Проблема с чтением в минифильтре
От: Suares  
Дата: 26.11.14 17:38
Оценка:
Работаю над подменой буферов и раньше была проблема при чтении — вылетал БСОД.
PreRead возвращал FLT_PREOP_SUCCESS_WITH_CALLBACK. В таком случае PostRead процедура выполнялась на DPC уровне. Но в PostRead я использую — FltSendMessage, которая выполняется не выше APC. Нужна она для того что бы кусок зашифрованного файла переслать в юзер мод, где он преобразуется к оригиналу и потом этот кусок запихнуть в новый подменяемый буфер.
Я это исправил с помощью возвращаемого значения FLT_PREOP_SYNCHRONIZE в PreRead. Теперь PostRead выполняется на APC уровне.

Что написано на msdn про FLT_PREOP_SYNCHRONIZE:

The minifilter driver is returning the I/O operation to the filter manager for further processing, but it is not completing the operation. In this case, the filter manager calls the minifilter's post-operation callback in the context of the current thread at IRQL <= APC_LEVEL.


БСОДа больше нету и с текстовыми файлам все норм, почти все норм. Но с картинками почему-то беда при чтении.

Сохраняються в папке, т.е. шифруются она правильно. Это проверял. Записывается хедер с нужной информацией и само содержимое файла.
Но открыть у меня картинку не получается. Отображает ошибку в окне просмотра, что файл поврежден.

Если рассмотреть на примере картинки с названием 14kb.jpg, у которой AllocationSize = 16384, а EndOfFile = 13023(значение изменял принудительно) вот что вижу в DbgView:

00000103 SB!SwapPreRead: Name = C:\Private\14kb.jpg, readLen = 4096.
00000104 SB!SwapPreRead: Pid = 2444 newB = 84354000 newMdl = 86210D60 oldB = 06C285FC oldMdl = 00000000 len = 4096 byteOffset = 4096(0).
00000105 SB!SwapPreRead: Name = C:\Private\14kb.jpg, readLen = 4096.
00000106 SB!SwapPreRead: Pid = 2444 newB = 842E6000 newMdl = 86210E30 oldB = 00000000 oldMdl = 8428A388 len = 4096 byteOffset = 4096(0).
00000107 SB!SwapPostRead: Pid = 2444 i = 0 CopySize = 4080 ReplySize = 0 OffsetOrig = 0 OffsetEnc = 0.
00000108 SB!SwapPostRead: Pid = 2444 newB = 842E6000 status = 0x0 info = 13023 byteOffset = 0(0) Freeing.
00000109 SB!SwapPreRead: Name = C:\Private\14kb.jpg, readLen = 12288.
00000110 SB!SwapPreRead: Pid = 4 newB = 862A9000 newMdl = 86210E30 oldB = 00000000 oldMdl = 8428A388 len = 12288 byteOffset = 12288(4096).
00000111 SB!SwapPostReadWhenSafe: Pid = 2444 newB = 84354000 status = 0x0 info = 13023 byteOffset = 0(0) Freeing.
00000112 SB!SwapPostRead: Pid = 4 i = 0 CopySize = 8928 ReplySize = 8927 OffsetOrig = 0 OffsetEnc = 0.
00000113 SB!SwapPostRead: Pid = 4 newB = 862A9000 status = 0x0 info = 13023 byteOffset = 4096(0) Freeing.

Почему-то всегда сначала проскакивает PreRead с 4096, потом 12288 байтами. В сумме будет 16384, что соответствует AllocationSize.

Пара наблюдений:
1. При клике на картинку, проскакивают Read запросы, в то время как на текстовые файлы нет.
2. В памяти подменяемый буфер соответствует оригиналу картинки. Так как пробывал, в то время когда драйвер мониторит папку, копировать картинку в другую папку. Копируется норм, потому что потом этот скопировавшийся файл я могу открыть и увижу оригинальное изображение.

И еще одно, как правильно делать смещение, когда у тебя в файле есть хеадер с дополнитеьной информацией.
В PostCreate считую хеадер с помощью FltReadFile с флагом FLTFL_IO_OPERATION_DO_NOT_UPDATE_BYTE_OFFSET. Далее в PostQueryInformation изменял
fileAllInformation->PositionInformation.CurrentByteOffset.QuadPart = FILE_HEADER_LENGTH;

и
filePositionInformation->CurrentByteOffset.QuadPart = FILE_HEADER_LENGTH;

В PreRead же делала так:
iopb->Parameters.Read.ByteOffset.QuadPart = FILE_HEADER_LENGTH;

получалось вечное зацикливание и сейчас просто добавляю FILE_HEADER_LENGTH:
RtlCopyMemory(bufToUserMode, encryptBuf + FILE_HEADER_LENGTH, size);
Re: Проблема с чтением в минифильтре
От: EreTIk EreTIk's Box
Дата: 26.11.14 20:13
Оценка: 2 (1)
S>Почему-то всегда сначала проскакивает PreRead с 4096, потом 12288 байтами. В сумме будет 16384, что соответствует AllocationSize
S>Пара наблюдений:
S>1. При клике на картинку, проскакивают Read запросы, в то время как на текстовые файлы нет.
Я ставлю на неверно обрабатываемые запросы чтения или позиционирования.

S>И еще одно, как правильно делать смещение, когда у тебя в файле есть хеадер с дополнитеьной информацией.

S>В PostCreate считую хеадер с помощью FltReadFile с флагом FLTFL_IO_OPERATION_DO_NOT_UPDATE_BYTE_OFFSET. Далее в PostQueryInformation изменял
S>
S>fileAllInformation->PositionInformation.CurrentByteOffset.QuadPart = FILE_HEADER_LENGTH;
S>

S>и
S>
S>filePositionInformation->CurrentByteOffset.QuadPart = FILE_HEADER_LENGTH;
S>

Один раз? А как обрабатывается ситуация, когда вызывающий код делает seek + read?

S>В PreRead же делала так:

S>
iopb->>Parameters.Read.ByteOffset.QuadPart = FILE_HEADER_LENGTH;
S>

S>получалось вечное зацикливание и сейчас просто добавляю FILE_HEADER_LENGTH:
S>
S>RtlCopyMemory(bufToUserMode, encryptBuf + FILE_HEADER_LENGTH, size);
S>

Почему присвоение, а не корректировка смещения? Опять же: как обрабатывается seek + read с произвольной позиции файла?

Предлагаю вам все упростить: храните свой заголовок в конце файла. Это позволит убрать манипуляции с текущим смещением. Придется только обработать размер файла и переносить служебные данные при расширении. ИМХО так будет проще.

А еще проще хранить свои мета-данные рядом в срытом файле или ADS. Но тут нужно разруливать ситуацию, когда пользователь перезаписывает мета-данные.
Re[2]: Проблема с чтением в минифильтре
От: Suares  
Дата: 28.11.14 16:58
Оценка:
Здравствуйте, EreTIk, спасибо, что откликнулись! Вы писали:

ETI>...seek + read?


Давайте пока это опустим.

ETI>Предлагаю вам все упростить: храните свой заголовок в конце файла. Это позволит убрать манипуляции с текущим смещением.


Переместил я метаданные в конец файла, переписал Read/Write, но все та же беда с картинками и все те же странности, которые я описывал ранее. Если с текстовыми файлами все нормально получается, а с картинками нет, то видимо я что-то упустил в процедурах чтения. Подскажите на что нужно обратить внимание в таком случае?

ETI>А еще проще хранить свои мета-данные рядом в срытом файле или ADS. Но тут нужно разруливать ситуацию, когда пользователь перезаписывает мета-данные.


Такой вариант я не рассматривал, так как пока у меня в метаданных только оригинальный размер файла.
Re[3]: Проблема с чтением в минифильтре
От: EreTIk EreTIk's Box
Дата: 30.11.14 12:47
Оценка:
S>Переместил я метаданные в конец файла, переписал Read/Write, но все та же беда с картинками и все те же странности, которые я описывал ранее. Если с текстовыми файлами все нормально получается, а с картинками нет, то видимо я что-то упустил в процедурах чтения. Подскажите на что нужно обратить внимание в таком случае?
Причин может быть много. Попробуйте Process Monitor: даже если по логу будет не понятно, то зная шаги можно написать тест, который будет читать два одинаковых файла (один через фильтр) и сравнивать результат. А дальше нужно будет внимательно протрассировать в отладчике первое чтение, расходящееся эталонным.

ETI>>А еще проще хранить свои мета-данные рядом в срытом файле или ADS. Но тут нужно разруливать ситуацию, когда пользователь перезаписывает мета-данные.

S>Такой вариант я не рассматривал, так как пока у меня в метаданных только оригинальный размер файла.
А его нельзя вычислить?
Re[4]: Проблема с чтением в минифильтре
От: Suares  
Дата: 01.12.14 16:46
Оценка:
Здравствуйте, EreTIk, Вы писали:

ETI>Причин может быть много. Попробуйте Process Monitor: даже если по логу будет не понятно, то зная шаги можно написать тест, который будет читать два одинаковых файла (один через фильтр) и сравнивать результат. А дальше нужно будет внимательно протрассировать в отладчике первое чтение, расходящееся эталонным.


За Process Monitor не додумался. И в нем, я думаю, увидел ответ. Картинка 56 128 байт открывается так:

ReadFile Offset: 0, Length: 4096, Priority: Normal
ReadFile Offset: 4096, Length: 4096, Priority: Normal
ReadFile Offset: 8192, Length: 4096, Priority: Normal
ReadFile Offset: 12288, Length: 4096, Priority: Normal
...
ReadFile Offset: 53248, Length: 2878, Priority: Normal

Спасибо, надеюсь я продвинулся. И теперь пару месяцев уйдет, что бы тут что-то придумать.

Т.е. как я понимаю каждый ReadFile это новый IRP_MJ_READ. Соответственно Pre- и PostRead нужно будет подстроить под такой сценарий. И IRP_MJ_WRITE тоже походу

ETI>А его нельзя вычислить?

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