Задание звучит следующим образом:
Необходимо реализовать программное средство, которое осуществляет шифрование файлов в заданной директории. Файлы в зашифрованном состоянии должны находиться на жестком диске, а при обращении к ним сторонних программ (notepad, Total Commander, Visual Studio, и т.д.) должна выполняться проверка доступности файла для данной программы. Если программа имеет разрешение на просмотр файла – то произвести расшифровку файла и передать открытое содержимое вызывающей программе; если программа не имеет разрешения – то передать зашифрованное содержимое файла. При добавлении файла в директорию автоматически должно производиться его шифрование.
Программное средство должно быть реализовано в виде драйвера, функционирующий в режиме ядра. Программное средство должно функционировать на 64-разрядной версии операционной системы Microsoft Windows 10. Имя и путь к директории задается на ваш выбор в коде драйвера. Список программ, имеющих разрешение на доступ к файлам, задается на ваш выбор.
Кто может подсказать каким образом это можно реализовать? Что нужно знать для этого? Что почитать?
Сам лично я никогда не писал драйвера, и понятия не имею с чего начать.
Я писал такую программу под Windows 95 на C++. Читать и знать надо очень много. Во-первых, нужно DDK, во-вторых, они меняются под каждую версию ОС, и программу приходится переписывать (во всяком случае, тогда пришлось переписывать под Windows XP), в-третьих, не знаю как сейчас, но тогда DDK не содержал подобных примеров, это издавалось отдельно с запретом поставки к нам, и пришлось нужное украсть, благо я работал в ФАПСИ. Так что начните со скачивания DDK, и попробуйте там найти подходящий пример. Если хотите, выложу наш код драйвера под Windows 95.
Вот что нужно знать в первую очередь, а раньше было "труднодоступно", чтобы писать драйверы уровня кернеля ноль для работы с файловой системой:
//
// undocumented ntoskrnl variable
//
extern PSHORT NtBuildNumber;
//
// NT Final Build number
//
#define NT4FINAL 1381
typedef struct _FILE_RENAME_INFORMATION {
BOOLEAN ReplaceIfExists;
HANDLE RootDirectory;
ULONG FileNameLength;
WCHAR FileName[1];
} FILE_RENAME_INFORMATION, *PFILE_RENAME_INFORMATION;
typedef struct _FILE_NAME_INFORMATION {
ULONG FileNameLength;
WCHAR FileName[1];
} FILE_NAME_INFORMATION, *PFILE_NAME_INFORMATION;
// Using NTREGMON-type "hooking" on ZwCreateFile;
// ObReferenceObjectByHandle, System WORKITEMS;
// ObOpenObjectByPointer and ZwReadFile I finally have a solution that
// appears stable.
NTKERNELAPI
NTSTATUS
ObOpenObjectByPointer(
IN PVOID Object,
IN ULONG HandleAttributes,
IN PACCESS_STATE PassedAccessState OPTIONAL,
IN ACCESS_MASK DesiredAccess OPTIONAL,
IN POBJECT_TYPE ObjectType OPTIONAL,
IN KPROCESSOR_MODE AccessMode,
OUT PHANDLE Handle
);
// There are two steps in getting the threads context. First you
// must get a handle to the thread via PsGetCurrentThread() or
// KeGetCurrentThread(). After you get the handle to the thread,
// you must call the following function:
NTSYSAPI NTSTATUS NTAPI ZwGetContextThread
(
IN HANDLE ThreadHandle,
IN OUT PCONTEXT ThreadContext
);
// Remember, when creating the thread, you must specify an access
// type of THREAD_GET_CONTEXT in order to read the context information
// from the thread.
NTSYSAPI
NTSTATUS
NTAPI
ZwOpenFile( OUT PHANDLE FileHandle,
IN ACCESS_MASK DesiredAccess,
IN POBJECT_ATTRIBUTES ObjectAttributes,
IN PIO_STATUS_BLOCK IoStatusBlock,
IN ULONG ShareAccess,
IN ULONG CreateOptions );
NTSYSAPI
VOID
NTAPI
HalDisplayString( PCHAR String );
NTKERNELAPI
NTSTATUS
IoQueryFileInformation(
IN PFILE_OBJECT FileObject,
IN FILE_INFORMATION_CLASS FileInformationClass,
IN ULONG Length,
OUT PVOID FileInformation,
OUT PULONG ReturnedLength
);
NTSYSAPI // preliminary guess
NTSTATUS
NTAPI
ZwQueryVolumeInformationFile(
IN HANDLE FileHandle,
OUT PIO_STATUS_BLOCK IoStatusBlock,
OUT PVOID FsInformation,
IN ULONG Length,
IN FS_INFORMATION_CLASS FsInformationClass
);
NTKERNELAPI // preliminary guess
NTSTATUS
IoQueryFileVolumeInformation(
IN PFILE_OBJECT FileObject,
IN FS_INFORMATION_CLASS FsInformationClass,
IN ULONG Length,
OUT PVOID FsInformation,
OUT PULONG ReturnedLength
);
NTSTATUS
ZwOpenDirectoryObject( OUT PHANDLE DirectoryHandle,
IN ULONG DesiredAccess,
IN POBJECT_ATTRIBUTES ObjectAttributes );
NTSTATUS
ZwOpenSymbolicLinkObject( OUT PHANDLE SymbolicLinkHandle,
IN ULONG DesiredAccess,
IN POBJECT_ATTRIBUTES ObjectAttributes );
NTSTATUS
ZwQuerySymbolicLinkObject( IN HANDLE SymbolicLinkHandle,
OUT PUNICODE_STRING ReturnedString,
OUT PULONG ReturnedLength );
NTSYSAPI
NTSTATUS
NTAPI
ZwCreateSection( OUT PHANDLE SectionHandle,
IN ACCESS_MASK DesiredAccess,
IN POBJECT_ATTRIBUTES ObjectAttributes, // Optional
IN PLARGE_INTEGER MaximumSize, // Optional
IN ULONG SectionPageProtection,
IN ULONG AllocationAttributes,
IN HANDLE FileHandle ); // Optional
//
// Parameters:
// SectionHandle if routine succeeds, you get back a section handle
// in this argument. If you want to use the section
// object in the context of some other process, use the
// ObReferenceObjectByHandle() and ObOpenObjectByPointer()
// combination to do so ...
//
// DesiredAccess set this to one of SECTION_MAP_EXECUTE, ...MAP_READ, or
// ..._MAP_WRITE
//
// ObjectAttributes - NULL, or use
// InitializeObjectAttributes() macro to initialize this.
// Use this to create a named section object if you wish
// to share it with user mode process.
//
// MaximumSize Must be non-NULL for a page-file backed section. If value
// specified for a mapped file and the file is not large enough,
// file will be extended. NOTE: this is a POINTER to a large int.
//
// SectionPageProtection use from PAGE_READONLY, READWRITE, ...WRITEONLY,
// and/or WRITECOPY.
//
// AllocationAttributes use SEC_IMAGE (executable only), SEC_FILE (for
// mapping in a data file), SEC_RESERVE, SEC_COMMIT.
// NOTE: These defines are ONLY in the "winnt.h" file as part
// of the SDK!!!
//
// FileHandle optional, BUT you must supply if you wish to map in a data
// file. Else VMM will create a section object backed by a
// page file.
//
//
// CcCanIWrite()
//
BOOLEAN
CcCanIWrite (
IN PFILE_OBJECT FileObject,
IN ULONG BytesToWrite,
IN BOOLEAN Wait,
IN BOOLEAN Retrying
);
//
// Resource Acquisition Constraints:
//
// If Wait is TRUE, the file system should ensure that no resources
// have been acquired. Else, the caller can choose the have the FCB
// resources unowned, acquired shared or exclusively.
//
// Parameters:
//
// FileObject Pointer to the file object structure representing
// the open operation performed by the thread.
//
// BytesToWrite Number of bytes to be modified.
//
// Wait This argument is used by the Cache Manager to determine
// whether the caller is prepared to wait in the routine
// until it is acceptable for the caller to be allowed
// to perform the write operation.
//
// Retrying The file system may have to keep requesting permission
// to proceed with a write operation (if Wait is supplied
// as FALSE), until it is allowed to do so. This argument
// allows the file system to notify the Cache Manager
// whether it had previously requested permission for the
// same write request (or if the current instance was the
// first time permission was being requested for the specific
// write operation).
//
// Functionality Provided:
//
// This routine is part of a group of routines that allow the file system
// to defer executing a write request until it is appropriate to do so.
// A number of reasons may make executing a write operation immediately,
// unattractive. They include the following:
//
// - The file system may wish to restrict the number of dirty pages
// outstanding per file stream at any given instance in time. This allows
// the file system to ensure that cached data for other file streams does
// not get discarded to make space for data belonging to a single file stream.
// Such a situation may arise if some process kept modifying data for a
// specific file stream at a very fast rate.
//
// - The Cache Manager tries to keep the total number of modified pages
// for all files that have their data cached. within a certain limit.
// This helps ensure that sufficient number of free pages are available
// for other purposes including memory for loading executable files,
// memory-mapped files, and memory for other system components.
//
// - The Virtual Memory Manager sets certain limits on the maximum number
// of dirty pages within the system (based upon the total amount of physical
// memory present on the system). If the write operation causes the limit
// to be exceeded, the VMM would prefer that the write be deferred until
// the modified page writer has flushed some of the existing dirty data to disk.
//
// In order to assist the Cache Manager and the Virtual Memory Manager in
// managing physical memory optimally, the file system driver can use
// the CcCanIWrite() routine to determine whether the current write operation
// should be allowed to proceed. Use of this routine is optional.
//
// The Wait argument allows the file system to specify whether the thread
// can be blocked until the write can be allowed to proceed. If Wait is
// FALSE and the write operation should be deferred, the routine returns FALSE.
// The file system can then determine an appropriate course of action - this
// might be to postpone the operation using the CcDeferWrite() routine described
// next in this section. Setting WAIT to TRUE causes the Cache Manager to block
// the current thread (by putting it to sleep) until the write can be allowed
// to proceed. Of course, the file system should ensure that no resources are
// acquired by the thread since this may lead to a system deadlock.
//
// The Retrying argument allows a file system to notify the Cache Manager
// whether permission is being requested (for the same write request) either
// for the first time, or whether such permission had been requested (and
// denied) at least once before. If set to TRUE, the Cache Manager assigns a
// slightly higher priority to the current request while determining whether
// it should be allowed to proceed or not (e.g. if two write requests are
// pending and one of them is being retried, the Cache Manager will try its
// best to allow the one being retried to proceed first. Note however, that
// there are no guarantees to ensure that the one being retried will indeed
// be allowed to proceed before the one not being retried).
//
// Conceptually, the functionality provided by the Cache Manager in this
// routine is fairly simple and is as follows:
//
// - First, check whether the current write operation can proceed based
// upon different criteria. These criteria include (among others): checking
// whether the outstanding number of dirty pages associated with a file
// stream have been exceeded, whether the total number of dirty pages
// in the system cache have exceeded some limit, or whether the Virtual
// Memory Manager might wish to block this write for some time until
// enough unmodified pages are available in the system.
//
// - If the write operation can proceed, return TRUE.
//
// - Else, if Wait is set to TRUE, put the current thread to sleep until
// the write operation can be allowed to proceed. Once the thread is woken
// from the sleep, return TRUE. However, if Wait is FALSE, return FALSE
// immediately.
//
typedef
VOID (*PCC_POST_DEFERRED_WRITE) (
IN PVOID Context1,
IN PVOID Context2
);
//
// CcDeferWrite()
//
VOID
CcDeferWrite (
IN PFILE_OBJECT FileObject,
IN PCC_POST_DEFERRED_WRITE PostRoutine,
IN PVOID Context1,
IN PVOID Context2,
IN ULONG BytesToWrite,
IN BOOLEAN Retrying
);
//
// Resource Acquisition Constraints:
//
// No resources should be acquired before invoking this routine.
//
// Parameters:
//
// FileObject Pointer to the file object structure representing
// the open operation performed by the thread.
//
// PostRoutine The routine to be invoked whenever it is appropriate
// for the current write request to proceed. Typically,
// this is a recursive call into the file system write
// routine.
//
// Context1 & Context2 These are arguments that the PostRoutine will
// accept (when invoked). Typically, if the post
// routine is the same as the generic write routine,
// these arguments are the DeviceObject and the Irp
// (for the current request).
//
// BytesToWrite Number of bytes being modified.
//
// Retrying Allows the file system to specify whether the check
// (should the write be allowed to proceed ?) is being
// performed for the first time - or has already been
// performed before.
//
// Functionality Provided:
//
// This routine is part of a group of routines that allow the file system
// to defer executing a write request until it is appropriate to do so.
// As discussed above, the CcCanIWrite() routine allows a file system driver
// to query the Cache Manager whether the current write request should be
// allowed to proceed immediately. If the CcCanIWrite() routine returns FALSE,
// the file system can utilize the CcDeferWrite() routine to queue up the
// write until it is appropriate for the write to proceed.
//
// The PostRoutine argument allows the file system to specify the routine
// that will perform the actual write operation when invoked. It is quite
// possible that the Cache Manager might chose to invoke the post routine
// immediately (in the context of the thread invoking the CcDeferWrite()
// routine). Typically however, the post routine is invoked asynchronously
// whenever sufficient number of dirty pages have been flushed to disk and
// the Cache Manager and Virtual Memory Manager feel more comfortable with
// allowing the particular write operation to proceed.
//
возник вопрос: Возможно ли сжать видеофайлы или видеопоток? Пытался использовать lz4 для сжатия данных, сначала использовал этот метод сжатия...
Пишу алгоритм бинарной сортировки (в целях обучения)Компилятор - MinGW-w64 с флагом оптимизации -o0