Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Архив1 / docx53 / Отчет №4

.docx
Скачиваний:
23
Добавлен:
01.08.2013
Размер:
281.19 Кб
Скачать

Санкт-Петербургский государственный политехнический университет

Факультет технической кибернетики

Кафедра Компьютерные системы и программные технологии

Отчёт по лабораторной работе №4

Дисциплина: "Системное программное обеспечение"

Тема: Аудит объекта системы.

Выполнил студент гр. 5081/13 Залеский А. А.

Преподаватель __________ Душутина Е. В.

\

  1. Введение

Формулировка моего задания включает слово «Аудит», дадим определение этому понятию. Аудит — процесс записи информации о происходящих с каким-то объектом (или в рамках какого-то процесса) событиях в журнал (например, в файл). Таким образом в задании требуется записывать информацию о событиях с объектом. Решение проблемы я начал с обзора продуктов, позволяющих вести аудит файлов в системе.

  1. Обзор продуктов.

Интернет пестрит всевозможными программами для аудита файлов. Многие из них бесплатны, но некоторые бывают и платными. Приведу список самых популярных, на мой взгляд, программных продуктов: ChangeAuditor for Windows, File Servers, NetWrix Change Reporter Suite, Blackbird Auditor for File System,ADAudit Plus, CPTRAX for Windows, FileSure for Windows, File Audit. Есть и другие, но эти мне показались наиболее интересными. Рассмотрю же я всего один, последний. Программа File Audit абсолютно бесплатна, но, как и следовало ожидать, закрытым кодом. Внутри она предоставляет довольно скромный и очень понятный интерфейс:

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

  1. Своя реализация аудита папки.

Функция, позволяющая вести аудит всех файлов в каком-либо катологе называется ReadDirectoryChangesW(). Ниже представлено описание полей, которые она принимает:

_In_         HANDLE hDirectory, - сама директория, в которой ведется аудит

_Out_        LPVOID lpBuffer, - буфер, куда записывается информация аудита

_In_         DWORD nBufferLength, - длина этого буфера

_In_         BOOL bWatchSubtree, - флаг, указывающий нужно ли смотреть подкаталоги диектории, указанной в hDirectory

_In_         DWORD dwNotifyFilter, - тут описываются все действия, которые нужно подвергать аудиту: Запись,изменение имени, создание, удаление и т.д.

_Out_opt_    LPDWORD lpBytesReturned, - размер буфера для синхронной записи

_Inout_opt_  LPOVERLAPPED lpOverlapped, - структура, хранящая данные во время асинхронной записи

_In_opt_     LPOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine – структура необходимая при отмене аудита извне.

Как видно, все параметры, доступные в программе Audit File задаются программно в этой функции. Мной была написана программа, позволяющая отслеживать тот же функционал что и рассмотренная программа.

#define UNICODE

#include <Windows.h>

#include <stdio.h>

#include <stdlib.h>

static PCSTR GetActionName(DWORD Action)

{

static const PCSTR Actions[] = { //Возможные действия с файлом

"0",

"FILE_ACTION_ADDED", // файл добавлен

"FILE_ACTION_REMOVED", // файл удален

"FILE_ACTION_MODIFIED", // файл изменен

"FILE_ACTION_RENAMED_OLD_NAME", // файл переименован из этого имени

"FILE_ACTION_RENAMED_NEW_NAME" // файл переименован в это имя

};

static CHAR Buffer[16];

if (Action >= RTL_NUMBER_OF(Actions)) {

sprintf(Buffer, "%lu", Action);

return Buffer;

}

return Actions[Action];

}

int process(void) {

WCHAR DirectoryName[MAX_PATH];

HANDLE DirectoryHandle;

OVERLAPPED Overlapped = { 0 };

FILE_NOTIFY_INFORMATION *FileNotifyInformation;

PVOID FileNotifyInformationBuffer;

DWORD FileNotifyInformationSize;

DWORD BytesReturned;

BOOL Ret;

if (!GetCurrentDirectory(RTL_NUMBER_OF(DirectoryName), DirectoryName)) { // Получаем текущую директорию, в которой расположена программа

fprintf(stderr, "GetCurrentDirectory failed with %lu\n", GetLastError());

return EXIT_FAILURE;

}

DirectoryHandle = CreateFile(DirectoryName, // Узнаем хэндл текущей директории.

FILE_LIST_DIRECTORY,

FILE_SHARE_READ | FILE_SHARE_WRITE,

NULL,

OPEN_EXISTING,

FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED,

NULL);

if (DirectoryHandle == INVALID_HANDLE_VALUE) {

fprintf(stderr, "CreateFile failed with %lu\n", GetLastError());

return EXIT_FAILURE;

}

Overlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); // Создаем обработчик событий

if (Overlapped.hEvent == NULL) {

fprintf(stderr, "CreateEvent failed with %lu\n", GetLastError());

CloseHandle(DirectoryHandle);

return EXIT_FAILURE;

}

FileNotifyInformationSize = 2 * FIELD_OFFSET(FILE_NOTIFY_INFORMATION,FileName[MAX_PATH]); // создаем необходимые поля для функции ReadDirectoryChangesW

FileNotifyInformationBuffer = HeapAlloc(GetProcessHeap(),0,FileNotifyInformationSize); // создаем необходимые поля для функции ReadDirectoryChangesW

if (FileNotifyInformationBuffer == NULL) {

fprintf(stderr, "Failed to allocate %lu bytes\n", FileNotifyInformationSize);

CloseHandle(Overlapped.hEvent);

CloseHandle(DirectoryHandle);

return EXIT_FAILURE;

}

printf("Watching directory '%ls' for changes...\n", DirectoryName);

while (1) { // Бесконечный цикл, потому что остановка программы должна происходить пользователем извне

Ret = ReadDirectoryChangesW(DirectoryHandle, // Создаем листенер изменений в директории, который отлавливает все возможные действия с файлами в каталоге и всех подкаталогах. Делает он это асинхронно.

FileNotifyInformationBuffer,

FileNotifyInformationSize,

TRUE,

FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_SIZE | FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_LAST_ACCESS

| FILE_NOTIFY_CHANGE_CREATION | FILE_NOTIFY_CHANGE_SECURITY | FILE_NOTIFY_CHANGE_ATTRIBUTES,

NULL,

&Overlapped,

NULL);

if (!Ret) {

fprintf(stderr, "ReadDirectoryChangesW failed with %lu\n", GetLastError());

HeapFree(GetProcessHeap(), 0, FileNotifyInformationBuffer);

CloseHandle(Overlapped.hEvent);

CloseHandle(DirectoryHandle);

return EXIT_FAILURE;

}

Ret = GetOverlappedResult(DirectoryHandle, // Ожидаем событий, порождаемых изменением в директории

&Overlapped,

&BytesReturned,

TRUE);

if (!Ret) {

fprintf(stderr, "GetOverlappedResult failed with %lu\n", GetLastError());

HeapFree(GetProcessHeap(), 0, FileNotifyInformationBuffer);

CloseHandle(Overlapped.hEvent);

CloseHandle(DirectoryHandle);

return EXIT_FAILURE;

}

FileNotifyInformation = (FILE_NOTIFY_INFORMATION *)FileNotifyInformationBuffer;

BytesReturned = min(BytesReturned, FileNotifyInformationSize);

while (BytesReturned >= RTL_SIZEOF_THROUGH_FIELD(FILE_NOTIFY_INFORMATION, FileNameLength) &&

BytesReturned >= FIELD_OFFSET(FILE_NOTIFY_INFORMATION, FileName[FileNotifyInformation->FileNameLength / sizeof(WCHAR)])) { // При получении события, обрабатываем сообщение о совершенном событии. Извлекаем из структуры FileNotifyInformation имя файла, с которым связано действие и само совершенное действие

printf("File '%.*ls' has seen an action of type %s\n",

(int)FileNotifyInformation->FileNameLength / sizeof(WCHAR),

FileNotifyInformation->FileName,

GetActionName(FileNotifyInformation->Action));

if (FileNotifyInformation->NextEntryOffset == 0)

break;

if (BytesReturned < FileNotifyInformation->NextEntryOffset)

break;

BytesReturned -= FileNotifyInformation->NextEntryOffset; // Если событие произошло не одно, то обрабатываем всю очередь.

FileNotifyInformation = (FILE_NOTIFY_INFORMATION *)((ULONG_PTR)FileNotifyInformation + FileNotifyInformation->NextEntryOffset);

}

ZeroMemory(&Overlapped, FIELD_OFFSET(OVERLAPPED, hEvent));

ResetEvent(Overlapped.hEvent);

}

HeapFree(GetProcessHeap(), 0, FileNotifyInformationBuffer);

CloseHandle(Overlapped.hEvent);

CloseHandle(DirectoryHandle);

return EXIT_SUCCESS;

}

void main(int argc, TCHAR *argv[]){

int result = process();

int a;

scanf_s("%d", &a);

}

Программа отображает в консоли все действия в указанной директории:

Так как при создании файл имеет имя «Новый файл», то операция создания не отобразилась до конца(Видно лишь начало строки “File ` “) – не подключал русские символы в консоли.

  1. Аудит файлов с помощью Windows

Как бы хорошо и быстро ни работал описанный выше метод, он имеет два огромных недостатка: 1) Программа способна собирать информацию об аудите лишь тогда, когда включена. 2) Программа не может отследить открытие и закрытие файла, а так же его копирование в другое место. В связи с этим, я попробовал зайти с другого конца – через встроенную в систему windows возможность аудита файлов. Каждый файл в windows кроме своего содержания хранит еще важную информацию для обеспечения безопастности. Устройство это информации показано на рисунке. Меня интересуют последние два поля – указатель на DACL и SACL. Разберемся что это такое. Список управления избирательным доступом (discretionary access-control list, DACL)Указывает, кто может получать доступ к объекту и какие виды доступа. Системный список управления доступом (system access-control list, SACL) Указывает, какие операции и каких пользователей должны регистрироваться в журнале аудита безопасности. Эти понятия объединяются общим термином ACL. Список управления доступом(access-control list, ACL) состоит из заголовка и может содержать элементы (access-control entries, АСЕ). B DACL каждый ACE содержит SID и маску доступа (а также набор флагов), причем ACE могут быть четырех типов: «доступ разрешен» (access allowed), «доступ отклонен» (access denied), «разрешенный объект» (allowed-object) и «запрещенный объект» (denied-object). Первый тип ACE разрешает пользователю доступ к объекту, а второй – отказывает в предоставлении прав, указанных в маске доступа.

    Разница между ACE типа «разрешенный объект» и «доступ разрешен», а также между ACE типа «запрещенный объект» и «доступ отклонен» заключается в том, что эти типы используются только в Active Directory. ACE этих типов имеют поле глобально уникального идентификатора (globally unique identifier, GUID), которое сообщает, что данный ACE применим только к определенным объектам или под объектам (с GUID-идентификаторами). Кроме того, необязательный GUID указывает, что тип дочернего объекта наследует ACE при его (объекта) создании в контейнере Active Directory, к которому применен АСЕ. (GUID – это гарантированно уникальный 128-битный идентификатор.)

    За счет аккумуляции прав доступа, сопоставленных с индивидуальными АСЕ, формируется набор прав, предоставляемых ACL-списком. Если в дескрипторе защиты нет DACL (DACL = null), любой пользователь получает полный доступ к объекту. Если DACL пуст (т. е. в нем нет АСЕ), доступа к объекту не получает никто.

 SACL состоит из ACE двух типов: системного аудита (system audit ACE) и объекта системного аудита (system audit-object АСЕ). Эти ACE определяют, какие операции, выполняемые над объектами конкретными пользователями или группами, подлежат аудиту. Информация аудита хранится в системном журнале аудита. Аудиту могут подлежать как успешные, так и неудачные операции. Как и специфические для объектов ACE из DACL, ACE объектов системного аудита содержат GUID, указывающий типы объектов или под-объектов, к которым применим данный АСЕ, и необязательный GUID, контролирующий передачу ACE дочерним объектам конкретных типов. При SACL, равном null, аудит объекта не ведется. Флаги наследования, применимые к DACL АСЕ, применимы к ACE системного аудита и объектов системного аудита.

Разобравшись как устроен аудит файлов с помощью встроенных в windows опций, я начал искать как их можно включить. На сайте MSDN приводится подробная инструкция включения аудита у файла с помощью GUI windows:

Включение аудита доступа пользователей к файлам, папкам и принтерам:

  • Информационные записи системного аудита заносятся в журнал событий "Безопасность". Для включения системного аудита выполните следующие действия: В меню "Пуск" выберите пункт "Панель управления", щелкните по ссылке "Производительность и обслуживание" и откройте группу программ "Администрирование".

  • Откройте элемент "Локальная политика безопасности".

  • Разверните элемент "Локальные политики".

  • Выберите папку "Политика аудита".

  • Двойным щелчком мыши откройте параметр "Аудит доступа к объектам".

  • Для отслеживания удачных попыток доступа к файлам, папкам и принтерам установите флажок "Успех".

  • Для отслеживания неудачных попыток доступа к файлам, папкам и принтерам установите флажок "Отказ".

  • Для отслеживания всех попыток доступа к объектам аудита установите оба флажка.

  • Нажмите кнопку "ОК".

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

  1. Программная реализация включения/выключения аудита windows.

Что бы в системе можно было включить аудит файла, необходимо в политике безопасности включить соответствующую привилегию. Это можно сделать вручную, запустив «Локальные параметры безопасности» из меню «Администрирование». Выбрать «Локальные политики» → «Политики Аудита» и поставив в «параметре безопасности» Успех/Отказ. Можно так же это сделать и программно, использовав функцию LsaSetInformationPolicy().

NTSTATUS LsaSetInformationPolicy(

_In_  LSA_HANDLE PolicyHandle, - Хендл текущей политики безопастности. Берется из функции LsaOpenPolicy().

_In_  POLICY_INFORMATION_CLASS InformationClass, - Определяет один класс локальной политики, для которого нужно изменить параметр безопасности. В моем случае он равен PolicyAuditEventsInformation

_In_  PVOID Buffer – буфер, в который определенным образом записываются данные, о том какие из политик аудита включить.

);

#include "stdafx.h"

#include <Windows.h>

#include <stdio.h>

#include <ntsecapi.h>

#pragma hdrstop

int IsAuditOn( BOOL forceAuditOn )

{

int rc = 0;

POLICY_ACCOUNT_DOMAIN_INFO *ppadi = NULL;

SECURITY_QUALITY_OF_SERVICE sqos;

LSA_OBJECT_ATTRIBUTES lsaOA;

LSA_HANDLE polHandle;

NTSTATUS nts;

sqos.Length = sizeof(SECURITY_QUALITY_OF_SERVICE);

sqos.ImpersonationLevel = SecurityImpersonation;

sqos.ContextTrackingMode = SECURITY_DYNAMIC_TRACKING;

sqos.EffectiveOnly = FALSE;

lsaOA.Length = sizeof(LSA_OBJECT_ATTRIBUTES); //формируем структуру доступа к политике безопасности

lsaOA.RootDirectory = NULL;

lsaOA.ObjectName = NULL;

lsaOA.Attributes = 0;

lsaOA.SecurityDescriptor = NULL;

lsaOA.SecurityQualityOfService = &sqos;

nts = LsaOpenPolicy( возвращает хендл, указывающий на структуру политики безопасности windows на текущем компьютере.

NULL, // NULL = current machine.

&lsaOA,

POLICY_VIEW_LOCAL_INFORMATION | GENERIC_READ | GENERIC_EXECUTE |

POLICY_ALL_ACCESS,

&polHandle);

if (nts != 0) return -1;

nts = LsaQueryInformationPolicy( //По полученному хэндлу, получаем саму структуру политики безопасности, записываемую в ppadi

polHandle,

PolicyAuditEventsInformation,

(PVOID*) &ppadi);

if (nts != 0) return -1;

if ( forceAuditOn )

{

// Устанавливаем все нужные политики в положение enable.

ppadi->DomainName.Buffer[0] = 3; // restart_shutdown_and_system

ppadi->DomainName.Buffer[2] = 3; // logon_and_logoff

ppadi->DomainName.Buffer[4] = 3; // file_and_object_access

ppadi->DomainName.Buffer[6] = 3; // use_of_user_rights

ppadi->DomainName.Buffer[8] = 3; // process_tracking

ppadi->DomainName.Buffer[10] = 3; // security_policy_changes

ppadi->DomainName.Buffer[12] = 3; // user_and_group_management

ppadi->DomainName.Length = 1;

nts = LsaSetInformationPolicy( // Устанавливаем обновленную политику безопасности

polHandle,

PolicyAuditEventsInformation,

ppadi);

if (nts != 0) return -1;

rc = 1;

}

LsaFreeMemory(polHandle); //Освобождаем память

return rc;

}

int _tmain(int argc, _TCHAR* argv[])

{

int rc;

rc = IsAuditOn( TRUE );

if ( rc == 1 )

puts( "Auditing has been enabled." );

else if ( rc == 0 )

puts( "The audit state is unchanged." );

else

puts( "Oops!" );

return 0;

}

После того, как включена возможность записи аудита в журнал безопастности. осталось лишь включить аудит какого-либо файла. Однако сделать это не так просто. Для начала нужно получить все данные о файле(security information), включая SID владельца, DACL , SACL и прочую информацию. Делается это с помощью функции GetNamedSecurityInfo()

DWORD WINAPI GetNamedSecurityInfo(

_In_       LPTSTR pObjectName, - путь до объекта.

_In_       SE_OBJECT_TYPE ObjectType, - тип объекта. В нашем случае объект может быть любым, поэтому определяем его тип функцией DetermineObjectTypeFromPath

_In_       SECURITY_INFORMATION SecurityInfo, - набор бит, определяющий какую именно информацию нам необходимо получить

_Out_opt_  PSID *ppsidOwner, - SID владельца объекта

_Out_opt_  PSID *ppsidGroup, - SID группы объекта

_Out_opt_  PACL *ppDacl, - Указатель на структуру DACL

_Out_opt_  PACL *ppSacl, - Указатель на структуру SACL

_Out_opt_  PSECURITY_DESCRIPTOR *ppSecurityDescriptor – указатель на всю структуру security information, включающей все прошлые пункты.

);

После того, как мы получили security information о объекте, нужно вычленить старый SACL объекта, что бы к нему приписать новое ACE. Получается от с помощью функции GetAclInformation()

BOOL WINAPI GetAclInformation(

_In_   PACL pAcl, - Указатель на структуру SACL из GetNamedSecurityInfo

_Out_  LPVOID pAclInformation, - буфер, куда будет помещена информация

_In_   DWORD nAclInformationLength, - длина буфера

_In_   ACL_INFORMATION_CLASS dwAclInformationClass – определяет вид получения данных. Может принимать всего 2 варианта, в моем случае, AclSizeInformation

);

Затем определяем новый SACL с помощбю функции InitializeAcl()

BOOL WINAPI InitializeAcl(

_Out_  PACL pAcl, - указатель на созданную структуру

_In_   DWORD nAclLength, - размер буфера для новой структуры

_In_   DWORD dwAclRevision – уровень ревизии

);

Теперь добавляем к созданной структуре SACL все старые ACE из полученного ранее старого SACL( функция GetAce() ) А так же новый ACE. Функция добавления ACE: AddAce()

(Разберу одну, потому что они очень похожи)

BOOL WINAPI AddAce(

_Inout_  PACL pAcl, - указатель на созданную структуру

_In_     DWORD dwAceRevision, - уровень ревизии

_In_     DWORD dwStartingAceIndex, - позиция в SACL на которую добавтся новый ACE

_In_     LPVOID pAceList, - Самое важное – параметры нового ACE

_In_     DWORD nAceListLength – и длина листа с параметрами ACE

);

Наконец у нас готов новый SACL и мы можем его добавить к нашей security information! Добавляем функцией SetNamedSecurityInfo(). Она абсолютна аналогична функции GetNamedSecurityInfo() и я не стану снова ее разбирать.

А вот и сама функция добавления аудита к файлу:

int CNTFS::AddACEToSACL(CString & I_objPath,

CString & I_securityPrincipal,

DWORD I_objPermission,

BOOL I_auditSuccess,

BOOL I_auditFailure)

{

int returnCode = ERROR_SUCCESS;

BOOL isUser = TRUE;

UCHAR BuffSid[256];

PSID pSID = (PSID)BuffSid;

PACL pOldSACL = NULL;

PACL pNewSACL = NULL;

PSECURITY_DESCRIPTOR pSD = NULL;

SECURITY_INFORMATION ACLSecInfo = SACL_SECURITY_INFORMATION;

ACL_SIZE_INFORMATION ACLInfo;

SE_OBJECT_TYPE SEObjType = SE_UNKNOWN_OBJECT_TYPE;

memset(&ACLInfo, 0, sizeof(ACL_SIZE_INFORMATION));

if (I_objPath == "")

{

returnCode = ERROR_INVALID_PARAMETER;

}

if (I_securityPrincipal == "")

{

returnCode = ERROR_INVALID_PARAMETER;

}

if (I_objPermission == 0)

{

returnCode = ERROR_INVALID_PARAMETER;

}

if (returnCode == ERROR_SUCCESS)

{

returnCode = ResolveSID(I_securityPrincipal, pSID, isUser);

}

if (returnCode == ERROR_SUCCESS)

{

returnCode = AdjustToken();

}

if (returnCode == ERROR_SUCCESS)

{

SEObjType = DetermineObjectTypeFromPath(I_objPath); // Определяем тип объекта, который лежит по указанному пути.

returnCode = GetNamedSecurityInfo( // Получаем все данные о файле

I_objPath.GetBuffer(_MAX_PATH), // object name

SEObjType, // object type

ACLSecInfo, // information type

NULL, // owner SID

NULL, // primary group SID

NULL, // DACL

&pOldSACL, // SACL

&pSD); // SD

}

// Get SACL size information

if ((returnCode == ERROR_SUCCESS) && (pOldSACL != NULL))

{

BOOL getACLResult = GetAclInformation(pOldSACL, //Выцепляем из структуры полученных данных, необходимый нам SACL

&ACLInfo,

sizeof(ACLInfo),

AclSizeInformation);

if (!getACLResult)

{

returnCode = GetLastError();

}

}

if (returnCode == ERROR_SUCCESS)

{

DWORD cb = 0;

DWORD cbExtra = 0;

if (ACLInfo.AclBytesInUse == 0)

{

cbExtra = sizeof(ACL) +

sizeof(SYSTEM_AUDIT_ACE) -

sizeof(DWORD) +

GetLengthSid(pSID);

}

else

{

cbExtra = sizeof(SYSTEM_AUDIT_ACE) - sizeof(DWORD) + GetLengthSid(pSID);

}

cb = ACLInfo.AclBytesInUse + cbExtra; //Формируем новый ACE размером равным предыдущим ACE в SACL плюс под новые записи.

pNewSACL = static_cast<PACL>(HeapAlloc(GetProcessHeap(),0,cb));

BOOL initACLResult = InitializeAcl(pNewSACL, cb, ACL_REVISION); // Инициализируем новую структуру ACL, в данном случае под SACL

if (!initACLResult)

{

returnCode = GetLastError();

}

}

if (returnCode == ERROR_SUCCESS)

{

for (DWORD i = 0; i < ACLInfo.AceCount; ++i)

{

ACE_HEADER * pACE = 0;

GetAce(pOldSACL, i, reinterpret_cast<void**>(&pACE));

pACE->AceFlags = CONTAINER_INHERIT_ACE | OBJECT_INHERIT_ACE;

pACE->AceType = SYSTEM_AUDIT_ACE_TYPE;

AddAce(pNewSACL, ACL_REVISION, MAXDWORD, pACE, pACE->AceSize); // Добавляем все уже существующие ACE в проинициализированную новую структуру ACL

}

BOOL addACEResult = AddAuditAccessAceEx(pNewSACL,

ACL_REVISION,

CONTAINER_INHERIT_ACE |

OBJECT_INHERIT_ACE,

I_objPermission,

pSID,

I_auditSuccess,

I_auditFailure); // добавляем новую ACE, с параметрами заданными в структуре I_objPermission (это один из аргументов функции, задает аудит на какие действия включать) в конец структуры ACL.

if (!addACEResult)

{

returnCode = GetLastError();

}

}

if (returnCode == ERROR_SUCCESS)

{

DWORD setSIResult = SetNamedSecurityInfo( // Записываем наш только что сформированный SACL в данные безопасности файла вместо старого.

I_objPath.GetBuffer(_MAX_PATH), // object name

SEObjType, // object type

ACLSecInfo, // type

NULL, // new owner SID

NULL, // new primary group SID

NULL, // new DACL

pNewSACL); // new SACL

if (!setSIResult)

{

returnCode = setSIResult;

}

}

if (pSD != NULL)

{

LocalFree(pSD);

}

if (pNewSACL != NULL)

{

HeapFree(GetProcessHeap(),0, pNewSACL);

}

return returnCode;

}

Формат вызова функции следующий:

DWORD accessMask = FILE_ALL_ACCESS | FILE_GENERIC_READ | FILE_GENERIC_WRITE | FILE_GENERIC_EXECUTE | DELETE;

CString user = "1";

CString path = "D:\\Lab_1.docx";

int status = AddACEToSACL(path,

user,

accessMask,

TRUE,

TRUE);

После этого у файла D:\\Lab_1.docx появится аудит, и любые действия с ним будут отображаться в журнале безопасности windows. К примеру, открытие файла для чтения порождает событие:

  1. Чтение журнала безопасности windows.

Последним, на чем мне хотелось остановить внимание – автоматическое чтение журнала windows для получения информации о конкретном файле. К сожалению, существует лишь одна winAPI функция для чтения данных из журнала безопасности: ReadEventLog()

BOOL ReadEventLog(

_In_   HANDLE hEventLog, - Хэндл, какой из журналов читать

_In_   DWORD dwReadFlags, - параметр чтения – случайно/с начала/с конца

_In_   DWORD dwRecordOffset, - Смещение при чтении

_Out_  LPVOID lpBuffer, - буфер, куда будут записываться данные.

_In_   DWORD nNumberOfBytesToRead, Размер буфера

_Out_  DWORD *pnBytesRead, - количество читаемых байт

_Out_  DWORD *pnMinNumberOfBytesNeeded – минимальное количество считываемых байт

);

Эта функция возвращает структуру EVENTLOGRECORD , содержащую следующие поля:

typedef struct _EVENTLOGRECORD {

DWORD Length;

DWORD Reserved;

DWORD RecordNumber;

DWORD TimeGenerated;

DWORD TimeWritten;

DWORD EventID;

WORD  EventType;

WORD  NumStrings;

WORD  EventCategory;

WORD  ReservedFlags;

DWORD ClosingRecordNumber;

DWORD StringOffset;

DWORD UserSidLength;

DWORD UserSidOffset;

DWORD DataLength;

DWORD DataOffset;

}

Как видно, среди них нету поля с именем объекта к которому применялось действие. Поэтому у меня не получилось отфильтровать журнал событий на предмет событий аудита с нужным файлом. Вероятно, это можно сделать каким-то образом через перехват событий, но я не разобрался с этим. На последок приведу программу, считывающую все данные из журнала безопасности windows, вкладки Security:

#include "stdafx.h"

#include <Windows.h>

#define BUFFER_SIZE 16384

void ReadAnyLog();

int _tmain(int argc, _TCHAR* argv[])

{

ReadAnyLog();

char LogName[15];

scanf("%s", LogName);

return 0;

}

void ReadAnyLog()

{

HANDLE h;

EVENTLOGRECORD *pevlr;

BYTE bBuffer[BUFFER_SIZE];

DWORD dwRead, dwNeeded, cRecords, dwThisRecord;

h = OpenEventLog( NULL, (LPCWSTR)"Security");

if (h == NULL)

printf("\n Could not open the Application event log\n");

pevlr = (EVENTLOGRECORD *) &bBuffer;

GetOldestEventLogRecord(h, &dwThisRecord);

while (ReadEventLog(h, // event log handle

EVENTLOG_FORWARDS_READ | // reads forward

EVENTLOG_SEQUENTIAL_READ, // sequential read

0, // ignored for sequential read

pevlr, // pointer to buffer

BUFFER_SIZE, // size of buffer

&dwRead, // number of bytes read

&dwNeeded)) // bytes in next record

{

while (dwRead > 0)

{

printf("%02d Event ID: 0x%08X ",

dwThisRecord++, pevlr->EventID);

printf("EventType: %d Source: %s\n",

pevlr->EventType, (LPSTR) ((LPBYTE) pevlr +

sizeof(EVENTLOGRECORD)));

dwRead -= pevlr->Length;

pevlr = (EVENTLOGRECORD *)((LPBYTE) pevlr + pevlr->Length);

}

pevlr = (EVENTLOGRECORD *) &bBuffer;

}

CloseEventLog(h);

}

  1. Выводы

  • В ходе работы я прочитал много статей с различных источников. В основном, это был MSDN и книжка автора: Руссинович Марк - Книга: "3.Внутреннее устройство Windows . Почерпнул очень много интересного как о аудите в целом, так и его применимости в среде windows. Научился работать с security information объектов и узнал её структуру. Ближе познакомился с журналом безопасности windows и его профилированием. На мой взгляд работа была очень интересной, хотя и очень объемной.

Источники:

http://www.rulit.net/books/3-vnutrennee-ustrojstvo-windows-gl-8-11-read-17203-7.html

http://www.sepago.de/d/helge/2009/03/12/permissions-a-primer-or-dacl-sacl-owner-sid-and-ace-explained

http://www.codeproject.com/Articles/10042/The-Windows-Access-Control-Model-Part-1

http://www.osp.ru/win2000/2001/05/174875/

http://support.microsoft.com/kb/310399/ru

http://technet.microsoft.com/ru-ru/library/cc738931%28v=ws.10%29.aspx

http://stavkombez.ru/method/PASOIB/html/content/lab_9.html

http://stackoverflow.com/questions/1083372/listening-to-file-changes-in-c-c-on-windows

http://msdn.microsoft.com/en-us/library/aa365261%28VS.85%29.aspx

http://www.softpedia.com/get/System/System-Miscellaneous/File-Audit.shtml

http://msdn.microsoft.com/en-us/library/aa364417%28VS.85%29.aspx

http://msdn.microsoft.com/en-us/library/aa365465%28v=vs.85%29.aspx

http://msdn.microsoft.com/ru-ru/library/windows/desktop/aa363646%28v=vs.85%29.aspx

http://msdn.microsoft.com/ru-ru/library/windows/desktop/aa363674%28v=vs.85%29.aspx

http://msdn.microsoft.com/ru-ru/library/windows/desktop/aa379579%28v=vs.85%29.aspx

http://msdn.microsoft.com/ru-ru/library/windows/desktop/aa446635%28v=vs.85%29.aspx

http://msdn.microsoft.com/ru-ru/library/windows/desktop/aa446645%28v=vs.85%29.aspx

http://msdn.microsoft.com/ru-ru/library/windows/desktop/aa378853%28v=vs.85%29.aspx

…. и еще множество ссылок на msdn.

Санкт-Петербург

2012г

Соседние файлы в папке docx53