commit 32256494e97f2164916ddcd9236cfec87da0d8cc Author: Benjamin Höglinger-Stelzer Date: Sat Jan 21 01:45:10 2023 +0100 Initial commit diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..1ff0c42 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,63 @@ +############################################################################### +# Set default behavior to automatically normalize line endings. +############################################################################### +* text=auto + +############################################################################### +# Set default behavior for command prompt diff. +# +# This is need for earlier builds of msysgit that does not have it on by +# default for csharp files. +# Note: This is only used by command line +############################################################################### +#*.cs diff=csharp + +############################################################################### +# Set the merge driver for project and solution files +# +# Merging from the command prompt will add diff markers to the files if there +# are conflicts (Merging from VS is not affected by the settings below, in VS +# the diff markers are never inserted). Diff markers may cause the following +# file extensions to fail to load in VS. An alternative would be to treat +# these files as binary and thus will always conflict and require user +# intervention with every merge. To do so, just uncomment the entries below +############################################################################### +#*.sln merge=binary +#*.csproj merge=binary +#*.vbproj merge=binary +#*.vcxproj merge=binary +#*.vcproj merge=binary +#*.dbproj merge=binary +#*.fsproj merge=binary +#*.lsproj merge=binary +#*.wixproj merge=binary +#*.modelproj merge=binary +#*.sqlproj merge=binary +#*.wwaproj merge=binary + +############################################################################### +# behavior for image files +# +# image files are treated as binary by default. +############################################################################### +#*.jpg binary +#*.png binary +#*.gif binary + +############################################################################### +# diff behavior for common document formats +# +# Convert binary document formats to text before diffing them. This feature +# is only available from the command line. Turn it on by uncommenting the +# entries below. +############################################################################### +#*.doc diff=astextplain +#*.DOC diff=astextplain +#*.docx diff=astextplain +#*.DOCX diff=astextplain +#*.dot diff=astextplain +#*.DOT diff=astextplain +#*.pdf diff=astextplain +#*.PDF diff=astextplain +#*.rtf diff=astextplain +#*.RTF diff=astextplain diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..6bb8216 --- /dev/null +++ b/.gitignore @@ -0,0 +1,385 @@ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. +## +## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore + +# User-specific files +*.rsuser +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Mono auto generated files +mono_crash.* + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +[Ww][Ii][Nn]32/ +[Aa][Rr][Mm]/ +[Aa][Rr][Mm]64/ +bld/ +[Bb]in/ +[Oo]bj/ +[Oo]ut/ +[Ll]og/ +[Ll]ogs/ + +# Visual Studio 2015/2017 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# Visual Studio 2017 auto generated files +Generated\ Files/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUnit +*.VisualState.xml +TestResult.xml +nunit-*.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# Benchmark Results +BenchmarkDotNet.Artifacts/ + +# .NET Core +project.lock.json +project.fragment.lock.json +artifacts/ + +# ASP.NET Scaffolding +ScaffoldingReadMe.txt + +# StyleCop +StyleCopReport.xml + +# Files built by Visual Studio +*_i.c +*_p.c +*_h.h +*.ilk +*.meta +*.obj +*.iobj +*.pch +*.pdb +*.ipdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*_wpftmp.csproj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile +*.VC.db +*.VC.VC.opendb + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# Visual Studio Trace Files +*.e2e + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# AxoCover is a Code Coverage Tool +.axoCover/* +!.axoCover/settings.json + +# Coverlet is a free, cross platform Code Coverage Tool +coverage*.json +coverage*.xml +coverage*.info + +# Visual Studio code coverage results +*.coverage +*.coveragexml + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# Note: Comment the next line if you want to checkin your web deploy settings, +# but database connection strings (with potential passwords) will be unencrypted +*.pubxml +*.publishproj + +# Microsoft Azure Web App publish settings. Comment the next line if you want to +# checkin your Azure Web App publish settings, but sensitive information contained +# in these scripts will be unencrypted +PublishScripts/ + +# NuGet Packages +*.nupkg +# NuGet Symbol Packages +*.snupkg +# The packages folder can be ignored because of Package Restore +**/[Pp]ackages/* +# except build/, which is used as an MSBuild target. +!**/[Pp]ackages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/[Pp]ackages/repositories.config +# NuGet v3's project.json files produces more ignorable files +*.nuget.props +*.nuget.targets + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Windows Store app package directories and files +AppPackages/ +BundleArtifacts/ +Package.StoreAssociation.xml +_pkginfo.txt +*.appx +*.appxbundle +*.appxupload + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!?*.[Cc]ache/ + +# Others +ClientBin/ +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.jfm +*.pfx +*.publishsettings +orleans.codegen.cs + +# Including strong name files can present a security risk +# (https://github.com/github/gitignore/pull/2483#issue-259490424) +#*.snk + +# Since there are multiple workflows, uncomment next line to ignore bower_components +# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) +#bower_components/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm +ServiceFabricBackup/ +*.rptproj.bak + +# SQL Server files +*.mdf +*.ldf +*.ndf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings +*.rptproj.rsuser +*- [Bb]ackup.rdl +*- [Bb]ackup ([0-9]).rdl +*- [Bb]ackup ([0-9][0-9]).rdl + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat +node_modules/ + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio 6 auto-generated workspace file (contains which files were open etc.) +*.vbw + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +.paket/paket.exe +paket-files/ + +# FAKE - F# Make +.fake/ + +# CodeRush personal settings +.cr/personal + +# Python Tools for Visual Studio (PTVS) +__pycache__/ +*.pyc + +# Cake - Uncomment if you are using it +# tools/** +# !tools/packages.config + +# Tabs Studio +*.tss + +# Telerik's JustMock configuration file +*.jmconfig + +# BizTalk build output +*.btp.cs +*.btm.cs +*.odx.cs +*.xsd.cs + +# OpenCover UI analysis results +OpenCover/ + +# Azure Stream Analytics local run output +ASALocalRun/ + +# MSBuild Binary and Structured Log +*.binlog + +# NVidia Nsight GPU debugger configuration file +*.nvuser + +# MFractors (Xamarin productivity tool) working folder +.mfractor/ + +# Local History for Visual Studio +.localhistory/ + +# BeatPulse healthcheck temp database +healthchecksdb + +# Backup folder for Package Reference Convert tool in Visual Studio 2017 +MigrationBackup/ + +# Ionide (cross platform F# VS Code tools) working folder +.ionide/ + +# Fody - auto-generated XML schema +FodyWeavers.xsd +/TEMP/nssidswap/nssidswap.cat +/TEMP/nssidswap/nssidswap.inf +/TEMP/nssidswap/nssidswap.sys +/setup.inf +/setup.rpt +/v2.0.1.0/Signed_1152921505695688239.zip +/v2.0.1.0/disk1/nssidswap_x64.cab +/v2.0.1.0/drivers/nssidswap_x64/LICENSE +/v2.0.1.0/drivers/nssidswap_x64/nssidswap.cat +/v2.0.1.0/drivers/nssidswap_x64/nssidswap.inf +/v2.0.1.0/drivers/nssidswap_x64/nssidswap.man +/v2.0.1.0/drivers/nssidswap_x64/nssidswap.sys +/v2.0.1.0/nssidswap_unsigned_v2.0.1.0.zip +/v2.0.1.0/nssidswap_v2.0.1.0.zip +/v2.0.2.0/Signed_1152921505695690331.zip +/v2.0.2.0/disk1/nssidswap_x64.cab +/v2.0.2.0/drivers/nssidswap_x64/LICENSE +/v2.0.2.0/drivers/nssidswap_x64/nssidswap.cat +/v2.0.2.0/drivers/nssidswap_x64/nssidswap.inf +/v2.0.2.0/drivers/nssidswap_x64/nssidswap.man +/v2.0.2.0/drivers/nssidswap_x64/nssidswap.sys +/v2.0.2.0/nssidswap_v2.0.2.0.zip diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..72deb08 --- /dev/null +++ b/LICENSE @@ -0,0 +1,40 @@ + +nssudeaudio - USB Bus Class Filter Driver for fixing UDE compatibility with USBAUDIO.SYS + +Copyright (c) 2022-2023, Nefarius Software Solutions e.U. + All rights reserved. + + Redistribution and use in bytecode or binary forms, without modification, + are permitted provided that the following conditions are met: + + * Redistributions in bytecode or binary form must reproduce the above + copyright notice, this list of conditions and the following disclaimer + in the documentation and/or other materials provided with the + distribution. This includes repository READMEs for open-source projects + interfacing with this product, websites or in-application credits. + + * Neither the name of the nssudeaudio.sys nor the names of its contributors may + be used to endorse or promote products derived from or distributed + with this software without specific prior written permission. + + * Bundling or otherwise redistributing copies of binaries signed by + Nefarius Software Solutions e.U. is prohibited without specific prior + written permission. + + * Personal use for research, experiment, and testing for + the benefit of public knowledge, personal study, private + entertainment, hobby projects, amateur pursuits, or religious + observance, without any anticipated commercial application, + is use for a permitted purpose. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..bb5c828 --- /dev/null +++ b/README.md @@ -0,0 +1,7 @@ +# Class Filter Driver for fixing UDE compatibility with USBAUDIO.SYS + +Demo USB class filter driver to [fix UDE compatibility with USBAUDIO.SYS](https://fosstodon.org/@Nefarius/110089542325783941) in the lab. + +## Dependencies + +[DmfBusFilterExtension](https://git.nefarius.at/nefarius/DmfBusFilterExtension) diff --git a/nssudeaudio.sln b/nssudeaudio.sln new file mode 100644 index 0000000..064a898 --- /dev/null +++ b/nssudeaudio.sln @@ -0,0 +1,44 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.4.33122.133 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "nssudeaudiofix", "src\nssudeaudio.vcxproj", "{AE58270A-E8BC-4805-9A09-23E91D4A21D5}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{ABA785CC-A32A-48DE-9EDD-43BCB226530F}" + ProjectSection(SolutionItems) = preProject + LICENSE = LICENSE + nssidswap_ARM64.ddf = nssidswap_ARM64.ddf + nssidswap_x64.ddf = nssidswap_x64.ddf + nssidswap_x86.ddf = nssidswap_x86.ddf + README.md = README.md + EndProjectSection +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|ARM64 = Debug|ARM64 + Debug|x64 = Debug|x64 + Release|ARM64 = Release|ARM64 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {AE58270A-E8BC-4805-9A09-23E91D4A21D5}.Debug|ARM64.ActiveCfg = Debug|ARM64 + {AE58270A-E8BC-4805-9A09-23E91D4A21D5}.Debug|ARM64.Build.0 = Debug|ARM64 + {AE58270A-E8BC-4805-9A09-23E91D4A21D5}.Debug|ARM64.Deploy.0 = Debug|ARM64 + {AE58270A-E8BC-4805-9A09-23E91D4A21D5}.Debug|x64.ActiveCfg = Debug|x64 + {AE58270A-E8BC-4805-9A09-23E91D4A21D5}.Debug|x64.Build.0 = Debug|x64 + {AE58270A-E8BC-4805-9A09-23E91D4A21D5}.Debug|x64.Deploy.0 = Debug|x64 + {AE58270A-E8BC-4805-9A09-23E91D4A21D5}.Release|ARM64.ActiveCfg = Release|ARM64 + {AE58270A-E8BC-4805-9A09-23E91D4A21D5}.Release|ARM64.Build.0 = Release|ARM64 + {AE58270A-E8BC-4805-9A09-23E91D4A21D5}.Release|ARM64.Deploy.0 = Release|ARM64 + {AE58270A-E8BC-4805-9A09-23E91D4A21D5}.Release|x64.ActiveCfg = Release|x64 + {AE58270A-E8BC-4805-9A09-23E91D4A21D5}.Release|x64.Build.0 = Release|x64 + {AE58270A-E8BC-4805-9A09-23E91D4A21D5}.Release|x64.Deploy.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {471FE4BF-6C4E-4A41-B16F-0FFA7BD410B3} + EndGlobalSection +EndGlobal diff --git a/nssudeaudio.sln.DotSettings b/nssudeaudio.sln.DotSettings new file mode 100644 index 0000000..e77e487 --- /dev/null +++ b/nssudeaudio.sln.DotSettings @@ -0,0 +1,18 @@ + + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True + True \ No newline at end of file diff --git a/src/Device.c b/src/Device.c new file mode 100644 index 0000000..4087495 --- /dev/null +++ b/src/Device.c @@ -0,0 +1,370 @@ +/* + * nssudeaudio - USB Bus Class Filter Driver for fixing UDE compatibility with USBAUDIO.SYS + * + * Copyright (c) 2022-2023, Nefarius Software Solutions e.U. + * All rights reserved. + * + * Redistribution and use in bytecode or binary forms, without modification, + * are permitted provided that the following conditions are met: + * + * * Redistributions in bytecode or binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. This includes repository READMEs for open-source projects + * interfacing with this product, websites or in-application credits. + * + * * Neither the name of the nssudeaudio.sys nor the names of its contributors may + * be used to endorse or promote products derived from or distributed + * with this software without specific prior written permission. + * + * * Bundling or otherwise redistributing copies of binaries signed by + * Nefarius Software Solutions e.U. is prohibited without specific prior + * written permission. + * + * * Personal use for research, experiment, and testing for + * the benefit of public knowledge, personal study, private + * entertainment, hobby projects, amateur pursuits, or religious + * observance, without any anticipated commercial application, + * is use for a permitted purpose. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + + +#include "Driver.h" +#include "Device.tmh" + +#include + + +static +VOID +UsbInterfaceReference( + _In_ PVOID Context +) +{ + const PCHILD_DEVICE_CONTEXT pCtx = ChildDeviceGetContext(Context); + + pCtx->OriginalInterface.InterfaceReference(pCtx->OriginalInterface.BusContext); +} + +static +VOID +UsbInterfaceDereference( + _In_ PVOID Context +) +{ + const PCHILD_DEVICE_CONTEXT pCtx = ChildDeviceGetContext(Context); + + pCtx->OriginalInterface.InterfaceDereference(pCtx->OriginalInterface.BusContext); +} + +static +NTSTATUS +USB_BUSIFFN +UsbInterfaceQueryBusTime( + IN PVOID BusContext, + IN OUT PULONG CurrentUsbFrame +) +{ + FuncEntry(TRACE_DEVICE); + + const PCHILD_DEVICE_CONTEXT pCtx = ChildDeviceGetContext(BusContext); + + NTSTATUS status = pCtx->OriginalInterface.QueryBusTime( + pCtx->OriginalInterface.BusContext, + CurrentUsbFrame + ); + + if (CurrentUsbFrame) + { + TraceInformation( + TRACE_DEVICE, + "UsbInterfaceQueryBusTime.CurrentUsbFrame = %d", + *CurrentUsbFrame + ); + } + + // fake-succeed the call + if (CurrentUsbFrame && status == STATUS_NOT_SUPPORTED) + { + *CurrentUsbFrame = 0; + status = STATUS_SUCCESS; + } + + FuncExit(TRACE_DEVICE, "status=%!STATUS!", status); + + return status; +} + +static +NTSTATUS +USB_BUSIFFN +UsbInterfaceSubmitIsoOutUrb( + IN PVOID BusContext, + IN PURB Urb +) +{ + const PCHILD_DEVICE_CONTEXT pCtx = ChildDeviceGetContext(BusContext); + + return pCtx->OriginalInterface.SubmitIsoOutUrb( + pCtx->OriginalInterface.BusContext, + Urb + ); +} + +BOOLEAN +USB_BUSIFFN +UsbInterfaceIsDeviceHighSpeed( + IN PVOID BusContext +) +{ + const PCHILD_DEVICE_CONTEXT pCtx = ChildDeviceGetContext(BusContext); + + return pCtx->OriginalInterface.IsDeviceHighSpeed( + pCtx->OriginalInterface.BusContext + ); +} + +NTSTATUS +USB_BUSIFFN +UsbInterfaceQueryBusInformation( + IN PVOID BusContext, + IN ULONG Level, + IN OUT PVOID BusInformationBuffer, + IN OUT PULONG BusInformationBufferLength, + OUT PULONG BusInformationActualLength +) +{ + const PCHILD_DEVICE_CONTEXT pCtx = ChildDeviceGetContext(BusContext); + + return pCtx->OriginalInterface.QueryBusInformation( + pCtx->OriginalInterface.BusContext, + Level, + BusInformationBuffer, + BusInformationBufferLength, + BusInformationActualLength + ); +} + +VOID +USB_BUSIFFN +UsbInterfaceGetUSBDIVersion( + IN PVOID BusContext, + IN OUT PUSBD_VERSION_INFORMATION VersionInformation, + IN OUT PULONG HcdCapabilities +) +{ + const PCHILD_DEVICE_CONTEXT pCtx = ChildDeviceGetContext(BusContext); + + pCtx->OriginalInterface.GetUSBDIVersion( + pCtx->OriginalInterface.BusContext, + VersionInformation, + HcdCapabilities + ); +} + +NTSTATUS +EvtChildDeviceAdded( + _In_ WDFDEVICE Device, + _In_ DMFBUSCHILDDEVICE ChildDevice +) +{ + NTSTATUS status; + WDF_OBJECT_ATTRIBUTES attributes; + PCHILD_DEVICE_CONTEXT childContext = NULL; + + FuncEntry(TRACE_DEVICE); + + WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&attributes, CHILD_DEVICE_CONTEXT); + + if (NT_SUCCESS(status = WdfObjectAllocateContext( + ChildDevice, + &attributes, + (void**)&childContext + ))) + { + childContext->Parent = Device; + } + else + { + TraceError( + TRACE_DEVICE, + "WdfObjectAllocateContext failed with status %!STATUS!", + status + ); + EventWriteFailedWithNTStatus(NULL, __FUNCTION__, L"WdfObjectAllocateContext", status); + } + + FuncExit(TRACE_DEVICE, "status=%!STATUS!", status); + + return status; +} + +BOOLEAN +EvtChildDeviceQueryInterface( + _In_ DMFBUSCHILDDEVICE ChildDevice, + _In_ PIRP Irp +) +{ + FuncEntry(TRACE_DEVICE); + + const PCHILD_DEVICE_CONTEXT pCtx = ChildDeviceGetContext(ChildDevice); + const PIO_STACK_LOCATION currentStack = IoGetCurrentIrpStackLocation(Irp); + + if (KeGetCurrentIrql() > PASSIVE_LEVEL) + { + return FALSE; + } + + if (!pCtx) + { + TraceError( + TRACE_DEVICE, + "Child device context not yet allocated" + ); + return FALSE; + } + + // skip not interested + if (!IsEqualGUID(currentStack->Parameters.QueryInterface.InterfaceType, &USB_BUS_INTERFACE_USBDI_GUID) || + currentStack->Parameters.QueryInterface.Version != 1) + { + return FALSE; + } + + PUSB_BUS_INTERFACE_USBDI_V1 pUpperInterface = (PUSB_BUS_INTERFACE_USBDI_V1)currentStack->Parameters.QueryInterface. + Interface; + + TraceInformation( + TRACE_DEVICE, + "PRE QueryInterface.InterfaceType = %!GUID!", + currentStack->Parameters.QueryInterface.InterfaceType + ); + + TraceInformation( + TRACE_DEVICE, + "PRE QueryInterface.Version = %d", + currentStack->Parameters.QueryInterface.Version + ); + + KEVENT ke; + IO_STATUS_BLOCK iosb; + + RtlZeroMemory(&iosb, sizeof(IO_STATUS_BLOCK)); + + PUSB_BUS_INTERFACE_USBDI_V1 pUsbInterface = ExAllocatePool2( + PagedPool, + sizeof(USB_BUS_INTERFACE_USBDI_V1), + NSS_POOL_TAG + ); + + if (!pUsbInterface) + { + return FALSE; + } + + RtlZeroMemory(pUsbInterface, sizeof(USB_BUS_INTERFACE_USBDI_V1)); + + const PDEVICE_OBJECT deviceObject = DMF_BusFilter_WdmAttachedDeviceGet(ChildDevice); + + KeInitializeEvent(&ke, NotificationEvent, FALSE); + + const PIRP qiIrp = IoBuildSynchronousFsdRequest( + IRP_MJ_PNP, + deviceObject, + NULL, + 0, + NULL, + &ke, + &iosb + ); + qiIrp->IoStatus.Status = STATUS_NOT_SUPPORTED; // required initialize + qiIrp->IoStatus.Information = 0; + + const PIO_STACK_LOCATION qiStack = IoGetNextIrpStackLocation(qiIrp); + + qiStack->MajorFunction = IRP_MJ_PNP; + qiStack->MinorFunction = IRP_MN_QUERY_INTERFACE; + + qiStack->Parameters.QueryInterface.InterfaceType = currentStack->Parameters.QueryInterface.InterfaceType; + qiStack->Parameters.QueryInterface.Version = currentStack->Parameters.QueryInterface.Version; + qiStack->Parameters.QueryInterface.Size = currentStack->Parameters.QueryInterface.Size; + qiStack->Parameters.QueryInterface.Interface = (PINTERFACE)pUsbInterface; + qiStack->Parameters.QueryInterface.InterfaceSpecificData = NULL; + + const NTSTATUS status = IoCallDriver(deviceObject, qiIrp); + + if (status == STATUS_PENDING) + { + KeWaitForSingleObject(&ke, Executive, KernelMode, FALSE, NULL); + } + + BOOLEAN ret = FALSE; + + if (NT_SUCCESS(qiIrp->IoStatus.Status)) + { + TraceInformation( + TRACE_DEVICE, + "IoCallDriver succeeded with status %!STATUS!", + qiIrp->IoStatus.Status + ); + + TraceInformation( + TRACE_DEVICE, + "POST usbInterface.Version = %d", + pUsbInterface->Version + ); + + TraceInformation( + TRACE_DEVICE, + "POST usbInterface.Size = %d", + pUsbInterface->Size + ); + + pCtx->OriginalInterface.Size = pUpperInterface->Size = pUsbInterface->Size; + pCtx->OriginalInterface.Version = pUpperInterface->Version = pUsbInterface->Version; + + // save original functions + pCtx->OriginalInterface.InterfaceReference = pUsbInterface->InterfaceReference; + pCtx->OriginalInterface.InterfaceDereference = pUsbInterface->InterfaceDereference; + pCtx->OriginalInterface.GetUSBDIVersion = pUsbInterface->GetUSBDIVersion; + pCtx->OriginalInterface.SubmitIsoOutUrb = pUsbInterface->SubmitIsoOutUrb; + pCtx->OriginalInterface.QueryBusInformation = pUsbInterface->QueryBusInformation; + pCtx->OriginalInterface.IsDeviceHighSpeed = pUsbInterface->IsDeviceHighSpeed; + pCtx->OriginalInterface.QueryBusTime = pUsbInterface->QueryBusTime; + + // report proxy functions + pUpperInterface->InterfaceReference = UsbInterfaceReference; + pUpperInterface->InterfaceDereference = UsbInterfaceDereference; + pUpperInterface->GetUSBDIVersion = UsbInterfaceGetUSBDIVersion; + pUpperInterface->SubmitIsoOutUrb = UsbInterfaceSubmitIsoOutUrb; + pUpperInterface->QueryBusInformation = UsbInterfaceQueryBusInformation; + pUpperInterface->IsDeviceHighSpeed = UsbInterfaceIsDeviceHighSpeed; + pUpperInterface->QueryBusTime = UsbInterfaceQueryBusTime; + + // keep original bus context + pCtx->OriginalInterface.BusContext = pUsbInterface->BusContext; + // replace context object so we get it in our hooked function + pUpperInterface->BusContext = ChildDevice; + + Irp->IoStatus.Status = STATUS_SUCCESS; + // causes the module to complete the request + ret = TRUE; + } + + ExFreePoolWithTag(pUsbInterface, NSS_POOL_TAG); + + FuncExitNoReturn(TRACE_DEVICE); + return ret; +} diff --git a/src/Device.h b/src/Device.h new file mode 100644 index 0000000..c10fed5 --- /dev/null +++ b/src/Device.h @@ -0,0 +1,67 @@ +/* + * nssudeaudio - USB Bus Class Filter Driver for fixing UDE compatibility with USBAUDIO.SYS + * + * Copyright (c) 2022-2023, Nefarius Software Solutions e.U. + * All rights reserved. + * + * Redistribution and use in bytecode or binary forms, without modification, + * are permitted provided that the following conditions are met: + * + * * Redistributions in bytecode or binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. This includes repository READMEs for open-source projects + * interfacing with this product, websites or in-application credits. + * + * * Neither the name of the nssudeaudio.sys nor the names of its contributors may + * be used to endorse or promote products derived from or distributed + * with this software without specific prior written permission. + * + * * Bundling or otherwise redistributing copies of binaries signed by + * Nefarius Software Solutions e.U. is prohibited without specific prior + * written permission. + * + * * Personal use for research, experiment, and testing for + * the benefit of public knowledge, personal study, private + * entertainment, hobby projects, amateur pursuits, or religious + * observance, without any anticipated commercial application, + * is use for a permitted purpose. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + + +#pragma once +#include + +// +// Child device context +// +typedef struct _CHILD_DEVICE_CONTEXT +{ + WDFDEVICE Parent; + + USB_BUS_INTERFACE_USBDI_V1 OriginalInterface; + +} CHILD_DEVICE_CONTEXT, * PCHILD_DEVICE_CONTEXT; + +WDF_DECLARE_CONTEXT_TYPE_WITH_NAME(CHILD_DEVICE_CONTEXT, ChildDeviceGetContext) + + +// +// Bus filter module callbacks +// + +EVT_DMF_BusFilter_DeviceAdd EvtChildDeviceAdded; + +EVT_DMF_BusFilter_DeviceQueryInterface EvtChildDeviceQueryInterface; diff --git a/src/Dmf.props b/src/Dmf.props new file mode 100644 index 0000000..e010b1d --- /dev/null +++ b/src/Dmf.props @@ -0,0 +1,20 @@ + + + + + + <_PropertySheetDisplayName>Driver Module Framework + + $(SolutionDir)..\ + + + + $(DmfRootPath)\DMF\Modules.Library;$(DmfRootPath)\DMF\Modules.Template;$(DmfRootPath)\DMF\Modules.Library.Tests;$(DmfRootPath)\DMF\Framework;$(IntDir);%(AdditionalIncludeDirectories) + + + $(DmfRootPath)\$(Configuration)\$(PlatformName)\lib\DmfK\DmfK.lib;$(DmfRootPath)\$(Configuration)\$(PlatformName)\individual_libs\DmfKModules.Template\DmfKModules.Template.lib;%(AdditionalDependencies); + $(DmfRootPath)\$(Configuration)\$(PlatformName)\lib\DmfU\DmfU.lib;$(DmfRootPath)\$(Configuration)\$(PlatformName)\individual_libs\DmfUModules.Template\DmfUModules.Template.lib;%(AdditionalDependencies); + + + + diff --git a/src/DmfBusFilterExtension.props b/src/DmfBusFilterExtension.props new file mode 100644 index 0000000..ce98705 --- /dev/null +++ b/src/DmfBusFilterExtension.props @@ -0,0 +1,18 @@ + + + + + + <_PropertySheetDisplayName>DMF Bus Filter Extension + $(SolutionDir)..\ + + + + $(DmfBusFilterExtensionRootPath)\src;$(IntDir);%(AdditionalIncludeDirectories) + + + $(DmfBusFilterExtensionRootPath)\bin\$(Configuration)\$(PlatformName)\DmfBusFilterExtension.lib;%(AdditionalDependencies); + + + + diff --git a/src/Driver.c b/src/Driver.c new file mode 100644 index 0000000..4bd9246 --- /dev/null +++ b/src/Driver.c @@ -0,0 +1,149 @@ +/* + * nssudeaudio - USB Bus Class Filter Driver for fixing UDE compatibility with USBAUDIO.SYS + * + * Copyright (c) 2022-2023, Nefarius Software Solutions e.U. + * All rights reserved. + * + * Redistribution and use in bytecode or binary forms, without modification, + * are permitted provided that the following conditions are met: + * + * * Redistributions in bytecode or binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. This includes repository READMEs for open-source projects + * interfacing with this product, websites or in-application credits. + * + * * Neither the name of the nssudeaudio.sys nor the names of its contributors may + * be used to endorse or promote products derived from or distributed + * with this software without specific prior written permission. + * + * * Bundling or otherwise redistributing copies of binaries signed by + * Nefarius Software Solutions e.U. is prohibited without specific prior + * written permission. + * + * * Personal use for research, experiment, and testing for + * the benefit of public knowledge, personal study, private + * entertainment, hobby projects, amateur pursuits, or religious + * observance, without any anticipated commercial application, + * is use for a permitted purpose. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + + +#include "Driver.h" +#include "Driver.tmh" + + +#pragma code_seg("INIT") +NTSTATUS +DriverEntry( + _In_ PDRIVER_OBJECT DriverObject, + _In_ PUNICODE_STRING RegistryPath +) +{ + WPP_INIT_TRACING(DriverObject, RegistryPath); + + EventRegisterNefarius_USB_Bus_Class_Filter_Driver_for_fixing_UDE_compatibility_with_USBAUDIO_SYS(); + + FuncEntry(TRACE_DRIVER); + + WDFDRIVER driver = NULL; + WDF_OBJECT_ATTRIBUTES attributes; + WDF_OBJECT_ATTRIBUTES_INIT(&attributes); + attributes.EvtCleanupCallback = EvtDriverContextCleanup; + + WDF_DRIVER_CONFIG config; + WDF_DRIVER_CONFIG_INIT(&config, + DMF_BusFilter_DeviceAdd // provided by module + ); + + NTSTATUS status = WdfDriverCreate( + DriverObject, + RegistryPath, + &attributes, + &config, + &driver + ); + + if (!NT_SUCCESS(status)) + { + TraceError( + TRACE_DRIVER, + "WdfDriverCreate failed %!STATUS!", + status + ); + EventWriteFailedWithNTStatus(NULL, __FUNCTION__, L"WdfDriverCreate", status); + goto errorExit; + } + + DMF_BusFilter_CONFIG filterConfig; + + DMF_BusFilter_CONFIG_INIT(&filterConfig, DriverObject); + + filterConfig.DeviceType = FILE_DEVICE_BUS_EXTENDER; + + filterConfig.EvtDeviceAdd = EvtChildDeviceAdded; + filterConfig.EvtDeviceQueryInterface = EvtChildDeviceQueryInterface; + + status = DMF_BusFilter_Initialize(&filterConfig); + + if (!NT_SUCCESS(status)) + { + TraceEvents( + TRACE_LEVEL_ERROR, + TRACE_DRIVER, + "DMF_BusFilter_Initialize failed %!STATUS!", + status + ); + EventWriteFailedWithNTStatus(NULL, __FUNCTION__, L"DMF_BusFilter_Initialize", status); + goto errorExit; + } + + EventWriteStartEvent(NULL, DriverObject, status); + + FuncExit(TRACE_DRIVER, "status=%!STATUS!", status); + + return status; + +errorExit: + EventUnregisterNefarius_USB_Bus_Class_Filter_Driver_for_fixing_UDE_compatibility_with_USBAUDIO_SYS(); + WPP_CLEANUP(DriverObject); + return status; +} +#pragma code_seg() + +// +// Called on driver object disposal +// +#pragma code_seg("PAGED") +VOID +EvtDriverContextCleanup( + _In_ WDFOBJECT DriverObject +) + +{ + PAGED_CODE(); + + FuncEntry(TRACE_DRIVER); + + EventWriteUnloadEvent(NULL, DriverObject); + + EventUnregisterNefarius_USB_Bus_Class_Filter_Driver_for_fixing_UDE_compatibility_with_USBAUDIO_SYS(); + + // + // Stop WPP Tracing + // + WPP_CLEANUP(WdfDriverWdmGetDriverObject((WDFDRIVER)DriverObject)); +} +#pragma code_seg() diff --git a/src/Driver.h b/src/Driver.h new file mode 100644 index 0000000..3f96458 --- /dev/null +++ b/src/Driver.h @@ -0,0 +1,72 @@ +/* + * nssudeaudio - USB Bus Class Filter Driver for fixing UDE compatibility with USBAUDIO.SYS + * + * Copyright (c) 2022-2023, Nefarius Software Solutions e.U. + * All rights reserved. + * + * Redistribution and use in bytecode or binary forms, without modification, + * are permitted provided that the following conditions are met: + * + * * Redistributions in bytecode or binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. This includes repository READMEs for open-source projects + * interfacing with this product, websites or in-application credits. + * + * * Neither the name of the nssudeaudio.sys nor the names of its contributors may + * be used to endorse or promote products derived from or distributed + * with this software without specific prior written permission. + * + * * Bundling or otherwise redistributing copies of binaries signed by + * Nefarius Software Solutions e.U. is prohibited without specific prior + * written permission. + * + * * Personal use for research, experiment, and testing for + * the benefit of public knowledge, personal study, private + * entertainment, hobby projects, amateur pursuits, or religious + * observance, without any anticipated commercial application, + * is use for a permitted purpose. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + + +#pragma once + +#pragma warning(disable:5040) +#include +#pragma warning(default:5040) + +#include + +#include +#include +#define NTSTRSAFE_LIB +#include +#include +#include +#include + +#include "nssudeaudioETW.h" + +#include "Trace.h" +#include "Util.h" +#include "Device.h" + +#define MAX_ID_CHARS 200 +#define MAX_ID_SIZE (MAX_ID_CHARS * sizeof(WCHAR)) +#define NSS_POOL_TAG 'uSSN' + +DRIVER_INITIALIZE DriverEntry; + +EVT_WDF_OBJECT_CONTEXT_CLEANUP EvtDriverContextCleanup; diff --git a/src/Trace.h b/src/Trace.h new file mode 100644 index 0000000..b5a3fbc --- /dev/null +++ b/src/Trace.h @@ -0,0 +1,62 @@ +#pragma once + +// +// Define the tracing flags. +// +// Tracing GUID - {DA6816E8-ED3C-4593-91A1-2CE2DF70184C} +// + +#define WPP_CONTROL_GUIDS \ + WPP_DEFINE_CONTROL_GUID( \ + nssudeaudioTraceGuid, (da6816e8,ed3c,4593,91a1,2ce2df70184c), \ + \ + WPP_DEFINE_BIT(MYDRIVER_ALL_INFO) \ + WPP_DEFINE_BIT(DMF_TRACE) \ + WPP_DEFINE_BIT(TRACE_DRIVER) \ + WPP_DEFINE_BIT(TRACE_DEVICE) \ + WPP_DEFINE_BIT(TRACE_UTIL) \ + ) + +#define WPP_FLAG_LEVEL_LOGGER(flag, level) \ + WPP_LEVEL_LOGGER(flag) + +#define WPP_FLAG_LEVEL_ENABLED(flag, level) \ + (WPP_LEVEL_ENABLED(flag) && \ + WPP_CONTROL(WPP_BIT_ ## flag).Level >= level) + +#define WPP_LEVEL_FLAGS_LOGGER(lvl,flags) \ + WPP_LEVEL_LOGGER(flags) + +#define WPP_LEVEL_FLAGS_ENABLED(lvl, flags) \ + (WPP_LEVEL_ENABLED(flags) && WPP_CONTROL(WPP_BIT_ ## flags).Level >= lvl) + +// +// This comment block is scanned by the trace preprocessor to define our +// Trace function. +// +// USEPREFIX and USESUFFIX strip all trailing whitespace, so we need to surround +// FuncExit messages with brackets +// +// begin_wpp config +// FUNC Trace{FLAG=MYDRIVER_ALL_INFO}(LEVEL, MSG, ...); +// FUNC TraceEvents(LEVEL, FLAGS, MSG, ...); +// FUNC FuncEntry{LEVEL=TRACE_LEVEL_VERBOSE}(FLAGS); +// FUNC FuncEntryArguments{LEVEL=TRACE_LEVEL_VERBOSE}(FLAGS, MSG, ...); +// FUNC FuncExit{LEVEL=TRACE_LEVEL_VERBOSE}(FLAGS, MSG, ...); +// FUNC FuncExitVoid{LEVEL=TRACE_LEVEL_VERBOSE}(FLAGS); +// FUNC TraceError{LEVEL=TRACE_LEVEL_ERROR}(FLAGS, MSG, ...); +// FUNC TraceInformation{LEVEL=TRACE_LEVEL_INFORMATION}(FLAGS, MSG, ...); +// FUNC TraceVerbose{LEVEL=TRACE_LEVEL_VERBOSE}(FLAGS, MSG, ...); +// FUNC FuncExitNoReturn{LEVEL=TRACE_LEVEL_VERBOSE}(FLAGS); +// USEPREFIX(FuncEntry, "%!STDPREFIX! [%!FUNC!] --> Entry"); +// USEPREFIX(FuncEntryArguments, "%!STDPREFIX! [%!FUNC!] --> Entry <"); +// USEPREFIX(FuncExit, "%!STDPREFIX! [%!FUNC!] <-- Exit <"); +// USESUFFIX(FuncExit, ">"); +// USEPREFIX(FuncExitVoid, "%!STDPREFIX! [%!FUNC!] <-- Exit"); +// USEPREFIX(TraceError, "%!STDPREFIX! [%!FUNC!] ERROR:"); +// USEPREFIX(TraceEvents, "%!STDPREFIX! [%!FUNC!] "); +// USEPREFIX(TraceInformation, "%!STDPREFIX! [%!FUNC!] "); +// USEPREFIX(TraceVerbose, "%!STDPREFIX! [%!FUNC!] "); +// USEPREFIX(FuncExitNoReturn, "%!STDPREFIX! [%!FUNC!] <--"); +// end_wpp +// \ No newline at end of file diff --git a/src/Util.c b/src/Util.c new file mode 100644 index 0000000..a2d0b00 --- /dev/null +++ b/src/Util.c @@ -0,0 +1,313 @@ +/* + * nssudeaudio - USB Bus Class Filter Driver for fixing UDE compatibility with USBAUDIO.SYS + * + * Copyright (c) 2022-2023, Nefarius Software Solutions e.U. + * All rights reserved. + * + * Redistribution and use in bytecode or binary forms, without modification, + * are permitted provided that the following conditions are met: + * + * * Redistributions in bytecode or binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. This includes repository READMEs for open-source projects + * interfacing with this product, websites or in-application credits. + * + * * Neither the name of the nssudeaudio.sys nor the names of its contributors may + * be used to endorse or promote products derived from or distributed + * with this software without specific prior written permission. + * + * * Bundling or otherwise redistributing copies of binaries signed by + * Nefarius Software Solutions e.U. is prohibited without specific prior + * written permission. + * + * * Personal use for research, experiment, and testing for + * the benefit of public knowledge, personal study, private + * entertainment, hobby projects, amateur pursuits, or religious + * observance, without any anticipated commercial application, + * is use for a permitted purpose. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + + +#include "Driver.h" +#include "Util.tmh" + + + // + // Set a device property on the provided PDO + // +#pragma code_seg("PAGE") +_IRQL_requires_max_(PASSIVE_LEVEL) +NTSTATUS +SetDeviceProperty( + _In_ DMFBUSCHILDDEVICE Device, + _In_ const DEVPROPKEY* PropertyKey, + _In_ DEVPROPTYPE PropertyType, + _In_ PWSTR Buffer +) +{ + FuncEntry(TRACE_UTIL); + + NTSTATUS status = STATUS_SUCCESS; + const PDEVICE_OBJECT pdo = DMF_BusFilter_WdmPhysicalDeviceGet(Device); + + PAGED_CODE(); + + do { + if (!pdo) + { + TraceError( + TRACE_UTIL, + "Failed to get PDO device object" + ); + status = STATUS_INVALID_DEVICE_REQUEST; + break; + } + + size_t numChars = 0; + WCHAR* retval = (WCHAR*)Buffer; + WCHAR* szIter = (WCHAR*)Buffer; + + switch (PropertyType) + { + case DEVPROP_TYPE_STRING_LIST: + + while (szIter && *szIter && numChars + wcslen(szIter) + 2 <= MAX_ID_SIZE) + { + numChars += wcslen(szIter) + 1; + szIter += wcslen(szIter) + 1; + } + + numChars++; + + break; + case DEVPROP_TYPE_STRING: + + numChars = wcslen(retval) + 1; + + break; + default: + status = STATUS_NOT_SUPPORTED; + break; + } + + if (!NT_SUCCESS(status)) + { + break; + } + + status = IoSetDevicePropertyData( + pdo, + PropertyKey, + LOCALE_NEUTRAL, + 0, + PropertyType, + (ULONG)numChars * sizeof(WCHAR), + (PVOID)Buffer + ); + } while (FALSE); + + FuncExit(TRACE_UTIL, "status=%!STATUS!", status); + + return status; +} +#pragma code_seg() + +// +// Helper function to query device identifiers +// +#pragma code_seg("PAGE") +_IRQL_requires_max_(PASSIVE_LEVEL) +NTSTATUS BusQueryId( + PDEVICE_OBJECT DeviceObject, + BUS_QUERY_ID_TYPE IdType, + PWCHAR Buffer, + ULONG BufferLength +) +{ + NTSTATUS status; + KEVENT ke; + IO_STATUS_BLOCK iosb; + PIRP irp; + PIO_STACK_LOCATION stack; + + FuncEntry(TRACE_UTIL); + + PAGED_CODE(); + + const ULONG maxNumChars = BufferLength / sizeof(WCHAR); + + KeInitializeEvent(&ke, NotificationEvent, FALSE); + + RtlZeroMemory(&iosb, sizeof(IO_STATUS_BLOCK)); + irp = IoBuildSynchronousFsdRequest( + IRP_MJ_PNP, + DeviceObject, + NULL, + 0, + NULL, + &ke, + &iosb + ); + irp->IoStatus.Status = STATUS_NOT_SUPPORTED; // required initialize + stack = IoGetNextIrpStackLocation(irp); + stack->MinorFunction = IRP_MN_QUERY_ID; + stack->Parameters.QueryId.IdType = IdType; + + status = IoCallDriver(DeviceObject, irp); + + if (status == STATUS_PENDING) + { + // + // Normally, we will not hit this, because QueryId should not be an expensive operation + // + KeWaitForSingleObject(&ke, Executive, KernelMode, FALSE, NULL); + } + + if (NT_SUCCESS(status)) + { + if (iosb.Information) + { + size_t length = 0; + WCHAR* retval = (WCHAR*)iosb.Information; + WCHAR* szIter = (WCHAR*)iosb.Information; + + switch (IdType) // NOLINT(clang-diagnostic-switch-enum) + { + // + // Double-null terminated multi-strings + // + case BusQueryHardwareIDs: + case BusQueryCompatibleIDs: + + // + // Calculate size in characters by finding last double-NULL characters + // + while (szIter && *szIter && length + wcslen(szIter) + 2 <= maxNumChars) + { + length += wcslen(szIter) + 1; + szIter += wcslen(szIter) + 1; + } + + length++; + + RtlCopyMemory(Buffer, retval, length * sizeof(WCHAR)); + ExFreePool(retval); // IRP_MN_QUERY_ID requires this + break; + // + // Single line string + // + default: + if (wcslen(retval) + 1 > maxNumChars) + { + ExFreePool(retval); // IRP_MN_QUERY_ID requires this + status = STATUS_BUFFER_TOO_SMALL; + break; + } + + RtlStringCchCopyNW(Buffer, maxNumChars, retval, wcslen(retval) + 1); + ExFreePool(retval); // IRP_MN_QUERY_ID requires this + break; + } + } + else + { + status = STATUS_INVALID_DEVICE_REQUEST; + } + } + + FuncExit(TRACE_UTIL, "status=%!STATUS!", status); + + return status; +} +#pragma code_seg() + +// +// Retrieves the device instance ID of the PDO +// +#pragma code_seg("PAGE") +_IRQL_requires_max_(PASSIVE_LEVEL) +NTSTATUS +GetDeviceInstanceIdProperty( + _In_ DMFBUSCHILDDEVICE ChildDevice, + _Out_ WDFMEMORY* Value +) +{ + NTSTATUS status = STATUS_NOT_IMPLEMENTED; + WCHAR buffer[MAX_ID_CHARS]; + ULONG requiredSize = 0; + DEVPROPTYPE type = 0; + WDF_OBJECT_ATTRIBUTES attributes; + PUCHAR memBuffer = NULL; + + FuncEntry(TRACE_UTIL); + + PAGED_CODE(); + + PDEVICE_OBJECT pdo = DMF_BusFilter_WdmPhysicalDeviceGet(ChildDevice); + + do + { + if (!NT_SUCCESS(status = IoGetDevicePropertyData( + pdo, + &DEVPKEY_Device_InstanceId, + LOCALE_NEUTRAL, + 0, + MAX_ID_CHARS, + buffer, + &requiredSize, + &type + ))) + { + TraceError( + TRACE_UTIL, + "IoGetDevicePropertyData failed with status %!STATUS!", + status + ); + break; + } + + WDF_OBJECT_ATTRIBUTES_INIT(&attributes); + attributes.ParentObject = ChildDevice; + + // + // Create context memory + // + if (!NT_SUCCESS(status = WdfMemoryCreate( + &attributes, + NonPagedPoolNx, + NSS_POOL_TAG, + requiredSize, + Value, + (void**)&memBuffer + ))) + { + TraceError( + TRACE_UTIL, + "WdfMemoryCreate failed with status %!STATUS!", + status + ); + break; + } + + RtlCopyMemory(memBuffer, buffer, requiredSize); + + } while (FALSE); + + FuncExit(TRACE_UTIL, "status=%!STATUS!", status); + + return status; +} +#pragma code_seg() diff --git a/src/Util.h b/src/Util.h new file mode 100644 index 0000000..74f5134 --- /dev/null +++ b/src/Util.h @@ -0,0 +1,69 @@ +/* + * nssudeaudio - USB Bus Class Filter Driver for fixing UDE compatibility with USBAUDIO.SYS + * + * Copyright (c) 2022-2023, Nefarius Software Solutions e.U. + * All rights reserved. + * + * Redistribution and use in bytecode or binary forms, without modification, + * are permitted provided that the following conditions are met: + * + * * Redistributions in bytecode or binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. This includes repository READMEs for open-source projects + * interfacing with this product, websites or in-application credits. + * + * * Neither the name of the nssudeaudio.sys nor the names of its contributors may + * be used to endorse or promote products derived from or distributed + * with this software without specific prior written permission. + * + * * Bundling or otherwise redistributing copies of binaries signed by + * Nefarius Software Solutions e.U. is prohibited without specific prior + * written permission. + * + * * Personal use for research, experiment, and testing for + * the benefit of public knowledge, personal study, private + * entertainment, hobby projects, amateur pursuits, or religious + * observance, without any anticipated commercial application, + * is use for a permitted purpose. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + + +#pragma once + +_IRQL_requires_max_(PASSIVE_LEVEL) +NTSTATUS +SetDeviceProperty( + _In_ DMFBUSCHILDDEVICE Device, + _In_ const DEVPROPKEY* PropertyKey, + _In_ DEVPROPTYPE PropertyType, + _In_ PWSTR Buffer +); + +_IRQL_requires_max_(PASSIVE_LEVEL) +NTSTATUS +BusQueryId( + PDEVICE_OBJECT DeviceObject, + BUS_QUERY_ID_TYPE IdType, + PWCHAR Buffer, + ULONG BufferLength +); + +_IRQL_requires_max_(PASSIVE_LEVEL) +NTSTATUS +GetDeviceInstanceIdProperty( + _In_ DMFBUSCHILDDEVICE ChildDevice, + _Out_ WDFMEMORY* Value +); diff --git a/src/nssudeaudio.inf b/src/nssudeaudio.inf new file mode 100644 index 0000000..92889fc --- /dev/null +++ b/src/nssudeaudio.inf @@ -0,0 +1,62 @@ +; +; Nefarius USB Bus Class Filter Driver for fixing UDE compatibility with USBAUDIO.SYS +; + +[Version] +Signature = "$WINDOWS NT$" +Class = USB +ClassGuid = {36FC9E60-C465-11CF-8056-444553540000} +DriverPackageType = ClassFilter +Provider = %ManufacturerName% +CatalogFile = nssudeaudio.cat +DriverVer = +PnpLockdown = 1 + + +[SourceDisksNames] +1 = %DiskName%,,,"" + +[SourceDisksFiles] +nssudeaudio.sys = 1,, + +[DestinationDirs] +DefaultDestDir = 12 +nssudeaudio.DriverFiles = 12 + +[DefaultInstall.NT$ARCH$] +OptionDesc = %nssudeaudioServiceDesc% +CopyFiles = nssudeaudio.DriverFiles +AddReg = nssudeaudio_AddReg + +[DefaultUninstall.NT$ARCH$] +LegacyUninstall = 1 +DelFiles = @nssudeaudio.sys +DelReg = nssudeaudio_DelReg + +[nssudeaudio_AddReg] +;Add nssudeaudio to UpperFilters +HKLM, System\CurrentControlSet\Control\Class\{36FC9E60-C465-11CF-8056-444553540000}, UpperFilters, 0x00010008, nssudeaudio + +[nssudeaudio_DelReg] +;Delete nssudeaudio from UpperFilters +HKLM, System\CurrentControlSet\Control\Class\{36FC9E60-C465-11CF-8056-444553540000}, UpperFilters, 0x00018002, nssudeaudio + +[nssudeaudio.DriverFiles] +nssudeaudio.sys + +[DefaultInstall.NT$ARCH$.Services] +AddService = %nssudeaudioServiceName%,,nssudeaudio.Service + +[nssudeaudio.Service] +DisplayName = %nssudeaudioServiceName% +Description = %nssudeaudioServiceDesc% +ServiceBinary = %12%\nssudeaudio.sys +ServiceType = 1 ; SERVICE_KERNEL_DRIVER +StartType = 3 ; SERVICE_DEMAND_START +ErrorControl = 1 ; SERVICE_ERROR_NORMAL + +[Strings] +ManufacturerName = "Nefarius Software Solutions e.U." +DiskName = "nssudeaudio Installation Disk" +nssudeaudioServiceDesc = "Nefarius USB Bus Class Filter Driver for fixing UDE compatibility with USBAUDIO.SYS" +nssudeaudioServiceName = "nssudeaudio" diff --git a/src/nssudeaudio.man b/src/nssudeaudio.man new file mode 100644 index 0000000..a34bbd9 --- /dev/null +++ b/src/nssudeaudio.man @@ -0,0 +1,44 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/nssudeaudio.rc b/src/nssudeaudio.rc new file mode 100644 index 0000000..3cbac44 --- /dev/null +++ b/src/nssudeaudio.rc @@ -0,0 +1,49 @@ +// +// Include the necessary resources +// +#include +#include + +#ifdef RC_INVOKED + +// +// Set up debug information +// +#if DBG +#define VER_DBG VS_FF_DEBUG +#else +#define VER_DBG 0 +#endif + +// ------- version info ------------------------------------------------------- + +VS_VERSION_INFO VERSIONINFO +FILEVERSION 2,0,2,0 +PRODUCTVERSION 2,0,2,0 +FILEFLAGSMASK VS_FFI_FILEFLAGSMASK +FILEFLAGS VER_DBG +FILEOS VOS_NT +FILETYPE VFT_DRV +FILESUBTYPE VFT2_DRV_SYSTEM +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" + BEGIN + VALUE "Comments", "Nefarius USB Devices filter driver" + VALUE "CompanyName", "Nefarius Software Solutions e.U." + VALUE "FileDescription", "Nefarius USB Devices filter driver" + VALUE "FileVersion", "2.0.2.0" + VALUE "InternalName", "Nefarius USB Devices filter driver" + VALUE "LegalCopyright", "(C) 2022 Nefarius Software Solutions e.U." + VALUE "OriginalFilename", "nssudeaudio.sys" + VALUE "ProductName", "Nefarius USB Devices filter driver" + VALUE "ProductVersion", "2.0.2.0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x0409,1200 + END +END +#endif \ No newline at end of file diff --git a/src/nssudeaudio.vcxproj b/src/nssudeaudio.vcxproj new file mode 100644 index 0000000..5cc4460 --- /dev/null +++ b/src/nssudeaudio.vcxproj @@ -0,0 +1,206 @@ + + + + + Debug + x64 + + + Release + x64 + + + Debug + ARM64 + + + Release + ARM64 + + + + {AE58270A-E8BC-4805-9A09-23E91D4A21D5} + {1bc93793-694f-48fe-9372-81e2b05556fd} + v4.5 + 12.0 + Debug + x64 + nssudeaudio + 10.0.22621.0 + + + + Windows10 + true + WindowsKernelModeDriver10.0 + Driver + KMDF + Universal + + + Windows10 + false + WindowsKernelModeDriver10.0 + Driver + KMDF + Universal + Off + + + Windows10 + true + WindowsKernelModeDriver10.0 + Driver + KMDF + Universal + + + Windows10 + false + WindowsKernelModeDriver10.0 + Driver + KMDF + Universal + Off + + + + + + + + + + + + + DbgengKernelDebugger + true + + + DbgengKernelDebugger + true + true + $(SolutionDir)bin\$(DDKPlatform)\ + + + DbgengKernelDebugger + true + + + DbgengKernelDebugger + true + true + $(SolutionDir)bin\$(DDKPlatform)\ + + + + sha256 + + + true + true + Trace.h + + + wdmsec.lib;$(DmfRootPath)\$(Configuration)\$(PlatformName)\lib\DmfK\DmfK.lib;$(DmfRootPath)\$(Configuration)\$(PlatformName)\individual_libs\DmfKModules.Template\DmfKModules.Template.lib;%(AdditionalDependencies); + + + + + sha256 + + + true + true + Trace.h + + + 2.0.2.0 + + + wdmsec.lib;$(DmfRootPath)\$(Configuration)\$(PlatformName)\lib\DmfK\DmfK.lib;$(DmfRootPath)\$(Configuration)\$(PlatformName)\individual_libs\DmfKModules.Template\DmfKModules.Template.lib;%(AdditionalDependencies); + + + + + sha256 + + + true + true + Trace.h + + + 2.0.2.0 + + + wdmsec.lib;$(DmfRootPath)\$(Configuration)\$(PlatformName)\lib\DmfK\DmfK.lib;$(DmfRootPath)\$(Configuration)\$(PlatformName)\individual_libs\DmfKModules.Template\DmfKModules.Template.lib;%(AdditionalDependencies); + + + + + sha256 + + + true + true + Trace.h + + + wdmsec.lib;$(DmfRootPath)\$(Configuration)\$(PlatformName)\lib\DmfK\DmfK.lib;$(DmfRootPath)\$(Configuration)\$(PlatformName)\individual_libs\DmfKModules.Template\DmfKModules.Template.lib;%(AdditionalDependencies); + + + + + + + + + + + + + + + + + + + + + + + + + + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + true + %(Filename)ETW + %(Filename)ETW + %(Filename)ETW + %(Filename)ETW + %(Filename)ETW + %(Filename)ETW + %(Filename)ETW + %(Filename)ETW + + + + + + \ No newline at end of file diff --git a/src/nssudeaudio.vcxproj.filters b/src/nssudeaudio.vcxproj.filters new file mode 100644 index 0000000..bca4c14 --- /dev/null +++ b/src/nssudeaudio.vcxproj.filters @@ -0,0 +1,62 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + {8E41214B-6785-4CFE-B992-037D68949A14} + inf;inv;inx;mof;mc; + + + + + Driver Files + + + + + Source Files + + + Source Files + + + Source Files + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + + + Resource Files + + + Resource Files + + + + + + \ No newline at end of file