Задача такая: Внедрить .dll написанную на ЯВУ в программу, не патча ее на диске. При этом программа не должна ничего понять, если вдруг попытается. Длл не малварная, пользователь знает об инжекте, но желательно чтоб антивирусы\фаерволы сильно не орали. Решение должно быть несложным, но в то же время эффективным. Несложным - значит юзермод. Должно работать на XP,висте,7ке. Пока что я остановился на коде, который создает процесс с флагом CREATE_SUSPENDED, сохраняет eip потока (GetThreadContext), выделяет в процессе память и записывает туда шеллкод (VirtualAllocEx+WriteProcessMemory), предварительно в шеллкод записывается начальный eip потока и RVA LoadLibraryA меняет eip на адрес шеллкода (SetThreadContext), запускает поток (ResumeThread). CloseHandle не используются, т.к. процесс-launcher всеравно после этого завершается. Шеллкод в свою очередь пихает в стек начальный адрес потока как адрес возврата, сохраняет все регистры получает базу kernel32.dll, при этом используются допущения, что начальный адрес потока находится в kernel32.dll, что образ kernel32.dll в памяти не поврежден, и что все его страницы доступны для чтения, добавляет к базе kernel32.dll RVA LoadLibraryA, и вызывает ее, загружая нужную длл, затем восстанавливает регистры и возвращается на начальный адрес потока. Собственно для меня основная непонятность - это безопасно ли вообще вызывать LoadLibrary до инициализации процесса в юзермоде, не случится ли чего? Просьба высказываться по существу дела, а не "фасм фигня, код неоптимальный, ТС неуч, и т.п." Сырец в аттаче.
Шеллкод получает управление уже после завершения базовой инициализации – в конце концов, до этой инициализации в адресном пространстве процесса нет даже kernel32.dll. К тому моменту, когда шеллкод начинает выполнение, все прямо и косвенно импортируемые длл уже промаплены, их релоки настроены, а точки входа вызваны с кодом DLL_PROCESS_ATTACH. Также уже вызваны tls-колбеки, длльные и экзешные. Из точек входа и tls-колбеков модули могут определить, что eip начального контекста подменён (не совпадает со стандартной ntdll!RtlUserThreadStart – ну или что там для конкретной оси). Определение несоответствия не составляет труда – третьим параметром в точки входа\tls-колбеки передаётся указатель на [псевдо]начальный контекст. Почему так? Очень просто – перед началом выполнения первичной функции потоку доставляется инициализирующая APC с rip == ntdll!LdrInitializeThunk. Т.е. актуальное выполнение начинается именно оттуда. >начальный адрес потока находится в kernel32.dll Для w7 это ntdll!RtlUserThreadStart. Впрочем, это не важно здесь. >безопасно ли вообще вызывать LoadLibrary до инициализации процесса в юзермоде? Как можно видеть, процесс к тому моменту уже почти проинициализирован. Так что в тот момент – да, считаем что вполне безопасно. Раньше (до загрузки kernel32) – можно воспользовать ntdll!LdrLoadDll.
GoldFinch Я когда-то писал тулень для мониторинга мемори ликов, и там почти так же пробовал инжектиться, так вот наблюдались иногда при этом очень станные дедлоки, для некоторых приложений. Тогда мне опыта\знаний не хватило, чтобы расковырять за разумное время из-за чего это происходит, и я стал использовать то, что, кажется, в eax энтри пойнт хрантся, если после "create suspended" снять контекст, ну это для xp, а про висту и семерку мне не нужно было тогда париться.
GoldFinch Когда поток перейдёт к исполнению кода по адресу в регистре Eip контекста инициализация процесса будет завершена. Поток не отсюда начинает исполняться, ядро сохранит в стеке потока пользовательский контекст, после чего загрузит ссылку на процедуру инициализации процесса и доставит юзермодную стартупапк, в конце которой пользовательский контекст будет загружен из стека в процессор, в общем как и сказал Sol_Ksacap. Поэтому вам можно не заботится про инициализацию процесса. Sol_Ksacap Единственное причина там оказаться это подгрузка верификатора, сразу за которой следует подгрузка kernel32. Есчо ранее лодер не инициализирован.