Rogue XInput Capabilities Bug – Part 1

Greetings!

It’s time to shed some light on yet another interesting ViGEm/XUSB bug I had to wrap my head around for quite some time now. The related issue has been around since mid-summer 2017 but about half a year is still a good average time span for me fixing bugs 😅 Like the headphone-device-bug this one required some sniffing, disassembly, and trial and error before the puzzle pieces fell into place. So let’s dive into the details.

Summary of the issue

First a quick summary of the problem. This time it’s affecting the high-level API function XInputGetCapabilities, which reports features of the device to query. The passed XINPUT_CAPABILITIES structure contains information about available buttons, axes and vibration attributes which then let the caller decide if the device fulfills the desired requirements for interacting with the process/game. The XINPUT_GAMEPAD member of the structure of a successful request for a typical X360 controller looks like this:

FF F3 FF FF C0 FF C0 FF C0 FF C0 FF

I won’t go over every bit in detail; it basically describes that all buttons and axes expected to be on a XINPUT_DEVTYPE_GAMEPAD are reported present by the XInput sub-system. Now in case of a ViGEm-device this response suddenly becomes filled with random data:

Where by random I don’t mean “I have no clue what these values mean” (which I also didn’t by the time analyzing 😉) but truly baseless garbage that changes every time you re-plug the pad…

After a bit of testing this behavior was indeed unique to ViGEm and had to be addressed since popular solutions like the GameCube Emulator Dolphin failed to receive inputs because they relied on this function to work as expected. So my initial plan of simply ignoring the issue wasn’t an option 😏

The Analysis

ViGEm mimics a USB bus so the answer has to be hidden in the processing of the URBs (USB Request Blocks). But since I already ported over and implemented all the features I knew from maintaining the ScpVBus plus my own research I hit a dead end pretty soon, so I decided to take a look at the top of the stack first and fed the Interactive Disassembler with the user-mode XInput1_3.dll.

Now despite doing a fair amount of reverse engineering I usually avoid the Disassembler if possible. There seems to be a threshold in my brain where it starts to panic if we get too close to the CPU (on an instructional level) and tries to shut down 😖 Anyways, so I shoved this inner daemon aside and forced myself to navigate through the instructions. Thankfully Microsoft provides debug symbols for their OS, libraries and even drivers so I can at least work with resolved function names.

Right, so after some digging and following references we’ll find this gem of a function: DriverComm::GetCapabilities

Alright so at this point the DLL simply sends the I/O-Control-Code IOCTL_XINPUT_GET_CAPABILITIES to XUSB22.SYS via DeviceIoControl function and receives the desired capabilities via the output buffer. Time to abandon ship; we need to dive into deeper waters and take a peak at the driver itself 😮

Inspecting XUSB22.SYS we encounter this function:

bool __fastcall XInputControllerDevice::SendCapabiltiesRequest(XInputControllerDevice *this)

Here’s the key information of what’s going on:

Aha! The driver requests capability information from the controller via the control endpoint (that’s what WdfUsbDeviceWrapper::SendControlRequest tells us). Let’s see how ViGEm responds to control requests, shall we:

😬 Oh. Well. That’s not helping, is it 😅

To be continued…

New ViGEm Installer

Merry Christmas y’all! 😃

I have a small yet powerful Christmas present for my trusty users. As you might have noticed, the installation of the ViGEm Bus was a bit rough on both the documentation and the procedure itself. I’ve experimented a lot with conventional and unconventional methods, even with my beloved Advanced Installer. But in the end, driver installation isn’t really a common task in most setup maker utilities so I decided to roll my own. As much as I enjoy .NET I’ve always neglected using the  Windows PowerShell for more than a view lines of scripting automation. This changed a lot over the last couple month since I was successfully implementing more and more complex tasks in PowerShell at my job. Therefore I also stumbled upon the neat possibility of developing PowerShell binary modules. In short, these are pieces of code collections written in C# and compiled to a DLL while exposing Cmdlets like you’d do in scripts. This grants me the power I was looking for:

  • Hide/abstract device creation and driver installation from the end user
  • Stick to C# rather than maintaining lots of additional PowerShell scripts
  • Utilize existing and supported distribution mechanisms
  • No GUI development required (I hate that and it slows me down)
  • Profit from built-in PowerShell advantages like passing objects
  • Built into Windows 10 and – provided via Updates – Windows 7 and newer
  • Simple update management

Now I know that not everyone – especially Gamer who just like their stuff to work – enjoys fiddling around with command line interfaces but when my past projects told me one thing, it’s that you can’t satisfy everyone a 100% so I’ll stick to satisfying myself first 😛 Well, that came out weirder than I intended… Anyways, enough babbling, let me show you how it’s done! 😎

How to install ViGEm Bus & Driver

First and foremost: you’ll find a compact version of this article at the repository wiki which I’ll build up more and more as time passes. In this blog post I’ll go into more detail so newcomers don’t get scared too much while we dive into using the command line 😉

Since you need administrative privileges to install drivers I recommend you execute the following commands in an elevated PowerShell session. Since there’s already a ton of articles out there how to fire up PowerShell I won’t comment on it further. In short: you’re dealing with a window you type or paste in text that’s commanding your PC to do awesome stuff as soon as you hit Enter. If something went wrong or further actions are required it will print out some text. That’s really it. Oh, and you won’t need your mouse 😏

Add the Software Repository

I’ve decided to run and host my own software repository. Cloud storage is undoubtedly cool and convenient, but just like GitHub Releases it slows me down too much and since I’m already running a Webserver I might as well host the software my own. Now instead of the conventional way of downloading a setup executable and running through a wizard, a PowerShell (or NuGet in general) repository is optimized to install, update and remove software packages with one or more simple commands. In our case we need to tell PowerShell where to “find” the ViGEm installer module. This is achieved via the Register-PSRepository command:

Register-PSRepository -Name nuget.vigem.org -SourceLocation https://nuget.vigem.org/ -InstallationPolicy Trusted

This command might ask for confirmation to update NuGet, please confirm to do so:

NuGet provider is required to continue
PowerShellGet requires NuGet provider version '2.8.5.201' or newer to interact with NuGet-based repositories. The NuGet
 provider must be available in 'C:\Program Files\PackageManagement\ProviderAssemblies' or
'C:\Users\Nefarius\AppData\Local\PackageManagement\ProviderAssemblies'. You can also install the NuGet provider by
running 'Install-PackageProvider -Name NuGet -MinimumVersion 2.8.5.201 -Force'. Do you want PowerShellGet to install
and import the NuGet provider now?
[Y] Yes  [N] No  [S] Suspend  [?] Help (default is "Y"):

Now the package management sub-system knows that there’s a new online location where software can get downloaded and installed from.

Install the Management Module

The driver installer is included in the ViGEmManagementModule. We can install (and update) it via the following command:

Install-Module ViGEmManagementModule -Repository nuget.vigem.org

As with the tradition of Command-lets you won’t get any response if the command succeeded, so don’t worry. Warnings and error messages will get printed though but we don’t want those, do we 😉

We’re now ready for action!

Working with the ViGEm Cmdlets

With the module installed we now have access to functions – called Cmdlets – which allow us to manage the bus and its driver. Let’s start with listing existing bus devices.

Get-ViGEmBusDevice

On a vanilla system the Get-ViGEmBusDevice Cmdlet won’t return any output. This is to be expected since the purpose of the command is to list the bus instances present on the system. But if I invoke this command on e.g. my development Laptop I’ll get the following output:

DevicePath         : \\?\ROOT#SYSTEM#0004#{96E42B22-F5E9-42F8-B043-ED0F932F014F}
InstanceId         : ROOT\SYSTEM\0004
DeviceName         : Virtual Gamepad Emulation Bus
DriverVersion      : 1.13.0.0
Manufacturer       : Benjamin Höglinger-Stelzer
DriverProviderName : Benjamin Höglinger-Stelzer

This means that on my system there’s one instance of the bus driver present running the driver version 1.13.0.0. At the time of this writing there’s a newer version available so let’s update while we’re on a roll 😎

Install-ViGEmBusDeviceDriver

To freshly install (or update) the bus driver, we simply invoke the Cmdlet Install-ViGEmBusDeviceDriver:

Install-ViGEmBusDeviceDriver

The command downloads the latest bus driver from downloads.vigem.org, extracts the archive and installs (or updates) the driver, considering the Operating Systems architecture. Depending on your systems state you might get a message that a reboot is required. To validate that the installation was successful we can simply call Get-ViGEmBusDevice again:

DevicePath         : \\?\ROOT#SYSTEM#0004#{96E42B22-F5E9-42F8-B043-ED0F932F014F}
InstanceId         : ROOT\SYSTEM\0004
DeviceName         : Virtual Gamepad Emulation Bus
DriverVersion      : 1.14.1.0
Manufacturer       : Benjamin Höglinger-Stelzer
DriverProviderName : Benjamin Höglinger-Stelzer

As you can see the driver version has changed. Nicely done!

Add-ViGEmBusDevice

Now what if the previous call to Get-ViGEmBusDevice didn’t return anything? Glad you asked! On a virgin system we first need to create a so called pseudo-device or Virtual Hardware. The Cmdlet Add-ViGEmBusDevice will do this:

Add-ViGEmBusDevice

Now don’t forget to call Install-ViGEmBusDeviceDriver afterwards so the new device gets the driver attached and loaded.

Remove-ViGEmBusDevice

To get rid of one or more bus devices utilize the Remove-ViGEmBusDevice Cmdlet. In contrast to the other commands we learned this one actually needs a bit of information on which device to remove. There are multiple ways to achieve that. The simplest one is to pipeline (“chain”) the Get-ViGEmBusDevice and Remove-ViGEmBusDevice like so:

Get-ViGEmBusDevice | Remove-ViGEmBusDevice

Now while this looks weird it’s one of the more neat features of PowerShell. The devices returned by the first command get “fed” into the second command which will use this information to identify the bus device(s) to remove. Once again no output will be displayed on success.

Now if you want to have control over which instance of the bus should be removed we can call the command with the following syntax:

Remove-ViGEmBusDevice -InstanceId ROOT\SYSTEM\0004

This will remove (uninstall) the device with the “virtual” Hardware Identifier (Instance ID) of ROOT\SYSTEM\0004. As you might have guessed; this value is taken from the Get command. You’ll also find this value in Device Manager when you look at the Device instance path property:

Conclusion

That wasn’t too bad was it? And keep in mind: since the process only involved some text commands you can easily make your own silent “batch” or script file to simplify installation even more.

Good luck & happy holidays! 🙂

O how joyfully

Greetings,

Public announcement: I am not dead. End of announcement.

Last few weeks I had to devote more time towards my job and keeping the Christmas money rolling in 😜 Private life also wanted a slice of my cake of time, didn’t want to share but you know… can’t always escape to the code cave. Anyways, I plan on getting back on track within the Christmas holidays and maybe publish a small present to my brave and patient readers and followers.

Next on my list is adding compatibility of PCSX2 with Shibari. Which reminds me: I missed another announcement 😮

ScpToolkit successor: Shibari

I think it’s time to lift the curtain: I won’t continue development for ScpToolkit anymore, at least no major updates. The development and community feedback regarding the ScpToolkit uncovered a lot of issues only a re-write could solve. So that’s what I did. The successor is called Shibari, is still in an early yet working stage and is designed with manageability and extend-ability in mind. I can’t really do it justice in this short paragraph so I’ll devote a separate article to it at a later time.

Over and out 👋

Started working on AirBender

Hey,

it’s been a while since I touched topics solely devoted to my beloved Sony DualShock 3 controller, mainly because, well, ViGEm 😁 Trace on ScpToolkit has gone cold for a couple months now but a shard of hope I can present for the community. I will split and port the connection-oriented low-level components within the toolkit to its own respective native Windows drivers, including wireless functionalities.

Connecting the DS3 to a standard PC running Windows via Bluetooth has always been an annoyance because the DS3 lacks a compatible SDP layer. I was thinking a lot about a convenient solution where you can keep your existing Bluetooth software stack so the DS3 can connect side by side to your existing gadgets like keyboard, mouse, headset, you name it. Well, unfortunately this is not possible. Now I very rarely use the phrase “not possible” or “impossible” in tech because as a developer you literally have the power to create and change your (virtual) environment as you please but sometimes you have to accept the limitations of the environment you’re dealing with (Windows in this case).

Thing is, you have the abilities to create Bluetooth profile drivers with tools Microsoft provides you with, but once again the DS3 being a non-standard bastard needs adjustments lower in the stack where you can’t easily hack into without risking stability of other devices.

I’ve decided that the best solution is the existing design of sacrificing a dedicated Bluetooth host dongle for the entire purpose of communicating with the DS3, but as a real driver. But a user-mode driver this time! This has several advantages over a kernel-mode function driver:

  • Faster development due to easier testing and debugging
  • An uncaught error only crashes a process and not the entire system
  • Increased security; no more kernel privileges needed
  • Faster and easier signing process

But it’s only fair to also mention the cons:

  • UMDF 2 requires at least Windows 8.1 (thanks, Microsoft 😑)
  • No kernel-mode features like spawning children (PDOs)
  • Slightly but probably unnoticeable less performance

Now I know I’m getting hate for ignoring the still popular Windows 7 demographic but hear me out: a driver written for UMDF 2 can be be ported to a Windows 7 (or even older) compatible KMDF driver at any time. So once I’m finished I might consider going the extra mile and building and releasing it for Windows 7 too. Time will tell, as always 😋

Have a nice day,
c’ya!

PS: last but not least: the project repository 😀

ViGEm v1.13.0.0 released

Hey,

Version 1.13.0.0 is out, containing the following improvements:

  • Fixed freezing the host machine on Windows 7
  • Attaching virtual devices (plugging in children) is now a blocking operation. It’s backwards compatible to software using the deprecated ViGEmUM library. The new ViGEmClient library provides APIs for both blocking and asynchronous plugin.
  • New API documentation.
  • Updated example implementations.

So two big chunks from my previous post are already live and test feedback is mostly positive. More to come, stay tuned!

Cya!

PS: I know the .NET wrapper is still toast, will update soon, promise! 🙃

ViGEm Roadmap-thingy

Yo,

once again I’d like to inform you what’s going on in the development dungeon. Whacking together a quick list of stuff I wanna work on the next couple days/weeks regarding the ViGEm framework.

Redesign user-mode library

Currently ViGEmUM.dll is responsible for interaction with the bus driver and providing developers with access to the emulation sub-system. The library has some serious flaws due to rushed development and bad test coverage. Since fixing most of the stuff I’m unsatisfied with would inevitably break both API and ABI backwards-compatibility I decided to start again from scratch and make it a static library instead since most of my users compile it like that anyways. I’m also investigating some tools to provide decent API documentation, one of the is Read the Docs. Do keep in mind that I’ve never designed an API before this project so I’m learning as I code along 🙃

Redesign .NET stuff

There’s no beating around the bush; my .NET-wrappers are (still) in a pitiful state, mainly caused by their dependency to the native user-mode library which introduces issues with CPU architectures and compatibility between updates. My approach is to port the user-mode functionality entirely to the managed .NET world and implement it a 100% in C# so only one nice and clean assembly is necessary for communication with the bus driver. This would also simplify the creation of a NuGet package.

Blocking device attachment

Actions like adding another virtual device to the bus are inherently asynchronous because once the bus device (FDO) is instructed to report another of its children (PDO) to the system, it’s the Windows PNP-Managers responsibility to bring that new child to live so it becomes available to the system (“boot-up”). This usually takes around 300 to 700 milliseconds. Within this time frame it’s not possible to interact with the PDO through the bus drivers control mechanisms. I never had a problem with this fact but feedback from the community suggests it would be better to have this plugin procedure be a blocking action until the virtual device is truly ready for interaction. I agree. But you need to understand that at the driver level it’s not as easy as it seems because once the bus driver has announced a new child it no more has responsibility or control over it’s boot-up progress. I did some research and found a way of interaction between the FDO and the PDO which could satisfy this need. I’ll keep you updated on this topic.

Generic HID-Device emulation

I receive more and more feature requests to support a dynamic multi-purpose DirectInput-compatible joystick HID device like vJoy can. While I certainly sympathize with the idea behind it due to its complexity I’d rank this a bit further down the list of priorities for now. Time will tell, be assured 😄

Well, that’s it for now,
Cya!

ViGEm v1.10.2.0 released

Ey,

a big update of the bus driver was just released. I’m happy to announce, that I was finally able to fix two of the nastiest long-time bugs in the bus driver:

Fortunately both were linked to the same (stupid) mistake I made when porting some sections over from the legacy ScpVBus driver sub-project of the ScpServer/ScpToolkit. Since it’s a rather subtle yet “hidden in plain sight”-obvious bug I’d like to explain it in greater detail.

When you emulate USB devices, you typically want to mimic the physical devices properties as close as possible in your virtual environment as well. Sometimes (depending on the device and the driver stack it uses) you can get away with either slight or even major simplifications of the original implementation and everything is still working fine (the device might have unused interfaces you can ditch or special power/sleep attributes you don’t have to replicate in an emulated device) but typically – especially when debugging – it’s the best idea to emulate everything as precise as possible. Now why is that important? Let’s dive into more detail on how the Xbox 360 Controller interacts with its USB host.

An XUSB-compatible game pad typically exposes four interfaces, where the first one has two endpoints (Interrupt In and Interrupt Out), the second one has four endpoints (two pairs of Interrupt In and Interrupt Out) and the last two interfaces are unused and non of our concern.

When emulating the X360 pad, only the first interface and its Interrupt In endpoint is used to transfer pad state changes to the XUSB/XInput subsystem (while the Interrupt Out endpoint delivers vibration and LED state changes) which then get reflected to games using the XInput API (and DInput, ofc.). This was also the first logic I ported over and tested when first developing the ViGEm Bus ground up.

Now you have to know, that ViGEm is built using the Windows Driver Frameworks, an abstraction layer for lots and lots of boilerplate and pitfalls from WDM-land, which ScpVBus is written in. Why do I bring this up? Well, the same code you need in WDF to queue an IRP and mark it pending are roughly two, with proper locking, maybe five lines of code whereas in WDM it’s more like thirteen to fifteen lines of code. When hunting down the bus I mentioned I used the most basic option available; compare the code of the legacy yet working project to the brand new shiny yet faulty project. I read the same passages over and over and over and didn’t see any difference so I made the mistake of wasting my time looking in other areas for the issue. Then I came back and read again. And again. And ag… wait a minute. What’s this line doing, I’m not checking the value in ViGEm. Ok, that’s a major fail in plain sight but why is the check which pipe the request is associated to important?

if (Pipe == 0x81)
{
	status = STATUS_PENDING;
	IoMarkIrpPending(Irp);

	KeAcquireSpinLock(&pdoData->PendingQueueLock, &PrevIrql);
	{
		IoSetCancelRoutine(Irp, Bus_CancelIrp);

		if (Irp->Cancel == TRUE)
		{
			IoSetCancelRoutine(Irp, NULL);
			KeReleaseSpinLock(&pdoData->PendingQueueLock, PrevIrql);

			Irp->IoStatus.Status = STATUS_CANCELLED;
			Irp->IoStatus.Information = 0;

			IoCompleteRequest(Irp, IO_NO_INCREMENT);
		}
		else
		{
			PPENDING_IRP le = ExAllocateFromNPagedLookasideList(&g_LookAside);

			le->Irp = Irp; InsertTailList(&pdoData->PendingQueue, &le->Link);
			KeReleaseSpinLock(&pdoData->PendingQueueLock, PrevIrql);
		}
	}
}
else
{
	status = STATUS_PENDING;
	IoMarkIrpPending(Irp);

	KeAcquireSpinLock(&pdoData->PendingQueueLock, &PrevIrql);
	{
		IoSetCancelRoutine(Irp, Bus_CancelIrp);

		if (Irp->Cancel == TRUE)
		{
			IoSetCancelRoutine(Irp, NULL);
			KeReleaseSpinLock(&pdoData->PendingQueueLock, PrevIrql);

			Irp->IoStatus.Status = STATUS_CANCELLED;
			Irp->IoStatus.Information = 0;

			IoCompleteRequest(Irp, IO_NO_INCREMENT);
		}
		else
		{
			PPENDING_IRP le = ExAllocateFromNPagedLookasideList(&g_LookAside);

			le->Irp = Irp; InsertTailList(&pdoData->HoldingQueue, &le->Link);
			KeReleaseSpinLock(&pdoData->PendingQueueLock, PrevIrql);
		}
	}
}

Both sections look identical so what’s this check for? 🤔 Wait a minute:

&pdoData->HoldingQueue

What the hell are you? 😮 I’ve never seen you in my entire life, what’s this queue for?! Are you kidding me, how could I have missed that?

Dammit! Flash of genius! That’s the culprit right there; in ViGEm I simply checked for the transfer direction but didn’t distinguish the pipes which are mapped to different endpoints. So since both IRPs from different pipes ended up in the same queue reserved for input reports only, some packets got randomly (race condition too, yay 😖) sent to the wrong pipe. When you send a D-Pad Up state change, it would look like this on the wire:

0x00 0x14 0x01 ...

Which happens to be one of the “headset got inserted” control codes of the XUSB protocol 😂 Feeding two pipes from one queue also caused every second or even third submit request getting swallowed by the wrong pipe and therefore no state changes in XInput. What a beast!

Thankfully the fix was very easy; just introduce a second queue in ViGEm which holds the control interrupt pipe requests pending until device destruction, distinguish the pipes properly and everything is fine! 😀

’till next time!

ViGEm v1.10.1.0 released

Yo,

a stable release for real this time 😅 I reverted the dummy audio device pseudo-fix I blogged about in the past.

But we have some progress also; the axis value offset calculation in XnaGuardian was faulty due to my impressive math skills 😁 This is also fixed now, meaning that the values submitted via the override functions now get reflected 1:1 on the output like you’d expect.

’till next time!

ViGEm v1.10.0.0 faulty

Ey,

I did a lot of research and testing the last couple days and have to share some results. In the latest release I assumed I fixed the bug where a deaf XBOX 360 headset was appearing on the system when – for some odd reason – the Up button on the D-Pad was pressed.

After an awful lot of searching and reading various threads I came across the IRP_MN_QUERY_DEVICE_RELATIONS request, which seemed to be linked to my particular issue. Since ViGEm uses the WDF I assumed that this request was handled differently than in WDM, the driver model that the ancestor ScpVBus uses. Well, I was partially right; the request does indeed get handled per default by the KMDF internally so i decided to just intercept and fail the BusRelations Request in my driver which at first glance seemed like it did the trick! Sadly due to all the euphoria I slapped together a new build and released it without further testing 🙄

But in reality I wasn’t intentionally fixing the issue with my code like I thought; I just forgot to read all of the documentation which stated that you also need to call IoSkipCurrentIrpStackLocation(Irp) after pre-processing the IRP or else! Well, from what I understand this ruined the IRPs stack in a way that the request got left in a pending state which looked fine after you create and use the emulated device but goes horribly wrong once you try to cleanly unplug it.

Ok, so I know what I have to revert but now we aren’t any closer to a proper solution like we were prior to this release 😕 Further investigation followed. In this case it was once again time for a Wireshark session and a real physical X360 pad. Simply pressing and holding the Up button on the D-Pad really isn’t a challenge and we receive the following expected INTERRUPT_IN traffic:

0000   1b 00 10 10 d5 b1 86 b8 ff ff 00 00 00 00 09 00 
0010   01 01 00 02 00 81 01 14 00 00 00 00 14 01 00 00 
0020   00 5e f5 24 03 20 fa 4f 08 00 00 00 00 00 00    

The last twenty bytes represent the transfer buffer content of one input HID report (well, it isn’t HID-compatible but you know what I mean) which looks just fine. Although this doesn’t differ in any way like my emulation layer does the native pad won’t announce it’s headphone jack while the virtual one does. I’m baffled. And out of ideas. For the moment.

I’ll be back on this! 😠

ViGEm v1.10.0.0 released

I know the latest ViGEm release has bin out for quite some time but I have to drop a few notes on this one. Although I managed to fix an annoying long-term bug it seems I went a bit overboard from what users are reporting. I will investigate and – yet again – fix it and also try to provide some close-to-stable user-mode libraries for the published driver editions as well. Thanks again for the patience and continuous feedback and last but not least the slowly but steadily rising donations 😘

’till next time!