Я предполагаю, что вам нужен код, который можно расположить в любом месте памяти и по-прежнему работать, независимо от того, просто ли вы просто перепрыгиваете в него явно или он загружается как исполняемый образ, как и любой другой. Он не будет зависеть от «предпочтительного» базового адреса или данных в разделе .relocation (если он вообще существует). Этот код не будет зависеть от каких-либо других частей исполняемого образа (таких как IAT, раздел .data или любой из различных заголовков), однако он всегда будет определяться платформой c (то есть Windows) и может быть указан c для некоторых версий Windows, в зависимости от того, как он написан, однако Windows agnosti c код достижим.
Вам просто нужно, чтобы ваш код был создан таким образом, чтобы он не зависел на жестко закодированных адресах ИЛИ жестко закодированных смещениях из относительной базы изображений. Это тот же тип кода, который используется для управления программой в эксплойтах безопасности.
Этот код почти всегда требует использования явных инструкций на языке ассемблера, включая сам код точки входа. Например, вы не можете использовать код запуска C Runtime, начиная с Main, WinMain, DllMain или аналогичного. Этот процесс можно сделать менее сложным, если использовать пользовательские C MACRO и встроенную сборку, однако вам все равно необходимо общее понимание базовых инструкций по сборке.
Вместо того, чтобы использовать жестко закодированные указатели или относительное «изображение» Базовый адрес для ссылки на функции и данные, ваши функции и указатели данных должны быть построены вручную относительно места в вашем коде точки входа. Это проще, чем кажется, и может быть так же просто, как относительный CALL, за которым следует инструкция POP для получения вашего «базового» адреса (архитектура X86). Затем ваши данные могут быть смешаны между байтами кода, прыгая по мере необходимости, указатели создаются не иначе, как относительные указатели на ваши функции.
Используя независимые от позиции инструкции и обнаруживая местоположение вашей точки входа во время выполнения, теоретически вы можете перенести секцию .text получившегося образа PE и JMP в вашу точку входа, даже если результирующий EXE-файл также будет работать нормально. Просто ожидайте, что вы сделаете много грязной работы самостоятельно, вплоть до того момента, когда вы сможете динамически разрешать Windows адреса API. Это может быть не для слабонервных, однако это довольно просто. Эта область изучения даст вам глубокое понимание того, как Windows работает под прикрытием, и вы станете лучшим программистом для этого.
Для этого есть множество информации в inte rnet топи c. Ищите «шеллкод» и руководства по написанию упаковщиков / распаковщиков. Вызов API windows означает, что вам нужно написать собственный загрузочный код для разрешения этих адресов во время выполнения; упаковщики и распаковщики делают то же самое.
Рекомендованные книги, описывающие этот процесс, в первую очередь разрешение импорта адресов: «Программирование с помощью Shellcoder (Kaspersky)», «Руководство по Shellcoder» (Anley) и «Арсенал руткитов» (Blunden); последний немного затрагивает C MACRO для управления аспектом сложности. Некоторые детали обсуждаются в следующей статье: Расположение KERNEL32 в памяти ASLR .
Удачи!