отслеживание записи из r0 в r3

Тема в разделе "WASM.NT.KERNEL", создана пользователем volodya, 22 ноя 2008.

  1. volodya

    volodya wasm.ru

    Публикаций:
    0
    Регистрация:
    22 апр 2003
    Сообщения:
    1.169
    Господа, есть вопрос к лицам компетентным. Возможно ли как-то узнать (в общем случае) пишет ли та или иная ядровая функция в r3?

    Вот, предположим, вызвал я fopen. Далее, по цепочке CreateFile => NtCreateFile => syscall => SST => NtCreateFile => IoCreateFile. И, вот, вопрос: можно ли разработать какую-то тулзу, которая бы сказала, предположим, что ZwCreateFile пишет (или не пишет) туда-то и туда-то в r3?
     
  2. wsd

    wsd New Member

    Публикаций:
    0
    Регистрация:
    8 авг 2007
    Сообщения:
    2.824
    volodya
    если точный ответ нужен, наверно только в ручную


    может скажешь для какой это цели и более рентабельные решения у кого-то появяться.
     
  3. CrystalIC

    CrystalIC New Member

    Публикаций:
    0
    Регистрация:
    26 июл 2008
    Сообщения:
    500
  4. zorro

    zorro New Member

    Публикаций:
    0
    Регистрация:
    8 ноя 2008
    Сообщения:
    33
    Можно конечно, они ж все перед записью в р3 ProbeForWrite() дергают.
     
  5. volodya

    volodya wasm.ru

    Публикаций:
    0
    Регистрация:
    22 апр 2003
    Сообщения:
    1.169
    Цель-то, конечно, мне сказать не жалко. Есть такая тулза - valgrind. Под линухом она себе живет и здравствует. А, когда попробовали скатить ее под винду, то обнаружился ряд заморочек, от которых сильно поплохело.

    valgrind замечателен, прежде всего, своей абсолютно дикой точностью. Процент false positive/false negative ничтожен. Достигается это, помимо прочего, очень качественными аннотациями сисколлов. Вот пример:

    Код (Text):
    1. PRE(sys_llseek)
    2. {
    3.    PRINT("sys_llseek ( %d, 0x%x, 0x%x, %p, %d )", ARG1,ARG2,ARG3,ARG4,ARG5);
    4.    PRE_REG_READ5(long, "llseek",
    5.                  unsigned int, fd, unsigned long, offset_high,
    6.                  unsigned long, offset_low, vki_loff_t *, result,
    7.                  unsigned int, whence);
    8.    PRE_MEM_WRITE( "llseek(result)", ARG4, sizeof(vki_loff_t));
    9. }
    10. POST(sys_llseek)
    11. {
    12.    vg_assert(SUCCESS);
    13.    if (RES == 0)
    14.       POST_MEM_WRITE( ARG4, sizeof(vki_loff_t) );
    15. }
    Видим PRE/POST-обработчики. Эти обработчики вносят нужные коррекции во внутренние карты памяти волгринда. Т.о. волгринд дико точно определяет внутреннее состояние программы во время ее выполнения. Именно поэтому волгринд так популярен.

    http://valgrind.org/docs/manual/dist.readme-missing.html - вот тут подробнее.

    Теперь о сути проблемы.

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

    Хочется решить вопрос более интеллектуальным способом. Для этого, опять таки, в качестве примера, рассмотрим цепочку:

    ZwQueryInformationProcess => syscall => NtQueryInformationProcess

    Функция достаточно проста в плане r3-части. Существуют много более сложные функции, например, DbgPrint, которая может вызвать самые разные сисколлы в зависимости от входных данных. Часть аннотации на данный сисколл у нас есть благодаря тому, что мы знаем прототип функции (или ее сигнатуру - как угодно):

    Код (Text):
    1. NTSTATUS WINAPI ZwQueryInformationProcess(
    2.   __in       HANDLE ProcessHandle,
    3.   __in       PROCESSINFOCLASS ProcessInformationClass,
    4.   __out      PVOID ProcessInformation,
    5.   __in       ULONG ProcessInformationLength,
    6.   __out_opt  PULONG ReturnLength
    7. );
    Благодаря этому мы можем проаннотировать сисколл. Можем, да не совсем :-\

    Итак, после syscall управление переходит в ядро, где принимается исполняться код NtQueryInformationProcess. И, чтобы написать POST-аннотации для такого сисколла, нужно знать, а не шалит ли NtQueryInformationProcess с записью в r3. Может быть, он меняет там что-то еще, помимо __out PVOID ProcessInformation и __out_opt PULONG ReturnLength? Мы этого не знаем. Выхода два:

    1. Глазками для каждой функции в SST (и всех остальных таблицах) смотрим, чего она делает => читай вариант про индусов.
    2. Придумываем что-то более интеллектуальное. То, что, хотя бы полуавтоматом сможет выполнить часть работы. Допустим: автоматически сгенеренное утверждение: NtQueryInformationProcess ничего не пишет в r3. Допустим: автоматически сгенеренное утверждение: NtQueryInformationProcess пишет в r3 в строке PAGE:0049CEDB.

    Тогда у нас несколько сужается диапазон поиска. Нужно просматривать уже не все функции, а не которые. И для этих некоторых смотреть не всю функцию, а ее куски.

    И, на основании этих данных, писать POST-аннотации.
     
  6. z0mailbox

    z0mailbox z0

    Публикаций:
    0
    Регистрация:
    3 фев 2005
    Сообщения:
    635
    Адрес:
    Russia СПБ
    Нельзя
    Ядро может читать-писать напрямую без ексепшинов
    Если страница RO - есть бит WP в CR0
    ProbeForWrite совсем необязательно дергать - можно на СЕХах сделать

    Можно такое сделать для совершенно конкретного случая, например для ReadFile мы знаем в какой буфер будет запись
    С этим буфером можно тогда химичить
    Но generic - нельзя ИМХО
     
  7. wasm_test

    wasm_test wasm test user

    Публикаций:
    0
    Регистрация:
    24 ноя 2006
    Сообщения:
    5.582
    Сбросить Present для всех страниц в юзермоде конкретного процесса и ловить PF для этого процесса пока работает отслеживаемая функция. Адреса будут, потом уже можно посмотреть по входным параметрам и найти что означает адрес. фиксирован ли он (KUSER_SHARED_DATA какой-нибудь), является ли буффером выходным и т.п.
    Хоть что-то будет
     
  8. CrystalIC

    CrystalIC New Member

    Публикаций:
    0
    Регистрация:
    26 июл 2008
    Сообщения:
    500
    Может протрассировать ?
     
  9. wasm_test

    wasm_test wasm test user

    Публикаций:
    0
    Регистрация:
    24 ноя 2006
    Сообщения:
    5.582
    Трассировать и логировать каждую инструкцию, которая обращается к памяти? Самоубийство.
    Проще уж все страницы невалидными сделать
     
  10. CrystalIC

    CrystalIC New Member

    Публикаций:
    0
    Регистрация:
    26 июл 2008
    Сообщения:
    500
    Great
    Наверно нужно запретить запись, а чтение этих строниц разрешить если оно было разрешено.
    Тогда со стеком множество проблем возникнет, не забываем про KiUser*.
    А если секция два раза спроецирована, как за этим следить...
     
  11. wasm_test

    wasm_test wasm test user

    Публикаций:
    0
    Регистрация:
    24 ноя 2006
    Сообщения:
    5.582
    Ну если надо следить обращения - тогда P=0, если запись - тогда W=0 и CR0.WP=1
    почему? я же сказал - только на время выполнения нужной кернел функции. просят то только ядерную функу отследить. а там не будет лишних обращений, кроме KUSER_SHARED_DATA
    поясни?
     
  12. Folk Acid

    Folk Acid New Member

    Публикаций:
    0
    Регистрация:
    23 авг 2005
    Сообщения:
    432
    Адрес:
    Ukraine
    Боюсь показаться ламером, но почему нельзя включить отладку с помощью отладочных регистров доступа к памяти, на чтение соотв. сегмента LDT/GDT?

    Ну или, если значение cs разное для r0 и r3, то оформить свою дескрипторную таблицу-ловушку.
     
  13. green

    green New Member

    Публикаций:
    0
    Регистрация:
    15 июл 2003
    Сообщения:
    1.217
    Адрес:
    Ukraine
    Можно покопать в сторону ring -1. Т.е. аппаратной виртуализации.
     
  14. wasm_test

    wasm_test wasm test user

    Публикаций:
    0
    Регистрация:
    24 ноя 2006
    Сообщения:
    5.582
    разве можно поставить hw-бряк на область больше 4х байт?
    конечно разное. можно записать в DS сегмент невалидный и ловить исключение
    можно и шлюз ловушки (а что он тебе даст кроме перехвата управления? которое можно осуществить хуком в SSDT нужной функции)

    но мне кажется что лучше будет сбросить PDPE.P у первых двух записей из четырех. меньше всего хлопот
    хукаем в ssdt нужную функцию, при вызове делаем невалидным юзермодное АП и ставим хук на #PF. дальше смотрим если адрес юзермодный то попались.

    а лучше даже не хук в ssdt, а подменить саму таблицу в KTHREAD->ServiceTable. Чтобы это влияло только на конкретный поток и замораживалось юзермодное АП конкретного процесса.
     
  15. wsd

    wsd New Member

    Публикаций:
    0
    Регистрация:
    8 авг 2007
    Сообщения:
    2.824
    Great
    теоретически функция может вести себя по разному, в зависимости от
    значений аргументов. Т.Е. получается чтобы получить варианты результатов,
    нужно будет её(функцию) прогнать на всю область значений аргументов.
    поправь меня пожалуйста если что не так.
     
  16. wasm_test

    wasm_test wasm test user

    Публикаций:
    0
    Регистрация:
    24 ноя 2006
    Сообщения:
    5.582
    Теоритически да, практически же писать она обычно может либо в выходной буффер, адрес и размер которого будем считать известными (видимо для каждой функции придется указать что является выходным буффером, можно взять из prefast annotations всякие там _out _out_bcount) и яано заданными, либо в какой-то буффер, адрес которого лежит во входных структкрах, либо в буффер, помеченный как in & out, либо в независимую от аргументов область (KUSER_SHARED_DATA например). я ничего не упустил?
     
  17. Folk Acid

    Folk Acid New Member

    Публикаций:
    0
    Регистрация:
    23 авг 2005
    Сообщения:
    432
    Адрес:
    Ukraine
    Изначально моя мысль потерялась где-то в недрах перехвата обращения к самой таблице GDT/LDT, они ж должны описывать сами себя. Хотя и не факт, что сами регистры DR0-DR3 не отлавливают лишь асмовские интрукции, а не обращение процессора к памяти, или что таблицы не кешируются где-нибудь внутри процессора.
     
  18. wasm_test

    wasm_test wasm test user

    Публикаций:
    0
    Регистрация:
    24 ноя 2006
    Сообщения:
    5.582
    Записи действительно кешируются в теневых частях сегментных регистров.
     
  19. wsd

    wsd New Member

    Публикаций:
    0
    Регистрация:
    8 авг 2007
    Сообщения:
    2.824
    Great
    наверно нет.
    только всёравно мы сейчас стоим на ручном труде -
    ручной разбор сигнатур на айн, оут и айн - оут .
    и прокручивать весь диапазон входных значений(аргументов) для
    получения возможных выходных значений.
    проще наверно будет продизасмить в ручную
    у тебя какие предположения автоматизации этого процесса?
     
  20. volodya

    volodya wasm.ru

    Публикаций:
    0
    Регистрация:
    22 апр 2003
    Сообщения:
    1.169
    ну а чем плох прогон всех возможных значений? тот же фаззер. вызываем ZwQueryInformationProcess со всеми возможными аргументами, смотрим, в какие странички памяти r3 оно ползает. писать такой фаззер проще, чем делать ручной разбор.