Введение во внутреннее устройство Windows

Обеспечение безопасности в Windows

Показывать лекцию целиком

Задание 1. Определить идентификатор защиты SID текущего пользователя.

Указания к выполнению.

1. Узнать SID текущего пользователя можно несколькими способами.

Способ 1. При помощи утилиты Process Explorer.

Запустите в виртуальной машине утилиту Process Explorer. Сделайте двойной щелчок на процессе explorer.exe (или любом другом процессе, запущенном текущим пользователем). Когда откроется окно свойств процесса, перейдите на вкладку Security:

На рисунке вверху красным цветом выделен SID пользователя – владельца процесса. В данном случае, процесс запущен пользователем с именем Administrator, который является администратором системы, о чем говорит, во первых, RID = 500 (последнее число в SID, см. статью базы знаний Microsoft "Хорошо известные идентификаторы безопасности в операционных системах Windows"http://support.microsoft.com/kb/243330/ru), во вторых, то, что пользователь входит в группу администраторов (BUILTIN\Administrators).

Способ 2. При помощи утилиты PsGetSid.

Утилита PsGetSid специально предназначена для получения SID разных учетных записей. Данная утилита входит в набор PsTools и её можно скачать с сайта Sysinternals.

Запустите утилиту PsGetSid на виртуальной машине в командной строке. В качестве параметра утилиты можно указать либо имя учетной записи, либо SID. На рисунке ниже продемонстрированы оба варианта:

Удостоверьтесь, что SID полностью совпадают в первом и втором способах.

Задание 2. Определить тип файловой системы.

Указания к выполнению.

1. Следующие задания в данной лабораторной работе основываются на предположении, что системный раздел (логический диск) на виртуальной машине отформатирован с использованием файловой системы NTFS. Проверить, так ли это, можно следующим образом. Дважды щелкните на ярлыке My Computer – щелкните правой кнопкой на локальном диске C – выберите пункт Properties. На рисунке ниже обведен тип файловой системы логического диска:

Задание 3. Создать программу, которая открывает и читает файл.

Указания к выполнению.

1. Создайте пустой проект с названием, например, ReadFile, в Visual Studio и добавьте файл исходного кода main.cpp (см. лабораторную работу 2 "Процессы и потоки", задание 3).

Сохраните проект в папку c:\Programs\ReadFile.

2. Вставьте в main.cpp следующий исходный код (модифицированный пример из MSDN):

#include <windows.h>
#include <tchar.h>
#include <stdio.h>

#define BUFFERSIZE 81

void __cdecl _tmain(int argc, TCHAR *argv[])
{
HANDLE hFile;					// Дескриптор файла
DWORD  dwBytesRead = 0;			// Количество прочитанных байт
char   ReadBuffer[BUFFERSIZE] = {0};	// Буфер для чтения
char   FileName[] = "input.txt";	// Имя файла

// Точка останова
//__asm int 3

hFile = CreateFile(FileName,	// Имя файла для открытия
GENERIC_READ,		// Открываем для чтения
FILE_SHARE_READ,		// Файл можно открывать другим процессам
NULL,				// Атрибуты безопасности по умолчанию
OPEN_EXISTING,		// Открытие существующего файла
FILE_ATTRIBUTE_NORMAL,	// Атрибуты файла - обычные
NULL);			// Без шаблона

if (hFile == INVALID_HANDLE_VALUE) 
{ 
_tprintf("Terminal failure: unable to open file \"%s\" for read\n", FileName);
system("pause");
return; 
}

// Читаем на один символ меньше, чем помещается в буфер,
// чтобы сохранить место под завершающий нулевой символ

if( ReadFile(hFile, ReadBuffer, BUFFERSIZE-1, dwBytesRead, NULL) == FALSE)
{
printf("Terminal failure: Unable to read from file\n");
CloseHandle(hFile);
system("pause");
return;
}

if (dwBytesRead > 0  dwBytesRead <= BUFFERSIZE-1)
{
ReadBuffer[dwBytesRead]='\0'; // символ с кодом "0"
_tprintf("Data read from %s (%d bytes): \n\n", FileName, dwBytesRead);
printf("%s\n\n", ReadBuffer);
}
else if (dwBytesRead == 0)
{
_tprintf(TEXT("No data read from file %s\n"), FileName);
}
else
{
printf("\n ** Unexpected value for dwBytesRead ** \n");
}

CloseHandle(hFile);

system("pause");
}

Приведенная программа открывает файл input.txt при помощи функции CreateFile, пытается прочитать из него строку символов при помощи функции ReadFile (не более 80 символов) и выводит её на экран.

3. Создайте текстовый файл input.txt в папке проекта, в которой расположен файл main.cpp (например, c:\Programs\ReadFile\ReadFile).

Наберите в нем какой нибудь текст латиницей и сохраните файл.

4. Установите свойства проекта (см. лабораторную работу 2 "Процессы и потоки", задание 3):

  • конфигурацию Release;
  • Библиотека времени выполнения – Многопоточная (/MT).
  • 5. Проверьте работоспособность созданного приложения (клавиша F5):

    Задание 4. В приложении поставить точку останова.

    Указания к выполнению.

    1. В созданном проекте уберите комментарии (//) перед оператором, обозначающим точку останова:

    _asm int 3
    

    2. Запустите проект. Программа должна прерваться в точке останова. Её выполнение можно продолжить, нажав кнопку Продолжить:

    Задание 5. Запустить приложение ReadFile на виртуальной машине, установить точку останова на функции SeAccessCheck.

    Указания к выполнению.

    1. Исполняемый файл созданного в предыдущем пункте приложения ReadFile.exe после компиляции проекта должен находиться в следующей папке:

    c:\Programs\ReadFile\Release.
    

    Скопируйте исполняемый файл на виртуальную машину.

    Скопируйте текстовый файл input.txt на виртуальную машину в ту же папку, что и исполняемый файл.

    2. Запустите исполняемый файл. Выполнение программы должно прерываться, а управление перейти к отладчику WinDbg.

    3. Установите в отладчике точку останова на функции SeAccessCheck для процесса ReadFile.exe. Для этого сначала следует определить адрес объекта EPROCESS для процесса ReadFile.exe при помощи команды:

    !process 0 0 ReadFile.exe
    

    В данном случае адрес равен 0x8222F630.

    Установить точку останова для функции SeAccessCheck для процесса ReadFile.exe можно при помощи следующей команды:

    bp /p 8222F630 nt!SeAccessCheck
    

    Проверьте, что команда выполнена верно: в меню Edit отладчика выберите пункт Breakpoints…:

    Замечание. После перезапуска процесса ReadFile.exe его адрес может поменяться. В этом случае придется удалить старую точку останова и повторить нахождение адреса объекта EPROCESS и установки новой точки останова.

    4. Продолжите выполнение, нажав F5 в отладчике. Должна сработать точка останова на функции SeAccessCheck и откроется исходный код этой функции.

    Задание 6. Исследовать маркер доступа (access token).

    Указания к выполнению.

    1. Функция SeAccessCheck проверяет возможность доступа процесса с заданным маркером доступа к объекту с определенным дескриптором защиты (см. лекцию 13 "Безопасность в Windows").

    2. Адрес маркера доступа процесса содержится в поле PrimaryToken параметра SubjectSecurityContext. Чтобы узнать этот адрес, откройте в отладчике окно Locals (Alt+3) и раскройте параметр SubjectSecurityContext (нажмите "плюс" слева от имени параметра):

    На рисунке видно, что адрес в поле PrimaryToken равен 0xE1249870.

    3. Просмотрите содержимое структуры _TOKEN, по адресу, определенному в предыдущем пункте. Введите команду:

    dt _token 0xE1249870
    

    В этой структуре содержится вся информация о маркере. Например, ID маркера хранится в поле TokenID типа _LUID по смещению 0x010 от начала структуры. Чтобы узнать ID маркера, введите следующую команду:

    dt _LUID 0xE1249870+0x010
    

    В данном примере TokenID равен 0x963D2.

    SID учетной записи пользователя владельца маркера и групп, в которые он входит, хранятся по адресу в поле UserAndGroups:

    dt _SID_AND_ATTRIBUTES 0xe1249a00
    

    В первом поле структуры _SID_AND_ATTRIBUTES хранится адрес SID. Чтобы узнать какой SID расположен по данному адресу, можно воспользоваться следующей командой:

    !sid 0xe1249a58
    

    Очевидно, что это SID учетной записи с именем Administrator, ведь процесс ReadFile запускался из под неё.

    Структуры _SID_AND_ATTRIBUTES для групп, в которые входит учетная запись, расположены следом за той же структурой для учетной записи. Чтобы вывести адреса SID групп, можно набрать следующую команду:

    dd 0xe1249a00
    

    Структура _SID_AND_ATTRIBUTES для учетной записи Administrator выделена на рисунке красным, для первой группы, в которую входит Administrator – синим.

    Чтобы узнать SID групп, можно снова воспользоваться командой !sid:

    Этот SID соответствует группе Users (см. статью MSDN "Хорошо известные идентификаторы безопасности в операционных системах Windows").

    4. В отладчике WinDbg имеется специальная команда для удобного отображения содержимого маркера доступа – !token.

    Введите эту команду, указав адрес маркера доступа:

    !token 0xE1249870
    

    Сравните информацию, выводимую командой !token, с данными, полученными в предыдущем пункте путем анализа полей структуры TOKEN.

    Задание 7. Исследовать дескриптор защиты (security descriptor).

    Указания к выполнению.

    1. Адрес дескриптора защиты объекта (в данном случае – файла) содержится в параметре SecurityDescriptor функции SeAccessCheck:

    2. Дескриптор защиты, зная его адрес, можно посмотреть при помощи команды !sd:

    !sd 0xE186ABC0 1
    

    Параметр 1 в конце указывает, что нужно по возможности указывать имена для SID.

    Уровень доступа к объекту определяется в списке DACL маской доступа (поля Mask выделены на рисунке красным). В маске отдельные биты отвечают за определенные виды доступа.

    Выделяют стандартные права доступа (Standard Access Rights), применимые к большинству объектов, и специфичные для объектов права доступа (Object-Specific Access Rights) (см. лекцию 9 "Безопасность в Windows"). Описание стандартных прав доступа и соответствующих значений масок приведено в файле public\sdk\inc\ntseapi.h (строки 72–166), а также описаны в статье MSDN "Access Mask Format"http://msdn.microsoft.com/en-us/library/windows/desktop/aa374896(v=vs.85).aspx. Описание прав доступа для файлов и каталогов имеется в файле public\sdk\inc\ntioapi.h (строки 41–108), а также в статье MSDN "Access Mask"http://msdn.microsoft.com/en-us/library/windows/hardware/ff538834(v=vs.85).aspx.

    Для примера рассмотрим две маски, используемые для файла input.txt (см. рисунок выше): 0x001F01FF и 0x001200A9.

    Представим маску 0x001F01FF в двоичном виде и укажем, за что отвечает каждая единица:

    Как видно из рисунка, маска 0x001F01FF обозначает полный доступ к файлу. Такой доступ имеют члены группы Administrators и системная учетная запись Система (System).

    Рассмотрим вторую маску доступа 0x001200A9:

    Таким образом, члены группы Пользователи (Users) имеют доступ только на чтение и исполнение.

    Задания для самостоятельного выполнения

    Задание 1. Изменить права доступа на файл и зафиксировать изменения в DACL дескриптора защиты файла.

    Указания к выполнению.

    1. В виртуальной машине измените права доступа на файл input.txt. Для этого в свойствах файла перейдите на вкладку Security и сделайте необходимые изменения (добавьте/удалите пользователей и/или группы, измените их права):

    Замечание. Для осуществления некоторых действий (например, удаления пользователей) может потребоваться отказаться от наследования прав доступа объекта родителя (папки). Для этого нажмите кнопку Advanced – снимите флажок Allow inheritable permissions… – в появившемся окне нажмите кнопку Copy:

    2. Просмотрите дескриптор безопасности файла, повторив действия из задания 7 основной части работы.

    Задание 2. Исследовать функцию SeAccessCheck.

    Указания к выполнению.

    1. Выполните трассировку функции SeAccessCheck, пользуясь материалом лекции 9 "Безопасность в Windows" и документацией WRK.

    Задание 3. Исследовать расположение в памяти структуры SECURITY_DESCRIPTOR.

    Указания к выполнению.

    1. Выясните расположение в памяти структуры SECURITY_DESCRIPTOR, пользуясь информацией, изложенной в задании 7 данной лабораторной работы, материалом лекции 9 "Безопасность в Windows", документацией WRK и статьей MSDN "SECURITY_DESCRIPTOR"http://msdn.microsoft.com/en-us/library/cc230366(v=prot.10).aspx.

    Вернуться к учебному плану