PsSetLoadImageNotifyRoutine & NtProtectVirtualMemory

Тема в разделе "WASM.NT.KERNEL", создана пользователем freyr, 23 фев 2010.

  1. freyr

    freyr New Member

    Публикаций:
    0
    Регистрация:
    23 фев 2010
    Сообщения:
    95
    В обработчике калбэка ловлю ntdll.dll
    нахожу таблицу экспорта и пытаюсь изменить атрибуты защиты на EAT для функции LdrLoadDll
    NtProtectVirtualMemory возвращает C0000005 - STATUS_ACCESS_VIOLATION

    Прочитал ветку похожую http://wasm.ru/forum/viewtopic.php?id=25591&p=1


    Ну и еще есть некоторые ответы по той теме, например автор выяснил что

    это действительно так, потому как внутрях NtProtectVirtualMemory

    Код (Text):
    1.  result = ObReferenceObjectByHandle(ProcessHandle, 8u, PsProcessType, AccessMode[0], &BugCheckParameter1, 0);
    2.         if ( result >= 0 )
    3.         {
    4.           if ( v15 != BugCheckParameter1 )
    5.           {
    6.             KeStackAttachProcess((ULONG_PTR)BugCheckParameter1, (int)&v12);
    7.             v17 = 1;
    8.           }
    9.           v13 = MiProtectVirtualMemory(BugCheckParameter1, &v18, &v19, NewProtect, &v14);
    10.           if ( v17 )
    11.             KeUnstackDetachProcess(&v12);
    12.           ObfDereferenceObject(BugCheckParameter1);
    Кроме того, на сколько я понимаю, в это колбэке мы и так приаттачены к процессу от которого идет нотифи.

    исходя из этого у меня в коде макрос NtCurrentProcess()
    Код (Text):
    1. NtProtectVirtualMemory(NtCurrentProcess(), &BaseAddress, &Size, PAGE_READWRITE, &ulProtection);
    Ну и последнее, т.к я вызываю кернел версию NtProtectVirtualMemory, то скорее всего

    у меня они НЕ должны быть в юзер АП

    Вобщем мистика для меня...
     
  2. freyr

    freyr New Member

    Публикаций:
    0
    Регистрация:
    23 фев 2010
    Сообщения:
    95
    Никто ничего не подскажет ?
     
  3. Sol_Ksacap

    Sol_Ksacap Миша

    Публикаций:
    0
    Регистрация:
    6 мар 2008
    Сообщения:
    623
    KTHREAD.PreviousMode каков? Usermode, Kernelmode?
    Если один вызывает NtProtectVirtualMemory() с PreviousMode==Usermode и параметры-указатели определяют адреса за границей пользовательского пространства, то функция бросает исключение, ловит его – и выдаёт статус AV. Ведь если бы указатели не проверялись, пользовательский поток мог бы записать информацию по произвольному адресу в ядро, просто вызвав NtProtectVirutalMemory(), разве нет?

    Корректный путь – вызвать ZwProtectVirtualMemory().
     
  4. freyr

    freyr New Member

    Публикаций:
    0
    Регистрация:
    23 фев 2010
    Сообщения:
    95
    Да, в нотифи PreviousMode = Usermode

    ZwProtectVirtualMemory вызывать не очень хочется ИМХО это некрасиво в коде, да и под фильтры чужие можем попасть.


    Нашел кусок кода

    Код (Text):
    1. PreviousMode = KeGetPreviousMode();
    2.  
    3.     if (PreviousMode != KernelMode) {
    4.  
    5.         //
    6.         // Capture the region size and base address under an exception handler.
    7.         //
    8.  
    9.         try {
    10.  
    11.             ProbeForWritePointer (BaseAddress);
    12.             ProbeForWriteUlong_ptr (RegionSize);
    13.             ProbeForWriteUlong (OldProtect);
    14.  
    15.             //
    16.             // Capture the region size and base address.
    17.             //
    18.  
    19.             CapturedBase = *BaseAddress;
    20.             CapturedRegionSize = *RegionSize;
    21.  
    22.         } except (EXCEPTION_EXECUTE_HANDLER) {
    23.  
    24.             //
    25.             // If an exception occurs during the probe or capture
    26.             // of the initial values, then handle the exception and
    27.             // return the exception code as the status value.
    28.             //
    29.  
    30.             return GetExceptionCode();
    31.         }
    Не очень понятно из-за чего ловится exception, мб можно на время вызова переставить PreviousMode в KernelMode, не очень охото искать MiProtectVirtualMemory вызывая на прямую
     
  5. Sol_Ksacap

    Sol_Ksacap Миша

    Публикаций:
    0
    Регистрация:
    6 мар 2008
    Сообщения:
    623
    >под фильтры чужие можем попасть
    Но в таком случае фильтрование может осуществляться и на уровне NtProtectVirtualMemory(), и на уровне MiProtectVirtualMemory(). Т.е. мы бы не стали заморачиваться по этому поводу.

    >Не очень понятно из-за чего ловится exception
    Функции "ProbeForRead*" убеждаются, что параметр лежит в пользовательской области. Функции "ProbeForWrite*" убеждаются, что параметр лежит в пользовательской области и пытаются записать что-либо в каждую страницу, занимаемую параметром. +Проверка выравнивания. В случае несоответствия выполняется бросок.

    >мб можно на время вызова переставить PreviousMode в KernelMode
    Ну а кто ж запретит :)
     
  6. wasm_test

    wasm_test wasm test user

    Публикаций:
    0
    Регистрация:
    24 ноя 2006
    Сообщения:
    5.582
    freyr
    Я не нашел вопроса. Что тебе нужно, что подсказывать то? Там ясно написано как использовать ZwProtectVirtualMemory.
    У клерка научился?)) Забудь нафиг про неэкспортируемые внутренние апи.


    Единственный _корректный_ путь изменения аттрибутов защиты юзермодных страниц, особенно проекций секций, это ZwProtectVirtualMemory. Иначе у тебя есть все шансы похерить системный кеш, что, разумеется, ничем хорошим не закончится.
     
  7. freyr

    freyr New Member

    Публикаций:
    0
    Регистрация:
    23 фев 2010
    Сообщения:
    95
    Sol_Ksacap
    Спасибо большое, за объяснение всех моментов !

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

    И тем более так :)


    Код (Text):
    1. mov     eax, large fs:124h
    2. mov    [eax+140h], 0
    Так ? :)
     
  8. Clerk

    Clerk Забанен

    Публикаций:
    0
    Регистрация:
    4 янв 2008
    Сообщения:
    6.689
    Адрес:
    РБ, Могилёв
    Great
    Эм..
    Код (Text):
    1. ENTRY_MAXIMUM_LENGTH    equ 150H
    2.  
    3. OPCODE_CALL equ 0E8h
    4. OPCODE_RET  equ 0C3h
    5.  
    6. QueryMiProtectVirtualMemory proc uses ebx esi edi NtImageBase:PVOID, Sst:PVOID, MiProtectVirtualMemory:PVOID
    7. Local ImageHeader:PIMAGE_NT_HEADERS
    8. Local LocalSst:PVOID
    9. Local pNtProtectVirtualMemory:PVOID
    10. Local SizeOfOpcode:ULONG
    11. Local LastIp:PVOID
    12.     ENTER_SEH
    13.     invoke ImageNtHeader, NtImageBase, addr ImageHeader
    14.     test eax,eax
    15.     jnz exit_
    16.     invoke QueryNtProtectVirtualMemory, NtImageBase, addr LocalSst, addr pNtProtectVirtualMemory
    17.     test eax,eax
    18.     mov ebx,pNtProtectVirtualMemory
    19.     jnz exit_
    20.     lea esi,[ebx + ENTRY_MAXIMUM_LENGTH]
    21. step_:
    22.     invoke QueryInstructionSize, ebx, addr SizeOfOpcode
    23.     test eax,eax
    24.     jnz exit_
    25.     add ebx,SizeOfOpcode
    26.     cmp word ptr [ebx],75FFH    ; push dword ptr ss:[ebp + 14], (push NewProtectWin32)
    27.     jne next_
    28.     cmp byte ptr [ebx + 2],14H
    29.     jne next_
    30.     mov edi,6
    31.     mov LastIp,ebx
    32. @@:
    33.     invoke QueryInstructionSize, ebx, addr SizeOfOpcode
    34.     test eax,eax
    35.     jnz exit_
    36.     add ebx,SizeOfOpcode
    37.     dec edi
    38.     jnz @b
    39.     cmp byte ptr [ebx],OPCODE_CALL  ; Call MiProtectVirtualMemory
    40.     jne @f
    41.     mov edx,ImageHeader
    42.     add ebx,dword ptr [ebx + 1]
    43.     mov ecx,IMAGE_NT_HEADERS.OptionalHeader.SizeOfImage[edx]
    44.     cmp NtImageBase,ebx
    45.     jae @f
    46.     add ecx,NtImageBase
    47.     cmp ecx,ebx
    48.     ja valid_
    49. @@:
    50.     mov ebx,LastIp
    51.     jmp step_
    52. valid_:
    53.     add ebx,5
    54.     mov edx,MiProtectVirtualMemory
    55.     mov esi,LocalSst
    56.     mov ecx,Sst
    57.     sub ebx,NtImageBase
    58.     sub esi,NtImageBase
    59.     xor eax,eax
    60.     mov dword ptr [edx],ebx
    61.     mov dword ptr [ecx],esi
    62.     jmp exit_
    63. next_:
    64.     cmp ebx,esi
    65.     jb step_
    66. error_:
    67.     mov eax,STATUS_NOT_FOUND
    68. exit_:
    69.     LEAVE_SEH
    70.     ret
    71. QueryMiProtectVirtualMemory endp
    ;)
     
  9. Sol_Ksacap

    Sol_Ksacap Миша

    Публикаций:
    0
    Регистрация:
    6 мар 2008
    Сообщения:
    623
    freyr
    >замена начальных инструкций функции не в счет, уже никто давно так не балуется в ядре
    Хорошо знать :)

    >mov eax, large fs:124h
    >mov [eax+140h], 0
    А вот с этим аккуратно. Адрес объекта текущего потока в структуре _KPCR определён архитектурно (т.е. для всей 32х-битной линейки NT его гарантированно можно получить по смещению 124h относительно сегмента fs), однако смещения полей в объекте потока могут меняться от версии к версии. Так что смещение PreviousMode в KTHREAD лучше, вероятно, всякий раз вычленять из функции ExGetPreviousMode().
     
  10. Clerk

    Clerk Забанен

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