使用WinIO访问底层端口&寄存器

来源:互联网 发布:域名批量查询软件 编辑:程序博客网 时间:2024/05/18 01:25

在window系统中应用层程序没有权限访问底层,为了实现端口或者寄存器操作,就要借助高权限的程序。一般是将winio.dll 加载到驱动,借道实现底层操作。就好像我们借助驱动程序操作外设一样。

64位系统的应用层是兼容32位程序的,但驱动层是不能向下兼容的,所以winio64和winio32要用对。

 WinIo可以到官方网站:http://www.internals.com/去下载,里面包含了帮助文档和源码。

 因为需要加载驱动,程序要以管理员权限运行,我用的是64位WIN7系统,还需要对WinIo64.sys做交叉签名才能正常加载,没有签名的同学需要使用32位系统或使用测试模式。为了省去动态加载DLL,再动态获取函数地址去调用的麻烦,用官方的DLL源码,编译生成WinIo.lib,添加一行#pragmacomment(lib,"WinIo.lib"),修改一下winio.h,然后include就可以了。

二   winio.dll中提供的函数:

bool _stdcall InitializeWinIo();
本函数初始化WioIO函数库。
必须在调用所有其它功能函数之前调用本函数。

void _stdcall ShutdownWinIo();
本函数在内存中清除WinIO库
本函数必须在中止应用函数之前或者不再需要WinIO库时调用,

bool _stdcall GetPortVal(WORD wPortAddr, PDWORD pdwPortVal, BYTE bSize);
使用此函数从一个输入或输出端口读取一个字节/字/双字数据。
参数:
wPortAddr – 输入输出端口地址
pdwPortVal – 指向双字变量的指针,接收从端口得到的数据。
bSize – 需要读的字节数,可以是1 (BYTE), 2 (WORD) or 4 (DWORD).

bool _stdcall SetPortVal(WORD wPortAddr, DWORD dwPortVal, BYTE bSize);
使用本函数将一个字节/字/双字的数据写入输入或输出接口。
参数:
   wPortAddr – 输入输出口地址
   dwPortVal – 要写入口的数据
   bSize – 要写的数据个数,可以是 1 (BYTE), 2 (WORD) or 4 (DWORD).

PBYTE _stdcall MapPhysToLin(PBYTE pbPhysAddr, DWORD dwPhysSize, HANDLE *pPhysicalMemoryHandle)
使用此函数将物理内存的一部分映射到一个32位应用程序的线性地址空间。
下面是一个例子:
PBYTE pbLinAddr;
HANDLE PhysicalMemoryHandle;
pbLinAddr = MapPhysToLin(0xA0000, 65536, &PhysicalMemoryHandle);

该函数将把物理地址范围为0xA0000 - 0xAFFFF的地址空间映射到与应用程序对应的线性地址空间。 返回值为一个与物理地址0xA0000相关的线性地址。如果出现错误,则返回值为NULL。
参数:
   pbPhysAddr – 指向物理地址的指针
dwPhysSize – 需要映射的字节数
pPhysicalMemoryHandle – 变量指针,如果调用成功,负责接收物理内存句柄。随后本句柄在调用UnmapPhysicalMemory函数时作为其第一个参数。
bool _stdcall UnmapPhysicalMemory(HANDLE PhysicalMemoryHandle, PBYTE
pbLinAddr)
使用本函数解除原先使用MapPhysToLin函数映射的一段线性物理内存区域,该区域被映射到应用程序所属的线性地址空间。

Windows 9x 应用程序不需要调用此函数。
参数:
PhysicalMemoryHandle – 物理内存区域所属的句柄,此参数由对MapPhysToLin函数的调用返回。
pbLinAddr – MapPhysToLin函数调用返回的线性地址。
bool _stdcall GetPhysLong(PBYTE pbPhysAddr, PDWORD pdwPhysVal);
从指定的物理地址读取一个双字数据。
参数:
pbPhysAddr – 指向物理地址的指针。
pdwPhysVal – 指向一个双字变量的指针,接收从物理内存中传来的数据。
如果此函数调用成功,返回一个非零值。
如果函数调用失败,则返回一个零值。
bool _stdcall SetPhysLong(PBYTE pbPhysAddr, DWORD dwPhysVal);
将一个双字型数据写入指定的物理地址。
参数:
pbPhysAddr – 指向物理地址的指针。
pdwPhysVal – 指定待写入物理内存地址出的双字型数据。


三   调用

MFC:

[DllImport("WinIo64.dll")]

public static extern bool InitializeWinIo();


 BCB:   用函数指针来实现的

 typedef  bool  (_stdcall *pfInitializeWinIo)();  //定义函数指针类型
typedef  void  (_stdcall *pfShutdownWinIo)();
typedef  PBYTE (_stdcall *pfMapPhysToLin)(tagPhysStruct &PhysStruct);
typedef  bool  (_stdcall *pfUnmapPhysicalMemory)(tagPhysStruct &PhysStruct);
typedef  bool  (_stdcall *pfGetPhysLong)(PBYTE pbPhysAddr, PDWORD pdwPhysVal);
typedef  bool  (_stdcall *pfSetPhysLong)(PBYTE pbPhysAddr, DWORD dwPhysVal);
typedef  bool  (_stdcall *pfGetPortVal)(WORD wPortAddr, PDWORD pdwPortVal, BYTE bSize);
typedef  bool  (_stdcall *pfSetPortVal)(WORD wPortAddr, DWORD dwPortVal, BYTE bSize);
typedef  bool  (_stdcall *pfInstallWinIoDriver)(PSTR pszWinIoDriverPath, bool IsDemandLoaded);
typedef  bool  (_stdcall *pfRemoveWinIoDriver)(); 

   pfInitializeWinIo         XX_InitializeWinIo;  //定义函数指针
   pfShutdownWinIo       XX_ShutdownWinIo;
   pfMapPhysToLin        XX_MapPhysToLin;
   pfUnmapPhysicalMemory XX_UnmapPhysicalMemory;
   pfGetPhysLong          XX_GetPhysLong;
   pfSetPhysLong          XX_SetPhysLong;
   pfGetPortVal              XX_GetPortVal;
   pfSetPortVal               XX_SetPortVal;
   pfInstallWinIoDriver    XX_InstallWinIoDriver;
   pfRemoveWinIoDriver   XX_RemoveWinIoDriver;      


        hWinIo = LoadLibrary("WinIo32.dll"); //载入动态链接档
        if ( hWinIo != NULL )
        {
            
             XX_InitializeWinIo     = (pfInitializeWinIo)GetProcAddress(hWinIo, "InitializeWinIo") ;  //获取函数接口地址

            XX_ShutdownWinIo       = (pfShutdownWinIo)GetProcAddress(hWinIo, "ShutdownWinIo");

            XX_MapPhysToLin        = (pfMapPhysToLin)GetProcAddress(hWinIo, "MapPhysToLin");

            XX_GetPhysLong         = (pfGetPhysLong)GetProcAddress(hWinIo, "GetPhysLong");

             XX_UnmapPhysicalMemory = (pfUnmapPhysicalMemory)GetProcAddress(hWinIo, "UnmapPhysicalMemory");

             XX_GetPortVal          = (pfGetPortVal)GetProcAddress(hWinIo, "GetPortVal");

             XX_SetPortVal          = (pfSetPortVal)GetProcAddress(hWinIo, "SetPortVal");

         }

        调用:

         unsigned long v = 0;
         XX_GetPortVal(p, &v, 2); // 要读的地址, 读回的数据,数据的字节数

         释放资源

         FreeLibrary(hWinIo);
         hWinIo = NULL;


四 .使用

比如要访问superio 83627 ,SuperIO 的入口地址是:SuperIO_Cfg = 0x295; SuperIO_Dat = 0x296;

XX_SetPortVal(0x295,0x5D, 1);

Sleep(50);

XX_GetPortVal(0x296 , &buffer,1);















原创粉丝点击