Перехват АПИ, сплайсинг Vista, kernel

Тема в разделе "WASM.NT.KERNEL", создана пользователем sasha_s, 25 июн 2009.

  1. sasha_s

    sasha_s New Member

    Публикаций:
    0
    Регистрация:
    21 дек 2005
    Сообщения:
    165
    Адрес:
    Belarus
    Перехватываю некоторые ф-ции вставкой джампа (естественно дизассемблирую и т.д.).
    Адреса ф-ций беру из SDT, а ее в свою очередь читаю и высчитываю прямо из файла ntoskrnl.exe (ядро определяю какое в данный момент загружено).
    Так вот, стал тестить под Вистой, а там бсод.
    Ладно, добавил MmIsAddressValid. Проверил под XP, там перестали хукаться парочка ф-ций, причем устойчиво. До этого проверял только на NULL (найдена/не найдена ф-ция под данной операционкой) и все хукалось, джамп вставлялся без БСОДа.
    Под Вистой БСОД пропал, но там добрый десяток ф-ций не хукаются, потому как не срабатывает MmIsAddressValid.
    Проверил адреса ф-ций, мот не так высчитал, нет -- все совпадает с загруженной в данный момент SDT.

    Первое предположение: по какой-то причине страница, содержащая код этих ф-ций сброшена в файл подкачки.

    Что это за ситуация может быть и как с этим бороться?
     
  2. x64

    x64 New Member

    Публикаций:
    0
    Регистрация:
    29 июл 2008
    Сообщения:
    1.370
    Адрес:
    Россия
    Показывай код установки сплайса (т.е. jmp'а твоего) и анализ дампа (это обязательно). Также перечисли, какие именно функции перехватываешь. MmIsAddressValid здесь ни при чём.
     
  3. punxer

    punxer Андрей

    Публикаций:
    0
    Регистрация:
    16 окт 2006
    Сообщения:
    1.327
    Адрес:
    Ржев
    x64
    MmIsAddressValid здесь ни при чём.

    Капистан очевидность вернулся. Надо отпраздновать))
    Код фстудию!
     
  4. sasha_s

    sasha_s New Member

    Публикаций:
    0
    Регистрация:
    21 дек 2005
    Сообщения:
    165
    Адрес:
    Belarus
    Кто вернулся?
     
  5. sasha_s

    sasha_s New Member

    Публикаций:
    0
    Регистрация:
    21 дек 2005
    Сообщения:
    165
    Адрес:
    Belarus
    Дамп я не делаю, в WinDbg подключаюсь к виртуалке.
    !analyze -v подойдет?

    Ф-ции я перехватываю следующие:
    Все ф-ции для работы с реестром, NtCreateProcess(Ex), NtCreateThread(Ex), NtCreateSection, NtDebugActiveProcess, NtWriteVirtualMemory.

    Вот вам код:
    Код (Text):
    1.     ULONG CR0Reg;
    2.     DISABLE_INT(&CR0Reg);
    3.  
    4.     //тут идет сам перехват:
    5.     install_hook(fnNtWriteVirtualMemory, wrapNtWriteVirtualMemory, trampolineNtWriteVirtualMemory);
    6.     //где: fnNtWriteVirtualMemory -- адресс перехватываемой ф-ции
    7.     //wrapNtWriteVirtualMemory -- мой обработчик
    8.     //trampolineNtWriteVirtualMemory -- туда пишеться код вызова реальной ф-кии, т.е. копиться шапка (которую я
    9.     //заменил) и джапм обратно на код после шапки
    10.  
    11.     ...
    12.     ...
    13.  
    14.     ENABLE_INT(&CR0Reg);
    вот ф-ции:
    Код (Text):
    1. void DISABLE_INT(ULONG *CR0Reg)
    2. {
    3.     ULONG CR0RegLocal = 0;
    4.     __asm cli;
    5.     __asm mov eax, cr0;
    6.     __asm mov CR0RegLocal, eax;
    7.     __asm and eax, 0xFFFEFFFF;
    8.     __asm mov cr0, eax;
    9.     *CR0Reg = CR0RegLocal;
    10. }
    11.  
    12. void ENABLE_INT(ULONG *CR0Reg)
    13. {
    14.     ULONG CR0RegLocal = *CR0Reg;
    15.     __asm mov eax, CR0RegLocal;
    16.     __asm mov cr0, eax;
    17.     __asm sti;
    18. }
    19.  
    20. size_t install_hook(PVOID target_func, PVOID hook_func, PVOID trampoline)
    21. {
    22.     size_t original_size = CopyCodeCalcSize(target_func, sizeof(JMP_CODE), NULL);
    23.     if (original_size < sizeof(JMP_CODE)
    24.         || !target_func
    25.         || !hook_func
    26.         || !trampoline)
    27.     {
    28.         TRACE(("install_hook: ERROR CopyCodeCalcSize original_size=%d; sizeof(JMP_CODE)=%d", original_size, sizeof(JMP_CODE)));
    29.         TRACE(("install_hook: ERROR target_func=%X; hook_func=%X; trampoline=%X", target_func, hook_func, trampoline));
    30.         return 0;
    31.     }
    32.    
    33.     __try
    34.     {
    35.         size_t size = CopyCodeCalcSize(target_func, original_size, trampoline);
    36.         ASSERT(size == original_size);
    37.         init_JMP_CODE((PJMP_CODE)((PUCHAR)trampoline + original_size), (PUCHAR)target_func + original_size);
    38.  
    39.         init_JMP_CODE((PJMP_CODE)target_func, hook_func);
    40.  
    41.     }
    42.     __except(EXCEPTION_EXECUTE_HANDLER)
    43.     {
    44.         TRACE(("install_hook: EXCEPTION"));
    45.         return 0;
    46.     }
    47.    
    48.     return original_size;
    49. }
    50.  
    51. CopyCodeCalcSize -- дизасемблит код и высчитывает кол-во байт для копирования из шапки
    52. init_JMP_CODE -- вставляет джапм
    Весь код неоднократно использовался на ОСях 2к, ХР, 2к3 со всеми SP.
    Но вот на висте вылезло.
     
  6. sasha_s

    sasha_s New Member

    Публикаций:
    0
    Регистрация:
    21 дек 2005
    Сообщения:
    165
    Адрес:
    Belarus
    А почему она выдает FALSE для адресов ф-ций под XP, которые хукаются без проблем?
     
  7. x64

    x64 New Member

    Публикаций:
    0
    Регистрация:
    29 июл 2008
    Сообщения:
    1.370
    Адрес:
    Россия
    О ней и речь, давай её тоже сюда.
     
  8. x64

    x64 New Member

    Публикаций:
    0
    Регистрация:
    29 июл 2008
    Сообщения:
    1.370
    Адрес:
    Россия
    Да блин, MmIsAddressValid здесь ни при чём и вообще не показатель. Код многих функций в ядре является выгружаемым и запросто может вызвать page fault. Но это нормальная ситуация, которая будет корректно и прозрачно обработана Memory Manager'ом, тебе не нужно об этом думать.
     
  9. sasha_s

    sasha_s New Member

    Публикаций:
    0
    Регистрация:
    21 дек 2005
    Сообщения:
    165
    Адрес:
    Belarus
    Я тоже так думал. Тем более что хук я ставлю по запросу IOCTL из юзермода.
    Тока что спецом проверил IRQL, KeGetCurrentIrql выдала 0! Значит страничка должна подкачиваться. Под XP так и есть, а под Вистой что-то непонятное...

    Кстате !analyze -v выдал: "CURRENT_IRQL: 2", кто врет?

    Вот !analyze -v :

    DRIVER_IRQL_NOT_LESS_OR_EQUAL (d1)
    An attempt was made to access a pageable (or completely invalid) address at an
    interrupt request level (IRQL) that is too high. This is usually
    caused by drivers using improper addresses.
    If kernel debugger is available get stack backtrace.
    Arguments:
    Arg1: 819999c0, memory referenced
    Arg2: 000000ff, IRQL
    Arg3: 00000000, value 0 = read operation, 1 = write operation
    Arg4: 90516c06, address which referenced memory

    Debugging Details:
    ------------------

    READ_ADDRESS: 819999c0

    CURRENT_IRQL: 2

    FAULTING_IP:
    KernelProtect+bc06
    90516c06 0fb602 movzx eax,byte ptr [edx]

    DEFAULT_BUCKET_ID: VISTA_DRIVER_FAULT

    BUGCHECK_STR: 0xD1

    PROCESS_NAME: ProtectLoader.e

    TRAP_FRAME: 94b028d8 -- (.trap 0xffffffff94b028d8)
    ErrCode = 00000000
    eax=94b029de ebx=00000000 ecx=90520024 edx=819999c0 esi=84256538 edi=84080980
    eip=90516c06 esp=94b0294c ebp=94b02954 iopl=0 nv up di ng nz na pe nc
    cs=0008 ss=0010 ds=0023 es=0023 fs=0030 gs=0000 efl=00010086
    KernelProtect+0xbc06:
    90516c06 0fb602 movzx eax,byte ptr [edx] ds:0023:819999c0=8b
    Resetting default scope

    LAST_CONTROL_TRANSFER: from 81913c83 to 818f1a98

    STACK_TEXT:
    94b0249c 81913c83 00000003 7de0f231 00000000 nt!RtlpBreakWithStatusInstruction
    94b024ec 81914769 00000003 819999c0 90516c06 nt!KiBugCheckDebugBreak+0x1c
    94b028b8 81893fb9 0000000a 819999c0 000000ff nt!KeBugCheck2+0x66d
    94b028b8 90516c06 0000000a 819999c0 000000ff nt!KiTrap0E+0x2e1
    WARNING: Stack unwind information not available. Following frames may be wrong.
    94b02954 90517a91 819999c0 94b029c8 905201ac KernelProtect+0xbc06
    94b029ac 9051a80d 819999c0 819999c0 94b029c8 KernelProtect+0xca91
    94b02b20 9051aa90 819999c0 00000020 819999c0 KernelProtect+0xf80d
    94b02b50 9051aae3 819999c0 00000005 00000000 KernelProtect+0xfa90
    94b02b98 90511a16 819999c0 90510470 905254c0 KernelProtect+0xfae3
    94b02be0 9050e62a 00000004 81933c0e 00000000 KernelProtect+0x6a16
    94b02c2c 8188a976 84256538 84037a80 84037a80 KernelProtect+0x362a
    94b02c44 81a8c6a1 84080980 84037a80 84037af0 nt!IofCallDriver+0x63
    94b02c64 81a8ce46 84256538 84080980 00000000 nt!IopSynchronousServiceTail+0x1d9
    94b02d00 81a8df10 84256538 84037a80 00000000 nt!IopXxxControlFile+0x6b7
    94b02d34 81890c7a 00000088 00000000 00000000 nt!NtDeviceIoControlFile+0x2a
    94b02d34 77035e74 00000088 00000000 00000000 nt!KiFastCallEntry+0x12a
    0013f784 77034810 769250eb 00000088 00000000 ntdll!KiFastSystemCallRet
    0013f788 769250eb 00000088 00000000 00000000 ntdll!ZwDeviceIoControlFile+0xc
    0013f7e8 6cfd4473 00000088 00222044 00000000 kernel32!DeviceIoControl+0x14a
    0013f93c 6cfd8b48 00222044 00000000 00000000 kernelprotectdll!DrvLoader::sendIOCTL+0x113
    0013fb78 001bd721 13e176d0 00000000 00000000 kernelprotectdll!KernelProtect::LoadDriver+0x4a8
    0013fcc4 001bfe86 00000001 01b81c00 01b81c88 ProtectLoader!wmain+0x61
    0013fd10 001bfd5f 0013fd24 7694d0e9 7ffd5000 ProtectLoader!__tmainCRTStartup+0x116
    0013fd18 7694d0e9 7ffd5000 0013fd64 770119bb ProtectLoader!wmainCRTStartup+0xf
    0013fd24 770119bb 7ffd5000 7708abfd 00000000 kernel32!BaseThreadInitThunk+0xe
    0013fd64 7701198e 001bb569 7ffd5000 00000000 ntdll!__RtlUserThreadStart+0x23
    0013fd7c 00000000 001bb569 7ffd5000 00000000 ntdll!_RtlUserThreadStart+0x1b

    STACK_COMMAND: kb

    FOLLOWUP_IP:
    KernelProtect+bc06
    90516c06 0fb602 movzx eax,byte ptr [edx]

    SYMBOL_STACK_INDEX: 4

    SYMBOL_NAME: KernelProtect+bc06

    FOLLOWUP_NAME: MachineOwner

    MODULE_NAME: KernelProtect

    IMAGE_NAME: KernelProtect.sys

    DEBUG_FLR_IMAGE_TIMESTAMP: 4a44b5a6

    FAILURE_BUCKET_ID: 0xD1_KernelProtect+bc06

    BUCKET_ID: 0xD1_KernelProtect+bc06

    Followup: MachineOwner
    ---------
     
  10. Clerk

    Clerk Забанен

    Публикаций:
    0
    Регистрация:
    4 янв 2008
    Сообщения:
    6.689
    Адрес:
    РБ, Могилёв
    sasha_s
    Ну так ведь прерывания запрещены, вот и падает:
    >
    >
     
  11. Clerk

    Clerk Забанен

    Публикаций:
    0
    Регистрация:
    4 янв 2008
    Сообщения:
    6.689
    Адрес:
    РБ, Могилёв
    (IF сброшен) если не понятно.)
     
  12. sasha_s

    sasha_s New Member

    Публикаций:
    0
    Регистрация:
    21 дек 2005
    Сообщения:
    165
    Адрес:
    Belarus
    От чорт!
    Т.е. чтобы хукнуть ф-цию, надо вначале обратиться к ее адресу, чтобы страницу если что достали, а потом уже запретить прерывания и записать джапм?
     
  13. Clerk

    Clerk Забанен

    Публикаций:
    0
    Регистрация:
    4 янв 2008
    Сообщения:
    6.689
    Адрес:
    РБ, Могилёв
    Конечно, если вышружается. Хотя можно её вручную достать или прямо в свопе писать.

    А по нормальному модификация кода исполняется атомарно, тогда прерывания запрещать не нужно.
     
  14. sasha_s

    sasha_s New Member

    Публикаций:
    0
    Регистрация:
    21 дек 2005
    Сообщения:
    165
    Адрес:
    Belarus
    И как же сию операцию атомарно задолбить?
     
  15. Clerk

    Clerk Забанен

    Публикаций:
    0
    Регистрация:
    4 янв 2008
    Сообщения:
    6.689
    Адрес:
    РБ, Могилёв
    Взглянув на нужный код под дизасмом и помня про префикс Lock вы поймёте.
     
  16. sasha_s

    sasha_s New Member

    Публикаций:
    0
    Регистрация:
    21 дек 2005
    Сообщения:
    165
    Адрес:
    Belarus
    Уж не сочтите за тупого зануду, но я ничего не понял.

    На какой код мне взглянуть и у чего префикс Lock?
     
  17. x64

    x64 New Member

    Публикаций:
    0
    Регистрация:
    29 июл 2008
    Сообщения:
    1.370
    Адрес:
    Россия
    Всё бы хорошо, но вопрос - почему тогда у него не падает на Windows XP? И вот здесь в своей статье Ms-Rem пишет, что вот такой код работает без дополнительных телодвижений. Ммм?
     
  18. sasha_s

    sasha_s New Member

    Публикаций:
    0
    Регистрация:
    21 дек 2005
    Сообщения:
    165
    Адрес:
    Belarus
    Да, меня тоже мучит этот вопросс.
    Видно в Висте добавили парочку проверок.
    По другому не могу объяснить.
     
  19. Clerk

    Clerk Забанен

    Публикаций:
    0
    Регистрация:
    4 янв 2008
    Сообщения:
    6.689
    Адрес:
    РБ, Могилёв
    x64
    Потомучто чтото не выгружается, взялибы да посмотрели если так интересно, мне безразницы.
    sasha_s
    Intel® 64 and IA-32 Architectures Software Developer’s Manual Volume 3A System Programming Guide, 7.1 etc.
    На какой код взглянуть вам лучше знать, практически перед всеми сервисами есть свободное пространство в 5 байт, куда можно записать длинный джамп, а начало сервисов - пролог mov edi,edi двухбайтный, либо загрузка размера стекового фрейма инструкцией push #, в обоих случаях размер инструкции два байта, туда можно записать короткий джамп, например:
    Код (Text):
    1. 004B15BF                90      nop
    2. 004B15C0                90      nop
    3. 004B15C1                90      nop
    4. 004B15C2                90      nop
    5. 004B15C3                90      nop
    6. 004B15C4 NtWriteVirtualMemory       6A 1C       push 1C
    7. 004B15C6                68 D0EF4100 push 0041EFD0
    8. 004B15CB                E8 B3A8F5FF call _SEH_prolog
    После сплайсинга:
    Код (Text):
    1. 004B15BF                E9 XXXX     jmp near XXXX
    2. 004B15C4 NtWriteVirtualMemory       EB F9       jmp short 004B15BF
    3. 004B15C6                68 D0EF4100 push ntoskrnl.0041EFD0
    4. 004B15CB                E8 B3A8F5FF call _SEH_prolog
    Вначале пишем ниже на пять байт от сервиса дальний джамп, затем атомарно пишем короткий джамп туда:
    Код (Text):
    1.     mov ax,0F9EBH
    2.     lock xchg word ptr ds:[0x4B15C4],ax
    Ну или считам предварительно следующие два байта и менять атомарно сразу 4 байта(следующие два не меняются).
    Что тут может быть не понятно..
     
  20. sasha_s

    sasha_s New Member

    Публикаций:
    0
    Регистрация:
    21 дек 2005
    Сообщения:
    165
    Адрес:
    Belarus
    ASM -- ваша стихия. Я в асме далеко не супер-пупер.
    lock -- я не знал сей инструкции.
    Теперь все понятно!