S>Решение придумал такое, что есть некое приложение, через которое можно будет открыть эту папку.
Напомню, что злоумышленник может внедриться в процесс этого приложения и свободно читать/писать шифрованные файлы. Это можно решить, например, защищёнными службами, когда содержимое шифрованного файла читается/пишется исключительно из этой службы. Однако, если под "приложением" понималось всего лишь окошко для ввода пароля, то забей.
S>Повторюсь, у нас уже лежит ранее зашифрованный файл. При его чтении происходит следующее, выделяется буфер размером таким же как этот зашифрованный файл и заполняется этими данными, зашифрованными данными. Он называется swappedBuffer. Создается еще один буфер уже в PostRead, называется origBuf, для расшифрованного содержимого. И у origBuf размер ТАКОЙ ЖЕ как и у swappedBuffer. При этом мы знаем, что размер зашифрованных данных будет вегда больше чем реальных. Это связанно с блоками в AES алгоритме, в моем случае блоки кратны 16 байт. Во время копирования из swappedBuffer в origBuf происходит расшифровка. В итоге в origBuf будет лежать реальный контент файла. НО этот буфер велик для реальных данных и по этому при открытии файла я вижу в конце лишние байты(символы).
Есть такое понятие, как виртуализация файловой системы, которое само по себе состоит из нескольких аспектов, ну и как бы виртуализация размера файла — один из них. И реализовать это чисто технически особо и не проблема, знай себе перехватывай соответствующие запросы, где размер фигурирует (а именно query information, query directory и т.п.), и ставь там что необходимо, плюс реагируй на запросы изменения размера типа set information. Но в твоём случае надо ещё знать, какой размер оригинального файла, иначе просто непонятно, какое значение подставлять. Тут есть несколько вариантов решения проблемы. Например, можно к каждому шифруемому файлу добавлять заголовок в начало, добавлять, разумеется, прозрачно для приложений, ну а в заголовке хранить разную метаинформацию, например, размер оригинального файла, тип шифра, хеши всякие для валидации пароля и пр. Как вариант, можно также сообщать об изменениях в шифрованном файле из драйвера в некое управляющее приложение (службу), которое будет вести базу с метаинформацией о шифрованных файлах, хотя мне это не очень нравится. Этот вопрос уже обсуждался, воспользуйся поиском по форуму.
S>Я искал переменную, которая показывала бы размер файла, который считывается, например length = 64 байта, а после расшифрования присвоить ей реальный размер, там length = 55.
Лолшто? Нет никакой "переменной", которая "показывает" размер файла. Всё несколько сложнее, чем ты думаешь. Смотри, как всё происходит: первое, что необходимо сделать, это выровнять смещение (offset) и размер (length) в PreRead по длине блока твоего блочного шифра, т.е. если это AES, то блок 16 байт, значит и прочитать надо столько байт, сколько кратно 16, покажем на примере — оригинальный файл всего = 31 байт, шифрованный файл всего = 32 байта (выровнен же), приложением запрошено было = 17 байт по смещению = 4 байта, в коде PreRead ты ставишь смещение = 0 байт и длину = 32 байта, далее создаёшь буфер размером 32 байта и сохраняешь его адрес в completion-контексте, отправляешь запрос ниже и ловишь его же в PostRead, здесь у тебя есть всё, что необходимо, ты знаешь размер оригинальных данных и оригинальное смещение (из параметров запроса), у тебя есть буфер с шифрованными данными (swappedBuffer, из контекста), ты смотришь в IoStatus.Information, это кол-во байт, которое вернула тебе ФС, это значение может быть меньше запрошенных тобой 32 байт, но оно точно должно быть кратно 16, иначе можно предположить, что файл повреждён и тогда запрос следует завершить с ошибочным статусом (ну, скажем, STATUS_DATA_ERROR), если же всё в порядке, тогда из расшифрованного буфера ты берёшь 17 байт, начиная с 4-го байта, и копируешь их в буфер приложения (origBuf), в IoStatus.Information ставишь 17 и статус STATUS_SUCCESS. Это самый простой случай из возможных, но допустим приложение хочет прочитать не 17 байт, а 32 байта по смещению 0 (это — нормальная ситуация, приложение не обязано знать размер файла, оно может запросить сколько угодно, а ФС обязана вернуть столько, сколько возможно), но ведь размер файла 31, ты не можешь вернуть больше, а значит в PostRead ты должен знать размер оригинального файла, чтобы вычислить максимальное кол-во байт, которое допустимо вернуть из расшифрованного буфера.
S>И еще в добавок все переменные структур, которые я просматривал, связанные с размером файла по 512 байт.
Забудь про 512, и вообще забудь про размер сектора, оно тебе только на руку, в случае non-cached запроса тебе и размер и смещение придут уже в выровненном виде (по 512 или по 1024 или по 4096 это не важно, всё равно по 16 же), а в худшем случае, когда ничего не выровнено, что делать ты уже знаешь, теперь знаешь.
S>И того сейчас так S>strlen(origBuf) = strlen(swappedBuffer) = 64 байт S>в реале, для нашего примера, должно быть так S>strlen(origBuf) = 55 байт, а strlen(swappedBuffer) = 64 байт S>нужно как-то такое обойти, но не могу найти или придумать что-либо как усечь размер origBuf до нужно нам размера. S>Вообще можно смухлевать в драйвере с размерами файлов?
FLT_CALLBACK_DATA::IoStatus::Information, не?
+ еще надо будет подмухлевывать результаты IRP_MJ_QUERY_INFORMATION дабы EndOfFile возвращать корректный в FILE_STANDARD_INFORMATION. А еще — IRP_MJ_DIRECTORY_CONTROL, потому что в списке файлов в директории тоже размер возвращается. Изменение размера файла делается при помощи IRP_MJ_SET_INFORMATION/FileEndOfFileInformation — уверен вы не хотите чтобы приложения падали, увидев в только что отращенном хвосте файла некий мусор вместо ожидаемых нуликов.
Для затравки хватит, а потом придет x64 и все толком расскажет, если сами к тому времени не нагуглите примеры, которых, я уверен, в инете валом.
Как много веселых ребят, и все делают велосипед...
O>...нагуглите примеры, которых, я уверен, в инете валом.
Вот тут я сомневаюсь, покажите мне примеры полноценных прозрачно шифрующих файловых фильтров, да так, чтобы с подробными комментариями, с учётом всех возможных ситуаций и пр.
Сначала опишу, что я хочу сделать. Допустим у нас на компьютере есть папка E:\Data\Private, где будут лежать секретные файлы, содержащие схемы по отмыванию денег Так как они являются очень секретными, то и просматривать их хочу только я. Т.е. при сохранении файла в эту папку он будет шифроваться, а при чтении расшифровываться.
Решение придумал такое, что есть некое приложение, через которое можно будет открыть эту папку. И в тот момент когда происходит открытие папки, запускался драйвер, который будет перехватывать запросы по чтению/записи к E:\Data\Private.
За основу взял драйвер с WDK: SwapBuffer File System Minifilter Driver. Добавил только возможность пересылать массив символов с драйвера в мое приложение, где собственно будет шифрование/расшифрование данных. Алгоритм шифрования использую AES.
Пару месяцев работы прошли не зря, почти не зря. Я добился того, что бы при записи файлы шифровались, а при чтении расшифровывались. Рассматриваю для начала текстовые файлы. Но столкнулся с такой проблемой.
Повторюсь, у нас уже лежит ранее зашифрованный файл. При его чтении происходит следующее, выделяется буфер размером таким же как этот зашифрованный файл и заполняется этими данными, зашифрованными данными. Он называется swappedBuffer. Создается еще один буфер уже в PostRead, называется origBuf, для расшифрованного содержимого. И у origBuf размер ТАКОЙ ЖЕ как и у swappedBuffer. При этом мы знаем, что размер зашифрованных данных будет вегда больше чем реальных. Это связанно с блоками в AES алгоритме, в моем случае блоки кратны 16 байт. Во время копирования из swappedBuffer в origBuf происходит расшифровка. В итоге в origBuf будет лежать реальный контент файла. НО этот буфер велик для реальных данных и по этому при открытии файла я вижу в конце лишние байты(символы).
Создается origBuf буфер всего одной строчкой кода:
И как так получается, что этот буфер равняется размеру swappedBuffer для меня загадка.
Я искал переменную, которая показывала бы размер файла, который считывается, например length = 64 байта, а после расшифрования присвоить ей реальный размер, там length = 55. Как бы принудительно сказать системе, что там 55 байт, а не 64. Но не находил такого. И еще в добавок все переменные структур, которые я просматривал, связанные с размером файла по 512 байт.
И того сейчас так
strlen(origBuf) = strlen(swappedBuffer) = 64 байт
в реале, для нашего примера, должно быть так
strlen(origBuf) = 55 байт, а strlen(swappedBuffer) = 64 байт
нужно как-то такое обойти, но не могу найти или придумать что-либо как усечь размер origBuf до нужно нам размера.
Вообще можно смухлевать в драйвере с размерами файлов?
Re[3]: Можно ли изменить размер файла в режиме ядра?
Здравствуйте, x64, Вы писали:
O>>...нагуглите примеры, которых, я уверен, в инете валом.
x64>Вот тут я сомневаюсь, покажите мне примеры полноценных прозрачно шифрующих файловых фильтров, да так, чтобы с подробными комментариями, с учётом всех возможных ситуаций и пр.
osr dmk например, но ессно небесплатно
Re[2]: Можно ли изменить размер файла в режиме ядра?
Здравствуйте, x64, Вы писали:
x64>... знай себе перехватывай соответствующие запросы, где размер фигурирует (а именно query information, query directory и т.п.), и ставь там что необходимо, плюс реагируй на запросы изменения размера типа set information.
Спасибо за ответ! Некоторые моменты я понял.
Я просмотрел почти все кейсы в IRP_MJ_QUERY_INFORMATION пакете, т.е. структуры в которых есть поле связанное с размеров файла. И оказалось, что только один кейс проходит — FileStandardInformation, перед открытием файла, в котором поля AllocationSize и EndOfFile структуры FILE_STANDARD_INFORMATION отображают размер файла.
В post-callback делаю так:
Но Вы еще писали, что в IRP_MJ_DIRECTORY_CONTROL пакете тоже где-то указывается размер файла, я все еще не могу найти его. Пробывал по аналогии как в IRP_MJ_QUERY_INFORMATION сделать, ну естественно уже в IRP_MJ_DIRECTORY_CONTROL пакете, что-то типо такого:
switch (Data->Iopb->Parameters.DirectoryControl.QueryDirectory.FileInformationClass)
{
case FileBothDirectoryInformation:
bothDirInfo = (PFILE_BOTH_DIR_INFORMATION)Data->Iopb->Parameters.QueryFileInformation.InfoBuffer;
// print info.break;
case FileDirectoryInformation:
// ...case FileFullDirectoryInformation:
// ...
}
но это успехом не увенчалось. При выводе информации с bothDirInfo выводятся какие-то огромные цифры. Как же тут достучаться до цифры, показывающей размер файла?
И еще один вопрос. Я правильно понимаю, что мне нужно подставить свою цифру(цифру показывающую реальный размер файла после расшифрования) во все поля связанные с размером файла, который хочу открыть, иначе ничего не получится? Так как пробывал EndOfFile из FILE_STANDARD_INFORMATION переписывать, в итоге при открытии файла выводится ошибка: "Not enough storage is available to process this command".
Re[3]: Можно ли изменить размер файла в режиме ядра?
S>И оказалось, что только один кейс проходит — FileStandardInformation...
Нужно обрабатывать все.
Про FileAllInformation не забыл?
S>case FileStandardInformation: S>standardInfo = (PFILE_STANDARD_INFORMATION)Data->Iopb->Parameters.QueryFileInformation.InfoBuffer; S>// print info. S>break;
А где обработка?
S>...я все еще не могу найти его.
Обрати внимание на "QueryFileInformation", не тупи.
S>Пробывал...
Пожалуйста, не надо пробывать.
S>...по аналогии как в IRP_MJ_QUERY_INFORMATION сделать, ну естественно уже в IRP_MJ_DIRECTORY_CONTROL пакете, что-то типо такого:
Да где обработка-то?
S>При выводе информации с bothDirInfo выводятся какие-то огромные цифры.
Это в PostQueryDirectory, разумеется. Ну и результат операции-то проверить не забудем, т.е. если в IoStatus.Status не STATUS_SUCCESS и не STATUS_BUFFER_OVERFLOW, то данных просто нет, подменять нечего. Кроме того, в выходном буфере может находиться несколько записей, тебе нужно найти свою (по имени файла, например, или по ID или ещё как), нельзя подменять первую же попавшуюся, которая по адресу в поле .DirectoryBuffer.
S>...иначе ничего не получится?
В общем случае — да, ты правильно понимаешь. В частном случае, когда приложение не интересуется размером файла, а просто тупо читает сколько есть, эти манипуляции не нужны. Но мы ведь не халтурим, да?
S>Так как пробывал...
Пожалуйста...
S>...EndOfFile из FILE_STANDARD_INFORMATION переписывать, в итоге при открытии файла выводится ошибка: "Not enough storage is available to process this command".
Для начала, исправь грубейшую ошибку в коде, на которую я указал выше. А вообще, конечно, не видя полного исходника и не зная ничего конкретного о ситуации, сказать тут что-либо осмысленное проблематично. Я могу посоветовать только взять Process Monitor и нацелить его на конкретное приложение, в котором возникает данная проблема. Настроив правильно фильтры (и символы, чтобы стеки разглядывать), ты увидишь операцию, на которой произошёл сбой, это даст тебе дополнительную пищу для размышлений. Судя по возникшей ошибке, я могу лишь предположить, что произошло примерно следующее: ты некорректно подменил значение поля EndOfFile, в результате чего оно оказалось настолько большим, что приложение не смогло выделить столько памяти и/или создать секцию такого размера.
JID: x64j@jabber.ru
Re[4]: Можно ли изменить размер файла в режиме ядра?
GetDecryptedFileSize — возвращает оригинальный размер файла, который ранее был записан в хедер.
Это работает, для текстовых файлов вполне все ок. Т.е. открывается то количество байт, которое ранее было присвоено EndOfFile. Но Вы еще писали о том, что нужно в IRP_MJ_DIRECTORY_CONTROL тоже изменить значение в нужной записи:
x64>в выходном буфере может находиться несколько записей, тебе нужно найти свою...
Тут у меня и возникла проблема. В Post процедуре делаю так:
Я специально оставил только один файл в нужной мне папке. FileName показывает название нужного файла, а вот AllocSize и EndOfFile показывает либо 0, либо огромные числа.
Вот тут нужна подсказка, как правильно обработать кейс в таком случае?
Re[5]: Можно ли изменить размер файла в режиме ядра?
S>Я специально оставил только один файл в нужной мне папке. FileName показывает название нужного файла, а вот AllocSize и EndOfFile показывает либо 0, либо огромные числа.
Ты поди буфер-то подменил в PreQueryDirectory, да? А в поле DirectoryBuffer буфер приходит всегда оригинальный, в минифильтрах вообще все параметры в completion routine приходят оригинальные (читать внимательно комментарии в коде), и если моё предположение верно, то в оригинальный буфер тупо ничего не записалось, а записалось всё в твой буфер, там и ищи данные. Решение простое: не надо подменять буфер в PreQueryDirectory, потому что в сэмпле это делается в демонстрационных целях исключительно, никакой реальной необходимости у тебя в этом нет.
S>Вот тут нужна подсказка...
Здравствуйте, Suares, Вы писали:
S>Сначала опишу, что я хочу сделать. Допустим у нас на компьютере есть папка E:\Data\Private, где будут лежать секретные файлы, содержащие схемы по отмыванию денег Так как они являются очень секретными, то и просматривать их хочу только я. Т.е. при сохранении файла в эту папку он будет шифроваться, а при чтении расшифровываться.
S>Решение придумал такое, что есть некое приложение, через которое можно будет открыть эту папку. И в тот момент когда происходит открытие папки, запускался драйвер, который будет перехватывать запросы по чтению/записи к E:\Data\Private.
S>За основу взял драйвер с WDK: SwapBuffer File System Minifilter Driver. Добавил только возможность пересылать массив символов с драйвера в мое приложение, где собственно будет шифрование/расшифрование данных. Алгоритм шифрования использую AES.
А почему нельзя взять старый добрый TrueCrypt или что там принято вместо него сейчас использовать? Мне кажется вы изобретаете велосипед. Хотя поковыряться, если есть время в такие вещах очень интересно