eXeL@B —› Вопросы новичков —› Как внутри DllMain, определить возврата из загрузки длл в основной код? |
. 1 . 2 . >> |
Посл.ответ | Сообщение |
|
Создано: 24 сентября 2016 18:42 · Поправил: Kuzya69 · Личное сообщение · #1 Пропустил в названии слово "адрес" возврата. Не знаю как исправить на этом форуме. Пишу длл. Внутри ее DllMain, выполняю необходимую работу. Но по выходу из загрузки этой длл хочу удалить ее из памяти процесса. Т.е. если знать адрес возврата в основной код, то туда можно поместить код удаления этой длл, и загрузки оригинальной. Что я и делаю сейчас, поэтому приходится постоянно искать вручную адрес возврата , и задавать принудительно. Но хочется находить этот адрес автоматически внутри самой, загружаемой длл. Так вот, можно - ли каким-то образом узнать этот адрес? Изыскания в стеке с помощью ebp, не подходят. Некоторые протекторы рвут связанную цепочку кадров вызова фукций. Да и нет уверенности, что вложенность ф-ций будет постоянной на разных ОС и программах. |
|
Создано: 24 сентября 2016 19:37 · Личное сообщение · #2 |
|
Создано: 24 сентября 2016 19:42 · Поправил: dosprog · Личное сообщение · #3 |
|
Создано: 24 сентября 2016 21:59 · Личное сообщение · #4 |
|
Создано: 25 сентября 2016 20:05 · Поправил: Kuzya69 · Личное сообщение · #5 dosprog пишет: Так он хотел поковырять код, который вызвал LoadLibrary(). Пытается найти то место. Ну да. Именно это мне и надо. Только немного далее идущий код. А это место, скажем так, "отправная точка". То-есть в первую очередь, при работе в DllMain, в ехе-коде сделать свои изменения, которые мне нужны. Потом подгрузить в ехе-код, код с FreeLybrary(), на борту. По выходу из DllMain, подменить eax, на значение оригинальной длл. Ну и выгрузить свою длл, за ненадобностью. Скажу больше, я уже так и делаю. Но адрес возврата приходится вбивать вручную. Немного неудобно. dosprog пишет: И вообще, идея какая-то стрёмная. "Можно огласить весь список...Пожалуйста" (Это из нашей комедии, цитата) Поясните, если не трудно. Может есть более продвинутые идеи. |
|
Создано: 25 сентября 2016 21:00 · Личное сообщение · #6 |
|
Создано: 25 сентября 2016 21:31 · Поправил: dosprog · Личное сообщение · #7 Не может тут быть никаких идей. Я ж говорю, стрёмная затея. Но пускай, для конкретной ситуации, при нахождении в dllMain() определён адрес возврата из LoadLibrary(), как - это уже другой вопрос. Пускай он нащупан в стеке сравнением с диапазоном [.401000...fFFffFF]. Никто не мешает коду DLLMain() в стеке (где найден адрес возврата из LoadLibrary() ) этот адрес возврата уменьшить на 6, ещё выше в стеке в аргументах того вызова LoadLibrary() найти ссылку на имя DLL и изменить ту строку-имя DLL для загрузки, после чего из DLLMain() вернуть FALSE. Тогда весь парад завершится возвратом в точку приложения, где <call LoadLibrary()> (повторно, но уже с подкорректированной строкой-именем загружаемой DLL). И ничего в коде клиента менять не потребуется, всё будет прозрачно. Только для чего такой цирк может понадобиться, не представляю. script_kidis пишет: дать чёткое задание необходимый материал и $ а всё остальное сделают за вас. Это самый надёжный способ. Но нужны Денги. Если есть Денги, то можно даже попривередничать. Повыделываться то есть. Но Денег тогда надо много. |
|
Создано: 25 сентября 2016 21:34 · Личное сообщение · #8 |
|
Создано: 25 сентября 2016 21:39 · Поправил: dosprog · Личное сообщение · #9 |
|
Создано: 25 сентября 2016 21:49 · Поправил: difexacaw · Личное сообщение · #10 |
|
Создано: 25 сентября 2016 22:04 · Поправил: Kuzya69 · Личное сообщение · #11 dosprog пишет: ... этот адрес возврата уменьшить на 6, ещё выше в стеке в аргументах того вызова LoadLibrary() найти ссылку на имя DLL и изменить ту строку-имя DLL для загрузки ... Неясно, а зачем мне городить подмену имени? Я ж писАл: Внутри моей DllMain, гружу оригинальную dll. Запоминаю ее хэндл - базу загрузки. На точке возврата в основном коде помещаю свой код (вернее вызов "call МойКод"). В моем коде уже есть такое: 1. меняю в стеке адрес возврата из моего кода = адрес возврата - Length("call МойКод") 2. Восстанавливаю код в точке возврата. 3. Подменяю значение eax по выходу из моего кода на значение хэндла оригинальной длл. 4. Выгружаю свою длл. Мой код возвращается в точку возврата, как-будто загрузилась оригинальная длл. Наверное, для полного понимания картины надо добавить, что моя длл лежит в папке с программой, а оригинальная длл лежит в системной папке. Имена у них одинаковые. Ну как-то так. |
|
Создано: 25 сентября 2016 23:50 · Личное сообщение · #12 Kuzya69 А прокси dll не подойдет? в своей dll грузите ориг dll и пробрасываете весь экспорт на ориг dll а в dllmain выполняете свой пэйлоад код пример автоматизации создания dll есть Я успешно использовал такой трюк в 2х или 3х проектах. ну будет в памяти висеть твоя dll, это же не критично? |
|
Создано: 25 сентября 2016 23:53 · Личное сообщение · #13 ну короч если кто не понял - это всё продолжение сначала ТС пытался разрешить конфликт имён, теперь вот пыттается из своей дллмайн вернуть хендл той_другой_длл и всё это потому, что более простой и универсальный путь почему-то показался более сложным. по теме - а может, всё-таки стоит попробовать сделать полноценную длл-обёртку, если уж иначе никак? вместо всех этих загрузок-выгрузок. |
|
Создано: 25 сентября 2016 23:59 · Поправил: dosprog · Личное сообщение · #14 |
|
Создано: 26 сентября 2016 00:21 · Поправил: Kuzya69 · Личное сообщение · #15 -=AkaBOSS=- пишет: сначала ТС пытался разрешить конфликт имён, теперь вот пыттается из своей дллмайн вернуть хендл той_другой_длл и всё это потому, что более простой и универсальный путь почему-то показался более сложным. Не, обертка пока работает тоже. Но заметил я одну странность. В основном все ф-ции импортируются в главный код из этой длл через имена. Как-бы пофиг, написал прокладки-обертки, даже для недокументированных АПИ. Ведь нам на параметры наплевать (все параметры и так готовы уже к выполнению, надо только прыжок перенаправить.) Но вот несколько АПИ-ф-ций импортировались через ординал-номер. И тут меня начали мучать очередные сомнения. А если версия длл окажется не той, например обновится. И получим трудно отлавливаемую бяку. Вот и пытаюсь найти более стабильное решение. А новую тему завел, потому, что как-бы вопрос изменился, и не совсем соответствует той теме. dosprog пишет: и пипец той оригинальной загруженной DLL. Ну почему-же? А если на нее уже несколько ссылок. Ну или на крайняк, могу грузить оригинальную длл не в MainDll, а в "своем коде". Хотя сейчас, оригинальная длл, не выгружается вместе с моей длл, почему-то. Но это вопрос не важный сейчас. |
|
Создано: 26 сентября 2016 00:31 · Личное сообщение · #16 Kuzya69 пишет: если версия длл окажется не той, например обновится. И получим трудно отлавливаемую бяку по-моему, это несложно решить пересчётом хэша хэш не совпал - сообщить пользователю, что все дальнейшие глюки на его совести но кмк всё изначально стоило сделать иначе. написать лоадер, которым собственно и внедрять свою длл в процесс. если сильно нужен именно момент загрузки той_самой_длл, тогда хукать LoadLibrary и сравнивать имя, и действовать согласно ситуации. |
|
Создано: 26 сентября 2016 00:45 · Поправил: Kuzya69 · Личное сообщение · #17 -=AkaBOSS=- пишет: написать лоадер, которым собственно и внедрять свою длл в процесс. Там уже и так. 1. моя длл, пока, является как-бы обработчиком таблицы фиксов. Ну еще там некоторую работу делает. 2. сами фиксы размещены в оверлее ехешника. Чтобы длл не зависела от версий самой программы. И еще лоадер добавлять? Длл хочется оставить в конце концов, полностью автономной. Но это позже, когда разработаю единый алгоритм для создания таблицы фиксов. |
|
Создано: 26 сентября 2016 00:48 · Поправил: -=AkaBOSS=- · Личное сообщение · #18 в таком случае предлагаю такой изврат: из длл выделять себе память, и писать туда код, который отгрузит твою длл и подгрузить ту_самую_длл но с хэндлом всё равно сложно будет лучше всё таки через лодырь. больше свободы в плане действий, и нет необходимости морочиться с обратной подменой длл. вот его как раз можно будет сделать автономным, и внедрять чисто базонезависимый код. |
|
Создано: 26 сентября 2016 01:00 · Поправил: Kuzya69 · Личное сообщение · #19 -=AkaBOSS=- пишет: из длл выделять себе память, и писать туда код, который отгрузит твою длл и подгрузить ту_самую_длл но с хэндлом всё равно сложно будет Дык я так и делаю сейчас. У меня вопрос, только как автоматически определять адрес возврата в основной код, находясь в DllMain этой длл-ки. Ну типа избавиться от постоянного поиска адреса возврата вручную. Это мне и в будущем пригодится, когда перестану писать фиксы в оверлей. А эти фиксы сама длл-ка научится вычислять. А какие трудности-то с хэндлом? Вроде в моем случае, все работает. Апишки оригинальной длл работают нормально. Это если я меняю eax в конце загрузки моей длл на хэндл оригинальной длл. -=AkaBOSS=- пишет: лучше всё таки через лодырь. Ну не очень просто темиду через лодырь патчить. Защита прям лютует, даже не дает АПИ-шки из кернел32 трогать, а в нтдлл страшновато лезть на автомате. А с длл я уже привык. Во первых она грузится, прямо в самый нужный момент, для первого патча. К тому-же хочется как-то какой-то вариант определить. Я не спорю, есть у меня рабочие решения(два), но мне они пока не до конца нравятся. Боюсь, щас забью на это. Будет все работать нормально. А вот в какой-то момент, что-то изменится. Начнет моя реализация глючить, и буду долго вспоминать, где и что я делал. А так когда длл-ку закончу, успокоюсь, что ее уже ненадо мучать, можно будет про нее и забыть. Но это лирика. А советуюсь потому что думаю, может есть что-то, что я не знаю, а оно мне как раз нужно, для решения моего вопроса. Вот и жду, может кто натолкнет на путь истинный. |
|
Создано: 26 сентября 2016 01:10 · Личное сообщение · #20 -=AkaBOSS=- A. Загрузка модуля по желаемому адресу, что можно сделать на уровне загрузчика(или вручную загрузить, что тоже изврат) - вмешаться в процесс загрузки. B. Перезагрузить либу после возврата из загрузчика. Есть есчо одна важная деталь, загрузчик может использовать не системный, а левый. В этом случае вариант A не подходит, так же и по причине занятых ресурсов(норм нужно ждать пока поток покинет загрузчик, что бы никаких коллизий не возникло), получается что норм решение только B. Выделить стек вызовов обычно просто, но тут наверно сложный случай, возможно он как то шифруется или быть может вм юзается. Необходимо определить критерий, который позволит событие возврата из лодера определить; это может быть выход за пределы загрузочного кода или есчо какие события. Запускайте трассировку из dllmain, хардверную(TF) или через какие софтверные реализации(pin etc). ----- vx |
|
Создано: 26 сентября 2016 01:16 · Личное сообщение · #21 Kuzya69 пишет: как автоматически определять адрес возврата в основной код, находясь в DllMain этой длл-ки. универсального способа точно не найдёшь. инфа 100% можно попробовать перехватить известную точку - возврат из LoadLibrary/LoadLibraryEx/LdrLoadDll (тоесть натурально зацепиться за mov esp, ebp/ret X), но можно наловить косяков если несколько потоков одновременно будут грузить библиотеки. |
|
Создано: 26 сентября 2016 01:33 · Личное сообщение · #22 -=AkaBOSS=- пишет: можно попробовать перехватить известную точку - возврат из LoadLibrary/LoadLibraryEx/LdrLoadDll (тоесть натурально зацепиться за mov esp, ebp/ret X), но можно наловить косяков если несколько потоков одновременно будут грузить библиотеки. Ага, уже что-то более близкое к вопросу. Получается надо предусмотреть, чтоб поток был нужный. Теперь надо понять, что по вашему значит "зацепиться за mov esp, ebp/ret X". Предлагаете прерывание ставить, или просто джамп в свой код на проверку, момента сработки кода? Или как? По каким критериям лучше проверять потоки, что они свои-чужие? С таким я еще не работал. Обычно просто изменения джампов или значений в памяти-регистрах приходится делать, для преодоления защиты. |
|
Создано: 26 сентября 2016 01:36 · Личное сообщение · #23 |
|
Создано: 26 сентября 2016 01:45 · Личное сообщение · #24 difexacaw пишет: почему нельзя снять стек вызовов чуть выше уже мелькало слово темида Kuzya69 пишет: Некоторые протекторы рвут связанную цепочку кадров вызова фукций. Да и нет уверенности, что вложенность ф-ций будет постоянной на разных ОС и программах. Kuzya69 пишет: Теперь надо понять, что по вашему значит "зацепиться за mov esp, ebp/ret X". я имел в виду не конкретно эпилог функции, но где-то близко к нему. зацепиться - значит выбрать место и перехватить выполнение. уж как это провернуть - не мне решать) можно эксепшн устроить, а можно и аккуратно джампом обойтись. |
|
Создано: 26 сентября 2016 01:47 · Поправил: Kuzya69 · Личное сообщение · #25 difexacaw пишет: Если у вас стандартный загрузчик юзается, то почему нельзя снять стек вызовов через например rEbp, если это так, то работает какая то надстройка над кодом, что маловероятно ? Я ж пару постов назад написал. Темида. Вызывает она эти LoadLibrary из секции ВМ, потом работает эта ВМ через копии библиотек кернел32, адвапи32, и юсер32. У копий этих, базы загрузки иногда меняются. Ну вобщем много косяков. В какой-то из версий программы, вызов был вообще через retn-команду. Вобщем сложно придумать критерий, по которому можно однозначно сказать, что все, это уже закончился вызов LoadLibrary. -=AkaBOSS=- пишет: уж как это провернуть - не мне решать) Ну, с этим понял, а по какому параметру надежнее потоки разделять, что они свои-чужие? Просто прошу быструю подсказку, я конечно скоро полезу читать про потоки в букварь, но чтобы читая упор делать на нужные параметры. |
|
Создано: 26 сентября 2016 01:52 · Поправил: dosprog · Личное сообщение · #26 Вот как выглядит стек на входе в DllMain, безо всяких фемид: Code:
Если без фемиды - то интересующий адрес (число, попадающее в диапазон [.401000..fFFffFF]), будет вторым таким по счёту в стеке. Если с фемидой - надо определить, каким по счёту (из чисел, попадающих в диапазон [.401000..fFFffFF]), будет этот интересующий адрес. Так и искать. Но это жуткий костыль. |
|
Создано: 26 сентября 2016 02:07 · Поправил: Kuzya69 · Личное сообщение · #27 dosprog пишет: Но это жуткий костыль. Дык я в самом начале написал, что Изыскания в стеке с помощью ebp, не подходят.. К тому-же нет уверенности, что на всех ОС, этот номер будет один и тот-же. По крайней мере пока меня заинтересовал метод с "просеиванием" потоков в эпилоге функции LdrLoadDll, а потом, наверное, пошагово шлепать на конец LoadLibraryW. Но надо будет сначала знаний поднабрать про потоки. |
|
Создано: 26 сентября 2016 02:13 · Поправил: dosprog · Личное сообщение · #28 Kuzya69 пишет: Дык я в самом начале написал, что Изыскания в стеке с помощью ebp, не подходят.. Иногда другого выхода нет, тем более, что такие "тупые методы" тоже работают. Более или менее. Дополнительное условие нахождения нужного адреса в стеке - это присутствие в следующем слове указателя на аргумент. Аргумент известен. |
|
Создано: 26 сентября 2016 02:20 · Личное сообщение · #29 Так загрузка заканчивается при возврате из системного лодера(LdrLoadDll()). Нужно только это место, что там дальше не важно. На этом месте можно выгрузиться и загрузить оригинальный модуль. Это стабильный механизм и есть апи для получения стека, RtlWalkFrameChain() etc. Но лучше как и сказал трассировать до нужного места, потому что стек может чем то быть испорчен(в случае протекторов). > "просеиванием" потоков в эпилоге функции LdrLoadDll В этом случае с потоками никаких проблем не возникает, если конечно код не портить. Хотя конечно можно точку останова туда поставить. ----- vx |
|
Создано: 26 сентября 2016 02:30 · Личное сообщение · #30 |
. 1 . 2 . >> |
eXeL@B —› Вопросы новичков —› Как внутри DllMain, определить возврата из загрузки длл в основной код? |