И еще раз инжект. Некоторые приложения иногда падают.

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

  1. l_inc

    l_inc New Member

    Публикаций:
    0
    Регистрация:
    29 сен 2005
    Сообщения:
    2.566
    Инжектирую самым классическим способом: OpenProcess/VirtualAllocEx/WriteProcessMemory; OpenThread/SuspendThread/GetThreadContext/SetThreadContext/ResumeThread. Инжектированный код инициализирует что-то вроде таблицы импорта будущего потока и создает новый поток, после чего управление передается на первоначальный EIP, откуда был прерван поток. Ну что еще... адрес внутри kernel32 получаю через SEH (кстати, под OllyDbg, при проверке ERR на "последнесть" в списке, иногда странным образом возникает исключение).
    При таком инжекте у меня в 50 процентах случаев падает Opera (вероятность подсчитана по принципу "варианта два: упадет или не упадет", но часто как падает, так и не падает). Причем как до отработки новосозданного потока, так и после. Бывает просто выгружается без предупреждения, бывает "Отправить отчет", бывает unknown software exception, а бывает все проходит нормально. За остальными приложениями вроде такого не замечал. Ну и собственно вопрос, почему, и как этого избежать? Может стоит останавливать все потоки? Если да, то тоже почему... не рассогласование потоков же?
    И еще вопрос сюда же. Поток, в который я делаю инжект, выбирается практически отфанаря. Т.е. перечисляю все потоки в системе и в первый же поток, родительский процесс которого имеет нужный PID, делаю инжект. Как мне получить ID именно основного потока процесса (подозреваю, что вопрос часто встречающийся, но что-то не нашел нигде)?
     
  2. dead_body

    dead_body wasm.ru

    Публикаций:
    0
    Регистрация:
    3 сен 2004
    Сообщения:
    603
    Адрес:
    Украина;г.Харьков;г.Н.Каховка
    l_inc
    контекст точно нормально сохраняеться?
     
  3. l_inc

    l_inc New Member

    Публикаций:
    0
    Регистрация:
    29 сен 2005
    Сообщения:
    2.566
    dead_body
    Вот это начало кода:
    Код (Text):
    1. CALL loaderProc
    2. JMP NEAR 0 ; этот переход модифицируется инжектирующим кодом в соответствии с полученным исходным eip...
    Думаю, если бы я прыжок формировал неверно, то все программы бы вылетали в любом случае. А насчет остального контекста... Ну loaderProc выглядит вот так:
    Код (Text):
    1. loaderProc:
    2. PUSHFD
    3. PUSHAD
    4.   ;<здесь инициализация "таблицы импорта" нового потока и его создание>
    5. POPAD
    6. POPFD
    7. RET
    Стэк сбиться к моменту выхода из loaderProc просто никак не может. FPU/MMX/SSE не использую... да и не особо умею. :)
    В принципе я понимаю, что при чтении моего вопроса может непроизвольно возникнуть мысль "а куда я свой гадальный хрустальный шар засунул...", но я ждал ответа хотя бы на вопрос о получении ID основного потока процесса.
     
  4. asmfan

    asmfan New Member

    Публикаций:
    0
    Регистрация:
    10 июл 2006
    Сообщения:
    1.004
    Адрес:
    Abaddon
    А как отличить основной поток от не основного?
     
  5. l_inc

    l_inc New Member

    Публикаций:
    0
    Регистрация:
    29 сен 2005
    Сообщения:
    2.566
    asmfan
    Тот, ID которого вернул CreateProcess.
     
  6. asmfan

    asmfan New Member

    Публикаций:
    0
    Регистрация:
    10 июл 2006
    Сообщения:
    1.004
    Адрес:
    Abaddon
    Тот, что в PROCESS_INFORMATION пишется при создании? Имхо никак во время ижекта, т.к. адреса этой структуры мы не знаем, а у процесса уже м.б куча id'ов потоков. Хотя можно попровать в PEB'е поискать что-то подобное первичное.
     
  7. l_inc

    l_inc New Member

    Публикаций:
    0
    Регистрация:
    29 сен 2005
    Сообщения:
    2.566
    asmfan
    Я где-то статью видел, что "с помощью недокументированных функций можно получить ID основного потока процесса", но там кроме этой фразы на эту тему ничего не было написано.
     
  8. z0mailbox

    z0mailbox z0

    Публикаций:
    0
    Регистрация:
    3 фев 2005
    Сообщения:
    635
    Адрес:
    Russia СПБ
    l_inc
    нету такого. стартовый поток (тот что в PROCESS_INFORMATION) после создания любого другого потока безболезненно для процесса убивается. См.например lsass.exe
     
  9. l_inc

    l_inc New Member

    Публикаций:
    0
    Регистрация:
    29 сен 2005
    Сообщения:
    2.566
    z0mailbox
    При этом дать определение основному потоку можно такое: первый поток, созданный тем, который был основным до уничтожения.
    Ну скажем цитата вот отсюда:
    http://www.xakep.ru/magazine/xa/103/024/1.asp
    Если Вы скажете, что там написан бред, поверю на слово.
     
  10. asmfan

    asmfan New Member

    Публикаций:
    0
    Регистрация:
    10 июл 2006
    Сообщения:
    1.004
    Адрес:
    Abaddon
    По ссыле
    Вот у него-то и стоит спросить;)
     
  11. PROFi

    PROFi New Member

    Публикаций:
    0
    Регистрация:
    13 июл 2003
    Сообщения:
    690
    l_inc

    Опера просто обязана контролировать целостность своего кода, иначе никакой защиты от проникновения. Возможно это здесь имеет место.
    Пришли исходник.
     
  12. l_inc

    l_inc New Member

    Публикаций:
    0
    Регистрация:
    29 сен 2005
    Сообщения:
    2.566
    PROFi
    На правду не похоже. Инжект часто проходит успешно.
    А я все думаю, когда же мне либо про исходник, либо про гадальные карты...

    Инжектриуемый код приложил:
     
  13. PROFi

    PROFi New Member

    Публикаций:
    0
    Регистрация:
    13 июл 2003
    Сообщения:
    690
    l_inc

    Поступи примерно так. Под софт айсом поставь АППАРАТНУЮ точку останова по чтению и вторую по выполнению на памяти в том месте куда пишешь код. (Я думаю про бит WP управляющего регистра ты не зыбыл.) И далее смотри кто пытается читать, или исполнять код. И еще - во время модификации нужно остановить все потоки приложения, или как то делать синхронизацию - иначе вызов не полностью модифицированных байтов из той же оперы но 2го процессора например даст ошибку.
     
  14. l_inc

    l_inc New Member

    Публикаций:
    0
    Регистрация:
    29 сен 2005
    Сообщения:
    2.566
    PROFi
    После этого Вашего предложения как раз вспомнил, почему до сих пор не выкладывал код. :) Я последние несколько дней занимаюсь функциональной частью инжектируемого кода и особо времени потыкать брэйкпоинты не было... тем более, что я в оперу инжектриовать пока не хотел. Думал, что может кто-то сразу скажет, почему именно с оперой проблемы. А так... я думаю мне и OllyDbg хватит.
    Ага. Не знал, потому и не забыл. Откуда такое доверие? Я - пока чайник. :)
     
  15. PROFi

    PROFi New Member

    Публикаций:
    0
    Регистрация:
    13 июл 2003
    Сообщения:
    690
    l_inc

    Бит WP нужно учитывть. В пользовательском режиме это функция VirtualProtectEx с указанием PAGE_EXECUTE_READWRITE. Иначе на PAGE Access наткнешся в некоторых приложениях, а в ядре это бит WP регистра CR0. Еще раз проверь синхронизацию. Если функция очень часто используется приложением, то возможен момент неполной модификации кода и => приложение будет исполнять не то что задумано. Кстати int 3 иммено для этого придумана - самая безопасная модификация (1 байт opcode).
    Т.е. установи свой обработчик исключений и поставь int 3.
     
  16. l_inc

    l_inc New Member

    Публикаций:
    0
    Регистрация:
    29 сен 2005
    Сообщения:
    2.566
    PROFi
    Код вы, наверное, не смотрели... кстати я его битком напичкал комментариями.
    Я инжектирую код в пользовательском режиме. В режиме ядра я бы вряд ли вызывал MessageBoxA. :)
    Насколько я знаю, для WriteProcessMemory вполне достаточно PAGE_EXECUTE, но делаю все равно с PAGE_EXECUTE_READWRITE, т.к. мне нужно писать в себя во время инициализации "таблицы импорта" нового потока.
    Опять таки... код не посмотрели... я не устанавливаю перехват. Это просто тестовый вариант, в котором я только вывожу MessageBox в отдельном потоке и тут же его завершаю.
    Ну тут я в курсе. Но чем возиться со своим обработчиком, я лучше OllyDbg'овским воспользуюсь... собственно как я всегда и делаю.

    P.S. Ой. Последний комментарий отменяется... Только понял, что Вы имели ввиду INT3 для установки перехвата, а не для отладки. Ну тогда, как я уже говорил: перехват я не ставлю.
     
  17. PROFi

    PROFi New Member

    Публикаций:
    0
    Регистрация:
    13 июл 2003
    Сообщения:
    690
    l_inc

    stdcall ExitThread,0 это последнее чем заканчивается текст (у меня скачивается с ошибкой - конец архива)
    В коде функции WriteProcessMemory нет в помине. И как организована межпроцессорная передача данных мне из твоего кода непонятно.
     
  18. l_inc

    l_inc New Member

    Публикаций:
    0
    Регистрация:
    29 сен 2005
    Сообщения:
    2.566
    PROFi
    Так WriteProcessMemory в инжектирующем коде, а не в инжектируемом. Не выложил, чтобы не пинали за то, что он на VB. :) Если нужно, выложу, если не пошлете меня на все три за это.
    Перепроверил: нормально скачивается. А stdcall ExitThread,0 - это действительно последняя строчка.
     
  19. PROFi

    PROFi New Member

    Публикаций:
    0
    Регистрация:
    13 июл 2003
    Сообщения:
    690
    Не знаю может я что-то не понимаю но порядок действий такой
    1) План.
    - из чужого процесса нужно вывести окно нашей функцией MessageBox как только приложение обратиться к функции XXX
    2) Часть 1. Выделить в чужом процессе память
    ...
    VirtualAllocEx(h(чужой процесс)Process, .... PAGE_EXECUTE_READWRITE )
    Перебросить код нашей функции MessageBox
    WriteProcessMemory.
    2) далее перехват функции
    Найти все потоки чужого процесса и сделать с каждым из них SuspendThread
    Сдалать VirtualProtectEx(та станица в которую пишем код, PAGE_EXECUTE_READWRITE )
    Поменять точку входа в функции ХХХ WriteProcessMemory.
    ResumeThread

    Вот и все. Работате как часики.

    Да по коду. Где проверка - найдены ли функции которые тебе нужны или нет. Может функция поиска функций не справляется и т.д.
     
  20. l_inc

    l_inc New Member

    Публикаций:
    0
    Регистрация:
    29 сен 2005
    Сообщения:
    2.566
    PROFi
    Неверно. Еще раз: я не устанавливаю перехват. А MessageBox выводится сразу после передачи управления инжектированному коду (я писал в первом посте, что управление инжектированному коду передается через SetThreadContext). Инжектированный код получает управление сразу после инжекта, а возвращает с помощью того джампа, который в самом начале кода стоит.