Внедрение кода x86 в процесс x86 из процесса x64

Я понимаю названиенемного запутанный, поэтому позвольте мне объяснить, что яЯ пытаюсь сделать:

Я только что закончил писать простой DLL-инжектор для проверки концепции IЯ пытаюсь написать. Программа делает снимок текущих процессов, перечисляет дерево процессов и внедряет DLL в свой прямой родительский процесс. Теперь в идеальных условиях это работает отлично: 32-битная версия инжектора может внедряться в 32-битные родительские процессы, а 64-битная версия инжектора может внедряться в 64-битные родительские процессы.

Что я'Теперь я собираюсь внедрить 32-битную DLL в 32-битный родительский процесс из инжектора x64. Как только эта DLL вставлена, я надеялся затем внедрить вызов одной из функций, экспортируемых внедренной DLL. Я'Я не уверен, однако, если этоНа самом деле это возможно сделать. (Я'мы уже собрали некоторый код, чтобы определить, является ли родительский процесс 32-битным или 64-битным процессом, так чтоэто не проблема)

Сейчас я'мы уже нашли некоторый код, который, кажется, делает первую частьвнедрение предварительно скомпилированного машинного кода в процесс, (По крайней мере, я думаю, чточто это?s) Обычно после ввода вызова LoadLibraryW яполучить адрес, возвращаемый этим вызовом, добавить относительное смещение к экспортируемой функции, которую я хочу вызвать, и ввести вызов этой функции. В этом случае, однако, я могузагрузить 32-битную библиотеку в мой 64-битный инжектор, чтобы я могнайти относительное смещение функции, используяGetProcAddress как обычно. Я справился с этой проблемой, выполнив следующее:

Так как я могунайти смещение функции 32-битной DLL, используя обычные средства, ям в настоящее время чтение файла в буфер, используя этот буфер для заполненияIMAGE_NT_HEADERS32 struct и перечисляя IMAGE_EXPORT_DIRECTORY, чтобы найти имена и относительные смещения всех экспортируемых функций.

Итак, на данный момент у меня есть следующее:

32-битная DLL загружена в 32-битный процессЗначение, эквивалентное funcAddr при запуске следующего кода в 32-разрядном процессе:

Код:

HMODULE hInjectedDLL = LoadLibrary("mydll.dll");
DWORD funcAddr = (DWORD)GetProcAddress(hInjectedDLL, "ExportedFunc") - (DWORD)hInjectedDLL;

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

Есть идеи?

(Также я'Я знаю, что я могу избавить себя от многих проблем, просто скомпилировав две версии инжектора и запустив одну из них, когда родительский процесс 'архитектура процессора нене совпадают. Я'хотя я стараюсь не идти по этому пути.)

редактировать: Понял, что это может помочь объяснить, что яЯ на самом деле пытаюсь достичь в этом доказательстве концепции.

Я экспериментировал с идеей. Мне нужно было разрешить выполнение дочернего процесса в текущей консоли без необходимости, чтобы исходный процесс ожидал завершения дочернего процесса. С тех пор'нет встроенного API для этого в консольном приложении, выОбычно они привязаны к дереву процессов, все ожидают завершения своего дочернего процесса. Чтобы облегчить эту функциональность, я хочу сделать следующее:

впрыскивание

Инжектор DLL будет играть роль "выполнение процесса ", (процесс, который обычно должен ждать завершения дочернего процесса). При запуске он определяет платформу своего родительского процесса и определяет, является ли родительский процесс даже консольным приложением. Если оно'нет, процесс просто используетсемейство функций exec чтобы запустить нужный подпроцесс, выход немедленно. Если родительский процесс является консольным приложением, инжектор определяет, какую DLL использовать, приостанавливает поток, который первоначально создал процесс инжектора, а затем внедряет DLL в родительский процесс.

Решение нашей функции

Как только DLL установлена, инжектор определяет этот адрес функции, экспортируемой DLL. (Обычно ясделать это, позвонивCreateRemoteThread сделать начальную инъекцию, а затем использоватьGetExitCodeThread в этом потоке, чтобы получить базовый адрес DLL в родительском процессе. Как только я это получу,Простая арифметика, чтобы найти адрес нашей экспортируемой функции, которую я затем могу использовать, чтобы ввести второй вызов этой функции.

Называя нашу функцию

Экспортируемая функция будет выглядеть примерно так:

BOOL RewriteHProcess (HANDLE hProcess)

Инжектор снова будет использовать CreateRemoteThread для вызова этой функции из контекста родительского процесса, а hProcess является дескриптором процесса инжектора. На стороне DLL, функция будет делать одну из двух вещей (яЯ не совсем уверен, возможна ли моя первая идея, учитывая ограничения безопасности доступа к памяти между потоками, поэтому я собрал вторую идею, на которой можно отступить, если первая нене получается.)

RewriteHProcess откроет ранее приостановленный поток для чтения и записи и использованияReadProcessMemory, он будет искать процесс "Память для РУКОВОДСТВА к нашему процессу инжектора. (Мы'делает предположение, что родительский процесс в настоящее время блокирует дальнейшее выполнение с помощьюWaitForSingleObject функция. Я знаю, что командная строка делает, по крайней мере, и чтоПока я фокусируюсь) Затем DLL вызывает внутреннюю функцию для создания желаемого дочернего процесса, закрывает старый дескриптор и перезаписывает память дескриптором на наш новый дочерний процесс. В этот момент он убирает все, что может, и возвращает. Затем инжектор выполнит любую оставшуюся очистку, в которой он нуждается, возобновит приостановленный поток, закроет дескрипторы процесса и потока и завершит работу, оставив родительский процесс для продолжения блокировки, пока он ожидает завершения нового дочернего процесса.

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

Ответы на вопрос(2)

Ваш ответ на вопрос