Вообщем я хочу создать процесс, который допустим нельзя грохнуть или запретить менять для него владельца. То есть хочу отобрать некоторые права у самого себя. Ниже привожу код, пытаюсь запустить калькулятор, без прав на его завершения. Код работает без ошибок, но процесс все равно грохается без проблем. Подскажите в чем может быть проблема? Код (Text): #ifndef UNICODE #define UNICODE #endif #include <windows.h> #include <stdio.h> #include <lm.h> int main() { HANDLE hProcess; ACL *lpDacl; // указатель на список доступа DWORD dwDaclLength; // длина списка доступа wchar_t wchUserName[UNLEN]; // имя пользователя DWORD dwLengthOfDomainName = 0; // длина имени домена DWORD dwLengthOfSid = 0; // длина SID SID *lpSid = NULL; // указатель на SID LPTSTR lpDomainName = NULL; // указатель на имя домена SID_NAME_USE typeOfSid; // тип учетной записи SECURITY_DESCRIPTOR sd; // дескриптор безопасности SECURITY_ATTRIBUTES sa; // атрибуты защиты DWORD dwRetCode; // код возврата // вводим имя пользователя, которому разрешим\запретип доступ printf("Input a user name: "); _getws(wchUserName); // определяем длину SID пользователя if (!LookupAccountName( NULL, // ищем имя на локальном компьютере wchUserName, // имя пользователя NULL, // определяем длину SID &dwLengthOfSid, // длина SID NULL, // определяем имя домена &dwLengthOfDomainName, // длина имени домена &typeOfSid)) // тип учетной записи { dwRetCode = GetLastError(); if (dwRetCode == ERROR_INSUFFICIENT_BUFFER) { // распределяем память для SID и имени домена lpSid = (SID*) new char[dwLengthOfSid]; lpDomainName = (LPTSTR) new wchar_t[dwLengthOfDomainName]; } else { // выходим из программы printf("Lookup account name failed.\n"); printf("Error code: %d\n", dwRetCode); getchar(); return dwRetCode; } } // определяем SID и имя домена пользователя if(!LookupAccountName( NULL, // ищем имя на локальном компьютере wchUserName, // имя пользователя lpSid, // указатель на SID &dwLengthOfSid, // длина SID lpDomainName, // указатель на имя домена &dwLengthOfDomainName, // длина имени домена &typeOfSid)) // тип учетной записи { dwRetCode = GetLastError(); printf("Lookup account name failed.\n"); printf("Error code: %d\n", dwRetCode); getchar(); return dwRetCode; } // проверяем тип SID if (typeOfSid != SidTypeUser) { printf("This is not a user name.\n"); getchar(); return 1; } // определем длину списка DACL dwDaclLength = sizeof(ACL) + sizeof(ACCESS_ALLOWED_ACE) - sizeof(DWORD) + dwLengthOfSid + sizeof(ACCESS_DENIED_ACE) - sizeof(DWORD) + dwLengthOfSid; // распределяем память под DACL lpDacl = (ACL*)new char[dwDaclLength]; // инициализируем список DACL if (!InitializeAcl( lpDacl, // адрес DACL dwDaclLength, // длина DACL ACL_REVISION)) // версия DACL { dwRetCode = GetLastError(); printf("Lookup account name failed.\n"); printf("Error code: %d\n", dwRetCode); getchar(); return dwRetCode; } // добавляем запрещающий элемент в список DACL if (!AddAccessDeniedAce( lpDacl, // адрес DACL ACL_REVISION, // версия DACL PROCESS_TERMINATE, // запрещаем грохать объект lpSid)) // адрес SID { dwRetCode = GetLastError(); perror("Add access denied ace failed.\n"); printf("The last error code: %u\n", dwRetCode); getchar(); return dwRetCode; } // добавляем разрешающий элемент в список DACL if (!AddAccessAllowedAce( lpDacl, // адрес DACL ACL_REVISION, // версия DACL WRITE_DAC, // разрешаем менять dacl lpSid)) // адрес SID { dwRetCode = GetLastError(); perror("Add access allowed ace failed.\n"); printf("The last error code: %u\n", dwRetCode); getchar(); return dwRetCode; } // инициализируем версию дескриптора безопасности if (!InitializeSecurityDescriptor( &sd, SECURITY_DESCRIPTOR_REVISION)) { dwRetCode = GetLastError(); printf("Initialize security descroptor failed.\n"); printf("Error code: %d\n", dwRetCode); getchar(); return dwRetCode; } // устанавливаем SID владельца объекта if (!SetSecurityDescriptorOwner( &sd, // адрес дескриптора безопасности NULL, // не задаем владельца SE_OWNER_DEFAULTED)) // определить владельца по умолчанию { dwRetCode = GetLastError(); perror("Set security descriptor owner failed.\n"); printf("The last error code: %u\n", dwRetCode); getchar(); return dwRetCode; } // устанавливаем SID первичной группы владельца if (!SetSecurityDescriptorGroup( &sd, // адрес дескриптора безопасности NULL, // не задаем первичную группу SE_GROUP_DEFAULTED)) // определить первичную группу по умолчанию { dwRetCode = GetLastError(); perror("Set security descriptor group failed.\n"); printf("The last error code: %u\n", dwRetCode); getchar(); return dwRetCode; } // устанавливаем DACL в дескриптор безопасности if (!SetSecurityDescriptorDacl( &sd, // адрес дескриптора безопасности TRUE, // DACL присутствует lpDacl, // указатель на DACL FALSE)) // DACL не задан по умолчанию { dwRetCode = GetLastError(); perror("Set security descriptor group failed.\n"); printf("The last error code: %u\n", dwRetCode); getchar(); return dwRetCode; } // проверяем структуру дескриптора безопасности if (!IsValidSecurityDescriptor(&sd)) { dwRetCode = GetLastError(); perror("Security descriptor is invalid.\n"); printf("The last error code: %u\n", dwRetCode); getchar(); return dwRetCode; } // инициализируем атрибуты безопасности sa.nLength = sizeof(sa); // устанавливаем длину атрибутов защиты sa.lpSecurityDescriptor = &sd; // устанавливаем адрес SD sa.bInheritHandle = FALSE; // дескриптор не наследуемый STARTUPINFO si; PROCESS_INFORMATION pi; ZeroMemory( &si, sizeof(si)); si.cb = sizeof(si); ZeroMemory( &pi, sizeof(pi)); CreateProcess(L"C:\\Windows\\System32\\calc.exe",NULL,&sa,NULL,FALSE,0,NULL,NULL,&si,&pi); if (pi.hProcess == NULL) { dwRetCode = GetLastError(); perror("Create process failed.\n"); printf("The last error code: %u\n", dwRetCode); getchar(); return dwRetCode; } printf("The process is created.\n"); getchar(); // освобождаем память delete[] lpSid; delete[] lpDomainName; delete[] lpDacl; CloseHandle(pi.hProcess); return 0; }
А если я на компе админ, разве я не могу сам у себя отобрать права? Если мой метод неверен, подскажите тогда куда копать.
Убивает процесс ядро. Если вы хукаете, к приемеру, ExitProcess целевого процесса, то это никак не помешает вам убить его из другого процесса, например из диспетчера задач. Тут где-то были на форуме попытки залочить что-то в системных параметрах процесса, но на сколько я помню ничего путного не вышло...
То есть если я добавил в dacl процесса запрет на завершения, то это вообще на что-нибудь будет влиять?
То есть в теории я двигаюсь в правильном направлении? Влияет ли то, что я работаю под админом? Может проблема при получении SID?
Ваш код пока не смотрел, но Вы можете проверить его работу с помощью ProcessExplorer (скрин в аттаче). Для того, чтобы Ваш процесс нельзя было завершить другим процессом, надо выполнить два условия: 1. Для пользователя, от имени которого запускается второй процесс должен быть запрещающий ACE PROCESS_TERMINATE в DACL первого (защищаемого) процесса. 2. У второго процесса не должна быть включена привилегия отладки (SeDebugPrivilege). Привилегия отладки позволяет обходить проверку DACL при открытии процесса.
Попробовал сейчас открыть только что созданный процесс с помощью OpenProcess(PROCESS_TERMINATE,FALSE,pi.dwProcessId), возвращает error 5 (доступ запрещен), значит правила устанавливаются корректно. Вопрос почему это не спасает от TerminateProcess?
Немного не понял Ваш ответ. То есть чтобы процесс А запустил защищенный процесс В, он должен запретить в DALC процесса B PROCESS_TERMINATE, верно? Так же чтобы некий процесс Х не смог грохнуть процесс В у него не должно быть привилегий отладки?
Хендл, полученный из функции CreateProcess. Вы таким образом защищаете запускаемый процесс не от его родителя, а от стороннего процесса, если он запущен от имени пользователя, для которого задан запрещающий ACE в DACL защищаемого процесса. И это не сработает, если у стороннего процесса будет включена привилегия отладки.
Теперь ясно. Только вот непонятно у диспетчера задач режим отладки выставлен в disabled (если верить ProcessExplorer), но это не мешает ему молча грохать процесс с DALC?
Если таскманагер запущен под админом, то он просто может установить нужные права для объекта-процесса, так как имеет привилегию установки владельца.
Привилегия может быть в 3 состояниях. Включена - привилегия активна Выключена - привилегия сейчас не используется, но может быть включена через AdjustTokenPrivileges Отсутствует - привилегии нет и её нельзя включить через AdjustTokenPrivileges П.С. надеюсь не наврал ничего )