Hardware Emulation Guide

Question
My application needs emulation of the hardware not existing any more. I am not allowed to change or patch. It's basically data acquisition software. I need to emulate a handful hardware ports and convince the application that it is talking to a real hardware.
Answer
Executeable DOS Windows 9x/Me Windows 32 bit Windows 64 bit
DOS native in a DOS Box InpOut32.dll doesn't run
(exception: DosBox, Wine for Windows)
Win16 direct I/O -native
with VxD Write a VxD-simulating VDD!
Win32 direct I/O Load giveio.sys Load this giveio.sys!
coming with a VxD (never seen) Write a simulating .SYS driver!
with inpout32.dll native
with giveio.sys Should run seemlessly
(needless driver silently fails to load)
native Replace giveio.sys!
with own 32-bit .SYS driver Insist making a 64-bit driver, or
disassemble .SYS driver (IDA)
and port to 64 bit + certify (*)
Win64 with certified .SYS driver - native

Generally speaking you need a Virtual Device Driver. You have at lot of options to deal with your problem.

  1. If your software is 16-bit, write a regular Virtual Device Driver (VDD) to emulate the missing hardware in user space. Easiest. See my InpOut32.dll source code for a possible starting point. It will work only reliable on non-printer ports (not 0x378, 0x278 nor 0x3BC), therefore you need to instruct your software to use a random port address. And you have to disable Port Access Enabler software. If not possible, go to 6.
  2. If not, check how your 32-bit software accesses the ports. If it uses one of the well-known port access DLLs like inpout32.dll, dlportio.dll or similar, try replacing with my inpout32.dll (see link above) and modify its source to emulate the missing hardware. Also in user space, no kernel-mode hassle.
  3. If 2. fails, check if your software can run on Windows 98/Me and does direct port access (i.e. uses built-in in/out instructions, not using a VxD). If so, use my InpOut32.dll source again to fake Win9x/Me and trap port accesses as handled process-global exceptions in user space.

    If you encounter that this solution works but is too slow, you have to proceed with a kernel-mode driver below, but it's very likely that the entire project will fail: You have to rewrite the closed-source software.

  4. If still failing, you have to bite the bullet and go to kernel mode. There must be a .sys driver that handles I/O. The disassembler IDA is your friend: Check whether you can imitate your hardware at DeviceIoControl level. When you understand what to do, you have the advantage that your software can run on Win64 later too because you can compile your replacement driver for 64 bit target.
  5. If you cannot understand the DeviceIoControl interface (because the driver is quite big), check whether the driver uses READ_PORT_UCHAR and similar HAL functions, or uses hard-coded in/out instructions. In the first case, trapping is easy, use the code seen in vlpt.c, and omit all code lines dealing with the IDT, debug registers, etc.
  6. If not, use vlpt.c and omit all lines of code dealing with READ_PORT_UCHAR (etc) redirection. However, lot of code deals with the correct stack frame for calling other kernel (here: USB) functions. It's much easier to take the source of DongleCracker as starting point.
  7. If this still fails, because your driver resets bit 3 of CR4 before each in/out instruction, you must either return to step 4, or use a Virtual Machine (VM). Inside the VM, run your program, and outside the VM, run the DongleCracker derivate. Complicated and error-prone but the last resort.
  8. Note that there is a working and certified giveio.sys for Windows 64 available. This driver enables port access from user mode without speed loss.
1., 5., 6., and 7. require 32-bit architectures.