Совместное использование памяти между двумя процессами (C, Windows)
Поскольку я не нашел ответа на вопрос, заданный ранее здесь, я пробую другой подход.
Есть ли способ разделить память между двумя процессами?
Второй процесс получает информацию из инъекции, поскольку это устаревшая программа, которая больше не поддерживается.
Моя идея состоит в том, чтобы внедрить некоторый код туда, в структуре, которую я передаю внедренной программе, передать адрес (или любой другой) в общую память, где находятся данные, которые мне нужно запустить. Как только я получу данные, я заполню свои собственные переменные внутри введенного потока.
Это возможно? Как?
Код ценится.
РЕДАКТИРОВАТЬ:
Я думаю, что это не ясно, поэтому я уточню. Я знаю, как вводить. Я уже делаю это. Проблема здесь состоит в том, чтобы передавать динамические данные для инъекции.
7 ответов
Вы можете попробовать отображенный в памяти файл.
Это дает немного больше пошаговых деталей.
Хотя windows поддерживает разделяемую память через API-интерфейс сопоставления файлов, вы не можете легко внедрить сопоставление совместно используемой памяти непосредственно в другой процесс, поскольку MapViewOfFileEx не принимает аргумент процесса.
Однако вы можете вставить некоторые данные, выделив память в другом процессе, используя VirtualAllocEx и WriteProcessMemory. Если вы хотите скопировать в дескриптор, используя DuplicateHandle, а затем внедрить заглушку, которая вызывает MapViewOfFileEx, вы можете установить отображение общей памяти в другом процессе. Поскольку, похоже, вы все равно будете вводить код, это должно работать для вас.
Подводя итог, вам нужно:
- Создайте анонимный дескриптор сегмента совместно используемой памяти, вызвав CreateFileMapping с INVALID_HANDLE_VALUE для hFile и NULL для lpName.
- Скопируйте этот дескриптор в целевой процесс с помощью DuplicateHandle
- Выделите немного памяти для кода, используя VirtualAllocEx, с flAllocationType = MEM_COMMIT | MEM_RESERVE и flProtect = PAGE_EXECUTE_READWRITE
- Запишите свой код заглушки в эту память, используя WriteProcessMemory. Эта заглушка, вероятно, должна быть написана на ассемблере. Передайте РУЧКУ от DuplicateHandle, написав это где-то здесь.
- Выполните свою заглушку, используя CreateRemoteThread. Затем заглушка должна использовать полученную РУЧКУ для вызова MapViewOfFileEx. Затем процессы будут иметь общий сегмент общей памяти.
Возможно, вам будет немного проще, если ваша заглушка загружает внешнюю библиотеку, то есть просто вызовите LoadLibrary (поиск адреса LoadLibrary оставлен читателю в качестве упражнения) и выполните свою работу из точки входа библиотеки dllmain. В этом случае использование именованной совместно используемой памяти, вероятно, будет проще, чем работа с DuplicateHandle. См. Статью MSDN о CreateFileMapping для получения более подробной информации, но, по сути, передайте INVALID_HANDLE_VALUE для hFile и имя для lpName.
Изменить: так как ваша проблема заключается в передаче данных, а не фактическое внедрение кода, вот несколько вариантов.
- Используйте разделяемую память переменного размера. Ваша заглушка получает размер и либо имя, либо дескриптор общей памяти. Это уместно, если вам нужно обмениваться данными только один раз. Обратите внимание, что размер сегмента общей памяти не может быть легко изменен после создания.
- Используйте именованную трубу. Ваша заглушка получает имя или ручку к трубе. Затем вы можете использовать соответствующий протокол для обмена блоками переменного размера - например, напишите size_t для длины, за которой следует фактическое сообщение. Или используйте PIPE_TYPE_MESSAGE и PIPE_READMODE_MESSAGE и следите за ERROR_MORE_DATA, чтобы определить, где заканчиваются сообщения. Это подходит, если вам нужно обмениваться данными несколько раз.
Редактировать 2: Вот эскиз того, как вы могли бы реализовать хранение дескриптора или указателя для вашей заглушки:
.db B8 ;; mov eax, imm32
.dl handle_value ;; fill this in (located at the start of the image + one byte)
;; handle value is now in eax, do with it as you will
;; more code follows...
Вы также можете просто использовать фиксированное имя, что, вероятно, проще.
Вы можете использовать общую память
Вы пытались использовать каналы (для памяти) или даже сериализацию (для ваших объектов)? Вы можете использовать файлы для управления памятью между процессами. Сокеты также хороши для установления связи между процессами.
Если вы говорите о Windows, то основным препятствием является то, что каждый процесс обрабатывается в собственном виртуальном адресном пространстве. К сожалению, вы не можете передавать обычные адреса памяти от процесса к процессу и получать ожидаемые результаты. (С другой стороны, все потоки живут в одном и том же адресном пространстве, поэтому потоки могут видеть память одинаково.)
Windows, однако, имеет общее пространство памяти, с которым вы должны быть очень осторожны, чтобы правильно управлять. Любой процесс, который выделяет пространство в пространстве общей памяти, отвечает за освобождение этой памяти явно. Это в отличие от локальной памяти, которая более или менее исчезает, когда процесс умирает.
Посмотрите в этой статье MSDN образец для некоторых идей о том, как вы могли бы использовать пространство совместно используемой памяти, чтобы захватить мир. Э-э, интерфейс с устаревшим программным обеспечением. Или что угодно:) Удачи, что бы ты ни делал!
Распределение памяти - это путь, вам даже не нужно создавать постоянное пространство памяти, сектор памяти выходит из области видимости, когда все процессы, разделяющие его, закрываются. Есть и другие способы. Быстрый и грязный способ передачи данных из одного приложения C в другое - просто использовать ОС. Тип командной строки app1 | app2
, Это приводит к тому, что app2 становится выходным адресатом app1 или iow команда printf из app1 отправляет его в app2 (это называется конвейером).
Вы можете попробовать использовать Boost.Interprocess для связи между двумя процессами. Но чтобы внедрить код в ранее существующее, не поддерживаемое программное обеспечение, вам, вероятно, придется использовать способ @bdonlan, используя WriteProcessMemory.