World's most simple Windows driver - windows

I have a slightly odd problem involving a MoGo mouse failing to charge when put in the cartridge slot of my Windows XP laptop. Long story, but one suggestion to fix it is to write a bespoke driver which only says "I'm functioning OK: don't turn the power off".
I'm figuring that this should be next to trivial, but my only experience of drivers is to download and install them through provided MSIs. I realised that I don't know:
What language they're written in.
What conventions they must follow.
How they are associated with their respective hardware.
Where they are located.
Or indeed, anything at all...
I also haven't found anything staggeringly helpful on the web - probably because they are aimed at a far higher level than I'm at.
Any insights would be welcome.

Microsoft provides a "Hello World" driver example in their documentation. This is an example of "World's most simple Windows driver". Unfortunately, it's 13 pages long and thus not a good fit for a StackOverflow answer.
The language they are written in is C++.
To get started, be sure you have Microsoft Visual Studio, the Windows
SDK, and the Windows Driver Kit (WDK) installed.
Their example contains one file called Driver.c that looks like this:
#include <ntddk.h>
#include <wdf.h>
DRIVER_INITIALIZE DriverEntry;
EVT_WDF_DRIVER_DEVICE_ADD KmdfHelloWorldEvtDeviceAdd;
NTSTATUS
DriverEntry(
_In_ PDRIVER_OBJECT DriverObject,
_In_ PUNICODE_STRING RegistryPath
)
{
// NTSTATUS variable to record success or failure
NTSTATUS status = STATUS_SUCCESS;
// Allocate the driver configuration object
WDF_DRIVER_CONFIG config;
// Print "Hello World" for DriverEntry
KdPrintEx(( DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "KmdfHelloWorld: DriverEntry\n" ));
// Initialize the driver configuration object to register the
// entry point for the EvtDeviceAdd callback, KmdfHelloWorldEvtDeviceAdd
WDF_DRIVER_CONFIG_INIT(&config,
KmdfHelloWorldEvtDeviceAdd
);
// Finally, create the driver object
status = WdfDriverCreate(DriverObject,
RegistryPath,
WDF_NO_OBJECT_ATTRIBUTES,
&config,
WDF_NO_HANDLE
);
return status;
}
NTSTATUS
KmdfHelloWorldEvtDeviceAdd(
_In_ WDFDRIVER Driver,
_Inout_ PWDFDEVICE_INIT DeviceInit
)
{
// We're not using the driver object,
// so we need to mark it as unreferenced
UNREFERENCED_PARAMETER(Driver);
NTSTATUS status;
// Allocate the device object
WDFDEVICE hDevice;
// Print "Hello World"
KdPrintEx(( DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "KmdfHelloWorld: KmdfHelloWorldEvtDeviceAdd\n" ));
// Create the device object
status = WdfDeviceCreate(&DeviceInit,
WDF_NO_OBJECT_ATTRIBUTES,
&hDevice
);
return status;
}
Full details found here:
https://learn.microsoft.com/en-us/windows-hardware/drivers/gettingstarted/writing-a-very-small-kmdf--driver

Related

Can I use SetupDiEnumDeviceInterfaces to get a DevicePath from SetupDiGetDeviceInterfaceDetail when no InterfaceClassGUID is known?

Overview...
I have read How to get device interface GUID for a device? and How to open a handle to a device using its Device Instance ID?, but I'm still confused about how I am to (or whether I should even) use SetupDiEnumDeviceInterfaces paired with SetupDiGetDeviceInterfaceDetail to get a DevicePath that can be opened with CreateFile to access the device when no device interface class GUID is known. My question is based on the MSDN article here and here which rely on these functions.
More details...
The high level of my problem is I've got an audio USB device I need to send control transfer commands. To do so, I want to use WinUSB's API, and to do that I need to get a handle to the device via CreateFile. Unfortunately, there is no .inf file associated with the device and so there is no known device interface class GUID. If one plugs the device in, Windows associates with it usbaudio.sys as the driver. To start talking over WinUSB, I use libwdi to install WinUSB as the device driver so that I can communicate with it via the WinUSB API. To accomplish the install of WinUSB, libwdi dynamically creates a self-signed .cat and .inf file pair, which unfortunately has no device interface class defined. In fact, the INF file has the following in it:
[NoDeviceInterfaceGUID]
; Avoids adding a DeviceInterfaceGUID for generic driver
So, despite the fact I now have swapped out usbaudio.sys for winusb.sys, I'm unable to communicate with the device.
At first I thought maybe I should try using GUID_DEVINTERFACE_USB_DEVICE, reasoning that this is WinUSB and therefore seen as a generic USB device. But, if I invoke
SetupDiEnumDeviceInterfaces(_deviceList,
&devInfo,
&GUID_DEVINTERFACE_USB_DEVICE,
0,
&usbInterface)
it fails and GetLastError returns 259, or ERROR_NO_MORE_ITEMS immediately. I'm assuming this means it doesn't implement the interface?
So, in general, when no interface class guid is known, am I able to use the aforementioned functions in any form to get the full device path?
Thanks in advance for your time.
Yes, first you need to get a device information set for devices that implement the interface via SetupDiGetClassDevs, then pick one of the devices and read its device interface data, and use that to get the device interface detail that contains the device path.
Example:
#include <windows.h>
#include <setupapi.h>
#include <initguid.h>
#include <usbioctl.h>
#include <stdio.h>
BOOL DevicePath(_In_ LPCGUID interfaceGuid, DWORD instance)
{
BOOL result = FALSE;
PSP_DEVICE_INTERFACE_DETAIL_DATA_W devInterfaceDetailData = NULL;
HDEVINFO hDevInfo = SetupDiGetClassDevsW(interfaceGuid, NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
if(hDevInfo == INVALID_HANDLE_VALUE)
goto cleanup;
SP_DEVICE_INTERFACE_DATA devInterfaceData;
devInterfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
if(!SetupDiEnumDeviceInterfaces(hDevInfo, NULL, interfaceGuid, instance, &devInterfaceData))
goto cleanup;
// Call this with an empty buffer to the required size of the structure.
ULONG requiredSize;
SetupDiGetDeviceInterfaceDetailW(hDevInfo, &devInterfaceData, NULL, 0, &requiredSize, NULL);
if(GetLastError() != ERROR_INSUFFICIENT_BUFFER)
goto cleanup;
devInterfaceDetailData = malloc(requiredSize);
if(!devInterfaceDetailData)
goto cleanup;
devInterfaceDetailData->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
if(!SetupDiGetDeviceInterfaceDetailW(hDevInfo, &devInterfaceData, devInterfaceDetailData, requiredSize, &requiredSize, NULL))
goto cleanup;
wprintf(L"%s\n", devInterfaceDetailData->DevicePath);
result = TRUE;
cleanup:
if(hDevInfo != INVALID_HANDLE_VALUE)
SetupDiDestroyDeviceInfoList(hDevInfo);
free(devInterfaceDetailData);
return result;
}
int main()
{
for(DWORD i = 0; DevicePath(&GUID_DEVINTERFACE_USB_DEVICE, i); ++i)
;
}

Log OutputDebugString to a file (without DebugView)

My WPF app consumes a third-party Win32 dll that logs messages via OutputDebugString.
I can see the OutputDebugString messages in Visual Studio or via DebugView, but I don't want to ask my customer to run DebugView. I'd like to capture the messages from OutputDebugString and automatically log them to a file, so if the customer has a problem, I can just ask her to send me that log file.
Is this possible? Or does the user necessarily have to start DebugView, reproduce the error, and then send me the log that way?
Hook OutputDebugStringW. I'd suggest using the Detours library for this.
#include <windows.h>
#include <detours.h>
#pragma comment(lib, "detours.lib")
BOOL SetHook(__in BOOL bState, __inout PVOID* ppPointer, __in PVOID pDetour)
{
if (DetourTransactionBegin() == NO_ERROR)
if (DetourUpdateThread(GetCurrentThread()) == NO_ERROR)
if ((bState ? DetourAttach : DetourDetach)(ppPointer, pDetour) == NO_ERROR)
if (DetourTransactionCommit() == NO_ERROR)
return TRUE;
return FALSE;
{
#define InstallHook(x, y) SetHook(TRUE, x, y)
VOID (WINAPI * _OutputDebugStringW)(__in_z_opt LPCWSTR lpcszString) = OutputDebugStringW;
VOID WINAPI OutputDebugStringHook(__in_z_opt LPCWSTR lpcszString)
{
// do something with the string, like write to file
_OutputDebugStringW(lpcszString);
}
// somewhere in your code
InstallHook((PVOID*)&_OutputDebugStringW, OutputDebugStringHook);
#Cody Gray's suggestion to "write your own debug listener, and then you've basically written an inferior clone of DebugView" sounds like it might actually be an answer to my question.
Here's a C# implementation of a basic OutputDebugString capture tool. I'd seen it in my Googling a couple of times, but my eyes glazed over it, assuming, "that can't possibly be what I want, can it?" Turns out, it just might be the answer to my question.

Allow Driver to Stop in Windows?

Some drivers on Windows, like Null and Beep, can be arbitrarily stopped and re-started through the ControlService(..., SERVICE_CONTROL_STOP, ...) operation. Most other drivers, however, cannot be stopped and restarted while the system is running.
I'm making my own driver. How can I tell Windows that my driver can be stopped?
It turns out that you need to add a DriverUnload function:
VOID NTAPI DriverUnload(IN DRIVER_OBJECT *DriverObject) { }
NTSTATUS NTAPI DriverEntry(IN PDRIVER_OBJECT DriverObject,
IN PUNICODE_STRING RegistryPath)
{
DriverObject->DriverUnload = DriverUnload; // <--- add this
return STATUS_SUCCESS;
}
However, this is only sufficient if you're linking with /DRIVER.
If you're linking with /DRIVER:WDM (meaning that IMAGE_DLLCHARACTERISTICS_WDM_DRIVER is set in the DllCharacteristics field) then it seems like this isn't sufficient. I think you may need to do more things, like handling IRPs as well. So check that too.

SysInternal's WinObj device listing mechanism

SysInternals's WinObj can list all device objects.
I wonder how it can list the devices.
Is there any open source we can read?(or a code snippet)
What is the most significant function I should know?
WinObj uses the NT system calls NtOpenDirectoryObject and NtQueryDirectoryObject. There is no driver or kernel code needed. You won't see the imports because these NT functions are loaded via LoadLibrary/GetProcAddress.
You don't have to enumerate the entire object namespace. If you're interested in the device objects call NtOpenDirectoryObject with "\Device", then call NtQueryDirectoryObject on the returned handle.
According to SysInternals' web page:
The native NT API provides routines
that allow user-mode programs to
browse the namespace and query the
status of objects located there, but
the interfaces are undocumented.
I've tried looking at WinObj's import table (dumpbin /imports winobj.exe) but there are no obvious suspects :-(
As per the answer from user1575778 you can use NtOpenDirectoryObject and NtQueryDirectoryObject (which from user mode are identical to ZwOpenDirectoryObject and ZwQueryDirectoryObject respectively) to list the objects inside the object manager namespace.
Have a look at objmgr.hpp of NT Objects aka ntobjx, in particular at the class NtObjMgr::Directory (or DirectoryT). It provides the same functionality nicely wrapped into a C++ class. The whole utility is open source under a liberal license (dual-licensed due to WTL-use: MIT and MS-PL), so bits and pieces can be reused however you please, provided you comply with the license terms.
But here's a simple C++ code example catering just your use case:
#include <Windows.h>
#include <tchar.h>
#include <cstdio>
#include <winternl.h>
NTSTATUS (NTAPI* NtOpenDirectoryObject)(PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES);
NTSTATUS (NTAPI* NtQueryDirectoryObject)(HANDLE, PVOID, ULONG, BOOLEAN, BOOLEAN, PULONG, PULONG);
VOID (NTAPI* RtlInitUnicodeString_)(PUNICODE_STRING, PCWSTR);
NTSTATUS (NTAPI* NtClose_)(HANDLE);
#define DIRECTORY_QUERY (0x0001)
#define DIRECTORY_TRAVERSE (0x0002)
typedef struct _OBJECT_DIRECTORY_INFORMATION {
UNICODE_STRING Name;
UNICODE_STRING TypeName;
} OBJECT_DIRECTORY_INFORMATION, *POBJECT_DIRECTORY_INFORMATION;
#ifndef STATUS_SUCCESS
#define STATUS_SUCCESS ((NTSTATUS)0x00000000L) // ntsubauth
#endif // STATUS_SUCCESS
#ifndef STATUS_MORE_ENTRIES
#define STATUS_MORE_ENTRIES ((NTSTATUS)0x00000105L)
#endif // STATUS_MORE_ENTRIES
#ifndef STATUS_NO_MORE_ENTRIES
#define STATUS_NO_MORE_ENTRIES ((NTSTATUS)0x8000001AL)
#endif // STATUS_NO_MORE_ENTRIES
int PrintDevices()
{
NTSTATUS ntStatus;
OBJECT_ATTRIBUTES oa;
UNICODE_STRING objname;
HANDLE hDeviceDir = NULL;
RtlInitUnicodeString_(&objname, L"\\Device");
InitializeObjectAttributes(&oa, &objname, 0, NULL, NULL);
ntStatus = NtOpenDirectoryObject(&hDeviceDir, DIRECTORY_QUERY | DIRECTORY_TRAVERSE, &oa);
if(NT_SUCCESS(ntStatus))
{
size_t const bufSize = 0x10000;
BYTE buf[bufSize] = {0};
ULONG start = 0, idx = 0, bytes;
BOOLEAN restart = TRUE;
for(;;)
{
ntStatus = NtQueryDirectoryObject(hDeviceDir, PBYTE(buf), bufSize, FALSE, restart, &idx, &bytes);
if(NT_SUCCESS(ntStatus))
{
POBJECT_DIRECTORY_INFORMATION const pdilist = reinterpret_cast<POBJECT_DIRECTORY_INFORMATION>(PBYTE(buf));
for(ULONG i = 0; i < idx - start; i++)
{
if(0 == wcsncmp(pdilist[i].TypeName.Buffer, L"Device", pdilist[i].TypeName.Length / sizeof(WCHAR)))
{
_tprintf(_T("%s\n"), pdilist[i].Name.Buffer);
}
}
}
if(STATUS_MORE_ENTRIES == ntStatus)
{
start = idx;
restart = FALSE;
continue;
}
if((STATUS_SUCCESS == ntStatus) || (STATUS_NO_MORE_ENTRIES == ntStatus))
{
break;
}
}
(void)NtClose_(hDeviceDir);
return 0;
}
_tprintf(_T("Failed NtOpenDirectoryObject with 0x%08X"), ntStatus);
return 1;
}
int _tmain(int /*argc*/, _TCHAR** /*argv*/)
{
HMODULE hNtDll = ::GetModuleHandle(_T("ntdll.dll"));
*(FARPROC*)&NtOpenDirectoryObject = ::GetProcAddress(hNtDll, "NtOpenDirectoryObject");
*(FARPROC*)&NtQueryDirectoryObject = ::GetProcAddress(hNtDll, "NtQueryDirectoryObject");
*(FARPROC*)&RtlInitUnicodeString_ = ::GetProcAddress(hNtDll, "RtlInitUnicodeString");
*(FARPROC*)&NtClose_ = ::GetProcAddress(hNtDll, "NtClose");
if (!NtOpenDirectoryObject || !NtQueryDirectoryObject || !RtlInitUnicodeString_ || !NtClose_)
{
_tprintf(_T("Failed to retrieve ntdll.dll function pointers\n"));
return 1;
}
return PrintDevices();
}
Some remarks: This will not delve into subdirectories, it will not list any types other than Device and it will not resolve symbolic links, if any. For any of those features, please look at the aforementioned utility's source code and adjust as needed. winternl.h should be available in any recent Windows SDK.
The functions RtlInitUnicodeString_ and NtClose_ have a trailing underscore to avoid clashes with these native API functions, which are declared in winternl.h, but use __declspec(dllimport).
Disclosure: I am the author of ntobjx.
You can use NtOpenDirectoryObject and NtQueryDirectoryObject to enumarate the objects list in a given directory.
To get the details of the object namespace, you must use the Windows NT Undocumented API. That is also used by the WinObj as it is described here that how WinOBj getting the all results..and for those who are saying that we need a driver to do this please, read these lines on given page.
"One obvious way is to use a driver – in kernel mode everything is accessible – so the client app can get the required information by communicating with its own driver. WinObj does not use a driver, however (this is one reason it’s able to execute without admin privileges, although with admin privileges it shows all objects as opposed to partial results)."
You can start with SetupDiCreateDeviceInfoList and use other related functions to enumerate all the devices. This stuff is painful to use.

Is anyone familiar with the undocumented ObReferenceObjectByName windows kernel function?

I read a very fascinating article that was about programming drivers using the wdk, and one of the functions it used is called ObReferenceObjectByName. This function has given me lots of headaches. The first bad thing is that it's not documented by microsoft. The second thing, is that the language used in the article was C++, and I want to keep my code in plain ol' C. I know that most of the time this shouldn't be a problem, but I haven't - for the life of me - been able to figure out how to include this function.
The code in the article goes something like:
extern "C"{
#include <ntifs.h>
NTSYSAPI NTSTATUS NTAPI ObReferenceObjectByName(PUNICODE_STRING ObjectName,
ULONG Attributes,
PACCESS_STATE AccessState,
ACCESS_MASK DesiredAccess,
POBJECT_TYPE ObjectType,
KPROCESSOR_MODE AccessMode,
PVOID ParseContext OPTIONAL,
PVOID* Object);
}
I've been trying to replicate this for hours. I tried declaring it without the 'extern' keyword, I tried changing the calling convention, I tried changing the includes... I always end up with the error "unresolved external symbol...".
I'm absolutely stumped, so if anyone could offer some advice, I'd be grateful. Thanks.
You wouldn't be reading http://www.codeproject.com/KB/recipes/keystroke-hook.aspx and trying to create your own Keyboard Logger would you?
Anyways, instead of using this, call ZwCreateFile then ObReferenceObjectByHandle instead.
Here is a test C code compiled and built with no problems:
#include <ntddk.h>
NTSYSAPI NTSTATUS NTAPI ObReferenceObjectByName(
PUNICODE_STRING ObjectName,
ULONG Attributes,
PACCESS_STATE AccessState,
ACCESS_MASK DesiredAccess,
POBJECT_TYPE ObjectType,
KPROCESSOR_MODE AccessMode,
PVOID ParseContext OPTIONAL,
PVOID* Object
);
NTSTATUS DriverEntry(
IN PDRIVER_OBJECT DriverObject,
IN PUNICODE_STRING RegistryPath
)
{
ObReferenceObjectByName(0, 0, 0, 0, 0, 0, 0, 0);
return STATUS_SUCCESS;
}
I don't know this API, but I can give you a trick that might help you diagnose the problem.
at a command prompt that has MSVC tools in the path
link /dump /exports ???.dll
where ???.dll is the dll were you expect this function to be. This will give you a complete list of exported symbol names and will tell you two things. 1) is the symbol there? and 2) is it being decorated the same as your attempted prototype.
For 32 bit kernel, you should expect this to be called _ObReferenceObjectByName#64,

Resources