Search code examples
c++winapidriver

Alternative for _outp and _inp APIs in Visual Studio 2017 C++


I'm currently working on a migrating project from vs 10 to Visual Studio 2017 using C++. In my codebase, I've been using the _outp() and _inp() APIs to perform I/O port operations, along with _outpw() and _inpw(). However, it seems that these APIs are not available or deprecated in Visual Studio 2017.

Could someone please suggest alternative APIs or methods that I can use to perform similar I/O port operations in Visual Studio 2017 using C++? I need to handle both byte and word-sized data for input and output operations.


Solution

  • In modern Windows systems you can't directly access I/O ports anymore from any normal userspace application. (*.exe, *.dll) The only way to access hardware directly is in kernel mode when you write a kernel driver.

    Specifically for x86 I/O port access there is one alternative: you can install the InpOut driver, which consists of both a Windows kernel driver that was already signed (+ some logic to auto-install it on first use), as well as a DLL (both in 32bit and 64bit variants) that provides functions you can use for port access. In your case that would primarily be the Inp32 (to read a single byte from an I/O port) and Out32 (to write a single byte to an I/O port). To read/write multiple bytes, invoke those functions repeatedly. This way you can have direct port I/O access from userspace by means of this trivial kernel driver that just passes everything on.

    Note however that if you do install that driver, you completely bypass the security model of modern Windows kernels when it comes to I/O port access, and anyone logged in on a system with that driver installed (regardless of privileges of the user) can likely perform a lot of shenanigans with the built-in hardware, possibly even bricking the system or gaining Administrator access.

    The far better option is to indeed write a kernel driver specifically for your hardware, that only accesses the ports of that device, and communicates with your user-space application via a DeviceIoControl interface that can only be used to access that specific hardware device, but not generic I/O ports. In the kernel driver itself you'd translate that to the actual port I/O. Within the kernel driver you can then use functions like READ_PORT_UCHAR and similar to do that. (This is also what the InpOut driver does internally.) Obviously this is more complicated (especially since you nowadays have to submit drivers to Microsoft), but it doesn't compromise the systems that use your hardware.