---( interprocess communication by mort[MATRiX] )--------------------------- This article is for educational purpose only and I AM NOT responsibille for anything nor my english, nor myself,...anyway, enjoy it... .xxx ---------------------------------------------------------------------------- Interprocess communication (IPC) is the way processes can communicate with each other. In window's enviroment each process has its own separate address space, so no process can directly see the memory of other process. Win32 API provides some features to IPC. IPC could be very helpfull for virii (eg. the one i like the most used in Vulcano...hi Benny :)), so i'll describe some ways despite im not sure all could be effectivelly used in virii, anyway as i said somewhere, im lamer. IPC ways described in this article: - atoms - file mapping - anonymous pipes - mailslots I wrote two virusses to describe some IPC nore detailed. It's ls and aiD virus. There's describtion of behaviour u can check at both virii. .------------. | here we go | '-----.------' . | |atoms | -'------------------------'------------------------------------------------- Atoms are very simple and <> ways of IPC. The point is the process can place string into atom's table and this string is vissible for other processes. When process place the string into atom's table it'll get back the 32bit value(atom), and this value is used to access the string. System doesn't difer the string by case, in other words it's not case sensitive. There're two types of atom tables - global (GAT) and the local one (LAT). .---<<<- |GAT is set up for 37 entries and is vissible for all process in system. | | functions | '----(adding string to GAT)------------------------------------------ | push _address_of_string - NULL terminated string max size is 255B call GlobalAddAtom(A/W) . | returns - eax - atom | '----(delete atom from GAT)------------------------------------------ | push _atom call GlobalDeleteAtom(A/W) . | returns - eax - 0 if succed | '----(find atom)----------------------------------------------------- | push _address_of_string - NULL terminated string max-size is 256B call GlobalFindAtom(A/W) . | returns - eax - 0 if fail otherwise atom | '----(get atom string via atom)--------------------------------------. | | push _size_of_buffer - buffer length |\ push _address_of_buffer - buffer | | push _atom - atom :) |\ call GlobalGetAtomName(A/W) | | | returs - if succed the buffer will be filled by atom string | | .------------------------------------------------------------------------' |LAT uses the same calls for atoms work, but without the 'Global' word. |Anyway LAT is vissible for the current process and no for others. The |values of entries is set by default up to 37, but it can be changed by 'the InitAtomTable API. The maximum it could be set is 3FFF. Huuuuum, this number is in MSDN but when i tried to get error-value of this call by the .to high value of entries i didnt find it. Functions seems work with any |numbert of entries,... | '----(inicialize LAT)-------------. | | push _LAT_size | call InitAtomTable | . | | returns - ... | '--------------------------------'|'--------------------------------------' .------'-----------. | All for atoms... | '------------.-----' . | |file mapping | -'---------------------------------------'---------------------------------- I think file mapping is well known way of accessing files. It's described in many articles so i wont waste the time with details. The point is we can map file into memory. Then with every change in memory we change the file. Due to IPC we can map the same file in several processes and communicate via it. functions ->>>-------------------------------------------------------. push template file handle ;default - 0 \ push flags and attributes ;default - 0 ----. push create/open flags \ push security attributes ;default - 0 | push share flags ;default - 1 | push object access | push file name .----------------' | call CreateFile(A/W) | \\\\\\\\\\\\\\\\\\\\ | >>>>>--------------------> returns - file handle | | create/open flags | CREATE_NEW equ 1 | CREATE_ALWAYS equ 2 \ OPEN_EXISTING equ 3 | OPEN_ALWAYS equ 4 | TRUNCATE_EXISTING equ 5 | | object access | GENERIC_READ equ 080000000h | GENERIC_WRITE equ 040000000h | GENERIC_EXECUTE equ 020000000h | GENERIC_ALL equ 010000000h / | The right mapping starts here,...object to map needn't to be opened by CreateFile(A/W) API. If we use (-1) value in next API file handle parameter, we'll map part of shared-able memory with out conecting to file,...ideal for IPC. . | .---------------------------------------------|---<><< |push name of file-mapping object ;default - 0 |push low-order 32 bits of object size ;default - size |push high-order 32 bits of object size ;default - 0 /|push protection ;default - 4 |u|push security attributes ;default - 0 |n|push file handle ;default - HNDL from CreateFile |c| |l|call CreateFileMapping(A/W) |e|\\\\\\\\\\\\\\\\\\\\\\\\\\\ | | returns - object handle |f| |u|this function create a map object and returns handle of it |c|>protection |k| PAGE_READONLY equ 2 |e| PAGE_READWRITE equ 4 |r| PAGE_WRITECOPY equ 8 \| |>security attributes - pointer can be set to NULL, anyway the struc: | SECURITY_ATTRIBUTES struc | _saSize dd ? ;struc size | _lpSecurityDescriptor dd ? ;pointer to sec. descriptor | _bInheritHandle dd ? ;bool val. True for inherit | SECURITY_ATTRIBUTES ends / | | .--------------------------------------------------------------<><< | |push name of mapping object |/|push inherit flag |w|push access mode |h| |o|call OpenFileMapping(A/W) |o|\\\\\\\\\\\\\\\\\\\\\\\\\ |o| return - object handle |o| |p|>access mode |s| FILE_MAP_WRITE equ 2 ;R/W access <--. |/| FILE_MAP_READ equ 4 ;R access <---| | | | | '--------. |\ | | |s| '--->-.-<--' |a| | now we have map object |m| .---' |e| |push bytes to map ;default - size |/ |push file offset low ;default - 0 | /|push file offset high ;default - 0 | |l|push access mode ;----------------------------------' |a|push object handle ;default - HNDL from Create(Open)FileMapping |m| |e|call MapViewOfFile \|\\\\\\\\\\\\\\\\\\ | return - map address | '-->--. | now we have file mapped in memory | we can write part fo mapped file to the disk using: | | push number of bytes to write | push start address | | call FlushViewOfFile | \\\\\\\\\\\\\\\\\\\\ .--<--' |push map address /|call UnmapViewOfFile ;unmaps the view of file |e|\\\\\\\\\\\\\\\\\\\\\ |n| |d|push object handle ;closing mapped object \|call CloseHandle |\\\\\\\\\\\\\\\\ | |push file handle ;closing file handle |call CloseHandle |\\\\\\\\\\\\\\\\ '-----------------------------------------------. | .---------------'---------. | All for file mapping,...| '---.---------------------' . | |anonymous pipes | -'-------------------------------------'------------------------------------ |There two types of pipes. The anonymous and the named ones. Named pipes |are a 'little' bit dificult to use then anonymous so i'll discuss them 'in some other article. Well, anonymous pipes are one-way, unnamed pipes. They can't be used for remote communication (despite the named pipes can). The point is that server create a pipe and receive read and write handle of pipe. Then it can send one of this handles to process to communicate to (we must send .it via some other IPC method, i think the best will be Atoms IPC, anyway |there are next ways...). \ |creating anonymous (unnamed) pipe / | push pipe size | push protection | push pointer to write pipe handle push pointer to read pipe handle 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 | | When pipe is created we have access to both ends. To read and write | one. Server is the one process which create pipe. After creating pipe, | server have to send one handle to client process. \ |read from pipe - this reading is synchronous one -> the func. wont end | until the read is done / | push pointer to struc for data | push pointer to bytes read number | push number of read bytes push pointer to read buffer push handle of read pipe call ReadFile \\\\\\\\\\\\\ >pointer to struc for data - this struc is use for asynchronous input | and output; so set to NULL | >pointer to bytes read number - pointer to dword which will contain | number of read bytes \ |write to pipe - this reading is synchronous one -> the func. wont end | until the read is done / | push pointer to struc for data | push pointer to bytes write number | push number of write bytes | push pointer to write buffer | push handle of write pipe | | call WriteFile | \\\\\\\\\\\\\\ | | Anonymous pipes lives until the read and write handle is open. We | can close it by using CloseHandle function. '-----------------------------------.-------------------------------------- | .-'--------------------------. | All for anonymous pipes,...| '---.------------------------' | . | |mailslots | -'-------------------------------------'------------------------------------ | Mailslots are next simple way of IPC between processes. The point is | one process(server) create a mailslot, and this one process has right | to read messages from it. Other processes (clients) can connect to | mailslot and send there message. The different from pipes is obvious, | anyway, there's one more. Maislots use datagrams for communication and | named pipes not(for remote communication). Uhghhh,... '-------------->>>-------------------------. | push protection | push time(ms) before read time-out | push maximum message size | push mailslot name | | call CreateMailslot(A/W) | | returns : mailslot handle | .--------<<<-------------------------------' |mailslot name - name has following form: | db "\\.\mailslot\[path]name",0 | - name must be unique, and there can be some | pseudodirectories (the [path]), and as ussual in this | article, it's not case-sensitive | |maximum message size - we can specify the maximum lenght of written | message to mailslot, anyway if this field is NULL | the message can be of any size | |time(ms) before read time-out - this is time, that will be the ReadFile | function wait if there's no message in mailslot yet. | There some special numbers: | | 0 - if no message in mailslot, func. wont wait :) | -1 - this spec. will wait until there'll be message | in mailslot -> (MAILSLOT_WAIT_FOREVER) ' Well, we created a mailslot and have handle of it. We can close it using CloseHandle,... .Now, mailslot is created and accessable by name. The clients can connect |to it via the CreateFile(A/W) API, using the mailslot name in filename |fields. After connecting, client receive handle to mailslot and is able |to write messages to mailslot. This is done by WriteFile API. Server |is reading from mailslot using the ReadFile API. All, CreateFile, |ReadFile and WriteFile, are explained somewhere here in text, so i wont |waste the space to explained it oncemore. Anyway, there're some other |functions for mailslots. Here we go,... ' mailslot server funcs: . |push pointer of read time-out |push pointer of number of messages |push pointer of size of next message |push pointer of maximum message size |push mailslot handle ;returned by the CreateMailslot(A/W) API | |call GetMailslotInfo ' returns - TRUE(1) if succeds .pointer of size of next message - this parameter could be NULL, anyway if | not, we'll received size of next message in mailslot. We can | received MAILSLOT_NO_MESSAGE(-1) -> no next messsage in mailslot. | |pointer of number of messages - this parameter could be NULL, anyway if | not, we'll receive total number of messages waiting to be read. | | 'To set mailslot time-out for read operation we can use: . |push read time-out |push mailslot handle | |call SetMailslotInfo ' .When we have mailslot handle we can use standart functions to get handle |informations about it. We can use: | | DuplicateHandle | GetFileTime | SetFileTime | GetHandleInformation | SetHandleInformation | -'-------------------------------------------------------------.------------ | | ' .-----------'----. | Thats all,... | '----------------' greet(s): Benny,...IPC forever . |\ | |.--. -|-. | || |.--|| | | \ m o r|t . .-'-----'\._''--'-. '--[MATRiX]-------' [mort@matrixvx.org] \\\\\\\\\\\\\\\\\\