обход DEP.. (снятие атрибута запрета на выполнение в ядре)

Тема в разделе "WASM.NT.KERNEL", создана пользователем ratix, 24 окт 2007.

  1. ratix

    ratix New Member

    Публикаций:
    0
    Регистрация:
    13 окт 2005
    Сообщения:
    52
    Адрес:
    Kyrgyzstan
    Похоже испытал на себе всю прелесть DEP (Data Execution Prevention)

    Мой старый код, который отлично работал в 32-х битном ядре отказывается выполняться на х64.
    подозреваю, что последовательность

    IoAllocateMdl
    MmProbeAndLockPages
    MmMapLockedPagesSpecifyCache

    резервирует MDL, по-умолчанию запрещенный к выполнению.. на х32 (без PAE) NX-бит не работает, а вот на х64 он включен..

    вобще, задача такая:
    промапить кусок кода из адресного пространства драйвера в адресное пространство какого-то процесса.
    для этого сначала вызываю KeStackAttachProcess
    затем создаю новый MDL:
    IoAllocateMdl

    MmProbeAndLockPages
    MmMapLockedPagesSpecifyCache - отдает адрес в юзермоде, на который потом прыгает для выполнения юзермодный процесс..

    так вот, в х32 - этот промапленный кусок кода замечательно выполняется..
    а в х64 - юзермод код выкидывает исключение на первой же инструкции промапленного кода:
    Problem Event Name: BEX64
    Exception Code: C0000005

    думаю, что это как-раз DEP срабатывает.

    вопрос в следующем: как изменить атрибуты этого куска памяти - пометить его "выполняемым".

    Олег
     
  2. Cr4sh

    Cr4sh New Member

    Публикаций:
    0
    Регистрация:
    17 апр 2006
    Сообщения:
    668
    NtProtectVirtualMemory на промапленый кусок возможно?
     
  3. ratix

    ratix New Member

    Публикаций:
    0
    Регистрация:
    13 окт 2005
    Сообщения:
    52
    Адрес:
    Kyrgyzstan
    Cr4sh

    Нет, мне нужен кернел-аналог этой ф-ции.. (причем присутствующий в экспортах ntoskrnl.exe, т.к. для доступа к сервисам ядра я разбираю ExportTable ntoskrnl.exe)..

    мне нужно изменять этот атрибут из ринг0
     
  4. ratix

    ratix New Member

    Публикаций:
    0
    Регистрация:
    13 окт 2005
    Сообщения:
    52
    Адрес:
    Kyrgyzstan
    возможно решением будет также разбор PDE/PTE вручную, и отключение NX-бита в задействованных страницах.. но хотелось бы чего-то попроще..
     
  5. TermoSINteZ

    TermoSINteZ Синоби даоса Команда форума

    Публикаций:
    2
    Регистрация:
    11 июн 2004
    Сообщения:
    3.552
    Адрес:
    Russia
    ratix

    Ага, сталкивался с такой херней. Выделяешь память и меняешь уровень доступа к ней.
    Либо меняй биты вручную.
    либо как вариант сделать аттач к процессу и заказать память с нужными аттрибутами через ZwAllocateVirtualMemory
     
  6. ratix

    ratix New Member

    Публикаций:
    0
    Регистрация:
    13 окт 2005
    Сообщения:
    52
    Адрес:
    Kyrgyzstan
    TermoSINteZ

    вот в том то и вопрос: как менять уровень доступа из ядра (NtProtectVirtualMemory/ZwAllocateVirtualMemory - юзермодные ф-ции)

    Есть указатель на промапленную память, и MDL.

    неужели нет способа кроме правки битов вручную в каталогах страниц?
     
  7. TermoSINteZ

    TermoSINteZ Синоби даоса Команда форума

    Публикаций:
    2
    Регистрация:
    11 июн 2004
    Сообщения:
    3.552
    Адрес:
    Russia
    ratix
    С какого это перепугу что они юзермодные? Если они есть в Ntdll.dll это не значит что их нет в ядре!
    Если ты хочешь тока через мдл и таблицы страниц... думаю нет других способов. Ихмо проще приаттачиться и заюзать. Ибо все равно никто это дело не просечет.
     
  8. ratix

    ratix New Member

    Публикаций:
    0
    Регистрация:
    13 окт 2005
    Сообщения:
    52
    Адрес:
    Kyrgyzstan
    нашел ф-цию
    MmProtectMdlSystemAddress

    но она почему-то работает тока для памяти промапленной в ядерное адресное просранство (вызов MmMapLockedPagesSpecifyCache(pMdl, KernelMode, ...))

    если же память замаплена в юзермод (с помощью MmMapLockedPagesSpecifyCache(pMdl, UserMode, ...), то MmProtectMdlSystemAddress возвращает ошибку 0хс0000019

    как же быть.. так не хочется разбирать страницы вручную..

    TermoSINteZ
    помоему атачиться только для того, чтобы изменит атрибуты - слишком сложный путь.. разбор и правка PDE/PTE и то проще..
     
  9. Cr4sh

    Cr4sh New Member

    Публикаций:
    0
    Регистрация:
    17 апр 2006
    Сообщения:
    668
    дык какая разница, вызывай её через int 2eh и все будет гуд
     
  10. yuzvir

    yuzvir New Member

    Публикаций:
    0
    Регистрация:
    20 май 2005
    Сообщения:
    97
    Код (Text):
    1. ULONG ExecuteFlags = MEM_EXECUTE_OPTION_ENABLE;
    2.  
    3. NtSetInformationProcess(
    4.     NtCurrentProcess(),    // (HANDLE)-1
    5.     ProcessExecuteFlags,   // 0x22
    6.     &ExecuteFlags,         // ptr to 0x2
    7.     sizeof(ExecuteFlags)); // 0x4
    http://www.securitylab.ru/analytics/263899.php

    подобная тема недавно на кряклабе обсуждалась
    http://cracklab.ru/f/index.php?action=vthread&forum=6&topic=10176
     
  11. rain

    rain New Member

    Публикаций:
    0
    Регистрация:
    22 апр 2006
    Сообщения:
    976
    и будет не гуд а бсод =) int2eh на х64 теперь только в юзере
    вы же не одни живёте всё уже написано =)
    (ц) моЁ =)
    Код (Text):
    1. int
    2. NXFree(DWORD_PTR ptr) // 64-bit not PAE!
    3. //
    4. //  disables NX bit for page pointed by ptr on x64 platform
    5. //
    6. {
    7.     DWORD_PTR* pPML4,* pPDP,* pPD,* pPT, PML4e, PDPe, PDe, PTe;
    8.     PHYSICAL_ADDRESS phys;
    9.    
    10.  
    11.     KDPRINT(("\nNXFree goes.. param = 0x%p\n", ptr));
    12.  
    13.     pPML4 = (DWORD_PTR*) GetPML4Base();
    14.     if (pPML4)
    15.     {
    16.         KDPRINT((" pPML4 = 0x%p\n", pPML4));
    17.        
    18.         phys.QuadPart = (LONGLONG)((ptrdiff_t)pPML4+ (ptrdiff_t)(VM_GET_PML4OFFSET(ptr)*sizeof(DWORD_PTR)));
    19.        
    20.         KDPRINT((" PML4 index = 0x%p, PML4 phys addr = 0x%p\n", VM_GET_PML4OFFSET(ptr), phys.QuadPart));
    21.  
    22.         pPML4 = (DWORD_PTR*)MmMapIoSpace(phys, sizeof(DWORD_PTR), MmNonCached);
    23.         if (!pPML4)
    24.         {
    25.             KDPRINT(("*** ERROR: PML4e phys map fails"));
    26.             return 0;
    27.         }
    28.         PML4e = *pPML4;
    29.         MmUnmapIoSpace((PVOID)pPML4, sizeof(ptrdiff_t));
    30.         if (PML4e)
    31.         {
    32.             KDPRINT((" PML4e = 0x%p\n", PML4e));
    33.  
    34.             phys.QuadPart = (LONGLONG)((ptrdiff_t)(PML4e & VM_MAP_BASE_POINTER) + (ptrdiff_t)(VM_GET_PDPOFFSET(ptr)*sizeof(DWORD_PTR)));
    35.  
    36.             KDPRINT((" PDP index = 0x%p, PDP phys addr = 0x%p\n", VM_GET_PDPOFFSET(ptr), phys.QuadPart));
    37.  
    38.             pPDP = MmMapIoSpace(phys, sizeof(DWORD_PTR), MmNonCached);
    39.             if (!pPDP)
    40.             {  
    41.                 KDPRINT(("*** ERROR: PDPe phys map fails"));
    42.                 return 0;
    43.             }
    44.             PDPe = *pPDP;
    45.             MmUnmapIoSpace(pPDP, sizeof(DWORD_PTR));
    46.             if (PDPe)
    47.             {
    48.                 KDPRINT((" PDPe = 0x%p\n", PDPe));
    49.  
    50.                 phys.QuadPart = (LONGLONG)((ptrdiff_t)(PDPe & VM_MAP_BASE_POINTER) + (ptrdiff_t)(VM_GET_PDOFFSET(ptr)*sizeof(DWORD_PTR)));
    51.  
    52.                 KDPRINT((" PD intex = 0x%p, PD phys addr = 0x%p\n", VM_GET_PDOFFSET(ptr), phys.QuadPart));
    53.  
    54.                 pPD = (DWORD_PTR *)MmMapIoSpace(phys, sizeof(DWORD_PTR), MmNonCached);
    55.                 if (!pPD)
    56.                 {
    57.                     KDPRINT(("*** ERROR: PDe phys map fails"));
    58.                     return 0;
    59.                 }
    60.                 PDe = *pPD;
    61.                
    62.  
    63.                 KDPRINT((" PDe = 0x%p\n", PDe));
    64.                 //
    65.                 //  checking for 4k/2m pages
    66.                 //
    67.                 if (PDe & PDE_PS)
    68.                 {
    69.                     // 2M pages
    70.                     KDPRINT(("2 megabyte page detected\n"));
    71.                     if (PDe & NX_FLAG)
    72.                     {
    73.                         *pPD = PDe & (~NX_FLAG);
    74.                         KDPRINT(("New PTE = 0x%p\n", *pPD));
    75.                     }
    76.                     else
    77.                     {
    78.                         KDPRINT(("page is already executable\n"));
    79.                     }
    80.                    
    81.                 }
    82.                 else
    83.                 {
    84.                     // 4K pages
    85.                     if (PDe)
    86.                     {
    87.    
    88.                         phys.QuadPart = (LONGLONG)((ptrdiff_t)(PDe & VM_MAP_BASE_POINTER) + (ptrdiff_t)(VM_GET_PTOFFSET(ptr)*sizeof(DWORD_PTR)));
    89.  
    90.                         KDPRINT((" PT index = 0x%p, PT phys addr = 0x%p\n", VM_GET_PTOFFSET(ptr), phys.QuadPart));
    91.  
    92.                         pPT = (DWORD_PTR *)MmMapIoSpace(phys, sizeof(DWORD_PTR), MmNonCached);
    93.                         if (!pPT)
    94.                         {
    95.                             KDPRINT(("*** ERROR: PTe phys map fails"));
    96.                            
    97.                             return 0;
    98.                         }
    99.                         PTe = *pPT;
    100.                        
    101.                         if (PTe)
    102.                         {
    103.                             KDPRINT((" PTe = 0x%p\n", PTe));
    104.  
    105.                             //
    106.                             // clear NX bite
    107.                             //
    108.                             if (PTe & NX_FLAG)
    109.                             {
    110.                                 WriteFlagClear();
    111.                                 *pPT = PTe & (~NX_FLAG);
    112.                                 WriteFlagRestore();
    113.                                 KDPRINT(("New PTE = 0x%p\n", *pPT));
    114.                             }
    115.                            
    116.                         }
    117.                         else
    118.                         {
    119.                             KDPRINT(("*** ERROR: PTe is empty"));
    120.                             return 0;
    121.                         }
    122.                         MmUnmapIoSpace(pPT, sizeof(DWORD_PTR));
    123.                     }
    124.                     else
    125.                     {
    126.                         KDPRINT(("*** ERROR: PDe is empty"));
    127.                         return 0;
    128.                     }
    129.                     //end 4k
    130.                 }
    131.                 KDPRINT(("unmap pPD...\n"));
    132.                 MmUnmapIoSpace(pPD, sizeof(DWORD_PTR));
    133.             }
    134.             else
    135.             {
    136.                 KDPRINT(("*** ERROR: PDPe is empty"));
    137.                 return 0;
    138.             }
    139.            
    140.         }
    141.         else
    142.         {
    143.             KDPRINT(("*** ERROR: PML4e is empty"));
    144.             return 0;
    145.         }
    146.     }
    147.     else
    148.     {
    149.         KDPRINT(("*** ERROR: pPML4 is empty"));
    150.         return 0;
    151.     }
    152.  
    153.     return 1;
    154. }
    Кстати сколько сталкивался зачастую при выделении памяти при ExAllocatePool память не содержит атрибута NX, а вот стек почти всегда его содержит
     
  12. Cr4sh

    Cr4sh New Member

    Публикаций:
    0
    Регистрация:
    17 апр 2006
    Сообщения:
    668
    PreviousMode тогда у своего потока на UserMode менять, или там как чекается?
     
  13. rain

    rain New Member

    Публикаций:
    0
    Регистрация:
    22 апр 2006
    Сообщения:
    976
    ыы, я заблуждался
    1) В ядре нет обрадотчика такого прерывания вообще, вызов его ведёт прямиком в KiUnexpectedInterrupt.
    Zw кернел заглушки для вызова Nt функций просто jmp'аются на KiServiceInternal
    2) int2eh вызывает нарушени доступа не только в кенел но и юзермоде даже в 32-х битных приложениях.
    Вызов из х32 кода системного сервиса выглядит примерно так:
    Код (Text):
    1. .text:7D61CFA8                 mov     eax, 52h        ; NtCreateFile
    2. .text:7D61CFAD                 xor     ecx, ecx
    3. .text:7D61CFAF                 lea     edx, [esp+arg_0]
    4. .text:7D61CFB3                 call    large dword ptr fs:0C0h
    по адресу fs:[c0h]:
    Код (Text):
    1. 78B81910   EA 2C3CB878 3300 JMP FAR 0033:78B83C2C                    ; Far jump
    чесно говоря я хз как проследить куда отсуда передаётся управление мой kd говорит : "The context is partially valid. Only x86 user-mode context is available." и отказывается трейсить :-\
    небезивестный skywing'а говорит:
    и приводит трейс:
    Код (Text):
    1. ntdll_777f0000!ZwWaitForMultipleObjects+0xe:
    2. 00000000`7783aebe 64ff15c0000000  call    dword ptr fs:[0C0h]
    3. 0:000:x86> t
    4. wow64cpu!X86SwitchTo64BitMode:
    5. 00000000`759c31b0 ea27369c753300  jmp     0033:759C3627
    6. 0:012:x86> t
    7. wow64cpu!CpupReturnFromSimulatedCode:
    8. 00000000`759c3627 67448b0424      mov     r8d,dword ptr [esp]
    Кстати заметил _любопытную особенность_, при тестинге на варе (5.5.2) в х64 коде если вызвать int 2eh варя навернётся с "*** Virtual machine kernel stack fault (hardware reset) ***" :) я не знаю почему, весёлая антиотладка, как считаете? )