Сейчас на форуме: tyns777, cppasm, dutyfree, asfa (+6 невидимых)

 eXeL@B —› Вопросы новичков —› Как внутри DllMain, определить возврата из загрузки длл в основной код?
. 1 . 2 . >>
Посл.ответ Сообщение

Ранг: 30.1 (посетитель)
Активность: 0.070
Статус: Участник

Создано: 24 сентября 2016 18:42 · Поправил: Kuzya69
· Личное сообщение · #1

Пропустил в названии слово "адрес" возврата. Не знаю как исправить на этом форуме.
Пишу длл. Внутри ее DllMain, выполняю необходимую работу. Но по выходу из загрузки этой длл хочу удалить ее из памяти процесса. Т.е. если знать адрес возврата в основной код, то туда можно поместить код удаления этой длл, и загрузки оригинальной. Что я и делаю сейчас, поэтому приходится постоянно искать вручную адрес возврата , и задавать принудительно. Но хочется находить этот адрес автоматически внутри самой, загружаемой длл.
Так вот, можно - ли каким-то образом узнать этот адрес?
Изыскания в стеке с помощью ebp, не подходят. Некоторые протекторы рвут связанную цепочку кадров вызова фукций. Да и нет уверенности, что вложенность ф-ций будет постоянной на разных ОС и программах.




Ранг: 2014.5 (!!!!), 1278thx
Активность: 1.340.25
Статус: Модератор
retired

Создано: 24 сентября 2016 19:37
· Личное сообщение · #2

Никак. Верни ошибку, винда сама отмапит как неудачно загруженную.



Ранг: 431.7 (мудрец), 390thx
Активность: 0.730.32
Статус: Участник

Создано: 24 сентября 2016 19:42 · Поправил: dosprog
· Личное сообщение · #3

Так он хотел поковырять код, который вызвал LoadLibrary().
Пытается найти то место.

Но, имхо, надёжного способа нет

И вообще, идея какая-то стрёмная.





Ранг: 92.1 (постоянный), 83thx
Активность: 0.110
Статус: Участник

Создано: 24 сентября 2016 21:59
· Личное сообщение · #4

Code:
  1. BOOL APIENTRY DllMain( HMODULE hModule,
  2.                        DWORD  ul_reason_for_call,
  3.                        LPVOID lpReserved
  4.                      )
  5. {
  6.     // payload
  7.     return FALSE;
  8. }




Ранг: 30.1 (посетитель)
Активность: 0.070
Статус: Участник

Создано: 25 сентября 2016 20:05 · Поправил: Kuzya69
· Личное сообщение · #5

dosprog пишет:
Так он хотел поковырять код, который вызвал LoadLibrary().
Пытается найти то место.

Ну да. Именно это мне и надо. Только немного далее идущий код. А это место, скажем так, "отправная точка".
То-есть в первую очередь, при работе в DllMain, в ехе-коде сделать свои изменения, которые мне нужны. Потом подгрузить в ехе-код, код с FreeLybrary(), на борту.
По выходу из DllMain, подменить eax, на значение оригинальной длл. Ну и выгрузить свою длл, за ненадобностью.
Скажу больше, я уже так и делаю. Но адрес возврата приходится вбивать вручную. Немного неудобно.
dosprog пишет:
И вообще, идея какая-то стрёмная.

"Можно огласить весь список...Пожалуйста" (Это из нашей комедии, цитата)
Поясните, если не трудно. Может есть более продвинутые идеи.




Ранг: 56.2 (постоянный), 14thx
Активность: 0.120
Статус: Участник

Создано: 25 сентября 2016 21:00
· Личное сообщение · #6

Может есть более продвинутые идеи.

да дать чёткое задание необходимый материал и $ а всё остальное сделают за вас.



Ранг: 431.7 (мудрец), 390thx
Активность: 0.730.32
Статус: Участник

Создано: 25 сентября 2016 21:31 · Поправил: dosprog
· Личное сообщение · #7

Не может тут быть никаких идей.
Я ж говорю, стрёмная затея.

Но пускай, для конкретной ситуации, при нахождении в dllMain() определён адрес возврата из LoadLibrary(), как - это уже другой вопрос.
Пускай он нащупан в стеке сравнением с диапазоном [.401000...fFFffFF].

Никто не мешает коду DLLMain() в стеке (где найден адрес возврата из LoadLibrary() ) этот адрес возврата уменьшить на 6, ещё выше в стеке в аргументах того вызова LoadLibrary() найти ссылку на имя DLL и изменить ту строку-имя DLL для загрузки, после чего из DLLMain() вернуть FALSE.

Тогда весь парад завершится возвратом в точку приложения, где <call LoadLibrary()> (повторно, но уже с подкорректированной строкой-именем загружаемой DLL).
И ничего в коде клиента менять не потребуется, всё будет прозрачно.

Только для чего такой цирк может понадобиться, не представляю.

script_kidis пишет:
дать чёткое задание необходимый материал и $ а всё остальное сделают за вас.


Это самый надёжный способ. Но нужны Денги.
Если есть Денги, то можно даже попривередничать. Повыделываться то есть.
Но Денег тогда надо много.






Ранг: 337.5 (мудрец), 348thx
Активность: 2.112.42
Статус: Участник

Создано: 25 сентября 2016 21:34
· Личное сообщение · #8

Потрейсить, в статике может не получится. Адреса возврата может не быть как такового, если стартует новый поток или же завершается.

-----
vx




Ранг: 431.7 (мудрец), 390thx
Активность: 0.730.32
Статус: Участник

Создано: 25 сентября 2016 21:39 · Поправил: dosprog
· Личное сообщение · #9

Это да. Априорно считали, что библиотека загружается динамически какой-то программой.
Иначе - адрес-то возврата будет всё равно, но он будет указывать куда-то в загрузчик OS.
Впрочем, выше описанный изврат и в этом случае тоже должен бы сработать.






Ранг: 337.5 (мудрец), 348thx
Активность: 2.112.42
Статус: Участник

Создано: 25 сентября 2016 21:49 · Поправил: difexacaw
· Личное сообщение · #10

dosprog

Теоретически можно очистить рабочий набор(EmptyWorkingSet()) и спустя время снять лог по подкаченным страницам(GetWsChanges()); в этом логе будет последовательность адресов, страницы с которыми были подгружены при возврате. Самый простой способ, но асинхронный.

-----
vx




Ранг: 30.1 (посетитель)
Активность: 0.070
Статус: Участник

Создано: 25 сентября 2016 22:04 · Поправил: Kuzya69
· Личное сообщение · #11

dosprog пишет:
... этот адрес возврата уменьшить на 6, ещё выше в стеке в аргументах того вызова LoadLibrary() найти ссылку на имя DLL и изменить ту строку-имя DLL для загрузки ...

Неясно, а зачем мне городить подмену имени?
Я ж писАл:
Внутри моей DllMain, гружу оригинальную dll. Запоминаю ее хэндл - базу загрузки.
На точке возврата в основном коде помещаю свой код (вернее вызов "call МойКод").
В моем коде уже есть такое:
1. меняю в стеке адрес возврата из моего кода = адрес возврата - Length("call МойКод")
2. Восстанавливаю код в точке возврата.
3. Подменяю значение eax по выходу из моего кода на значение хэндла оригинальной длл.
4. Выгружаю свою длл.
Мой код возвращается в точку возврата, как-будто загрузилась оригинальная длл.

Наверное, для полного понимания картины надо добавить, что моя длл лежит в папке с программой, а оригинальная длл лежит в системной папке. Имена у них одинаковые.
Ну как-то так.




Ранг: 85.5 (постоянный), 16thx
Активность: 0.040.05
Статус: Участник

Создано: 25 сентября 2016 23:50
· Личное сообщение · #12

Kuzya69
А прокси dll не подойдет?
в своей dll грузите ориг dll и пробрасываете весь экспорт на ориг dll а в dllmain выполняете свой пэйлоад код
пример автоматизации создания dll есть здесь , на форуме тоже вроде бы когда то пробегало подобное.

Я успешно использовал такой трюк в 2х или 3х проектах. ну будет в памяти висеть твоя dll, это же не критично?




Ранг: 150.3 (ветеран), 175thx
Активность: 0.160.07
Статус: Участник

Создано: 25 сентября 2016 23:53
· Личное сообщение · #13

ну короч если кто не понял - это всё продолжение вот этого адского изврата.

сначала ТС пытался разрешить конфликт имён, теперь вот пыттается из своей дллмайн вернуть хендл той_другой_длл

и всё это потому, что более простой и универсальный путь почему-то показался более сложным.

по теме - а может, всё-таки стоит попробовать сделать полноценную длл-обёртку, если уж иначе никак?
вместо всех этих загрузок-выгрузок.



Ранг: 431.7 (мудрец), 390thx
Активность: 0.730.32
Статус: Участник

Создано: 25 сентября 2016 23:59 · Поправил: dosprog
· Личное сообщение · #14

Kuzya69 пишет:
Внутри моей DllMain, гружу оригинальную dll. Запоминаю ее хэндл - базу загрузки.
...
4. Выгружаю свою длл.


и пипец той оригинальной загруженной DLL.

Не надо измудряться короче.





Ранг: 30.1 (посетитель)
Активность: 0.070
Статус: Участник

Создано: 26 сентября 2016 00:21 · Поправил: Kuzya69
· Личное сообщение · #15

-=AkaBOSS=- пишет:
сначала ТС пытался разрешить конфликт имён, теперь вот пыттается из своей дллмайн вернуть хендл той_другой_длл

и всё это потому, что более простой и универсальный путь почему-то показался более сложным.

Не, обертка пока работает тоже. Но заметил я одну странность. В основном все ф-ции импортируются в главный код из этой длл через имена. Как-бы пофиг, написал прокладки-обертки, даже для недокументированных АПИ. Ведь нам на параметры наплевать (все параметры и так готовы уже к выполнению, надо только прыжок перенаправить.)
Но вот несколько АПИ-ф-ций импортировались через ординал-номер. И тут меня начали мучать очередные сомнения. А если версия длл окажется не той, например обновится. И получим трудно отлавливаемую бяку. Вот и пытаюсь найти более стабильное решение. А новую тему завел, потому, что как-бы вопрос изменился, и не совсем соответствует той теме.
dosprog пишет:
и пипец той оригинальной загруженной DLL.

Ну почему-же? А если на нее уже несколько ссылок. Ну или на крайняк, могу грузить оригинальную длл не в MainDll, а в "своем коде". Хотя сейчас, оригинальная длл, не выгружается вместе с моей длл, почему-то.
Но это вопрос не важный сейчас.




Ранг: 150.3 (ветеран), 175thx
Активность: 0.160.07
Статус: Участник

Создано: 26 сентября 2016 00:31
· Личное сообщение · #16

Kuzya69 пишет:
если версия длл окажется не той, например обновится. И получим трудно отлавливаемую бяку

по-моему, это несложно решить пересчётом хэша
хэш не совпал - сообщить пользователю, что все дальнейшие глюки на его совести

но кмк всё изначально стоило сделать иначе.
написать лоадер, которым собственно и внедрять свою длл в процесс.
если сильно нужен именно момент загрузки той_самой_длл, тогда хукать LoadLibrary и сравнивать имя, и действовать согласно ситуации.



Ранг: 30.1 (посетитель)
Активность: 0.070
Статус: Участник

Создано: 26 сентября 2016 00:45 · Поправил: Kuzya69
· Личное сообщение · #17

-=AkaBOSS=- пишет:
написать лоадер, которым собственно и внедрять свою длл в процесс.

Там уже и так.
1. моя длл, пока, является как-бы обработчиком таблицы фиксов. Ну еще там некоторую работу делает.
2. сами фиксы размещены в оверлее ехешника. Чтобы длл не зависела от версий самой программы.
И еще лоадер добавлять?
Длл хочется оставить в конце концов, полностью автономной. Но это позже, когда разработаю единый алгоритм для создания таблицы фиксов.




Ранг: 150.3 (ветеран), 175thx
Активность: 0.160.07
Статус: Участник

Создано: 26 сентября 2016 00:48 · Поправил: -=AkaBOSS=-
· Личное сообщение · #18

в таком случае предлагаю такой изврат:
из длл выделять себе память, и писать туда код, который отгрузит твою длл и подгрузить ту_самую_длл
но с хэндлом всё равно сложно будет

лучше всё таки через лодырь.
больше свободы в плане действий, и нет необходимости морочиться с обратной подменой длл.
вот его как раз можно будет сделать автономным, и внедрять чисто базонезависимый код.



Ранг: 30.1 (посетитель)
Активность: 0.070
Статус: Участник

Создано: 26 сентября 2016 01:00 · Поправил: Kuzya69
· Личное сообщение · #19

-=AkaBOSS=- пишет:
из длл выделять себе память, и писать туда код, который отгрузит твою длл и подгрузить ту_самую_длл
но с хэндлом всё равно сложно будет

Дык я так и делаю сейчас. У меня вопрос, только как автоматически определять адрес возврата в основной код, находясь в DllMain этой длл-ки.
Ну типа избавиться от постоянного поиска адреса возврата вручную. Это мне и в будущем пригодится, когда перестану писать фиксы в оверлей. А эти фиксы сама длл-ка научится вычислять.
А какие трудности-то с хэндлом? Вроде в моем случае, все работает. Апишки оригинальной длл работают нормально. Это если я меняю eax в конце загрузки моей длл на хэндл оригинальной длл.
-=AkaBOSS=- пишет:
лучше всё таки через лодырь.

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




Ранг: 337.5 (мудрец), 348thx
Активность: 2.112.42
Статус: Участник

Создано: 26 сентября 2016 01:10
· Личное сообщение · #20

-=AkaBOSS=-

A. Загрузка модуля по желаемому адресу, что можно сделать на уровне загрузчика(или вручную загрузить, что тоже изврат) - вмешаться в процесс загрузки.

B. Перезагрузить либу после возврата из загрузчика.

Есть есчо одна важная деталь, загрузчик может использовать не системный, а левый. В этом случае вариант A не подходит, так же и по причине занятых ресурсов(норм нужно ждать пока поток покинет загрузчик, что бы никаких коллизий не возникло), получается что норм решение только B.

Выделить стек вызовов обычно просто, но тут наверно сложный случай, возможно он как то шифруется или быть может вм юзается. Необходимо определить критерий, который позволит событие возврата из лодера определить; это может быть выход за пределы загрузочного кода или есчо какие события. Запускайте трассировку из dllmain, хардверную(TF) или через какие софтверные реализации(pin etc).

-----
vx





Ранг: 150.3 (ветеран), 175thx
Активность: 0.160.07
Статус: Участник

Создано: 26 сентября 2016 01:16
· Личное сообщение · #21

Kuzya69 пишет:
как автоматически определять адрес возврата в основной код, находясь в DllMain этой длл-ки.

универсального способа точно не найдёшь. инфа 100%
можно попробовать перехватить известную точку - возврат из LoadLibrary/LoadLibraryEx/LdrLoadDll (тоесть натурально зацепиться за mov esp, ebp/ret X), но можно наловить косяков если несколько потоков одновременно будут грузить библиотеки.



Ранг: 30.1 (посетитель)
Активность: 0.070
Статус: Участник

Создано: 26 сентября 2016 01:33
· Личное сообщение · #22

-=AkaBOSS=- пишет:
можно попробовать перехватить известную точку - возврат из LoadLibrary/LoadLibraryEx/LdrLoadDll (тоесть натурально зацепиться за mov esp, ebp/ret X), но можно наловить косяков если несколько потоков одновременно будут грузить библиотеки.

Ага, уже что-то более близкое к вопросу. Получается надо предусмотреть, чтоб поток был нужный. Теперь надо понять, что по вашему значит "зацепиться за mov esp, ebp/ret X".
Предлагаете прерывание ставить, или просто джамп в свой код на проверку, момента сработки кода?
Или как?
По каким критериям лучше проверять потоки, что они свои-чужие?
С таким я еще не работал. Обычно просто изменения джампов или значений в памяти-регистрах приходится делать, для преодоления защиты.




Ранг: 337.5 (мудрец), 348thx
Активность: 2.112.42
Статус: Участник

Создано: 26 сентября 2016 01:36
· Личное сообщение · #23

Kuzya69

Если у вас стандартный загрузчик юзается, то почему нельзя снять стек вызовов через например rEbp, если это так, то работает какая то надстройка над кодом, что маловероятно ?

-----
vx





Ранг: 150.3 (ветеран), 175thx
Активность: 0.160.07
Статус: Участник

Создано: 26 сентября 2016 01:45
· Личное сообщение · #24

difexacaw пишет:
почему нельзя снять стек вызовов

чуть выше уже мелькало слово темида
Kuzya69 пишет:
Некоторые протекторы рвут связанную цепочку кадров вызова фукций. Да и нет уверенности, что вложенность ф-ций будет постоянной на разных ОС и программах.


Kuzya69 пишет:
Теперь надо понять, что по вашему значит "зацепиться за mov esp, ebp/ret X".

я имел в виду не конкретно эпилог функции, но где-то близко к нему.
зацепиться - значит выбрать место и перехватить выполнение. уж как это провернуть - не мне решать)
можно эксепшн устроить, а можно и аккуратно джампом обойтись.



Ранг: 30.1 (посетитель)
Активность: 0.070
Статус: Участник

Создано: 26 сентября 2016 01:47 · Поправил: Kuzya69
· Личное сообщение · #25

difexacaw пишет:
Если у вас стандартный загрузчик юзается, то почему нельзя снять стек вызовов через например rEbp, если это так, то работает какая то надстройка над кодом, что маловероятно ?

Я ж пару постов назад написал. Темида. Вызывает она эти LoadLibrary из секции ВМ, потом работает эта ВМ через копии библиотек кернел32, адвапи32, и юсер32. У копий этих, базы загрузки иногда меняются. Ну вобщем много косяков. В какой-то из версий программы, вызов был вообще через retn-команду. Вобщем сложно придумать критерий, по которому можно однозначно сказать, что все, это уже закончился вызов LoadLibrary.
-=AkaBOSS=- пишет:
уж как это провернуть - не мне решать)

Ну, с этим понял, а по какому параметру надежнее потоки разделять, что они свои-чужие?
Просто прошу быструю подсказку, я конечно скоро полезу читать про потоки в букварь, но чтобы читая упор делать на нужные параметры.



Ранг: 431.7 (мудрец), 390thx
Активность: 0.730.32
Статус: Участник

Создано: 26 сентября 2016 01:52 · Поправил: dosprog
· Личное сообщение · #26

Вот как выглядит стек на входе в DllMain, безо всяких фемид:

Code:
  1. Это [ESP] на входе в DllMain():
  2.  
  3. 0012F8A8   7C9011A7    RETURN to ntdll.7C9011A7
  4. ......... 
  5. .........  ....................................... 
  6. .........  тут туева хуча всякого в стеке ........
  7. .........  .......................................
  8. .........
  9. 0012FFA0  |7C801DA4    RETURN to kernel32.7C801DA4 from kernel32.LoadLibraryExA
  10. 0012FFA4  |00403000    ASCII "dummy.dll"
  11. 0012FFA8  |00000000
  12. 0012FFAC  |00000000
  13. 0012FFB0  |FFFFFFFF
  14. 0012FFB4  |7FFD7000
  15. 0012FFB8  \0012FFF0
  16. 0012FFBC   0040100A    RETURN to caller.<ModuleEntryPoint>+0A from <JMP.&kernel32.LoadLibraryA>
  17. 0012FFC0   00403000    ASCII "dummy.dll"
  18. 0012FFC4   7C816D4F    RETURN to kernel32.7C816D4F  - <RET TO DOS!!!>


Если без фемиды - то интересующий адрес (число, попадающее в диапазон [.401000..fFFffFF]), будет вторым таким по счёту в стеке.
Если с фемидой - надо определить, каким по счёту (из чисел, попадающих в диапазон [.401000..fFFffFF]), будет этот интересующий адрес.
Так и искать.

Но это жуткий костыль.





Ранг: 30.1 (посетитель)
Активность: 0.070
Статус: Участник

Создано: 26 сентября 2016 02:07 · Поправил: Kuzya69
· Личное сообщение · #27

dosprog пишет:
Но это жуткий костыль.

Дык я в самом начале написал, что Изыскания в стеке с помощью ebp, не подходят..
К тому-же нет уверенности, что на всех ОС, этот номер будет один и тот-же.
По крайней мере пока меня заинтересовал метод с "просеиванием" потоков в эпилоге функции LdrLoadDll, а потом, наверное, пошагово шлепать на конец LoadLibraryW. Но надо будет сначала знаний поднабрать про потоки.



Ранг: 431.7 (мудрец), 390thx
Активность: 0.730.32
Статус: Участник

Создано: 26 сентября 2016 02:13 · Поправил: dosprog
· Личное сообщение · #28

Kuzya69 пишет:
Дык я в самом начале написал, что Изыскания в стеке с помощью ebp, не подходят..


Иногда другого выхода нет,
тем более, что такие "тупые методы" тоже работают.
Более или менее.

Дополнительное условие нахождения нужного адреса в стеке - это присутствие в следующем слове указателя на аргумент. Аргумент известен.






Ранг: 337.5 (мудрец), 348thx
Активность: 2.112.42
Статус: Участник

Создано: 26 сентября 2016 02:20
· Личное сообщение · #29

Так загрузка заканчивается при возврате из системного лодера(LdrLoadDll()). Нужно только это место, что там дальше не важно. На этом месте можно выгрузиться и загрузить оригинальный модуль. Это стабильный механизм и есть апи для получения стека, RtlWalkFrameChain() etc. Но лучше как и сказал трассировать до нужного места, потому что стек может чем то быть испорчен(в случае протекторов).

> "просеиванием" потоков в эпилоге функции LdrLoadDll

В этом случае с потоками никаких проблем не возникает, если конечно код не портить. Хотя конечно можно точку останова туда поставить.

-----
vx





Ранг: 150.3 (ветеран), 175thx
Активность: 0.160.07
Статус: Участник

Создано: 26 сентября 2016 02:30
· Личное сообщение · #30

Kuzya69 пишет:
Но надо будет сначала знаний поднабрать про потоки.

хинт: TEB.ClientId.UniqueThread


. 1 . 2 . >>
 eXeL@B —› Вопросы новичков —› Как внутри DllMain, определить возврата из загрузки длл в основной код?
:: Ваш ответ
Жирный  Курсив  Подчеркнутый  Перечеркнутый  {mpf5}  Код  Вставить ссылку 
:s1: :s2: :s3: :s4: :s5: :s6: :s7: :s8: :s9: :s10: :s11: :s12: :s13: :s14: :s15: :s16:


Максимальный размер аттача: 500KB.
Ваш логин: german1505 » Выход » ЛС
   Для печати Для печати