1. Если вы только начинаете программировать на ассемблере и не знаете с чего начать, тогда попробуйте среду разработки ASM Visual IDE
    (c) на правах рекламы
    Скрыть объявление

Получение индекса текущего сервиса SSDT внутри его обработчика

Тема в разделе "WASM.NT.KERNEL", создана пользователем m0zg, 2 июн 2011.

  1. Charlief

    Charlief New Member

    Публикаций:
    0
    Регистрация:
    17 авг 2010
    Сообщения:
    129
    Да klzlk вы правы спутал Call Ebx и Call [ebx].


    Но чтобы вызвать из сохраненной таблицы оригинальный обработчик как раз и подойдёт, в ebx как раз и будет адрес оригинального обработчика.

    А жаль, вам всего-то одна ассемблерная инструкция необходима: push ebx или mov yourNtFunc, ebx. Может на С++ ассемблерную вставку сделать в начале вашей функции ?
     
  2. m0zg

    m0zg New Member

    Публикаций:
    0
    Регистрация:
    1 июл 2009
    Сообщения:
    21
    Да ассемблерную вставку то без проблем, если это поможет. Я сейчас ebx так и извлекаю: __asm { mov SavedEbx, ebx }
     
  3. m0zg

    m0zg New Member

    Публикаций:
    0
    Регистрация:
    1 июл 2009
    Сообщения:
    21
    Только сейчас дошло - индекс вообще ненужен получается =)
     
  4. Charlief

    Charlief New Member

    Публикаций:
    0
    Регистрация:
    17 авг 2010
    Сообщения:
    129
    Помоему там ещё один ньюанс, в зависимости от номера сервиса, _KiFastCallEntry этот сервис может вызвать из _KeServiceDescriptorTableShadow - а вдруг там другой указатель на ServiceTable которую вы не перехватываете, тогда возможно вообще ничего не получится. Чем SDT из _ KeServiceDescriptorTable от SDT из _KeServiceDescriptorTableShadow отличается я не знаю. Я выше написал что индекс сравнивается с ServiceLimit...
     
  5. m0zg

    m0zg New Member

    Публикаций:
    0
    Регистрация:
    1 июл 2009
    Сообщения:
    21
    хм... все таки в ebx не адрес оригинального обработчика =) там же адрес текущего...
    В Shadow XP еще 667 NtGdi и NtUser сервисов которые с KeServiceDescriptorTable вроде никак не пересекаются.

    Короче актуален вопрос с _KTRAP_FRAME, почему там в eax не индекс, а все время разные числа. Может я не оттуда получаю этот _KTRAP_FRAME?
     
  6. Charlief

    Charlief New Member

    Публикаций:
    0
    Регистрация:
    17 авг 2010
    Сообщения:
    129
    Ну точно мне ночью лучьше спать, я два раза уже протупил.

    При входе в сервис в eax его индекс, так как в _KiFastCallEntry ввыполняется следующий код:
    Код (Text):
    1. mov     ebx, [edi+eax*4]
    2. ...
    3. call    ebx
    в edi адрес ServiceTable, а в eax индекс который не затирается нигде до вызова сервиса.
     
  7. klzlk

    klzlk New Member

    Публикаций:
    0
    Регистрация:
    2 июн 2011
    Сообщения:
    449
    m0zg
    Почему то я думал что Eax там не меняется, оказалось что этот регистр не сохраняется. Можно есчо проверить к какой сст относится ссылка, для получения номера таблицы. Тоесть если SST{CONTEXT.rEax} = CONTEXT.rEbx, то Id = rEax, иначе если ShadowSST{CONTEXT.rEax} = CONTEXT.rEbx, то Id = rEax + 0x1000.
     
  8. m0zg

    m0zg New Member

    Публикаций:
    0
    Регистрация:
    1 июл 2009
    Сообщения:
    21
    Итог: в трезвом уме перечитав вот этот блог
    получил вот этот код на родном С++
    Код (Text):
    1.     undoc::PETHREAD pEThread = (undoc::PETHREAD)PsGetCurrentThread();
    2.     undoc::PKTRAP_FRAME pKTrapFrame = pEThread->Tcb.TrapFrame;
    3.  
    4.     PULONG *HardwareEsp = (PULONG *)pKTrapFrame->HardwareEsp;
    5.     PULONG pSystemCallStub = *HardwareEsp;
    6.     PULONG pCodeBytes = (PULONG)((ULONG)pSystemCallStub - 0x0000000C);
    7.     ULONG idx = ((*pCodeBytes) >> 8) & 0x00000FFF;
    Из недостатков только использование 3-х недокументированных структур да и всего остального =).

    И запасной вариант
    Код (Text):
    1.     CONTEXT ctx = {0};
    2.     RtlCaptureContext(&ctx);//Скажем ассемблерным вставкам НЕТ!
    3.  
    4.     ULONG ServiceLimit = KeServiceDescriptorTable->ntoskrnl.ServiceLimit;
    5.     PULONG pSST = (PULONG)KeServiceDescriptorTable->ntoskrnl.ServiceTable;
    6.     ULONG Id = 0;
    7.     while(Id < ServiceLimit)
    8.     {
    9.         if(ctx.Ebx == pSST[Id])
    10.             break;
    11.         Id++;
    12.     }
     
  9. TSS

    TSS New Member

    Публикаций:
    0
    Регистрация:
    13 апр 2009
    Сообщения:
    494
    m0zg
    Ну перехват сдт это тоже недокументированно, так что идеология сохранена =]
     
  10. klzlk

    klzlk New Member

    Публикаций:
    0
    Регистрация:
    2 июн 2011
    Сообщения:
    449
    TSS
    Вы предлагаете трогать пользователькую память(стек). Это худшее из возможных решений, так как там в памяти что угодно может быть.
     
  11. TSS

    TSS New Member

    Публикаций:
    0
    Регистрация:
    13 апр 2009
    Сообщения:
    494
    И чтоже там может быть если автор подменяет обработчики? Пример в студию.
     
  12. klzlk

    klzlk New Member

    Публикаций:
    0
    Регистрация:
    2 июн 2011
    Сообщения:
    449
    TSS
    ntdll!ZwCreateEvent:
    Jmp NewStub ; Интересно каким будет Id, если сюда поставить брейк :D
    Каким будет ID ?
    Можно есчо встроить это в какойнить фаер, прикольный обход получится..
     
  13. TSS

    TSS New Member

    Публикаций:
    0
    Регистрация:
    13 апр 2009
    Сообщения:
    494
    Ни на одной ос такого нет, пример высосан из пальца.
     
  14. klzlk

    klzlk New Member

    Публикаций:
    0
    Регистрация:
    2 июн 2011
    Сообщения:
    449
    TSS
    Ну вы же понимаете что читать данные из юзермода в ядерном хэндлере это маразм. Потенциальная дыра и крайне не стабильное решение. Это требует оригинальную проекцию модуля в памяти. Обычно такого нет, всякие инлайн патчи, точки останова и тп. используются часто. Тотже вирификатор про который вы писали в своём блоге сделает не возможным чтение сервисов(если описаны стабы в нем). Мне то конечно всёравно, но такое даже аверы не юзают =)
     
  15. TSS

    TSS New Member

    Публикаций:
    0
    Регистрация:
    13 апр 2009
    Сообщения:
    494
    klzlk
    Автор как я понимаю хочет просто универсальный логгер сервисов сделать для своих целей, для этого чтение юзермодной памяти в перехваченном хендлере это самое простое и незатратное решение. Конечно если он коммерческий AV продукт делает, то нужно что-то другое ( правда непонятно, зачем тогда все сервисы хватать ).
     
  16. klzlk

    klzlk New Member

    Публикаций:
    0
    Регистрация:
    2 июн 2011
    Сообщения:
    449
    TSS
    Чем же плохо решение выше(со scas) или это ?:
    Код (Text):
    1. kssdoit, Nt*:
    2.     if SDT.SST(Win32k).ServiceTable[eax*4] = Ebx
    3.         add eax,1000H
    4.     fi
    Да и вообще можно изменить менеджер сисколов как угодно. Вообще отморфить в буфер и установить ссылки на него(мср и 0x2e шлюз). Либо пофиксить сервисный шлюз в US. Или тупо пропатчить нтос. Ничем не хуже и не проще загрузки ссылок в сервисные таблицы. Более того, гибко получится(не нужно будет париться с определением входного контекста, так Pre-хэндлер).
     
  17. TSS

    TSS New Member

    Публикаций:
    0
    Регистрация:
    13 апр 2009
    Сообщения:
    494
    Решение должно быть оправдано поставленной цели.
    Если я делаю логгер сисколов для себя который будет запускаться на чистой машине(без перехватов юзермодных и тд), то зачем мне чего-то там морфить в буфер?
    Также если делается тулза именно на поимку малвари - то тут уже незачем вобще делать то, что делает автор, достаточно перехватить все в одном месте.
     
  18. klzlk

    klzlk New Member

    Публикаций:
    0
    Регистрация:
    2 июн 2011
    Сообщения:
    449
    TSS
    Я общие решения рассматриваю, а не уникальные для вашей машины и лично вами собранного ядра :)
    Морфить зачем - обьясню. Ну я например предпочитаю перенести оригинальный код в буфер, там его изменить и юзать, в обход детекторов. Можно релоцировать модуль, но это простое линейное копирование. Ребилд кода позволяет автоматизировать изменение кода, например интегрировать туда макрос, причём таким образом, что детекта не будет(вам то без разницы, но мне например это очень важно). Тотже Т-фрейм как формировать(это понадобится если захачить менеджер сискалов гдето ближе к входу в диспетчер) ? Регистрировать свои ISR и тп.. лучше взять у системы готовый участок кода.