DALC и процесс

Тема в разделе "WASM.WIN32", создана пользователем stoneman, 27 окт 2010.

  1. stoneman

    stoneman New Member

    Публикаций:
    0
    Регистрация:
    27 окт 2010
    Сообщения:
    10
    Вообщем я хочу создать процесс, который допустим нельзя грохнуть или запретить менять для него владельца.
    То есть хочу отобрать некоторые права у самого себя. Ниже привожу код, пытаюсь запустить калькулятор, без прав на его завершения.
    Код работает без ошибок, но процесс все равно грохается без проблем. Подскажите в чем может быть проблема?
    Код (Text):
    1.       #ifndef UNICODE
    2.       #define UNICODE
    3.       #endif
    4.       #include <windows.h>
    5.       #include <stdio.h>
    6.       #include <lm.h>
    7.        
    8.       int main()
    9.       {
    10.        
    11.        
    12.         HANDLE hProcess;
    13.         ACL *lpDacl;           // указатель на список доступа
    14.         DWORD dwDaclLength;    // длина списка доступа
    15.        
    16.         wchar_t wchUserName[UNLEN];      // имя пользователя
    17.        
    18.         DWORD dwLengthOfDomainName = 0;  // длина имени домена
    19.        
    20.         DWORD dwLengthOfSid = 0;         // длина SID
    21.         SID *lpSid = NULL;               // указатель на SID
    22.         LPTSTR lpDomainName = NULL;      // указатель на имя домена
    23.        
    24.         SID_NAME_USE typeOfSid;    // тип учетной записи
    25.        
    26.         SECURITY_DESCRIPTOR sd;    // дескриптор безопасности
    27.         SECURITY_ATTRIBUTES sa;    // атрибуты защиты
    28.        
    29.         DWORD dwRetCode;   // код возврата
    30.        
    31.         // вводим имя пользователя, которому разрешим\запретип  доступ
    32.         printf("Input a user name: ");
    33.         _getws(wchUserName);
    34.        
    35.         // определяем длину SID пользователя
    36.         if (!LookupAccountName(
    37.           NULL,              // ищем имя на локальном компьютере
    38.           wchUserName,       // имя пользователя
    39.           NULL,              // определяем длину SID
    40.           &dwLengthOfSid,    // длина SID
    41.           NULL,              // определяем имя домена
    42.           &dwLengthOfDomainName,  // длина имени домена
    43.           &typeOfSid))       // тип учетной записи
    44.         {
    45.           dwRetCode = GetLastError();
    46.        
    47.           if (dwRetCode == ERROR_INSUFFICIENT_BUFFER)
    48.           {
    49.             // распределяем память для SID и имени домена
    50.             lpSid = (SID*) new char[dwLengthOfSid];
    51.             lpDomainName = (LPTSTR) new wchar_t[dwLengthOfDomainName];
    52.           }
    53.           else
    54.           {
    55.             // выходим из программы
    56.             printf("Lookup account name failed.\n");
    57.             printf("Error code: %d\n", dwRetCode);
    58.       getchar();
    59.             return dwRetCode;
    60.           }
    61.         }
    62.        
    63.         // определяем SID и имя домена пользователя
    64.         if(!LookupAccountName(
    65.           NULL,              // ищем имя на локальном компьютере
    66.           wchUserName,       // имя пользователя
    67.           lpSid,             // указатель на SID
    68.           &dwLengthOfSid,    // длина SID
    69.           lpDomainName,      // указатель на имя домена
    70.           &dwLengthOfDomainName,  // длина имени домена
    71.           &typeOfSid))       // тип учетной записи
    72.         {
    73.           dwRetCode = GetLastError();
    74.        
    75.           printf("Lookup account name failed.\n");
    76.           printf("Error code: %d\n", dwRetCode);
    77.       getchar();
    78.           return dwRetCode;
    79.         }
    80.        
    81.         // проверяем тип SID
    82.         if (typeOfSid != SidTypeUser)
    83.         {
    84.           printf("This is not a user name.\n");
    85.           getchar();
    86.           return 1;
    87.         }
    88.        
    89.         // определем длину списка DACL
    90.         dwDaclLength = sizeof(ACL)
    91.           + sizeof(ACCESS_ALLOWED_ACE) - sizeof(DWORD) + dwLengthOfSid
    92.           + sizeof(ACCESS_DENIED_ACE) - sizeof(DWORD) + dwLengthOfSid;
    93.        
    94.         // распределяем память под DACL
    95.         lpDacl = (ACL*)new char[dwDaclLength];
    96.        
    97.         // инициализируем список DACL
    98.         if (!InitializeAcl(
    99.           lpDacl,          // адрес DACL
    100.           dwDaclLength,    // длина DACL
    101.           ACL_REVISION))   // версия DACL
    102.         {
    103.           dwRetCode = GetLastError();
    104.        
    105.           printf("Lookup account name failed.\n");
    106.           printf("Error code: %d\n", dwRetCode);
    107.       getchar();
    108.           return dwRetCode;
    109.         }
    110.        
    111.         // добавляем запрещающий элемент в список DACL
    112.         if (!AddAccessDeniedAce(
    113.           lpDacl,          // адрес DACL
    114.           ACL_REVISION,    // версия DACL
    115.           PROCESS_TERMINATE,     // запрещаем грохать объект
    116.           lpSid))          // адрес SID
    117.         {
    118.           dwRetCode = GetLastError();
    119.           perror("Add access denied ace failed.\n");
    120.           printf("The last error code: %u\n", dwRetCode);
    121.       getchar();
    122.           return dwRetCode;
    123.         }
    124.        
    125.         // добавляем разрешающий элемент в список DACL
    126.         if (!AddAccessAllowedAce(
    127.           lpDacl,        // адрес DACL
    128.           ACL_REVISION,  // версия DACL
    129.           WRITE_DAC,   // разрешаем менять dacl
    130.           lpSid))        // адрес SID
    131.         {
    132.           dwRetCode = GetLastError();
    133.           perror("Add access allowed ace failed.\n");
    134.           printf("The last error code: %u\n", dwRetCode);
    135.       getchar();
    136.           return dwRetCode;
    137.         }
    138.        
    139.         // инициализируем версию дескриптора безопасности
    140.         if (!InitializeSecurityDescriptor(
    141.           &sd,
    142.           SECURITY_DESCRIPTOR_REVISION))
    143.         {
    144.           dwRetCode = GetLastError();
    145.           printf("Initialize security descroptor failed.\n");
    146.           printf("Error code: %d\n", dwRetCode);
    147.       getchar();
    148.           return dwRetCode;
    149.         }
    150.        
    151.         // устанавливаем SID владельца объекта
    152.         if (!SetSecurityDescriptorOwner(
    153.           &sd,         // адрес дескриптора безопасности
    154.           NULL,        // не задаем владельца
    155.           SE_OWNER_DEFAULTED))    // определить владельца по умолчанию
    156.         {
    157.           dwRetCode = GetLastError();
    158.           perror("Set security descriptor owner failed.\n");
    159.           printf("The last error code: %u\n", dwRetCode);
    160.       getchar();
    161.           return dwRetCode;
    162.         }
    163.        
    164.         // устанавливаем SID первичной группы владельца
    165.         if (!SetSecurityDescriptorGroup(
    166.           &sd,         // адрес дескриптора безопасности
    167.           NULL,        // не задаем первичную группу
    168.           SE_GROUP_DEFAULTED))    // определить первичную группу по умолчанию
    169.         {
    170.           dwRetCode = GetLastError();
    171.           perror("Set security descriptor group failed.\n");
    172.           printf("The last error code: %u\n", dwRetCode);
    173.       getchar();
    174.           return dwRetCode;
    175.         }
    176.         // устанавливаем DACL  в дескриптор безопасности
    177.         if (!SetSecurityDescriptorDacl(
    178.           &sd,       // адрес дескриптора безопасности
    179.           TRUE,      // DACL присутствует
    180.           lpDacl,    // указатель на DACL
    181.           FALSE))    // DACL не задан по умолчанию
    182.         {
    183.           dwRetCode = GetLastError();
    184.           perror("Set security descriptor group failed.\n");
    185.           printf("The last error code: %u\n", dwRetCode);
    186.       getchar();
    187.           return dwRetCode;
    188.         }
    189.        
    190.         // проверяем структуру дескриптора безопасности
    191.         if (!IsValidSecurityDescriptor(&sd))
    192.         {
    193.           dwRetCode = GetLastError();
    194.           perror("Security descriptor is invalid.\n");
    195.           printf("The last error code: %u\n", dwRetCode);
    196.           getchar();
    197.           return dwRetCode;
    198.         }
    199.        
    200.         // инициализируем атрибуты безопасности
    201.         sa.nLength = sizeof(sa);       // устанавливаем длину атрибутов защиты
    202.         sa.lpSecurityDescriptor = &sd;   // устанавливаем адрес SD
    203.         sa.bInheritHandle = FALSE;     // дескриптор не наследуемый
    204.        
    205.         STARTUPINFO si;
    206.         PROCESS_INFORMATION pi;
    207.        
    208.         ZeroMemory( &si, sizeof(si));
    209.         si.cb = sizeof(si);
    210.         ZeroMemory( &pi, sizeof(pi));
    211.        
    212.        
    213.          CreateProcess(L"C:\\Windows\\System32\\calc.exe",NULL,&sa,NULL,FALSE,0,NULL,NULL,&si,&pi);
    214.          if (pi.hProcess == NULL)
    215.         {
    216.           dwRetCode = GetLastError();
    217.           perror("Create process failed.\n");
    218.           printf("The last error code: %u\n", dwRetCode);
    219.           getchar();
    220.           return dwRetCode;
    221.         }
    222.        
    223.         printf("The process is created.\n");
    224.         getchar();
    225.         // освобождаем память
    226.         delete[] lpSid;
    227.         delete[] lpDomainName;
    228.         delete[] lpDacl;
    229.        
    230.         CloseHandle(pi.hProcess);
    231.        
    232.         return 0;
    233.       }
     
  2. 7mm

    7mm New Member

    Публикаций:
    0
    Регистрация:
    15 дек 2009
    Сообщения:
    442
    В общем случае, из юзермода это не сделать.
     
  3. stoneman

    stoneman New Member

    Публикаций:
    0
    Регистрация:
    27 окт 2010
    Сообщения:
    10
    А если я на компе админ, разве я не могу сам у себя отобрать права?
    Если мой метод неверен, подскажите тогда куда копать.
     
  4. 7mm

    7mm New Member

    Публикаций:
    0
    Регистрация:
    15 дек 2009
    Сообщения:
    442
    Убивает процесс ядро. Если вы хукаете, к приемеру, ExitProcess целевого процесса, то это никак не помешает вам убить его из другого процесса, например из диспетчера задач. Тут где-то были на форуме попытки залочить что-то в системных параметрах процесса, но на сколько я помню ничего путного не вышло...
     
  5. stoneman

    stoneman New Member

    Публикаций:
    0
    Регистрация:
    27 окт 2010
    Сообщения:
    10
    То есть если я добавил в dacl процесса запрет на завершения, то это вообще на что-нибудь будет влиять?
     
  6. 7mm

    7mm New Member

    Публикаций:
    0
    Регистрация:
    15 дек 2009
    Сообщения:
    442
    Хм, перечитал ещё раз ваше сообщение. По идее это должно ограничивать, почему не пашет - не знаю :)
     
  7. stoneman

    stoneman New Member

    Публикаций:
    0
    Регистрация:
    27 окт 2010
    Сообщения:
    10
    То есть в теории я двигаюсь в правильном направлении? Влияет ли то, что я работаю под админом?
    Может проблема при получении SID?
     
  8. Deyton

    Deyton Member

    Публикаций:
    0
    Регистрация:
    7 мар 2007
    Сообщения:
    94
    Ваш код пока не смотрел, но Вы можете проверить его работу с помощью ProcessExplorer (скрин в аттаче). Для того, чтобы Ваш процесс нельзя было завершить другим процессом, надо выполнить два условия:
    1. Для пользователя, от имени которого запускается второй процесс должен быть запрещающий ACE PROCESS_TERMINATE в DACL первого (защищаемого) процесса.
    2. У второго процесса не должна быть включена привилегия отладки (SeDebugPrivilege). Привилегия отладки позволяет обходить проверку DACL при открытии процесса.
     
  9. n0name

    n0name New Member

    Публикаций:
    0
    Регистрация:
    5 июн 2004
    Сообщения:
    4.336
    Адрес:
    Russia
    посмотри права на объект и убедись что всё верно.
     
  10. stoneman

    stoneman New Member

    Публикаций:
    0
    Регистрация:
    27 окт 2010
    Сообщения:
    10
    Попробовал сейчас открыть только что созданный процесс с помощью OpenProcess(PROCESS_TERMINATE,FALSE,pi.dwProcessId), возвращает error 5 (доступ запрещен), значит правила устанавливаются корректно. Вопрос почему это не спасает от TerminateProcess?
     
  11. n0name

    n0name New Member

    Публикаций:
    0
    Регистрация:
    5 июн 2004
    Сообщения:
    4.336
    Адрес:
    Russia
    а хендл для TerminateProcess откуда берется?
     
  12. Deyton

    Deyton Member

    Публикаций:
    0
    Регистрация:
    7 мар 2007
    Сообщения:
    94
    #8
     
  13. stoneman

    stoneman New Member

    Публикаций:
    0
    Регистрация:
    27 окт 2010
    Сообщения:
    10
    Из PROCESS_INFORMATION, котороая заполняется CreateProcess(), см код.
     
  14. stoneman

    stoneman New Member

    Публикаций:
    0
    Регистрация:
    27 окт 2010
    Сообщения:
    10
    Немного не понял Ваш ответ. То есть чтобы процесс А запустил защищенный процесс В, он должен запретить в DALC процесса B PROCESS_TERMINATE, верно? Так же чтобы некий процесс Х не смог грохнуть процесс В у него не должно быть привилегий отладки?
     
  15. n0name

    n0name New Member

    Публикаций:
    0
    Регистрация:
    5 июн 2004
    Сообщения:
    4.336
    Адрес:
    Russia
    само собой он PROCESS_ALL_ACCESS :)
     
  16. stoneman

    stoneman New Member

    Публикаций:
    0
    Регистрация:
    27 окт 2010
    Сообщения:
    10
    Не понял, кто он?
     
  17. Deyton

    Deyton Member

    Публикаций:
    0
    Регистрация:
    7 мар 2007
    Сообщения:
    94
    Хендл, полученный из функции CreateProcess. Вы таким образом защищаете запускаемый процесс не от его родителя, а от стороннего процесса, если он запущен от имени пользователя, для которого задан запрещающий ACE в DACL защищаемого процесса. И это не сработает, если у стороннего процесса будет включена привилегия отладки.
     
  18. stoneman

    stoneman New Member

    Публикаций:
    0
    Регистрация:
    27 окт 2010
    Сообщения:
    10
    Теперь ясно. Только вот непонятно у диспетчера задач режим отладки выставлен в disabled (если верить ProcessExplorer), но это не мешает ему молча грохать процесс с DALC?
     
  19. tchunya

    tchunya New Member

    Публикаций:
    0
    Регистрация:
    13 ноя 2008
    Сообщения:
    29
    Если таскманагер запущен под админом, то он просто может установить нужные права для объекта-процесса, так как имеет привилегию установки владельца.
     
  20. 100gold

    100gold New Member

    Публикаций:
    0
    Регистрация:
    26 фев 2010
    Сообщения:
    165
    Привилегия может быть в 3 состояниях.
    Включена - привилегия активна
    Выключена - привилегия сейчас не используется, но может быть включена через AdjustTokenPrivileges
    Отсутствует - привилегии нет и её нельзя включить через AdjustTokenPrivileges
    П.С. надеюсь не наврал ничего )