一
在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;