The Assembly Programming Master Book

The CreateFile function is universal. This is because of the concept of a device adopted in the Windows operating system. In one of examples provided in Chapter 11 (see Listing 11.4), I used the CreateFile function for console output. Now, consider another example that demonstrates the principles of working with mailslots.

Mailslot

This device allows information to be exchanged between processes within the framework of a local area network, not only within a single computer. The only problem is that the mailslot volume doesn't exceed 64 KB. Nevertheless, after considering the mechanism of transmitting data using mailslots, you'll understand that the mailslot size isn't important because under the condition of bidirectional transmission, it is possible to transfer information in sequential blocks. The main idea of the mailslot mechanism is as follows :

Thus, after learning the main theory behind mailslots, it is possible to implement practical examples. Listings 13.1 and 13.2 provide the source code of the server software that creates a mailslot and reads messages from there, and the client that sends messages to that mailslot. Note that I have used the results of previous chapters and have written programs that can be translated using both MASM32 and TASM32. Note that starting from this chapter, most programs will be presented in this universal form.

Listing 13.1: The server software (SERVER.ASM) creates a mailslot and waits for messages

; Server that creates a mailslot and reads from there .586P ; Flat memory model .MODEL FLAT, stdcall ; Constants STD_OUTPUT_HANDLE equ -11 MAILSLOT_WAIT_FOREVER equ -1 ; Prototypes of external procedures IFDEF MASM EXTERN ReadFile@20:NEAR EXTERN CloseHandle@4:NEAR EXTERN lstrlenA@4:NEAR EXTERN WriteConsoleA@20:NEAR EXTERN CreateMailslotA@16:NEAR EXTERN ExitProcess@4:NEAR EXTERN GetStdHandle@4:NEAR ELSE EXTERN ReadFile:NEAR EXTERN CloseHandlerNEAR EXTERN lstrlenA:NEAR EXTERN WriteConsoleA:NEAR EXTERN CreateMailslotA:NEAR EXTERN GetStdHandle:NEAR EXTERN ExitProcess:NEAR WriteConsoleA@20 = WriteConsoleA ReadFile@20 = ReadFile lstrlenA@4 = lstrlenA CreateMailslotA@16 = CreateMailslotA ExitProcess@4 = ExitProcess GetStdHandle@4 = GetStdHandle CloseHandle@4 = CloseHandle ENDIF ; INCLUDELIB directives for the linker IFDEF MASM includelib c:\masm32\lib\user32.lib includelib c:\masm32\lib\kernel32.lib ELSE includelib c:\tasm32\lib\import32.lib ENDIF ;----------------------------------------------- ; Data segment _DATA SEGMENT LENS DD ? ; String length will be placed here PATHM DB "\.\mailslot\maill", 0 BUFER DB 1000 DUP.(0) H DD ? N DD ? HANDL DD ? ERRS DB 'Error!', 0 _DATA ENDS ; Code segment _TEXT SEGMENT START: PUSH STD_OUTPUT_HANDLE CALL GetStdHandle@4 MOV HANDL, EAX ; Create a mailslot PUSH 0 PUSH MAILSLOT_WAIT_FOREVER PUSH 0 PUSH OFFSET PATHM CALL CreateMailslotA@16 CMP EAX, -1 JNZ CON LEA EAX, ERRS MOV EDI, 1 CALL WRITE JMP EXI CON: MOV H, EAX ; Read from the mailslot PUSH 0 PUSH OFFSET N PUSH 1000 PUSH OFFSET BUFER PUSH H CALL ReadFile@20 ; Output the contents LEA EAX, BUFER MOV EDI, 1 CALL WRITE ; Close the mailslot PUSH H CALL CloseHandle@4 ; Exit the program EXI: PUSH 0 CALL ExitProcess@4 ; Display the string (terminated with line feed) ; EAX --- To the start of the string ; EDI --- With or without the line feed WRITE PROC ; Get the parameter length PUSH EAX PUSH EAX CALL lstrlenA@4 MOV ESI, EAX POP EBX CMP EDI, 1 JNE NO_ENT ; Trailing line feed MOV BYTE PTR [EBX+ESI], 13 MOV BYTE PTR [EBX+ESI+1], 10 MOV BYTE PTR [EBX+ESI+2], 0 ADD EAX, 2 NO_ENT: ; String output PUSH 0 PUSH OFFSET LENS PUSH EAX PUSH EBX PUSH HANDL CALL WriteConsoleA@20 RET WRITE ENDP _TEXT ENDS END START

 

The SERVER.ASM program creates a mailslot and then calls the ReadFile function. Note when creating the mailslot, the MAILSLOT_WAIT_FOREVER Parameter was set. This means that the ReadFile function will wait infinitely for the data to arrive at the mailslot. The function returns control only after the arrival of the data. The mailslot contents are then displayed on the console.

To translate this program using MASM32, issue the following:

ML /c /coff /DMASM server.ASM LINK /SUBSYSTEM:CONSOLE server.OBJ

To translate the same program using TASM32, issue the following:

TASM32 /ml server.ASM TLINK32 -ap server.OBJ

Listing 13.2: The client program (CLIENT.ASM) opens the mailslot and writes information there

;Client that opens the mailslot and writes information into it .586P ; Flat memory model .MODEL FLAT, stdcall ; Constants STD_OUTPUT_HANDLE equ -11 GENERIC_WRITE equ 40000000h FILE_SHARE_READ equ 1h OPEN_EXISTING equ 3 ; Prototypes of external procedures IFDEF MASM EXTERN WriteFile@20:NEAR EXTERN CreateFileA@28:NEAR EXTERN ExitProcess@4: NEAR EXTERN CloseHandle@4:NEAR ELSE EXTERN WriteFile:NEAR EXTERN CreateFileA:NEAR EXTERN ExitProcess:NEAR EXTERN CloseHandle:NEAR WriteFile@20 = WriteFile CreateFileA@28 = CreateFileA ExitProcess@4 = ExitProcess CloseHandle@4 = CloseHandle ENDIF ; INCLUDELIB directives for the linker IFDEF MASM includelib c:\masm32\lib\user32.lib includelib c:\masm32\lib\kernel32.lib ELSE includelib c:\tasm32\lib\import32.lib ENDIF ;------------------------------------------------ ; Data segment _DATA SEGMENT PATHM DB "\.\mailslot\mail1", 0 H DD ? MES DB 'Hello! Server!', 0 N DD ? _DATA ENDS ; Code segment _TEXT SEGMENT START: ; Open the mailslot PUSH 0 ; Must be zero PUSH 0 ; File attribute doesn't matter PUSH OPEN_EXISTING ; How to open PUSH 0 ; Pointer to the security attribute PUSH FILE SHARE_READ ; Shared access mode PUSH GENERIC_WRITE ; Access type PUSH OFFSET PATHM ; Mailslot name CALL CreateFileA@28 MOV H, EAX ; Write data to the mailslot PUSH 0 PUSH OFFSET N PUSH 16 ; Message length PUSH OFFSET MES PUSH H CALL WriteFile@20 ; Close the mailslot PUSH H CALL CloseHandle@4 ; Exit EXI: PUSH 0 CALL ExitProcess@4 _TEXT ENDS END START

 

The client program opens the mailslot using the CreateFile function. Having received the descriptor, it can send the data to the mailslot. The program sends a zero-terminated string.

To translate this program using MASM32, issue the following commands:

ML /c /coff /DMASM client.ASM LINK /SUBSYSTEM:CONSOLE client.OBJ

To translate it using TASM32, use the following:

TASM32 /ml client.ASM TLINK32 -ap client.OBJ

The programs in Listings 13.1 and 13.2 are simple. The server program carries out a single data-read operation from the mailslot. There are no difficulties in using the mailslot for permanent data exchange. For this purpose, it is necessary to remember the following:

Principally, the client also can create a mailslot, in which there will be bidirectional data exchange between the client and the server.

Pipes

Pipes provide an efficient method of bidirectional data exchange between processes. There are two types of pipes: anonymous and named. Anonymous pipes will be covered in Chapter 18 (see Listing 18.3). This type of pipes is convenient for use within the framework of a single application for data exchange between two processes. Named pipes are more powerful. They allow data to be exchanged with applications located on different computers within a local area network. In particular, the Microsoft SQL Server uses named pipes as one of the possible mechanisms of information exchange with clients .

Naturally, before using a named pipe, it is necessary to create it. For this purpose, the CreateNamePipe function is used. The process that creates the named pipe is called the server. When creating a named pipe, it is necessary to set several parameters that influence the way, in which this object will operate. The list of these parameters includes the parameter that defines the mode of operation through the pipe. Three modes of operation can be set:

Generally, the pipe name is represented by the following string: \\.\pipe\pipename . Here, pipename is the name of the pipe. As with mailslots, for named pipes it is possible

to set the mode for infinite waiting. In this case, the ReadFile and writeFile functions will complete execution only when data transmission is completed. Having created the pipe, use the ConnectNamedPipe function to allow client processes to connect to the pipein other words, to switch the server process to the waiting state.

The client process, as with mailslots, can connect to the pipe using the all-embracing CreateFile function. To open the pipe, it must use the same structure of the pipe name: \\.\pipe \ pipename . Thus, the client process must know the name of the pipe, to which it connects. If this attempt has failed, use the GetLastError function to discover the cause of the error. If the function returns the ERROR_PIPE_BUSY = 231 error code, [i] this means that the pipe is busy serving another process and it is necessary to wait until that process releases the pipe. To set the waiting mode, use the WaitNamedPipe function.

Disk Drives

The CreateFile function can also open disk devices. To open the first disk of your computer, it is necessary to use the \\.\PhysicalDrive0 name; to open the C: partition, use the \\. \C : name. The most interesting fact here is that after opening the device, you can use the ReadFile and WriteFile functions. [ii] Additionally, you have the DeviceIoControl function at your disposal. The latter function can carry out various operations, including getting statistics about the disk and even formatting the disk. I won't concentrate attention on this function but, instead, will provide an example illustrating the reading of the Master Boot Record (MBR) of the disk. When the device is opened, the MBR will be located at the starting position of the hypothetical file (Listing 13.3).

Listing 13.3: Reading the disk master boot record and partition table

.586P ; Flat memory model .MODEL FLAT, stdcall ; Constants STD_OUTPUT_HANDLE equ -11 GENERIC_READ equ 80000000h FILE_SHARE_WRITE equ 2h OPEN_EXISTING equ 3 ; Prototypes of external procedures IFDEF MASM EXTERN GetLastError@0:NEAR EXTERN wsprint fA:NEAR EXTERN lstrlenA@4:NEAR EXTERN ReadFile@20:NEAR EXTERN CreateFileA@28:NEAR EXTERN ExitProcess@4:NEAR EXTERN CloseHandle@4:NEAR EXTERN WriteConsoleA@20:NEAR EXTERN GetStdHandle@4:NEAR ELSE EXTERN GetLastError:NEAR EXTERN _wsprintfA:NEAR EXTERN GetStdHandle:NEAR EXTERN lstrlenA:NEAR EXTERN ReadFile:NEAR EXTERN CreateFileA:NEAR EXTERN ExitProcess:NEAR EXTERN CloseHandle:NEAR EXTERN WriteConsoleA:NEAR GetLastError@0 = GetLastError wsprintfA = 0 wsprintfA GetStdHandle@4'= GetStdHandle WriteConsoleA@20 = WriteConsoleA lstrlenA@4 = lstrlenA ReadFile@20 = ReadFile CreateFileA@28 = CreateFileA ExitProcess@4 = ExitProcess CloseHandle@4 = CloseHandle ENDIF ; INCLUDELIB directives for the linker IFDEF MASM includelib c:\masm32\lib\user32.lib includelib c:\masm32\lib\kernel32.lib ELSE includelib c:\tasm32\lib\import32.lib ENDIF ;------------------------------------------------ ; Data segment _DATA SEGMENT H DD 0 NN DD 0 ; Device name (first hard disk) PATHM DB "\.\PhysicalDrive0", 0 ALIGN 4 ; Alignment by the double-word boundary BUF DB 512 DUP(0) BUF1 DB 24 DUP(0) HANDL DD 0 LENS DD 0 ERRS DB "Error %u", 0 SINGL DB "Signature %x", 0 _DATA ENDS ; Code segment _TEXT SEGMENT START: PUSH STD_OUTPUT_HANDLE CALL GetStdHandle@4 MOV HANDL, EAX ; Open the physical disk PUSH 0 ; Must be zero PUSH 0 ; File attribute doesn't matter PUSH OPEN_EXISTING ; How to open PUSH 0 ; Pointer to the security attribute = NULL PUSH FILE_SHARE_WRITE ; Shared access mode PUSH GENERIC_READ ; Access type - Read PUSH OFFSET PATHM ; Device name CALL CreateFileA@28 CMP EAX, -1 JNZ NO_ERR ER: ; Get error number CALL GetLastError@0 ; MOVZX EAX, AX PUSH EAX PUSH OFFSET ERRS PUSH OFFSET BUF1 CALL wsprintfA ; Output error number LEA EAX, BUF1 MOV EDI, 1 CALL WRITE JMP EXI NO_ERR: MOV H, EAX ; Reading the partition table PUSH 0 PUSH OFFSET NN PUSH 512 PUSH OFFSET BUF PUSH H CALL ReadFile@20 CMP EAX, 0 JZ ER ; Display the partition table signature ; Must be aa55 PUSH DWORD PTR BUF+510 PUSH OFFSET SINGL PUSH OFFSET BUF1 CALL wsprintfA LEA EAX, BUF1 MOV EDI, 1 CALL WRITE ; Close the device PUSH H CALL CloseHandle@4 ; Exit EXI: PUSH 0 CALL ExitProcess@4 ; Display the string terminated by line feed ; EAX --- To the start of the string ; EDI --- With or without the line feed WRITE PROC ; Get the parameter length PUSH EAX PUSH EAX CALL lstrlenA@4 MOV ESI, EAX POP EBX CMP EDI, 1 JNE NO_ENT ; The string is terminated with the line feed MOV BYTE PTR [EBX+ESI], 13 MOV BYTE PTR [EBX+ESI+1], 10 MOV BYTE PTR [EBX+ESI+2], 0 ADD EAX, 2 NO_ENT: ; String output PUSH 0 PUSH OFFSET LENS PUSH EAX PUSH EBX PUSH HANDL CALL WriteConsoleA@20 RET WRITE ENDP _TEXT ENDS END START

 

Now, it is necessary to provide some comments about Listing 13.3.

Note that the starting point of the buffer, into which the sector will be read, must be aligned by the 4-byte boundary. To ensure this, the ALIGN directive is used. Such alignment is not needed for reading from a normal file except when you disable data caching (see the description of the CreateFile function in the opening section of this chapter).

In this program, I have used the GetLastError function for the first time. If an error occurs when you open or read from the device, the program will output the error code to the console. To determine the cause of the error, consult the documentation. You can also try to change the parameters of the CreateFile and ReadFile functions and view the error codes that will result. In fact, such experimenting is instructive.

To translate this program, issue the following commands using MASM32:

ML /c /coff /DMASM prog.ASM LINK /SUBSYSTEM:CONSOLE prog.OBJ

[i] Remember that to discover the cause of the error by its number, it is convenient to use the ERRLOOK.EXE program supplied as part of Microsoft Visual Studio.NET.

[ii] Do not write anything in such a way without carefully studying the disk structure before proceeding.

Категории