Взаимодействие между процессами


Взаимодействие между процессами (IPC) — это путь, с помощью которого процессы могут взаимодействовать между собой. У каждого процесса есть свое собственное отдельное адресное пространство, поэтому процессы не могут напрямую видеть память других процессов. Win32 API предоставляет несколько разновидностей IPC. IPC может быть очень полезно для вирусов, поэтому я объясню несколько путей, хотя я не уверен, что в вирусах применимы все из этих путей.

В этой статье объясняются следующие виды IPC:

  • атомы
  • мэппинг файлов
  • анонимные пайпы
  • мейлслоты

Атомы

Атомы — это очень простой и доступный путь IPC. Идея состоит в том, что процесс может поместить строку в таблицу атомов и эта строка будет видна другим процессам. Когда процесс помещает строку в таблицу атомов, он получает 32-х битное значение (атом), и это значение используется для доступа к строке. Система не различает регистр строки.

Есть два типа таблиц атомов — глобальная (GAT) и локальная (LAT).

  Добавление строки в 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                - атом :)
    call GlobalGetAtomName(A/W)
                                                                          |
    Если вызов прошел успешно, буфер будет заполнен строкой атома

| LAT использует те же функции для работы с атомами, только без приставки ‘Global’. Как бы то ни было, LAT виден тольк для текущего процесса, но не для других. Количество элементов по умолчанию равно 37, но его можно изменить с помощью функции InitAtomTable. Максимальное количество, которое можно установить, равно 3FFF. Хм, это число указано в MSDN, но я пытался получить сообщение об ошибке, вызывая эту функцию с более высоким значением, и у меня ничего не вышло. Похоже, что функция работает с любым количеством элементов.

 Инициализация LAT

   push _размер_LAT
   call InitAtomTable

   Возвращает ...

Вот и все об атомах…

Мэппинг файлов

Я думаю, что мэппинг файлов — это хорошо известный путь для доступа к файлам. Он объяснен во многих статьях, поэтому я не буду тратить время на подробности. Идея в том, что мы можем промэппировать файл в память. Тогда с каждым изменением в памяти, будет меняться и файл. Применительно к IPC мы можем промэппировать файл в нескольких процессах и взаимодействовать через него.

     функции

    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, я думаю, что лучше всего будет сделать это через атомы, хотя есть и другие пути…).

    создание анонимного (безымянного) пайпа

    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.

Вот и все об анонимных пайпах.

Мейлслоты

Мейлслоты — это еще один простой способ взаимодействия между процессами. Его суть заключается в том, что один процесс (сервер) может коннектиться к мейлслоту и посылать эти сообщения. Мейлслоты используют датаграмы для коммуникации, а именованные слоты — нет (для удаленного взаимодействия). Уффф…

  push защита
  push время(ms) ожидания
  push максимальный размер сообщения
  push имя мейлслота

  call CreateMailslot(A/W)

  Возвращает имя мейлслота

  имя мейлслота - имя, которое имеет следующую форму:
                  db "\\.\mailslot\[path]name", 0
                - имя должно быть уникальным, и в нем могут быть
                  псевдодиректории ([path]), и (как обычно) оно не
                  чувствительно к регистру

  максимальный размер сообщения - мы можем указать максимальную длину
                                  записанного сообщения в мейлслот, как бы то
                                  ни было, если это поле равно NULL, сообщение
                                  может быть любого размера

  время ожидания - это время, которое ReadFile будет ждать, если сообщение
                   еще не находится в мейлслоте. Есть несколько специальных
                   значений:

                  0  - если нет сообщения в мейлслоте, функция не будет
                       работать :)
                  -1 - функция будет ждать, пока в мейлслоте не появится
                       сообщение - (MAILSLOT_WAIT_FOREVER)

Ладно, мы создаем мейлслот и у нас есть его хэндл. Мы можем закрыть его с помощью CloseHandle…

Теперь мейлслот создан и к нему можено получить доступ по имени. Клиенты могут подсоединяться с помощью функции CreateFile(A/W), используя имя мейлслота в качестве имени файла. После подсоединения клиент получает хэндл мейлслота и может записывать сообщения в него. Это делается с помощью функции WriteFile. Сервер считывает сообщения с помощью ReadFile. Как CreateFile, и ReadFile уже затрагивались в этом тексте, поэтому я не буду тратить время на повторное объяснения. как бы то ни было, есть еще несколько функций для работы с мейлслотами.

  функции сервера мейлслота:

  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

Вот и все.

[C] mort[MATRiX], пер. Aquila

 

Источник WASM.RU /27.06.2002/

Поделиться в соц сетях

Оставить комментарий

  Подписаться  
Уведомление о

Есть идеи, замечания, предложения? Воспользуйтесь формой Обратная связь или отправьте сообщение по адресу replay@sciencestory.ru
© 2017 Истории науки. Информация на сайте опубликована в ознакомительных целях может иметь ограничение 18+