Battle DeviceIocontrol 6: Accessing physical ports

zhaozj2021-02-16  47

Q How to read CMOS data in NT / 2000 / XP?

Q How to control the speaker voice in NT / 2000 / XP?

Q How to directly access the physical port in NT / 2000 / XP?

A seems a small problem, how many good hamenes!

NT / 2000 / XP considered security, reliability, stability, application and operating system are separated, operating system code runs in core state, access system data and hardware, can perform privileged instructions; application run In a user state, the permissions that can be used and access system data are strictly limited. When the user program calls the system service, the processor captures the call and then switches the calling thread to the core state. When the system service is complete, the operating system switches the thread description table back to the user state, and the caller continues to run.

Want to implement I / O reading and writing in a user state application, directly access hardware, you can implement CreateFile, CloseHandle, DeviceIoControl, ReadFile, Writefile, etc. by writing drivers. Starting from Windows 2000, the concept of introducing the WDM core state driver.

Below is a very simple driver written by I, byte-type port I / O can be implemented.

#include

#include "myport.h"

// Device Type Definition

// 0-32767 is occupied by Microsoft, user-defined 32768-65535

#define file_device_myport 0x0000F000

// I / O control code definition

// 0-2047 is occupied by Microsoft, user-defined available 2048-4095

#define myport_ioctl_base 0xF00

#define ioctl_myport_read_byte ctl_code (file_device_myport, myport_iocTl_base, method_buffered, file_any_access)

#DEFINE ioctl_myport_write_byte ctl_code (file_device_myport, myport_ioc_base 1, method_buffered, file_Ane_access)

// IOPM is a bit shielding matrix of 65536 ports, including 8192 bytes (8192 x 8 = 65536)

// 0 bit: Allow the application to access the corresponding port

// 1 bit: Prohibition of application access correspondence port

#define ipm_size 8192

Typedef uchar ipm [ipm_size];

IOPM * piopm = null;

// Device name (requires Unicode)

Const Wchar NameBuffer [] = l "// device // myport";

Const Wchar DosnameBuffer [] = l "// dosdevices // myport";

// This is two service routines that have no documentation in ntoskrnl.exe

// There is no ready-made header file, our own statement

Void Ke386SetioAccessMap (int, IOPM *);

Void Ke386ioseetAccessProcess (peprocess, int);

// Function prototype pre-explanation

NTSTATUS MyPortdispatch (in PDevice_Object DeviceObject, in PIRP IRP);

Void Myportunload (in PDRIVER_Object DriverObject);

// Driver the program entry, is automatically called by the system, just like Win32 application WinmainntStatus Driverentry (in Punkode_String RegistryPath)

{

PDEvice_Object DeviceObject;

NTSTATUS STATUS;

Unicode_string uninamestring, unidosstring;

/ / Assign memory for IOPM

Piopm = mmallocateenoncachedmemory (sizeof (IOPM));

IF (piopm == 0)

{

Return status_insuffect_resources;

}

// IOPM is all initialized to 0 (allowing all ports to be accessed)

RTLZEROMEMORY (PIOPM, SIZEOF (IOPM));

// Load IOPM to the current process

Ke386ioseetaccessProcess (psgetcurrentprocess (), 1);

Ke386SetioAccessmap (1, piopm);

/ / Specify the drive name

RTLinitunicodeString (& uninameString, NameBuffer);

RTLinitunicodeString (& Unidosstring, DosnameBuffer);

// Create a device

Status = IocreateDevice (DriverObject, 0,

& uninameString,

FILE_DEVICE_MYPORT,

0, False, & DeviceObject);

IF (! NT_Success (status))

{

Return status;

}

// Create a symbolic connection required for WIN32 application

Status = IocreateSymbolicLink (& Unidosstring, & UninameString);

IF (! NT_Success (status))

{

Return status;

}

/ / Specify the module entry (function pointer) related to the operation

/ / Take the following two modules: MyPortdispatch and Myportunload

DriverObject-> majorfunction [IRP_MJ_CREATE] =

DriverObject-> majorfunction [IRP_MJ_CLOSE] =

DriverObject-> majorfunction [IRP_MJ_DEVICE_CONTROL] = myportdispatch;

DriverObject-> driverunload = myportunload;

Return status_success;

}

// IRP processing module

NTSTATUS MyPortdispatch (in PDevice_Object DeviceObject, in PIRP IRP)

{

PIO_STACK_LOCATION IRPSTACK;

Ulong dwinputbufferLength;

Ulong dwoutputbufferLength;

Ulong dwiocontrolcode;

Pulong pviobuffer;

NTSTATUS NTSTATUS;

// Fill a few default values

IRP-> iostatus.status = status_success; // Return Status

IRP-> iostatus.information = 0; // Output length IrPstack = IOGETCURRENTIRPSTACKLOCATION (IRP);

// Get The Pointer to the Input / Output Buffer And It's Length

/ / Enter the output shared buffer

// Because we specified Method_Buffered in IOCTL,

PVIOBUFFER = IRP-> Associatedirp.systembuffer;

Switch (Irpstack-> Majorfunction)

{

Case IRP_MJ_CREATE: / / Createfile in Win32 Application

Break;

Case IRP_MJ_CLOSE: // corresponds to a CloseHandle in the Win32 application

Break;

Case IRP_MJ_DEVICE_CONTROL: / / corresponds to DeviceIocontrol in Win32 application

Dwiocontrolcode = Irpstack-> Parameters.Deviceiocontrol.iocontrolcode;

Switch (dwiocontrolcode)

{

// We agree, two DWORDs in the buffer, the first DWORD is the port, the second DWORD is data

// General practice is specifically defined a structure, which is simplified here.

Case ioctl_myport_read_byte: // Read byte from port

PVIOBUFFER [1] = _inp (pviobuffer [0]);

IRP-> iostatus.information = 8; // output length is 8

Break;

Case ioctl_myport_write_byte: // Written to the port

_outp (Pviobuffer [0], PVIOBUFFER [1]);

Break;

Default: // Do not support IOCTL

IRP-> iostatus.status = status_INVALID_PARAMETER;

}

}

NTSTATUS = IRP-> iostatus.status;

IOCOMPLETEREQUEST (IRP, IO_NO_INCREMENT);

Return NTSTATUS;

}

// Remove the drive

Void myportunload (in PDRIVER_Object DriverObject)

{

Unicode_string unidosstring;

IF (piopm)

{

/ / Release the space occupied by IOPM

MMFreenonCachedMemory (Piopm, Sizeof (IOPM));

}

RTLinitunicodeString (& Unidosstring, DosnameBuffer);

// Remove symbol connections and devices

IodeleteSymbolicLink (& unidosstring);

IodeleteDevice (driverObject-> deviceObject);

}

The source code that implements the dynamic load of the device driver is given. The advantage of dynamic loading is that you don't have to do anything to add new hardware, or you don't have to edit the registry, you don't have to restart your computer.

/ / Install the driver and start the service

// LPSZDRIVERPATH: Driver path

// LPSZSERVICENAME: Service Name

Bool StartDriver (lpctstr lpszdriverpath, lpctstr lpszserviceename)

{

SC_HANDLE HSCMANAGER; / / Service Control Manager Handle SC_HANDLE HSERVICE; / / Service Handle

DWORD DWLASTERROR; / / error code

BOOL BRESULT = false; // Return value

// Open Service Control Manager

Hscmanager = OpenSCManager (NULL, NULL, SC_MANAGER_ALL_ACCESS);

IF (HScManager)

{

// Create a service

Hservice = CREATSERVICE (HScManager,

LPSZServiceName,

LPSZServiceName,

SERVICE_ALL_ACCESS,

Service_kernel_driver,

Service_demand_start,

Service_ERROR_NORMAL,

LPSZDRIVERPATH,

NULL,

NULL,

NULL,

NULL,

NULL);

IF (hservice == null)

{

IF (:: getLastError () == error_service_exists)

{

HService = :: OpenService (HScManager, LpszServiceName, Service_all_Access);

}

}

IF (HService)

{

// Start service

BRESULT = StartService (Hservice, 0, NULL);

// Turn off the service handle

ClosESERVICEHANDE (HSERVICE);

}

// Turn off the service control manager handle

CloseServiceHandle (HSCManager);

}

Return BRESULT;

}

/ / Stop the service and remove the drive

// LPSZSERVICENAME: Service Name

Bool Stopdriver (LPCTSTR LPSZSERVICENAME)

{

SC_HANDLE HSCMANAGER; / / Service Control Manager Handle

SC_HANDLE HSERVICE; / / Service Handle

BOOL BRESULT; / / Return Value

Service_status serviceArstatus;

BRESULT = FALSE;

// Open Service Control Manager

Hscmanager = OpenSCManager (NULL, NULL, SC_MANAGER_ALL_ACCESS);

IF (HScManager)

{

// Open service

HService = OpenService (HscManager, LPSZSERVICENAME, Service_all_Access);

IF (HService)

{

// Out of service

BRESULT = ControlService (hservice, service_control_stop, & service);

// Delete service

BRESULT = BRESULT && deleteService (Hservice);

// Turn off the service handle

ClosESERVICEHANDE (HSERVICE);

}

// Turn off the service control manager handle

CloseServiceHandle (HSCManager);

}

Return BRESULT;

}

The interface of the application implementation port I / O is as follows:

// Global equipment handle

Handle hmyport;

// Open the device

// LPSZDEVICEPATH: Path of the device

Handle OpenDevice (LPCTSTR LPSZDEVICEPATH)

{

Handle HDevice;

// Open the device

HDevice = :: createfile (lpszdevicePath, // device path

Generic_read | generic_write, // Read and write

File_share_read | file_share_write, // shared method

NULL, / / ​​Default security descriptor

Open_existing, // creation method

0, // Do not set file properties

NULL); // Do not need to refer to the template file

Return HDevice;

}

// Open port driver

Bool OpenMyport ()

{

Bool Bresult;

/ / The device is called "MyPort", the driver is located in the "System32 / Drivers" directory of Windows.

BRESULT = StartDriver ("System32 // Drivers // Myport.sys", "MyPort");

/ / The device path is "//./myport"

IF (BRESULT)

{

Hmyport = OpenDevice (".// myport");

}

Return (BRESULT && (Hmyport! = INVALID_HANDLE_VALUE));

}

// Turn off the port driver

Bool closemyport ()

{

Return (CloseHandle (HMYPORT) & STOPDRIVER ("MyPort");

}

/ / Read one byte from the specified port

// port: port

Byte ReadportByte (Word Port)

{

DWORD BUF [2]; // Input Output Buffer

DWORD dwoutBytes; // ioctl output data length

BUF [0] = port; // The first DWORD is the port

// BUF [1] = 0; // Second DWORD is data

// read port port with ioctl_myport_read_byte

:: Deviceiocontrol (Hmyport, // Equipment handle

IOCTL_MYPORT_READ_BYTE, // Take the device properties information

BUF, SIZEOF (BUF), // Enter data buffer

BUF, SIZEOF (BUF), // Output Data Buffer

& dwoutBytes, // Output data length

(LPOVERLAPPED) NULL); // Synchronous I / O

Return (Byte) BUF [1];

}

// Write a byte to the specified port

// port: port

// Data: byte data

Void Writeportbyte (Word Port, Byte Data)

{

DWORD BUF [2]; // Input Output Buffer

DWORD dwoutBytes; // ioctl output data length

BUF [0] = port; // The first DWORD is the port

BUF [1] = data; // Second DWORD is data

// Write port with IOCTL_MYPORT_WRITE_BYTE

:: Deviceiocontrol (Hmyport, // Equipment handle

IOCTL_MYPORT_WRITE_BYTE, // Take Device Properties Information

BUF, SIZEOF (BUF), // Enter data buffer

BUF, SIZEOF (BUF), / / ​​Output Data Buffer & DwoutBytes, // Output Data Length

(LPOVERLAPPED) NULL); // Synchronous I / O

}

With the two functions of Readportbyte and Writeportbyte, we can easily manipulate CMOS and Speaker (regarding the meaning of the CMOS value, please refer to the appropriate hardware information):

// 0x70 is a CMOS index port (written only)

// 0x71 is the CMOS data port

Byte ReadCMOS (byte index)

{

BYTE DATA;

:: WritePortbyte (0x70, INDEX);

Data = :: readportbyte (0x71);

Return Data;

}

// 0x61 is the Speaker Control Port

// 0x43 is the 8253/8254 timer control port

// 0x42 is the port of 8253/8254 timer channel 2

Void Sound (DWORD FREQ)

{

BYTE DATA;

IF ((FREQ> = 20) && (freq <= 20000)))

{

FREQ = 1193181 / FREQ;

Data = :: readportbyte (0x61);

IF ((Data & 3) == 0)

{

:: WritePortbyte (0x61, Data | 3);

:: WriteportByte (0x43, 0xB6);

}

:: WritePortbyte (0x42, (byte) (FREQ% 256));

:: WritePortbyte (0x42, (Byte) (freq / 256));

}

}

Void Noid (Void)

{

BYTE DATA;

Data = :: readportbyte (0x61);

:: WritePortbyte (0x61, Data & 0xFC);

}

/ / The following reads the CMOS 128 bytes

For (int i = 0; i <128; i )

{

BYTE DATA = :: readcmos (i);

...

}

/ / The following use C to play "more - come - rice"

// 1 = 262 hz

:: Sound (262);

:: Sleep (200);

:: nosound ();

// 2 = 288 hz

:: Sound (288);

:: Sleep (200);

:: nosound ();

// 3 = 320 Hz

:: Sound (320);

:: Sleep (200);

:: nosound ();

Q is a simple port I / O, so troubles can be realized, do you have a simple way? Is there a simple way?

A above, the reason why the driver is written, to the installation driver, to the launch service, to the access device, until the access device, until the read and write port, so that all the way is to reveal in NT / 2000 / XP hardware access The essence of technology. If all procedures are encapsulated, only OpenMyport, Closemyport, ReadportByte, Writeportbyte, and even higher READCMOS, WRITECMOS, SOUND, NOSOND to you, is it a lot of cool?

In fact, we usually do the secondary development based on a certain hardware, which generally install the driver (DRV) and user interface running library (DLL), and then develop our application (App) on this basis. DRV, DLL, APP three run in core state, core state / user-state liaison, user state. For example, I bought an image capture card. To install the core driver, its "develop Tool Kit", provides an API similar to PCV_Initialize, PCV_CAPTURE, etc., is the role of playing core state and user-state contact. We don't need Createfile, CloseHandle, DeviceIocontrol, readfile, Writefile, etc., etc. Yariv Kaplan wrote an example of WinIO, enable access to physical ports and memory, providing DRV, DLL, APP source code, if you are interested, you can study.

[related resources]

This article driver source code: myport.zip (3KB, compilation environment: VC6 2000DDK) This article application source code: myportio.zip (22KB, file myport.sys You need to copy to Windows System32 / Drivers Directory) Yariv Kaplan Home: http : //www.internals.com BHW98 column: http://www.9cbs.net/develop/author/netauthor/bhw98/

First release: 2003-03-05 Last revision: 2003-05-20

转载请注明原文地址:https://www.9cbs.com/read-23674.html

New Post(0)