Прототип KiUserApcDispatcher

Тема в разделе "WASM.BEGINNERS", создана пользователем HoShiMin, 14 дек 2017.

  1. HoShiMin

    HoShiMin Well-Known Member

    Публикаций:
    5
    Доброго здравия форумчанам.
    Думаю, сразу можно позвать Indy_, речь всё о том же.
    Чтобы отловить все апк, перехватываю KiUserApcDispatcher, но при попытке вызвать оригинал, обламываюсь на Access Violation в недрах KiUserCallForwarder.

    Пробовал прототип с hex.pp.ua, пробовал такой:
    Код (C):
    1.  
    2. VOID NTAPI KiUserApcDispatcher(
    3.     PVOID NormalContext,
    4.     PVOID SystemArgument1,
    5.     PVOID SystemArgument2,
    6.     CONTEXT Context // Целиком в стеке
    7. );
    8.  
    И прототип из WRK:
    Код (C):
    1.  
    2. VOID NTAPI KiUserApcDispatcher(
    3.     PVOID NormalContext,
    4.     PVOID SystemArgument1,
    5.     PVOID SystemArgument2,
    6.     PVOID NormalRoutine
    7. );
    8.  
    И на каждом прототипе при вызове оригинала получаю AV в KiUserCallForwarder на jmp rax. Win10 x64, использую MinHook. Как, всё-таки, перехватить его правильно?
     
  2. TermoSINteZ

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

    Публикаций:
    2
    А что мешает открыть IDAPro да и посмотреть как и че там
    Код (ASM):
    1.                  public KiUserApcDispatcher
    2. .text:00000001800A39E0 KiUserApcDispatcher proc near           ; CODE XREF: KiUserApcDispatcher+3Aj
    3. .text:00000001800A39E0                                         ; DATA XREF: .rdata:00000001801165E8o ...
    4. .text:00000001800A39E0
    5. .text:00000001800A39E0 arg_0           = qword ptr  8
    6. .text:00000001800A39E0 arg_8           = qword ptr  10h
    7. .text:00000001800A39E0 arg_10          = qword ptr  18h
    8. .text:00000001800A39E0
    9. .text:00000001800A39E0                 mov     rcx, [rsp+arg_10]
    10. .text:00000001800A39E5                 mov     rax, rcx
    11. .text:00000001800A39E8                 mov     r9, rsp
    12. .text:00000001800A39EB                 sar     rcx, 2
    13. .text:00000001800A39EF                 mov     rdx, [rsp+arg_0]
    14. .text:00000001800A39F4                 neg     rcx
    15. .text:00000001800A39F7                 mov     r8, [rsp+arg_8]
    16. .text:00000001800A39FC                 shld    rcx, rcx, 20h
    17. .text:00000001800A3A01                 test    ecx, ecx
    18. .text:00000001800A3A03                 jz      short loc_1800A3A35
    19. .text:00000001800A3A05                 mov     rcx, [rsp+0]
    20. .text:00000001800A3A09                 call    KiUserCallForwarder
    21. .text:00000001800A3A0E
    22. .text:00000001800A3A0E loc_1800A3A0E:                          ; CODE XREF: KiUserApcDispatcher+65j
    23. .text:00000001800A3A0E                 mov     rcx, rsp
    24. .text:00000001800A3A11                 mov     dl, 1
    25. .text:00000001800A3A13                 call    ZwContinue
    26. .text:00000001800A3A18                 test    eax, eax
    27. .text:00000001800A3A1A                 jz      short KiUserApcDispatcher
    28. .text:00000001800A3A1C                 cmp     eax, 0C000060Ah
    29. .text:00000001800A3A21                 jnz     short loc_1800A3A2A
    30. .text:00000001800A3A23                 mov     ecx, 30h
    31. .text:00000001800A3A28                 int     29h             ; Win8: RtlFailFast(ecx)
    32. .text:00000001800A3A2A ; ---------------------------------------------------------------------------
    33. .text:00000001800A3A2A
    34. .text:00000001800A3A2A loc_1800A3A2A:                          ; CODE XREF: KiUserApcDispatcher+41j
    35. .text:00000001800A3A2A                 mov     esi, eax
    36. .text:00000001800A3A2C
    37. .text:00000001800A3A2C loc_1800A3A2C:                          ; CODE XREF: KiUserApcDispatcher+53j
    38. .text:00000001800A3A2C                                         ; KiUserApcDispatcher+6Ej
    39. .text:00000001800A3A2C                 mov     ecx, esi
    40. .text:00000001800A3A2E                 call    RtlRaiseStatus
    41. .text:00000001800A3A33                 jmp     short loc_1800A3A2C
    42. .text:00000001800A3A35 ; ---------------------------------------------------------------------------
    43. .text:00000001800A3A35
    44. .text:00000001800A3A35 loc_1800A3A35:                          ; CODE XREF: KiUserApcDispatcher+23j
    45. .text:00000001800A3A35                 mov     eax, [rsp+0]
    46. .text:00000001800A3A38                 or      rcx, rax
    47. .text:00000001800A3A3B                 mov     rax, cs:Wow64ApcRoutine
    48. .text:00000001800A3A42                 test    rax, rax
    49. .text:00000001800A3A45                 jz      short loc_1800A3A0E
    50. .text:00000001800A3A47                 call    rax ; Wow64ApcRoutine
    51. .text:00000001800A3A49                 mov     esi, 0C000000Dh
    52. .text:00000001800A3A4E                 jmp     short loc_1800A3A2C
    53. .text:00000001800A3A4E KiUserApcDispatcher endp
    Код (C++):
    1. void __noreturn KiUserApcDispatcher()
    2. {
    3.   __int64 v0; // rdx@1
    4.   int v1; // eax@3
    5.   signed int i; // esi@6
    6.   void *retaddr; // [sp+0h] [bp+0h]@2
    7.   __int64 v4; // [sp+8h] [bp+8h]@0
    8.   __int64 v5; // [sp+10h] [bp+10h]@0
    9.   signed __int64 v6; // [sp+18h] [bp+18h]@0
    10.  
    11.   while ( 1 )
    12.   {
    13.     v0 = v4;
    14.     if ( (unsigned __int64)-(v6 >> 2) >> 0x20 )
    15.     {
    16.       KiUserCallForwarder(retaddr, v4, v5, &retaddr);
    17.     }
    18.     else if ( Wow64ApcRoutine )
    19.     {
    20.       Wow64ApcRoutine(
    21.         (unsigned int)retaddr | 0xFFFFFFFF00000000i64 * (v6 >> 2) | ((unsigned __int64)-(v6 >> 2) >> 0x20),
    22.         v4,
    23.         v5,
    24.         &retaddr);
    25.       i = 0xC000000D;
    26.       goto LABEL_7;
    27.     }
    28.     LOBYTE(v0) = 1;
    29.     v1 = ZwContinue(&retaddr, v0);
    30.     if ( v1 )
    31.     {
    32.       if ( v1 == 0xC000060A )
    33.         __fastfail(0x30u);
    34.       for ( i = v1; ; RtlRaiseStatus((unsigned int)i) )
    35. LABEL_7:
    36.         ;
    37.     }
    38.   }
    39. }
     
  3. unc1e

    unc1e Active Member

    Публикаций:
    2
    HoShiMin, неправильно ставишь хук, иных вариантов нет (вряд ли ниже rsp лежат данные, которые ты затираешь в обработчике хука. наверняка выравнивание стека сбилось). Попробуй обойтись без либы - использовать банальный сплайсинг.
    Обработчик будет примерно таким:

    Код (C):
    1. void __declspec(naked) wrapper_Render()
    2. {
    3.     __asm
    4.     {
    5.         pushad
    6.         pushfd
    7.  
    8.         call [handler_Render]
    9.  
    10.         popfd
    11.         popad
    12.  
    13.         push ebp //see disasm
    14.         lea ebp, [esp - 0x74]
    15.         jmp [retAddr_Render]
    16.     }
    17. }
    Тк пишешь под x64 - необходимо сохранять регистры в соответствии с соглашениями (киньте линк, где-то тут на форуме пдф валялась)
    // http://agner.org/optimize/calling_conventions.pdf
     
    Последнее редактирование: 14 дек 2017
  4. Indy_

    Indy_ Well-Known Member

    Публикаций:
    4
    У тс задача очень долгое время длится. Так как это не простая задача. Это локальное решение части общей задачи по анти инжектам.

    HoShiMin,

    Я дал вам общее решение, которое покрывает данное частное.

    Вы ведь понимаете что установка протект-фильтра в памяти юм не возможна, обсуждали ведь.

    А сам вопрос - что то крэшит, так откройте доки/маны/сурки и гляньте, я не вижу даже вопроса. Как описать крэш, его причины и прочее примитивное - думаю как то глупо и не уместно мой ник упомянать в таких вопросах. Эта примитивная рутина по разбору ошибок.
     
  5. HoShiMin

    HoShiMin Well-Known Member

    Публикаций:
    5
    Сколько ни пытаюсь нормально перехватить, не получается.
    Исходя из того, что передаётся в KiUserCallForwarder:
    RAX = [RSP + 18h] - адрес прыжка на APC-процедуру в KiUserCallForwarder
    RCX = [RSP] -???
    RDX = [RSP + 8] - ???
    R8 = [RSP + 10h] - ???
    R9 = RSP - указатель на CONTEXT, который дальше пойдёт в NtContinue

    Написал "сырой" обработчик с мостиком в сишный код:
    Код (ASM):
    1.  
    2. PUBLIC KiUserApcHandler
    3.  
    4. .CODE
    5.     EXTRN ApcHandler: PROC
    6.     EXTRN OriginalKiUserApcDispatcher: PROC
    7.  
    8.     KiUserApcHandler PROC
    9.         int 3h
    10.         push rax
    11.         push rcx
    12.         mov rcx, rsp
    13.         add rcx, 16
    14.         call ApcHandler
    15.         test rax, rax
    16.         pop rcx
    17.         pop rax
    18.         jz Exit
    19.         call OriginalKiUserApcDispatcher
    20. Exit:
    21.         ret
    22.     KiUserApcHandler ENDP
    23. END
    24.  
    Обработчик ApcHandler:
    Код (C):
    1.  
    2. BOOL FASTCALL ApcHandler(PCONTEXT Context) {
    3.     // ... Смотрим, что лежит в Context ...
    4.     return TRUE;
    5. }
    6.  
    В Context лежит мусор. Что же, всё-таки, лежит в стеке и по каким смещениям?
    MinHook сплайсит цепочками jmp'ов, регистры не меняет, стек не двигает.

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

    И всё же, вопрос скорее не об исправлении ошибок, а о том, как правильно перехватить нестандартную функцию, у которой все аргументы, несмотря на FASTCALL, лежат в стеке.
     
    Последнее редактирование: 15 дек 2017
  6. HoShiMin

    HoShiMin Well-Known Member

    Публикаций:
    5
    Быстрофикс. Не знаю, чей CONTEXT лежит в стеке, но пусть он и наполовину мусорный (почему?), но CS, SS и EFlags выглядят как и положено, а в P1Home (первое поле в CONTEXT) лежит адрес моей апк.
    Похоже на то, что я получил что хотел, но насколько это правильно? Действительно ли на х64 при входе в KiUserApcDispatcher вершина стека указывает на CONTEXT, и первое же поле (для адреса возврата, если сделать ret?) - адрес апк?

    upload_2017-12-15_3-54-18.png
     
  7. Indy_

    Indy_ Well-Known Member

    Публикаций:
    4
    HoShiMin,

    > для отдельно взятых процессов можно детектить даже подгрузку сторонних модулей через подмену импортов у доверенных библиотек (или самих библиотек), от чего не защитит визор.

    Это уже не задачи визора, он даст сервисные события, а их нужно соотвествующим образом обрабатывать. Вопрос проверки модулей ранее подробно рассматривался, это не решается в общем случае. Как узнать что модуль системный ?

    Делалось через запрос к службе sfc. Даже если модуль не системный, то он может быть каким то расширением, например ав. Или что то загружается в режиме совместимости.. Видимо нужно отловить событие инжекта, а его полезная нагрузка в случае защиты значения не имеет.

    > Похоже на то, что я получил что хотел, но насколько это правильно? Действительно ли на х64 при входе в KiUserApcDispatcher вершина стека указывает на CONTEXT

    Нужно изучить этот интерфейс, тоесть посмотреть какие и как параметры передаются из км, как они обрабатываются в юм. А главное сравнить как интерфейс меняется в версиях, может ли он меняться.
     
  8. Fail

    Fail Active Member

    Публикаций:
    0
    Апну тему, все же смежный вопрос. Почти:)

    А NtCreateDebugObject а Вин10 все еще присутствует?:blum3: Всмысле никаких изменений по поводу этой функи небыло? И аксесс маска DEBUG_OBJECT_TERMINATE все еще работает? Для выполнения только дебаг привилегия нужна?
     
    Последнее редактирование: 25 сен 2018