Сплайсинг

Тема в разделе "WASM.BEGINNERS", создана пользователем asmfan, 6 мар 2007.

  1. asmfan

    asmfan New Member

    Публикаций:
    0
    Регистрация:
    10 июл 2006
    Сообщения:
    1.004
    Адрес:
    Abaddon
    А настолько ли уж он, сплайсинг, безопасен в своей природе?
    Ладно уж если будем затирать nop'ы в тех или иных проявлениях (mov edi,edi), ну или сохранять в буфере код пролога, допустим, но ведь возможны же неэнтерабильные случаи, когда мы своим 2х (5ти) байтным жампом затрём или даже если сохраним, то только часть команд/команды, т.е. незаконно врежемся в середину какого-нить опкода... Ну а если тем более ф-я без пролога - сразу нужные команды неизвестной в рантайм длины.
    Интересно услышать ваши соображения.
     
  2. gilg

    gilg New Member

    Публикаций:
    0
    Регистрация:
    19 май 2005
    Сообщения:
    527
    Для этих случаев придумали дизассемблер. Например, у Ms Rem в коде к статье про перехваты функций используется простейший дизассемблер длин инструкций.

    Сплайсинг небезопасен, но по другим причинам:
    1) трудно получить эксклюзивную блокировку (тем не менее, решаемо как в ядре, так и в юзер-моде)
    2) нет гарантий, что другой поток не прервется между двумя инструкциями, которые мы потом заменим на свои (решаемо только в юзер-моде)
     
  3. wasm_test

    wasm_test wasm test user

    Публикаций:
    0
    Регистрация:
    24 ноя 2006
    Сообщения:
    5.582
    gilg
    Я думаю, что, наоборот, решаемо только в кернел моде, т.к. можно запретить планирование потоков через повышение IRQL до уровня DPC/Dispatch.
    действительно, все это решаемо, поэтому сплайсинг достаточно безопасен, если правильно его использовать

    А тебе не пофиг, что ты там затер своим джампом? Все равно потом из буфера восстановишь.

    Сплайсинг вообще даже с учетом всех минусов я считаю самым удобным способом перехвата апи в юзермоде и в кернел моде (тех функ, которых нет в SSDT).
     
  4. gilg

    gilg New Member

    Публикаций:
    0
    Регистрация:
    19 май 2005
    Сообщения:
    527
    Great
    А поток тем временем возобновит свое выполнение и попадет либо в середину инструкции, либо хз куда :) Имеется в виду, что поток может быть прерван ДО начала установки хука и возобновлен ПОСЛЕ. В ядре отследить этот факт невозможно
     
  5. asmfan

    asmfan New Member

    Публикаций:
    0
    Регистрация:
    10 июл 2006
    Сообщения:
    1.004
    Адрес:
    Abaddon
    Я имел ввиду установку своей функции-посредника, а не заместителя, т.е. продолжить исполнение исходной ф-ии с буфера. При неполных опкодах - не удастся, идея с дизассемблером длин как раз есть выход из ситуации, но разве простейшим можно обойтись при всём многообразии и избыточности решений?
     
  6. gilg

    gilg New Member

    Публикаций:
    0
    Регистрация:
    19 май 2005
    Сообщения:
    527
    Количество инструкций у процессора тем не менее конечно :)
     
  7. wasm_test

    wasm_test wasm test user

    Публикаций:
    0
    Регистрация:
    24 ноя 2006
    Сообщения:
    5.582
    Дизассемблер НЕ НУЖЕН!
    Ты затираешь первые 5 байт джампом, предварительно копируя их в буфер. Далее внутри хука для вызова оригинальной функции твои действия:
    - восстановить 5 байт из буфера
    - вызвать функцию
    - снова записать джамп.
    Короче, смотри мою статью про сплайсинг. Я там все написал, кажется =\
    Линк: http://forum.antichat.ru/thread32176.html
    У меня там новый обработчик NtQuerySystemInformation сначала снимает хук, потом вызывает оригинальную функцию и ставит хук обратно. Никаких дизассемблеров не надо

    Если другой поток будет прерван до установки хуки и возобновлен после (так и будет, если повышать IRQL), вроде бы ничего страшного не случится.. или я туплю?
    Ведь самое страшное будет если наш поток установки хука будет прерван посередине установки хука, то другой поток, который захочет вызвать функцию, вылетит.
    Ну а если мы повышаем IRQL до DPC/Dispatch, наш поток может быть прерван:
    - до установки хука. Тогда другой поток при вызове попадает в оригинальную функцию
    - после установки хука. Тогда другой поток попадает уже к нам в перехватчик.
    А во время установки хука он прерван быть не может, т.к. при IRQL >=DISPATCH_LEVEL потоки не планируются. Еще на всякий пожарный можно сбросить бит прерываний в регистре флагов - CLI
     
  8. gilg

    gilg New Member

    Публикаций:
    0
    Регистрация:
    19 май 2005
    Сообщения:
    527
    Great
    В момент каждого изменения этих первых пяти байт существует вероятность, что некий поток будет выполнять эти инструкции ==> GP или BSoD. Ни о какой стабильности здесь речи идти не может.
     
  9. wasm_test

    wasm_test wasm test user

    Публикаций:
    0
    Регистрация:
    24 ноя 2006
    Сообщения:
    5.582
    gilg
    Это, конечно, возможно. Тут тоже можно выкрутиться, если попробовать такой алгоритм:
    - запретить планирование потоков
    - просмотреть список потоков планировщика, готовых к выполнению. Если EIP какого-либо из них указывает как раз в эти инструкции, которые мы хотим (но еще не успели) перезаписать, разрешим этому потоку чуть-чуть выполниться и снова запретить планирование. Делать так, пока никакие потоки не будут прерваны во время исполнения начала перехватываемой функции
    - установить перехват
    - разрешить планирование потоков
     
  10. gilg

    gilg New Member

    Публикаций:
    0
    Регистрация:
    19 май 2005
    Сообщения:
    527
    Код (Text):
    1. push ebp
    2. --->   здесь поток прерывается
    3. mov ebp, esp
    4. sub esp, 30
    Устанавливаем хук, поток возобновляется и падает, потому что mov ebp, esp там уже не будет, а будет кусок джампа

    А теперь если подсчитать, во сколько процессору обходится каждое повышение IRQL на двухпроцессорной машине? Плюс опять же отсутствие надежности.

    Сплайсинговые хуки должны устанавливаться один раз при запуске приложения и сниматься при завершении. Тогда вероятность падения действительно низка. Накладные расходы при этом будут нулевые (2 far jump на вызов функции)
     
  11. gilg

    gilg New Member

    Публикаций:
    0
    Регистрация:
    19 май 2005
    Сообщения:
    527
    Это работает в юзер-моде, т.к. в ядре еще существуют прерывания, очереди DPC, APC и т.д. И во сколько обойдется просмотр списков планировщика? ;)
     
  12. wasm_test

    wasm_test wasm test user

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

    а как же быть, если хочется вызвать оригинальную функцию? Тогда может и потребуется дизассемблер длин, чтобы скопировать в буфер целое число команд, вместо джампа придется записывать CALL, потом придется мудрить с адресом возврата в стеке, сэмулировать выполнение команд из буфера и сделать джамп на адрес оригинальной функции после затертых байт. И не забыть оставить в стеке адрес возврата на наш перехватчик.
     
  13. wasm_test

    wasm_test wasm test user

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

    ЗЫ. Не в тему, но тут заикнулись вроде про MOV EDI,EDI. Я так и не понял, зачем эта байда лежит в начале многих функций?
     
  14. asmfan

    asmfan New Member

    Публикаций:
    0
    Регистрация:
    10 июл 2006
    Сообщения:
    1.004
    Адрес:
    Abaddon
    near relative jump = 2 bytes = sizeof(MOV EDI,EDI).
     
  15. gilg

    gilg New Member

    Публикаций:
    0
    Регистрация:
    19 май 2005
    Сообщения:
    527
    джамп. Алгоритм такой:

    Код (Text):
    1. orig_func:
    2. jmpf hook_start
    3. nop
    4. nop
    5. continued:
    6.  
    7. saved_code:
    8. push ebp
    9. mov ebp, esp
    10. ...
    11. jmpf continued
    12.  
    13. hook_start:
    14. ....
    15. call saved_code
    16. ...
     
  16. wasm_test

    wasm_test wasm test user

    Публикаций:
    0
    Регистрация:
    24 ноя 2006
    Сообщения:
    5.582
    asmfan
    и?
    gilg
    хм ) и правда. а я чето намудрил лишнего аж на 4 строчки текста словами))
     
  17. censored

    censored New Member

    Публикаций:
    0
    Регистрация:
    5 июл 2005
    Сообщения:
    1.615
    Адрес:
    деревня "Анонимные Прокси"
    hot patch.
    тема -- баян.
     
  18. wasm_test

    wasm_test wasm test user

    Публикаций:
    0
    Регистрация:
    24 ноя 2006
    Сообщения:
    5.582
    Вообщем, к чему мы все-таки пришли?
    В кернел моде нужно ставить хук один раз при запуске программы и больше не снимать до завершения. А для вызова оригинальной функции использовать код похожй на тот, что привел gilg, копируя целое число инструкций в буфер.
     
  19. n0name

    n0name New Member

    Публикаций:
    0
    Регистрация:
    5 июн 2004
    Сообщения:
    4.336
    Адрес:
    Russia
    Сплайсинг детектится легко. Проверяем первые команды по маске(push/ret, jmp, call, int).
    Я делал так:
    В начало функции копировал N инструкций своего обработчика, потом jmp на N+1 инструкцию. В буфер копировал начало оригинальной функции(те инструкции, которые затираются моим кодом и jmp), потом jmp на продолжение оригинальной функции. Поис по маске не проходит. Можно правда проверять куда передается управление, и если вне ntoskrnl.exe то бить тревогу, но пока я не встречал таких антируткитов. Сорц который всё это делает я выкладывал как пример сплайсинга.
     
  20. wasm_test

    wasm_test wasm test user

    Публикаций:
    0
    Регистрация:
    24 ноя 2006
    Сообщения:
    5.582
    n0name
    ну а кто сказал, что топикстартеру он нужен для злобных целей )