Включить Data Execution Prevention (DEP)

Тема в разделе "WASM.WIN32", создана пользователем kweed, 7 июн 2010.

  1. kweed

    kweed New Member

    Публикаций:
    0
    Регистрация:
    17 июн 2009
    Сообщения:
    81
    Программно, DEP отключается примерно так:
    Код (Text):
    1. DWORD flags = 0x02;
    2. NtSetInformationProcess((HANDLE)-1, 0x22, &flags, 4);
    все это проверено, все работает, НО, - я пытаюсь проделать обратную операцию:
    Код (Text):
    1. DWORD flags = 0x01;
    2. NtSetInformationProcess((HANDLE)-1, 0x22, &flags, 4);
    ProcessExplorer показавает что DEP успешно включен, но эксперименты со стеком показыавают обратное - код на стеке продолжает выполняться. Экспериментировал с разными значениями флагов - результат один... что я делаю не так, и как вообще можно программно включить DEP для одного конкретного процесса?

    зы. тестил на win xp sp2, проц amd64.
     
  2. Flasher

    Flasher Member

    Публикаций:
    0
    Регистрация:
    31 янв 2004
    Сообщения:
    640
    Обычно когда ручками вкл\выкл делаешь, требуется перезагрузить комп, мб именно в этом дело что надо ребутнуть?
    Кстати а как проверить программно DEP вкл или выкл?
     
  3. Flasher

    Flasher Member

    Публикаций:
    0
    Регистрация:
    31 янв 2004
    Сообщения:
    640
    А, Вы про вкл\выкл для определенного процесса, а я про глобально имел ввиду...
     
  4. kweed

    kweed New Member

    Публикаций:
    0
    Регистрация:
    17 июн 2009
    Сообщения:
    81
    можно через NtQueryInformationProcess с тем же флагом (0x22), хотя не проверял.. но люди вроде так делают...

    вот, кое-что http://forum.sysinternals.com/data-execution-prevention-dep_topic4687_page2.html конкретно, этот пост:
    - кстати тоже включить не могут =)
     
  5. Sol_Ksacap

    Sol_Ksacap Миша

    Публикаций:
    0
    Регистрация:
    6 мар 2008
    Сообщения:
    623
    kweed
    Ох, это простая одна. Включение\отключение DEP не меняет атрибуты существующих страниц.

    Если будет предпринята попытка выполнить невыполняемое, то произойдёт исключение; при выключенном относительно процесса DEP ядро отловит это исключение и снимет XD-бит у страницы, делая её выполняемой, после чего движение будет перезапущено (всё это происходит прозрачно для процесса). Соответственно, однажды выставленная для какой-либо страницы "выполнимость" сохраняется даже после включения DEP (до тех пор, пока кто-нибудь не воспользуется VirtualProtect() для снятия обсуждаемого атрибута).

    N.B.
    Весь пост чистая спекуляция; Лишь один из нескольких возможных вариантов.


    Да, кстати, раз уж мы здесь.
    Константа 0x22 – это член enum'а _PROCESSINFOCLASS, ProcessExecuteFlags.
    Эти флажки, в свою очередь, определяются элементом структуры _KPROCESS:
    Код (Text):
    1. 0:000> dt -v _kprocess flags.
    2. nt!_KPROCESS
    3. struct _KPROCESS, 35 elements, 0x80 bytes
    4.    +0x06b Flags  : struct _KEXECUTE_OPTIONS, 8 elements, 0x1 bytes
    5.       +0x000 ExecuteDisable : Bitfield Pos 0, 1 Bit
    6.       +0x000 ExecuteEnable : Bitfield Pos 1, 1 Bit
    7.       +0x000 DisableThunkEmulation : Bitfield Pos 2, 1 Bit
    8.       +0x000 Permanent : Bitfield Pos 3, 1 Bit
    9.       +0x000 ExecuteDispatchEnable : Bitfield Pos 4, 1 Bit
    10.       +0x000 ImageDispatchEnable : Bitfield Pos 5, 1 Bit
    11.       +0x000 DisableExceptionChainValidation : Bitfield Pos 6, 1 Bit
    12.       +0x000 Spare  : Bitfield Pos 7, 1 Bit
     
  6. kweed

    kweed New Member

    Публикаций:
    0
    Регистрация:
    17 июн 2009
    Сообщения:
    81
    Sol_Ksacap
    теперь понятно как делать, спасибо! за экспланацию флагов тоже спасибо =)
    как еще это можно сделать из user-mode?
     
  7. Sol_Ksacap

    Sol_Ksacap Миша

    Публикаций:
    0
    Регистрация:
    6 мар 2008
    Сообщения:
    623
    kweed
    >>Лишь один из нескольких возможных вариантов
    >как еще это можно сделать из user-mode?

    Здесь мы хотели сказать, что это один из вариантов объяснения наблюдаемого поведения. Т.е. касательно обработки ядром возможных ситуаций с DEP мы не имеем представления и почти весь пост состоял лишь из дрессированных догадок :)
     
  8. kweed

    kweed New Member

    Публикаций:
    0
    Регистрация:
    17 июн 2009
    Сообщения:
    81
    Sol_Ksacap
    так вот почему я до сих пор не могу включить его.. =)

    если серьезно, то с VirtualProtect есть такая неувязка: атрибуты страниц стека и так 0x04 - PAGE_READWRITE, вызов VirtualProtect с тем-же атрибутом ни к чему не приводит, да и с чего собсно? и с чего они должны изменяться при загрузке программы или после? ... или может быть я ни черта не понял?
     
  9. leo

    leo Active Member

    Публикаций:
    0
    Регистрация:
    4 авг 2004
    Сообщения:
    2.542
    Адрес:
    Russia
    kweed
    Дык, попробуй сначала установить EXECUTE, а затем просто READWRITE. Или выдели память VirtualAlloc-ом без EXECUTE и попробуй в ней выполнить код. Ну или создай новый поток и выполни код в его стеке. Если не сработает и для новых страниц, значит включение DEP в уже работающем приложении вообще не поддерживается
     
  10. kweed

    kweed New Member

    Публикаций:
    0
    Регистрация:
    17 июн 2009
    Сообщения:
    81
    leo
    речь не обязательно об уже работающем приложении, - возможно это как-то можно сделать на этапе загрузки..

    не думаю что эта функция так уж разборчива.. - на всякий случай проверил, - утешиться нечем =)
     
  11. kweed

    kweed New Member

    Публикаций:
    0
    Регистрация:
    17 июн 2009
    Сообщения:
    81
    тоже не катит. думаю все это не при чем здесь
     
  12. leo

    leo Active Member

    Публикаций:
    0
    Регистрация:
    4 авг 2004
    Сообщения:
    2.542
    Адрес:
    Russia
    kweed
    Вот и я так думаю ;)
    Во-первых, в 32-битной ОС хардварный DEP работает только при включенном PAE, а включать его для всех приложений только ради юзания одно NX\XD бита - выглядит довольно расточительным (из-за удвоения размера PDE\PTE). Поэтому возможно не зря в винде юзаются именно режимы OptIn и OptOut, когда DEP либо для всех выкл., либо для всех вкл. (за отдельными исключениями) и соотв-но при OptIn режим PAE по умолчанию не юзается. А если он не юзается изначально при создании образа, то и соотв-но и далее в процессе загрузки и работы приложения, включить его не возможно.
    Во-вторых, как бы то ни было, а отключить DEP во время работы приложения проще, чем включить, т.к. как уже сказал Sol_Ksacap, для отключения DEP достаточно сбрасывать установленные NX\XD-биты по мере возникновения исключений при доступе к страницам памяти. А вот для того чтобы его включить нужно "пробежаться" по всем PDE\PTE уже выделенных неисполняемых страниц и установить в них этот бит - явно лишняя морока, с которой мелкософты скорее всего решили не связываться ;)
     
  13. kweed

    kweed New Member

    Публикаций:
    0
    Регистрация:
    17 июн 2009
    Сообщения:
    81
    честно говоря я думал почему же нет чего-то вроде OptSingle... =) кстати, окуда система знает какие процессы нужно запускать с DEP в режиме OptIn?

    вот этот момент мне не понятен, - почему тогда включение DEP сразу же после отключения ни к чему не приводит (вернее приводит к исполнению стека):
    Код (Text):
    1.     Flags = 0x02;   //disable DEP
    2.     i = NtSetInformationProcess((HANDLE)-1, 0x22, &Flags, 4);
    3.  
    4.     Flags = 0x01;   //enable DEP
    5.     i = NtSetInformationProcess((HANDLE)-1, 0x22, &Flags, 4);
    6.  
    7.     __asm push    0x90909090;
    8.     __asm jmp     esp;
    ведь я не пытался исполнить стек между двумя вызовами NtSetInformationProcess
    прим. запускал в OptOut режиме.

    так может VirtualProtect будет работать в режиме PAE? (!)

    зы. как же всетаки включить все это при создании нового процесса???
     
  14. Clerk

    Clerk Забанен

    Публикаций:
    0
    Регистрация:
    4 янв 2008
    Сообщения:
    6.689
    Адрес:
    РБ, Могилёв
    kweed
    Там флажёк есть, запрещающий последующие изменения. Он на этапе инициализации процесса взводится, точно не помню, но вроде с GlobalFlags связано.
     
  15. kweed

    kweed New Member

    Публикаций:
    0
    Регистрация:
    17 июн 2009
    Сообщения:
    81
    Clerk
    нашел в msdn:
    http://msdn.microsoft.com/en-us/library/bb736299(v=VS.85).aspx

    кстати похоже что SetProcessDEPPolicy рулит... пожалуй обновлю до sp3 и попробую =)
     
  16. Clerk

    Clerk Забанен

    Публикаций:
    0
    Регистрация:
    4 янв 2008
    Сообщения:
    6.689
    Адрес:
    РБ, Могилёв
    kweed
    Код (Text):
    1. DECLSPEC_NOINLINE
    2. NTSTATUS
    3. MmSetExecuteOptions (
    4.     IN ULONG ExecuteOptions
    5.     )
    6.  
    7. /*++
    8.  
    9. Routine Description:
    10.  
    11.     This function sets the current process execution options that control NX
    12.     support and thunk emulation.
    13.  
    14. Arguments:
    15.  
    16.     ExecuteOptions - Supplies the process execution options.
    17.  
    18. Return Value:
    19.  
    20.     If the current process is a WIN64 process, a invalid set of execute
    21.     options is specified, or the permanent execute options bit is set,
    22.     then a failure status is returned. Otherwise, a success status is
    23.     returned.
    24.  
    25. --*/
    26.  
    27. {
    28.  
    29.     PEPROCESS CurrentProcess;
    30.     KLOCK_QUEUE_HANDLE LockHandle;
    31.     NTSTATUS Status;
    32.  
    33.     ASSERT (KeGetCurrentIrql () == PASSIVE_LEVEL);
    34.  
    35.     //
    36.     // Make sure reserved bits are clear.
    37.     //
    38.  
    39.     if ((ExecuteOptions & ~(MEM_EXECUTE_OPTION_VALID_FLAGS)) != 0) {
    40.         return STATUS_INVALID_PARAMETER;
    41.     }
    42.  
    43.     //
    44.     // Get the current process address.
    45.     //
    46.  
    47.     CurrentProcess = PsGetCurrentProcess ();
    48.  
    49. #if defined (_WIN64)
    50.  
    51.     if (CurrentProcess->Wow64Process == NULL) {
    52.         return STATUS_INVALID_PARAMETER;
    53.     }
    54.  
    55. #endif
    56.  
    57.     //
    58.     // Raise IRQL to SYNCH_LEVEL and acquire the process lock.
    59.     //
    60.     // If the permanent flag is set in the current process, then the process
    61.     // execute options cannot be set. Otherwise, set the process execution
    62.     // options.
    63.     //
    64.  
    65.     Status = STATUS_ACCESS_DENIED;
    66.     KeAcquireInStackQueuedSpinLockRaiseToSynch (&CurrentProcess->Pcb.ProcessLock,
    67.                                                 &LockHandle);
    68.  
    69.     if (CurrentProcess->Pcb.Flags.Permanent == 0) {
    70.         CurrentProcess->Pcb.Flags.ExecuteDisable = 0;
    71.         if ((ExecuteOptions & MEM_EXECUTE_OPTION_DISABLE) != 0) {
    72.             CurrentProcess->Pcb.Flags.ExecuteDisable = 1;
    73.         }
    74.    
    75.         if ((ExecuteOptions & MEM_EXECUTE_OPTION_ENABLE) != 0) {
    76.             CurrentProcess->Pcb.Flags.ExecuteEnable = 1;
    77.         }
    78.  
    79.         if ((ExecuteOptions & MEM_EXECUTE_OPTION_DISABLE_THUNK_EMULATION) != 0) {
    80.             CurrentProcess->Pcb.Flags.DisableThunkEmulation = 1;
    81.         }
    82.  
    83.         if ((ExecuteOptions & MEM_EXECUTE_OPTION_PERMANENT) != 0) {
    84.             CurrentProcess->Pcb.Flags.Permanent = 1;
    85.         }
    86.  
    87.         if ((ExecuteOptions & MEM_EXECUTE_OPTION_EXECUTE_DISPATCH_ENABLE) != 0) {
    88.             CurrentProcess->Pcb.Flags.ExecuteDispatchEnable = 1;
    89.         }
    90.  
    91.         if ((ExecuteOptions & MEM_EXECUTE_OPTION_IMAGE_DISPATCH_ENABLE) != 0) {
    92.             CurrentProcess->Pcb.Flags.ImageDispatchEnable = 1;
    93.         }
    94.  
    95.         if (CurrentProcess->Pcb.Flags.ExecuteEnable != 0) {
    96.             CurrentProcess->Pcb.Flags.ExecuteDispatchEnable = 1;
    97.             CurrentProcess->Pcb.Flags.ImageDispatchEnable = 1;
    98.         }
    99.  
    100.         Status = STATUS_SUCCESS;
    101.     }
    102.  
    103.     KeReleaseInStackQueuedSpinLock (&LockHandle);
    104.     return Status;
    105. }
    MEM_EXECUTE_OPTION_PERMANENT при инициализации процесса устанавливается. Ранее чем выполняется нотификация модулей. Можно использовать верификатор(application verifier).
     
  17. kweed

    kweed New Member

    Публикаций:
    0
    Регистрация:
    17 июн 2009
    Сообщения:
    81
    Clerk
    NtQueryInformationProcess не показывает его наличие (0x08?), и показывает успешное изменение других флагов... но флажек работает =), спасибо за инфу - сделаю патч на сервисы.
     
  18. Sol_Ksacap

    Sol_Ksacap Миша

    Публикаций:
    0
    Регистрация:
    6 мар 2008
    Сообщения:
    623
    В общем посмотрели эти механизмы. Сейчас пока времени нет все моменты описывать, но просто чтобы кто-нибудь не схватил неверные идеи сдампим основное:
    Не совсем верно. Атрибут меняется _только_ в PTE, причём временно (если бит валидности будет снят, то при его последующей установке будут выставлены реальные атрибуты). Обнаружить выполнимость такой 'модифицированной' страницы без экзаменации PTE (т.е. из ядра) нельзя никак (VirtualQuery() выдаёт "официальные" атрибуты). Также, как заметил leo, после включения DEP такие страницы не ревалидируются (на nt5; nt6 в рамках включения DEP корректно пробегает по валидным страницам из списка рабочего набора). Однократный VirtualProtect() (даже с прежними атрибутами) достаточен для исправления NX-бита. Любое снятие бита валидности PTE достаточно для исправления NX-бита.
    При проверке разрешения исполнимости эффективно OR'ятся контрольные флаги процесса и системы. Наличие любого разрешающего флага достаточно для выполнения. Отсутствие всех запрещающих флагов также ведёт к выполнению.
    Изменять флаги может только сам процесс, причём не все, причём большинство только в сторону разрешения, причём только если не выставлен флаг 'Permanent' (nt6 позволяет задать флаги извне при создании процесса, но при этом безусловно добавляется 'Permanent'; См. UpdateProcThreadAttribute()).

    kweed
    >так может VirtualProtect будет работать в режиме PAE? (!)
    Режим PAE обязателен для поддержки NX-бита.
     
  19. kweed

    kweed New Member

    Публикаций:
    0
    Регистрация:
    17 июн 2009
    Сообщения:
    81
    Sol_Ksacap
    GRACIAS SENORE!!! ТАК И ЕСТЬ:
    изначально, состояние флагов 0x00; после отключения получаю 0x32, а после включения 0x33 (!):
    Код (Text):
    1.     NtQueryInformationProcess((HANDLE)-1, 0x22, &Flags, 4, &size);
    2.     printf("%.8X\n", Flags);
    3.  
    4.     Flags = 0x02;
    5.     NtSetInformationProcess((HANDLE)-1, 0x22, &Flags, 4);
    6.     NtQueryInformationProcess((HANDLE)-1, 0x22, &Flags, 4, &size);
    7.     printf("%.8X\n", Flags);
    8.  
    9.     Flags = 0x01;
    10.     NtSetInformationProcess((HANDLE)-1, 0x22, &Flags, 4);
    11.     NtQueryInformationProcess((HANDLE)-1, 0x22, &Flags, 4, &size);
    12.     printf("%.8X\n", Flags);
    так что же это значит, - тупик (для user-mode)? и откуда могло взяться это 0x10 и 0x20? (т.е. ExecuteDispatchEnable и ImageDispatchEnable, как я понял)
     
  20. Clerk

    Clerk Забанен

    Публикаций:
    0
    Регистрация:
    4 янв 2008
    Сообщения:
    6.689
    Адрес:
    РБ, Могилёв
    kweed
    Код (Text):
    1. if (CurrentProcess->Pcb.Flags.ExecuteEnable != 0) {
    2.             CurrentProcess->Pcb.Flags.ExecuteDispatchEnable = 1;
    3.             CurrentProcess->Pcb.Flags.ImageDispatchEnable = 1;
    4.         }