通过驱动使应用程序直接操作IO口,通过端口终止PC喇叭发声

来源:互联网 发布:linux内核源码 陈莉君 编辑:程序博客网 时间:2024/05/02 12:06

在NT内核的windows系统上,应用层无法直接操作IO端口,必须通过驱动层处理,然后应用程序通过调用驱动间接操作IO端口。

在驱动方式实现由多种:

(a)驱动层通过汇编代码

(b)驱动层使用内核API

(c)应用层写汇编,然后将函数指针通过DeviceIoControl传递给驱动

(d)根据IO操作原理,驱动程序修改IO端口的EFLAGS寄存器的IOPL(I/O privilege)标志 和TSS(Task state Segment),详细的实现略。


由于暂时对汇编不太熟悉,本文就是要内核IO操作的API演示实例。

从指定的端口读数据的API:

READ_PORT_UCHAR 、READ_PORT_USHORT、READ_PORT_ULONG

READ_PORT_BUFFER_UCHAR、READ_PORT_BUFFER_USHORT、READ_PORT_BUFFER_ULONG

从指定的端口写数据API:

类似于READ,将read替换为WRITE


有关PC喇叭,设置的可编程定时器:

设置可编程定时器,驱动PC喇叭
pc的8253定时器2用于应用程序的时钟频率,需要设置控制寄存器和数据寄存器
(a)控制寄存器:
0位:0表示二进制,1表示bcd码
1-3位:000代码时钟以方式0运行
4-5位:00表示寄存器锁存,01只读写8字节,10只读写高8字节,11先读低8字节再读高8字节
6-7位:00选计数器0,01选计数器1,02选计数器2,11非法
(b)数据寄存器:
找到对应的寄存器的计数器端口

sys代码:

///////////////////////////////////////////////////////////////////////////////////// Copyright (c) 2014 - <company name here>////// Original filename: Io.cpp/// Project          : Io/// Date of creation : 2014-07-04/// Author(s)        : <author name(s)>////// Purpose          : <description>////// Revisions:///  0000 [2014-07-04] Initial revision.//////////////////////////////////////////////////////////////////////////////////// $Id$#ifdef __cplusplusextern "C" {#endif#include <ntddk.h>#include <string.h>#ifdef __cplusplus}; // extern "C"#endif#include "Io.h"#ifdef __cplusplusnamespace { // anonymous namespace to limit the scope of this global variable!#endifPDRIVER_OBJECT pdoGlobalDrvObj = 0;#ifdef __cplusplus}; // anonymous namespace#endifconst ULONG IOCTL_IO_OPERATION = CTL_CODE(FILE_DEVICE_IO, 0x01, METHOD_BUFFERED, FILE_READ_DATA | FILE_WRITE_DATA);const ULONG IOCTL_IO_READ = CTL_CODE(FILE_DEVICE_IO, 0x02, METHOD_BUFFERED, FILE_READ_DATA | FILE_WRITE_DATA);const ULONG IOCTL_IO_WRITE = CTL_CODE(FILE_DEVICE_IO, 0x03, METHOD_BUFFERED, FILE_READ_DATA | FILE_WRITE_DATA);const ULONG IOCTL_IO_SOUND = CTL_CODE(FILE_DEVICE_IO, 0x04, METHOD_BUFFERED, FILE_READ_DATA | FILE_WRITE_DATA);const ULONG IOCTL_IO_OFF_SOUND = CTL_CODE(FILE_DEVICE_IO, 0x05, METHOD_BUFFERED, FILE_READ_DATA | FILE_WRITE_DATA);NTSTATUS IO_DispatchCreateClose(    IN PDEVICE_OBJECTDeviceObject,    IN PIRPIrp    ){    NTSTATUS status = STATUS_SUCCESS;    Irp->IoStatus.Status = status;    Irp->IoStatus.Information = 0;    IoCompleteRequest(Irp, IO_NO_INCREMENT);    return status;}VOID sound(){ULONG uHz = 2000;//2000HzUSHORT B= 1193180/uHz;//从端口0x61取数ULONG uPort = 0x61;UCHAR uTemp = READ_PORT_UCHAR((PUCHAR)uPort);//低2位置1uTemp |= 3;//输出到0x61端口WRITE_PORT_UCHAR((PUCHAR)uPort,(UCHAR)uTemp);//输出到0x43UCHAR uPort43 = 0x43;WRITE_PORT_UCHAR((PUCHAR)uPort43,(UCHAR)0xb6);//输出到0x42UCHAR uPort42 = 0x42;WRITE_PORT_UCHAR((PUCHAR)uPort42,B & 0xF);//输出到0x42 写高8位WRITE_PORT_UCHAR((PUCHAR)uPort42,(B>>8) & 0xF);}VOID OffSound( ){//取端口0x61的字节UCHAR uPort61 = 0x61;UCHAR uData = READ_PORT_UCHAR((PUCHAR)uPort61);//强制置后2位为0uData &= 0xFC;WRITE_PORT_UCHAR((PUCHAR)uPort61,uData);}NTSTATUS IO_DispatchDeviceControl(    IN PDEVICE_OBJECTDeviceObject,    IN PIRPIrp    ){    NTSTATUS status = STATUS_SUCCESS;    PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);ULONG uCode = irpSp->Parameters.DeviceIoControl.IoControlCode;ULONG uInLen = irpSp->Parameters.DeviceIoControl.InputBufferLength;ULONG uOutLen = irpSp->Parameters.DeviceIoControl.OutputBufferLength;PULONG uDataBuffer =  (PULONG)Irp->AssociatedIrp.SystemBuffer;ULONG uPort = (ULONG)*uDataBuffer;uDataBuffer++;UCHAR uMethod = (UCHAR)*uDataBuffer;uDataBuffer++;ULONG uData = (ULONG)*uDataBuffer;ULONG uInfo = 0;    switch(uCode)    {    case IOCTL_IO_OPERATION:        // status = SomeHandlerFunction(irpSp);        break;case  IOCTL_IO_READ:{//操作输出缓冲区PULONG outPutBuffer = (PULONG)Irp->AssociatedIrp.SystemBuffer;switch (uMethod){case 1:{*outPutBuffer = READ_PORT_UCHAR((PUCHAR)uPort);}break;case 2:{*outPutBuffer = READ_PORT_USHORT((PUSHORT)uPort);}break;case 3:{*outPutBuffer =  READ_PORT_ULONG((PULONG)uPort);}break;default: break;}uInfo = 4;}break;case  IOCTL_IO_WRITE:{switch (uMethod){case 1:{ WRITE_PORT_UCHAR((PUCHAR)uPort,(UCHAR)uData);}break;case 2:{ WRITE_PORT_USHORT((PUSHORT)uPort,(USHORT)uData);}break;case 3:{WRITE_PORT_ULONG((PULONG)uPort,(ULONG)uData);}break;default: break;}uInfo = 0;}break;case  IOCTL_IO_SOUND:{sound();}break;case  IOCTL_IO_OFF_SOUND:{OffSound();}break;default:        Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;        Irp->IoStatus.Information = 0;        break;    }    status = Irp->IoStatus.Status;Irp->IoStatus.Information = uInfo;    IoCompleteRequest(Irp, IO_NO_INCREMENT);    return status;}VOID IO_DriverUnload(    IN PDRIVER_OBJECTDriverObject    ){    PDEVICE_OBJECT pdoNextDeviceObj = pdoGlobalDrvObj->DeviceObject;    IoDeleteSymbolicLink(&usSymlinkName);    // Delete all the device objects    while(pdoNextDeviceObj)    {        PDEVICE_OBJECT pdoThisDeviceObj = pdoNextDeviceObj;        pdoNextDeviceObj = pdoThisDeviceObj->NextDevice;        IoDeleteDevice(pdoThisDeviceObj);    }}#ifdef __cplusplusextern "C" {#endifNTSTATUS DriverEntry(    IN OUT PDRIVER_OBJECT   DriverObject,    IN PUNICODE_STRING      RegistryPath    ){    PDEVICE_OBJECT pdoDeviceObj = 0;    NTSTATUS status = STATUS_UNSUCCESSFUL;    pdoGlobalDrvObj = DriverObject;    // Create the device object.    if(!NT_SUCCESS(status = IoCreateDevice(        DriverObject,        0,        &usDeviceName,        FILE_DEVICE_UNKNOWN,        FILE_DEVICE_SECURE_OPEN,        FALSE,        &pdoDeviceObj        )))    {        // Bail out (implicitly forces the driver to unload).        return status;    };    // Now create the respective symbolic link object    if(!NT_SUCCESS(status = IoCreateSymbolicLink(        &usSymlinkName,        &usDeviceName        )))    {        IoDeleteDevice(pdoDeviceObj);        return status;    }    // NOTE: You need not provide your own implementation for any major function that    //       you do not want to handle. I have seen code using DDKWizard that left the    //       *empty* dispatch routines intact. This is not necessary at all!    DriverObject->MajorFunction[IRP_MJ_CREATE] =    DriverObject->MajorFunction[IRP_MJ_CLOSE] = IO_DispatchCreateClose;    DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = IO_DispatchDeviceControl;    DriverObject->DriverUnload = IO_DriverUnload;    return STATUS_SUCCESS;}#ifdef __cplusplus}; // extern "C"#endif

应用程序通过调用驱动间接调用IO端口:

// TestIO.cpp : 定义控制台应用程序的入口点。//#include "stdafx.h"#include "TestIO.h"#ifdef _DEBUG#define new DEBUG_NEW#endif// 唯一的应用程序对象CWinApp theApp;using namespace std;const ULONG IOCTL_IO_READ = ( ((0x8000) << 16) | ((1 | 2) << 14) | ((0x02) << 2) | (0) );const ULONG IOCTL_IO_WRITE = ( ((0x8000) << 16) | ((1 | 2) << 14) | ((0x03) << 2) | (0) );const ULONG IOCTL_IO_SOUND = ( ((0x8000) << 16) | ((1 | 2) << 14) | ((0x04) << 2) | (0) );const ULONG IOCTL_IO_OFF_SOUND = ( ((0x8000) << 16) | ((1 | 2) << 14) | ((0x05) << 2) | (0) );int _tmain(int argc, TCHAR* argv[], TCHAR* envp[]){int nRetCode = 0;// 初始化 MFC 并在失败时显示错误if (!AfxWinInit(::GetModuleHandle(NULL), NULL, ::GetCommandLine(), 0)){// TODO: 更改错误代码以符合您的需要_tprintf(_T("错误: MFC 初始化失败\n"));nRetCode = 1;}else{// TODO: 在此处为应用程序的行为编写代码。}HANDLE hdl = CreateFile(L"\\\\.\\IO_DeviceName",GENERIC_WRITE | GENERIC_READ,0,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL ,NULL);if (hdl == INVALID_HANDLE_VALUE){CString csLog;csLog.Format(L"CreateFile Error:%d",GetLastError());AfxMessageBox(csLog);return -1;}DWORD SendData[3] = {0x378,//port1,//1:8位操作,2:16位操作 3:32位操作0//data};DWORD dwRetLen = 0;BOOL bRet = DeviceIoControl(hdl,IOCTL_IO_WRITE,SendData,sizeof(SendData),NULL,0,&dwRetLen,NULL);if (!bRet){CString csLog;csLog.Format(L"DeviceIoControl Error:%d",GetLastError());AfxMessageBox(csLog);}bRet = DeviceIoControl(hdl,IOCTL_IO_SOUND,SendData,sizeof(SendData),NULL,0,&dwRetLen,NULL);if (!bRet){CString csLog;csLog.Format(L"DeviceIoControl Error:%d",GetLastError());AfxMessageBox(csLog);}Sleep(200);bRet = DeviceIoControl(hdl,IOCTL_IO_OFF_SOUND,SendData,sizeof(SendData),NULL,0,&dwRetLen,NULL);if (!bRet){CString csLog;csLog.Format(L"DeviceIoControl Error:%d",GetLastError());AfxMessageBox(csLog);}CloseHandle(hdl);system("PAUSE");return nRetCode;}


0 0
原创粉丝点击