Взаимодействие между процессами — Архив WASM.RU
Взаимодействие между процессами (IPC) - это путь, с помощью которого процессы могут взаимодействовать между собой. У каждого процесса есть свое собственное отдельное адресное пространство, поэтому процессы не могут напрямую видеть память других процессов. Win32 API предоставляет несколько разновидностей IPC. IPC может быть очень полезно для вирусов, поэтому я объясню несколько путей, хотя я не уверен, что в вирусах применимы все из этих путей.
В этой статье объясняются следующие виды IPC:
- атомы
- мэппинг файлов
- анонимные пайпы
- мейлслоты
Атомы
Атомы - это очень простой и доступный путь IPC. Идея состоит в том, что процесс может поместить строку в таблицу атомов и эта строка будет видна другим процессам. Когда процесс помещает строку в таблицу атомов, он получает 32-х битное значение (атом), и это значение используется для доступа к строке. Система не различает регистр строки.
Есть два типа таблиц атомов - глобальная (GAT) и локальная (LAT).
Код (Text):
Добавление строки в GAT push _address_of_string - строка, заканчивающаяся NULL, максимальный размер равен 255 байтам call GlobalAddAtom(A/W) Возвращает в eax атом Удаление атома из GAT push _atom call GlobalDeleteAtom(A/W) Возвращает 0 в eax, если вызов функции прошел успешно Поиск атома push _адрес_строки - заканчивающаяся NULL'ом строка, максимальный размер которой равен 256 байтам call GlobalFindAtom(A/W) Возвращает 0 в eax, если вызов функции неудался, либо атом, если вызов прошел успешно Получить строку атома, имея атом push _size_of_buffer - длина буфера push _address_of_buffer - буфер push _atom - атом <img src="styles/smiles_s/smile3.gif" class="mceSmilie" alt=":smile3:" title="Smile3 :smile3:"> call GlobalGetAtomName(A/W) | Если вызов прошел успешно, буфер будет заполнен строкой атома| LAT использует те же функции для работы с атомами, только без приставки 'Global'. Как бы то ни было, LAT виден тольк для текущего процесса, но не для других. Количество элементов по умолчанию равно 37, но его можно изменить с помощью функции InitAtomTable. Максимальное количество, которое можно установить, равно 3FFF. Хм, это число указано в MSDN, но я пытался получить сообщение об ошибке, вызывая эту функцию с более высоким значением, и у меня ничего не вышло. Похоже, что функция работает с любым количеством элементов.
Код (Text):
Инициализация LAT push _размер_LAT call InitAtomTable Возвращает ...Вот и все об атомах...
Мэппинг файлов
Я думаю, что мэппинг файлов - это хорошо известный путь для доступа к файлам. Он объяснен во многих статьях, поэтому я не буду тратить время на подробности. Идея в том, что мы можем промэппировать файл в память. Тогда с каждым изменением в памяти, будет меняться и файл. Применительно к IPC мы можем промэппировать файл в нескольких процессах и взаимодействовать через него.
Код (Text):
функции push шаблонный хэндл файла ; по умолчанию - 0 push флаги и аттрибуты ; по умолчанию - 0 push флаги открытия и создания push аттрибуты безопасности ; по умолчанию - 0 push флаги разделяемого доступа ; по умолчанию - 1 push доступ к файлу push имя файла call CreateFile(A/W) Возвращает хэндл файла флаги создания и открытия CREATE_NEW equ 1 CREATE_ALWAYS equ 2 OPEN_EXISTING equ 3 OPEN_ALWAYS equ 4 TRUNCATE_EXISTING equ 5 доступ к объекту GENERIC_READ equ 080000000h GENERIC_WRITE equ 040000000h GENERIC_EXECUTE equ 020000000h GENERIC_ALL equ 010000000h Правильный мэппинг файла начинается здесь, ...объект, который должен быть промэппирован, не нужно открывать CreateFile(A/W). Если мы используем значение (-1) в аргументе хэндла файла, мы промэппируем часть разделяемой пммяти без связывания с файлом, ...идеально для IPC. push имя промэппированного объекта ; по умолчанию - 0 push нижние 32 бита размера объекта ; по умолчанию - размер push верхние 32 32 bits of object size ; по умолчанию - 0 push защита ; по умолчанию - 4 push аттрибуты безопасности ; по умолчанию - 0 push хэндл файла ; по умолчанию - HNDL от CreateFile call CreateFileMapping(A/W) Возвращает хэндл объекта Эта функция создает объект мэппинга и возвращает хэндл его защиты PAGE_READONLY equ 2 PAGE_READWRITE equ 4 PAGE_WRITECOPY equ 8 Аттрибуты безопасности - указатель может быть установлен в NULL, как бы то ни было, вот структура: SECURITY_ATTRIBUTES struc _saSize dd ? ; размер структуры _lpSecurityDescriptor dd ? ; указатель на дескриптор ; безопасности _bInheritHandle dd ? ; булевое значение, истинно для ; наследования SECURITY_ATTRIBUTES ends push имя мэппирующегося объекта push флаг наследования push реим доступа call OpenFileMapping(A/W) Возвращает хэндл объекта Режим доступа FILE_MAP_WRITE equ 2 ;R/W access FILE_MAP_READ equ 4 ;R access теперь у нас есть map-объект push сколько байтов мэппировать ; по умолчанию - размер push нижняя часть смещения ; по умолчанию - 0 push верхняя часть смещения ; по умолчанию - 0 push access mode ;---------------------------------- push object handle ; по умолчанию - HNDL from Create(Open)FileMapping call MapViewOfFile Возвращает адрес в памяти теперь у нас есть промэппированный в память файл мы можем записать часть промэппированного файла на диск, используя: push количество байтов, которое нужно записать push начальный адрес call FlushViewOfFile push адрес в памяти call UnmapViewOfFile ; демэппирует файл push хэндл объекта ; закрывает объект мэппинга call CloseHandle push хэндл файла ; закрывает хэндл файла call CloseHandleВот и все о мэппинге файлов.
Анонимные пайпы
Есть два типа пайпов: анонимные и именованные. Именованные пайпы 'немного' труднее использовать, чем анонимные, поэтому я расскажу о них в другой статье.
Ладно, анонимные пайпы однонаправленны и безымянны. Они не могут быть использованы для удаленного взаимодействия (в отличии от именованных). Идея состоит в том, что сервер создает пайп и получает хэндлы чтения и записи в пайп. Тогда он может послать один из этих хэндлов процессу, с которым он хочет взаимодействовать (мы должны послать его через какой-нибудь другой метод IPC, я думаю, что лучше всего будет сделать это через атомы, хотя есть и другие пути...).
Код (Text):
создание анонимного (безымянного) пайпа push размер пайпа push защита push указатель на хэндл записи в пайп push указатель на хэндл чтения из пайпа call CreatePipe pipe size - size of pipe buffer if it's NULL system uses default size protection - pointer to SECURITY_ATTRIBUTES if it's NULL pipe cant be inherited размер пайпа - размер его буфера защита - указатель на SECURITY_ATTRIBUTES, если NULL - пайп нельзя унаследовать Когда пайп создается, мы имеем доступ к обоим концам. После создания пайпа, сервер должен отослать один хэндл клиентскому процессу. чтение из пайпа синхронно - это означает, что функция не возвратится, пока чтение не будет закончено push указатель на структуру данных push указатель на количество прочтенных байтов push количество байтов, которое нужно считать push указатель на буфер, куда будет производиться чтение push хэндл чтения из пайпа call ReadFile указатель на структуру данных - эта структура используется для асинхронного ввода и вывода; поэтому напишем NULL указатель на количество считанных байтов - указатель на dword, который будет содержать количество считанных байтов запись в пайп синхронна - это означает, что функция не возвратится, пока запись не будет выполнена push указатель на структуру данных push указатель на количество записанных байтов push количество байтов, которое нужно записать push указатель на буфер, содержащий записываемые данные push хэндл записи в пайп call WriteFile Анонимные пайпы живут, пока открыты хэндлы чтения и записи. Мы можем закрыть их с помощью функции CloseHandle.Вот и все об анонимных пайпах.
Мейлслоты
Мейлслоты - это еще один простой способ взаимодействия между процессами. Его суть заключается в том, что один процесс (сервер) может коннектиться к мейлслоту и посылать эти сообщения. Мейлслоты используют датаграмы для коммуникации, а именованные слоты - нет (для удаленного взаимодействия). Уффф...
Код (Text):
push защита push время(ms) ожидания push максимальный размер сообщения push имя мейлслота call CreateMailslot(A/W) Возвращает имя мейлслота имя мейлслота - имя, которое имеет следующую форму: db "\\.\mailslot\[path]name", 0 - имя должно быть уникальным, и в нем могут быть псевдодиректории ([path]), и (как обычно) оно не чувствительно к регистру максимальный размер сообщения - мы можем указать максимальную длину записанного сообщения в мейлслот, как бы то ни было, если это поле равно NULL, сообщение может быть любого размера время ожидания - это время, которое ReadFile будет ждать, если сообщение еще не находится в мейлслоте. Есть несколько специальных значений: 0 - если нет сообщения в мейлслоте, функция не будет работать <img src="styles/smiles_s/smile3.gif" class="mceSmilie" alt=":smile3:" title="Smile3 :smile3:"> -1 - функция будет ждать, пока в мейлслоте не появится сообщение - (MAILSLOT_WAIT_FOREVER)Ладно, мы создаем мейлслот и у нас есть его хэндл. Мы можем закрыть его с помощью CloseHandle...
Теперь мейлслот создан и к нему можено получить доступ по имени. Клиенты могут подсоединяться с помощью функции CreateFile(A/W), используя имя мейлслота в качестве имени файла. После подсоединения клиент получает хэндл мейлслота и может записывать сообщения в него. Это делается с помощью функции WriteFile. Сервер считывает сообщения с помощью ReadFile. Как CreateFile, и ReadFile уже затрагивались в этом тексте, поэтому я не буду тратить время на повторное объяснения. как бы то ни было, есть еще несколько функций для работы с мейлслотами.
Код (Text):
функции сервера мейлслота: push указатель на время ожидания чтения push указатель на количество соощений push указатель на размер следующего сообщения push указатель на максимальный размер сообщения push хэндл мейлслота ; возвращается функцией CreateMailslot(A/W) call GetMailslotInfo Возвращает TRUE(1), если вызов прошел успешно указатель на размер следующего сообщения - этот параметр может быть равен NULL, как бы то ни было, мы получим размер следующего сообщения в мейлслоте. Мы можем получить MAILSLOT_NO_MESSAGE(-1) - это значит, что в мейлслоте больше нет сообщений. указатель на количество сообщений - этот параметр может быть равен NULL, если нет, то мы получим общее количество сообщений, которое нужно прочитать. Чтобы установить время ожидания для операции чтения из мейлслота, мы можем использовать: push время ожидания для операции чтения push хэндл мейлслота call SetMailslotInfo Когда у нас есть хэндл мейлслота, мы можем использовать стандартные функции, чтобы получить информацию о нем. Мы можем использовать: DuplicateHandle GetFileTime SetFileTime GetHandleInformation SetHandleInformationВот и все. © mort[MATRiX], пер. Aquila
Взаимодействие между процессами
Дата публикации 27 июн 2002