Всем привет. Вопрос о работе PE-загрузчика, который загружает DLL, имеющую IMAGE_DIRECTORY_TLS. Реально ли написать такой загрузчик без использования сомнительных хаков (использование оффсетов в недокументированных структурах, вызов недокументированных API не до конца понятного назначения и т.д.) ? Насколько я сейчас понимаю, там нужно работать с TEB.ThreadLocalStoragePointer, да ещё и вызывать что-то при создании и завершении потока. Экспортируемых функций для работы с TLS на уровне ntdll!LdrXxx не нашел. Есть разбирающиеся в этом вопросе? Спасибо!
jeer0, > Реально ли написать такой загрузчик без использования сомнительных хаков Нет. Вы можите только эмулировать или вмешаться в логику работы системного загрузчика, например захватить его и симулировать некоторые данные. Иначе никак решить нельзя. Суть в том, что тлс отрабатывает на этапе загрузки апп, но так как ваше апп это загрузчик для другого апп, то получается что механизм не запускается, те корреляция. Обычно лучше симулировать данный механизм, так как врядле у вас загручик является надстройкой(такой за всё время был один и мой: LWE). Если вы вручную формируете образ в памяти, то данная задача смысла не имеет, конечно вы должны иммитировать тлс.
Ну и следует добавить что ручное" формирование образа это просто дикость, нубость, так как это абсолютная не совместимость с системой - загрузчик поддерживает огромное число механизмов. В таком случае использование системных механизмов бессмысленно и абсурдно. Полноценный лоадер должен являться надстройкой над системным загрузчиком - нтлдр захватывается и симулируются низкоуровневые данные. Таким образом он отрабатывает штатно, но данные подменяются. Лишь в этом случае имеет смысл спросить про тлс.
Пока я сталкивался только с проблемой с TLS, которая решается компиляцией C++ -кода с флагом /Zc:threadSafeInit- (речь идет о Visual Studio 2015). Просто хотелось раз и навсегда избавиться от необходимости указывать этот флаг всему коду, который может быть загружен моим собственным загрузчиком (тоесть, например, составляющий DLL, которая куда-то инжектится). Другие механизмы на практике проблем не вызывали. О каких именно идет речь? Это как? Что именно и где нужно перехватить и симулировать? Не могу найти в гугле LWE Кстати, да, покопавшись в проблеме я понял, что это называется implicit TLS и что загрузчик выделяет специальный слот в TEB.ThreadLocalStoragePointer и поддерживает актуальность этого слота при создании новых потоков. Короче, универсальное решение тут невозможно. Так что да, никак.
jeer0, Не слушай его. Его сейчас на аппаратной виртуализации переклинило и он думает, что без визоров вообще ничто действительно рабочее написать невозможно
rmn, Ну а причём тут визоры и вм ? jeer0, > Это как? Что именно и где нужно перехватить и симулировать? Не могу найти в гугле LWE Это работает следующим образом. На ключевые сервисы ставится фильтр, они иммитируются. Тоесть NtMapView отображает в память не файловую секцию, а декриптует в память образ. Что бы не портить патчем нэйтив(нтдлл) он линейно копируется в буфер(релоцируется) и там фиксятся сервисы, устанавливается на них фильтр. Затем происходит штатный вызов загрузчика, который перенесён в буфер. Он работает как обычно, за исключением симуляции образа. Я использовал knowndll секции. https://yadi.sk/d/vRgDzkySrRowe - дату посмотрите реализации Есчо можите посмотреть как скрыть образ https://yadi.sk/d/aK1r0ajK36X58R(pass: vx).
Indy_, угу, понятно. Вызвать обычную LoadLibrary, но перехватив NtMapView* и подсунув проекцию своей DLL "из памяти" вместо проекции DLL с диска. Я вот только боюсь следующего. Не получится ли так, что какой-нибудь функции виндового лоадера не понравится факт наличия загруженной DLL, у которой информация о View или Section не соответствует действительности (т.е. той информации, которую сохраняет лоадер в PEB) ? Вообще это выглядит как хороший способ, может быть, кто-то его использовал на практике и может высказаться о его стабильности и подводных камнях? > дату посмотрите реализации А когда последний раз это успешно использовалось?
jeer0, > Не получится ли так, что какой-нибудь функции виндового лоадера не понравится факт наличия загруженной DLL, у которой информация о View или Section не соответствует действительности Получится. Это касается защиты, например NX. Но это не проблема. > А когда последний раз это успешно использовалось? Не помню точно, но когда то запускали на 10-ке, оно работало. Не работало вроде как с .net, но я тогда отказался разбираться. А есчо наверно те файлы у ав в базах, так как на этом активно тестились ав, впрочем не важно.
> Получится. Это касается защиты, например NX. Но это не проблема. Что такое NX защита и почему это не проблема? Речь ведь не о noeXecute bit ("nx bit") ?
jeer0, Блокировка исполнения исключений(safeseh или nxseh не помню как называтеся, но это не важно) в не image памяти. Это очень старый механизм. Более того последние версии системы поддерживают кучу новых механизмов. Можно предсказать теоретически как что с ними связано на основе описаний. Но главная проблема в андок механизмах, их весьма много, всякие валидации стека и прочее, так что не имея самой новой ос предсказать ничего нельзя, увы. Я как то поднимал вопрос про модуля от новых версий ос, это помогло бы всем, но это никому не нужно и не интересно.)
superakira, Решает. Именно потому что изначально подход общий оно работает в новых версиях ос. Это нэйтив, он не меняется. Лишь глупый ньюби решится на симуляцию нтлдр. Принцип релокации элементарен - не зависимо от режима(86/64) кодовая секция нт может быть перемещена как линейный массив. В первом случае нет релатив(относительных адресов) адресации за пределы секции, это противоречит пе формату, это не возможно. Во втором случае фиксапов нет, они не нужны, так используется rip-адресация, так что это отлично сработает на 64.
В #12 я допустил ошибку и не правильно сказал. Из за предновогоднего состояния" ушёл от исходной задачи на свою Это не существенная деталь, но всё же следует поправить. Принцип следующий. Есть серия сервисных вызовов из нэйтив на которые нужно поставить фильтр и симулировать. Уставновка фильтра может быть выполнена многими способами, я использовал линейное копирование кодовой секции(86), для сокрытия(не изменять код и лишний раз не использовать ловушки). 86 модуля не имеют межсекционной релатив адресации. В 64 моде межсекционная релатив адресация присутствует, причём это нельзя в статике определить. Адресация в иную секцию происходит через фиксированное смещение при релатив адресации, а ссылки на данное смещение в пе не имеется. Таким образом 64 секция не может быть никак перенесена в другую область памяти. Поэтому фильтр на 64 следует ставить иным образом.
superakira, Повторяем диалог, ну что бы вам стало понятно: > Покажите ваше решение. >> Всё норм, есть траблы. status_bad. Буду копать. Есть мысли - дай знать, нет идей - нет сурков. > Фейк понятен. >> Вываливается, забей. Я отписал, может куму будет интересно.
superakira, В ядре 8-ки данного статуса нет, как и на msdn. Последний там следующий: Но данный статус находит гугл как STATUS_DYNAMIC_CODE_BLOCKED. Это значит что система отклоняет запрос на аллокацию исполняемой памяти. Не вижу проблемы в этом случае.
superakira, А что именно не так с нэйтивом ? Он не релоцируется, хоть имеет релоки на 86, но загружается первым и содержит глобальные указатели. На 64 rip адресация и релоки не нужны. Это значит что можно его копировать как строку. Сброс загрузчика необходим лишь в одном случае - это запуск образа с тлс. Но это очень плохой способ, отвалится многое. На 86 первый фейл будет при соеденении с csrss, повторное подключение невозможно.
Я попробовал, отлично получилось с дллкой. А вот с PE не очень понятно можно ли грузануть экзешник, вроде LoadLibrary отрабатывает, бинарь обрабатывается Ldr* ф-циями, релоки отрабатывают, но при попытке на точку входа прыгнуть, падает на ЦРТ ф-циях. Это вообще возможно, бинарь загрузить данной техникой?
Вру. Сейчас чекнул на минимальном фасмовском сепле Hello World x86, не обрабатываются импорты, секции не мапятся в вирт память, релоков тож нет, нифига короче не делается по сути. Попробую найти на чём зытыкается загрузчик, я так думаю что кроме отсутствия IMAGE_FILE_DLL 0x2000 в Characteristics ещё на чём-то