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.
Related
I am looking for a way to programmatically clear/flush the local win32 dns cache (Equivalent of calling "ipconfig /flushdns").
There were ways to do this with a hidden API in winsock.dll but winsock.dll is no longer part of Windows and as such this method will no longer work.
Does anyone know how this should be done now?
Checked ipconfig.exe's dependencies using Dependency Walker
Found dnsapi.dll among them
Checked its exported functions, and found DnsFlushResolverCache
Shallowly browsed the web, and found its signature (only found references like this on official site: [MS.Docs]: Windows 8 API Sets), meaning it's not public, so software relying on it, is not robust)
Created a small test program
main00.c:
#include <stdio.h>
#include <Windows.h>
typedef BOOL (WINAPI *DnsFlushResolverCacheFuncPtr)();
int main() {
HMODULE dnsapi = LoadLibrary("dnsapi.dll");
if (dnsapi == NULL) {
printf("Failed loading module: %d\n", GetLastError());
return -1;
}
DnsFlushResolverCacheFuncPtr DnsFlushResolverCache = (DnsFlushResolverCacheFuncPtr)GetProcAddress(dnsapi, "DnsFlushResolverCache");
if (DnsFlushResolverCache == NULL) {
printf("Failed loading function: %d\n", GetLastError());
FreeLibrary(dnsapi);
return -2;
}
BOOL result = DnsFlushResolverCache();
if (result) {
printf("DnsFlushResolverCache succeeded\n");
} else {
printf("DnsFlushResolverCache succeeded: %d\n", GetLastError());
}
FreeLibrary(dnsapi);
return 0;
}
Output:
e:\Work\Dev\StackOverflow\q052007372>"c:\Install\x86\Microsoft\Visual Studio Community\2015\vc\vcvarsall.bat" x64
e:\Work\Dev\StackOverflow\q052007372>dir /b
dnsapi_func_list.txt
main00.c
e:\Work\Dev\StackOverflow\q052007372>cl /nologo main00.c /link /OUT:main00.exe
main00.c
e:\Work\Dev\StackOverflow\q052007372>dir /b
dnsapi_func_list.txt
main00.c
main00.exe
main00.obj
e:\Work\Dev\StackOverflow\q052007372>main00.exe
DnsFlushResolverCache succeeded
Note: Even if the function call completed successfully, I am not sure how to check whether it did what it's supposed to do (or better: what its name suggests it should do, which seems to be what you need).
Let me know how it works.
Update #0
Thank you for the info #TimJohnson!! I was too in a rush to look at ipconfig /? ([MS.Docs]: ipconfig) output (which I had in another cmd window :d ) and notice the option :) . It does work (the cache is heavily updated, and I can see differences before and after running the program) !!!
I am building a dll for windows, using a Makefile, using cl.exe. I am using VS2015.. this dll uses CNG (bcrypt) for encryption operations, and bcryptr is loaded dynamically using loadlibrary call.
When i build with /Od option to disable optimization, i have no issues with any functionality. but if i use any optimization option /O1, /O2, /Ox, i see the strangest thing happen.. once i retrieve the address for a bcrypt function, such as BCryptGetFipsAlgorithmMode, using GetProcAddress, and then i make the call to that function ptr, the call stack goes away. This results in exception when the calling function tries to return.. it looks almost like when one calls a callback doesn't have the CALLBACK prefix, but i dont see the connection..
That bcrypt function's prototype looks like this:
NTSTATUS WINAPI BCryptGetFipsAlgorithmMode( __out BOOLEAN *pfEnabled)
and WINAPI seems to be defined:
define WINAPI __stdcall
Is there something I am missing? what does optimization have to do with this?
Any help would be appreciated.. Thank You!
Heres the code:
NTSTATUS GetFipsAlgorithmMode(BOOLEAN *pfEnabled )
{
FARPROC pBCryptGetFipsAlgorithmMode = NULL;
NTSTATUS (*_BCryptGetFipsAlgorithmMode)( __out BOOLEAN *);
NTSTATUS status = SPGC_ERR_LIBRARY_ADDRESS_LOOKUP_FAILURE;
if(g_hBCRYPTDLL != NULL)
{
pBCryptGetFipsAlgorithmMode = GetProcAddress(g_hBCRYPTDLL, _T("BCryptGetFipsAlgorithmMode"));
if(pBCryptGetFipsAlgorithmMode != NULL)
{
_BCryptGetFipsAlgorithmMode = (NTSTATUS (*)( __out BOOLEAN *)) pBCryptGetFipsAlgorithmMode;
status = _BCryptGetFipsAlgorithmMode(pfEnabled);
}
}
return status;
}
step over the call to _BCryptGetFipsAlgorithmMode(), and the call stack basically gets cleared.
Windows allows the creation of (named) Event objects.
An Event (the synchronization primitive in Windows) can be of type auto-reset (in which case you could say it's kind of a semaphore) or it can be of type manual-reset in which case it remains set until someone resets it.
Now, from the docs for CreateEvent, OpenEvent, SetEvent, etc. it does seem that there is no way to determine, once the event has been created, whether it's auto-reset or maual-reset.
I am in the situation, where one process creates a named Event and a 2nd process will have to operate on this event (it gets passed the name and then'll open the event and eventually signal it). Since the event should always be a manual-reset event for the whole thing to make sense, I would have liked to add a check in the 2nd process to make sure it is a manual-reset event. Is there any way to check for this?
(And yes, it's more of a nice-to-have in my situation, as it would be a bug anyway if any code would create a auto-reset event and then pass it to this process. But bugs happen, and the better if I can detect them.)
There's no documented way to do this, but it's actually not hard if you venture into undocumented land. (For your purposes, this should be fine since it doesn't really affect your program's functionality.)
The first thing you need to do is figure out if the handle given to you is an event or not. You use NtQueryObject for this. The function is documented here: http://msdn.microsoft.com/en-us/library/bb432383(v=vs.85).aspx. It comes with the usual provisios for native APIs that it might disappear or change without notice. Partial example:
#include <winternl.h>
typedef NTSTATUS (NTAPI * PFN_NtQueryObject)(
HANDLE Handle,
OBJECT_INFORMATION_CLASS ObjectInformationClass,
PVOID ObjectInformation,
ULONG ObjectInformationLength,
PULONG ReturnLength );
HMODULE ntdll = GetModuleHandle( L"ntdll.dll" );
auto NtQueryObject = (PFN_NtQueryObject)GetProcAddress( ntdll, "NtQueryObject" );
NTSTATUS result = NtQueryObject(
eventHandle,
ObjectTypeInformation,
buffer,
length,
&length );
This will give you a PUBLIC_OBJECT_TYPE_INFORMATION structure. The TypeName field will be "Event" if the object is actually an event.
Next, you call NtQueryEvent to get the event's type. All this is completely undocumented.
typedef enum _EVENT_INFORMATION_CLASS {
EventBasicInformation
} EVENT_INFORMATION_CLASS, *PEVENT_INFORMATION_CLASS;
typedef enum _EVENT_TYPE {
NotificationEvent,
SynchronizationEvent
} EVENT_TYPE, *PEVENT_TYPE;
typedef struct _EVENT_BASIC_INFORMATION {
EVENT_TYPE EventType;
LONG EventState;
} EVENT_BASIC_INFORMATION, *PEVENT_BASIC_INFORMATION;
typedef NTSTATUS (NTAPI * PFN_NtQueryEvent)(
HANDLE EventHandle,
EVENT_INFORMATION_CLASS EventInformationClass,
PVOID EventInformation,
ULONG EventInformationLength,
PULONG ReturnLength );
auto NtQueryEvent = (PFN_NtQueryEvent)GetProcAddress( ntdll, "NtQueryEvent" );
EVENT_BASIC_INFORMATION info;
ULONG length = sizeof( info );
NTSTATUS result = NtQueryEvent(
eventHandle,
EventBasicInformation,
&info,
length,
&length );
Now, just examine the EventType field in the info and you're done. "NotificationEvent" means manual reset and "SynchronizationEvent" means auto reset.
If you're wondering how I figured that second part out, I didn't. The information comes from here: http://undocumented.ntinternals.net/. Please use responsibly!
Call WaitForSingleObject( handle, 0 ) immediately after your initial WaitForSingleObject has returned. If the return value is WAIT_TIMEOUT then you know it is an auto-reset event, if it is WAIT_OBJECT_0 will be returned and it is a manual reset event.
This does rely on the handle being set in-between the two calls, so there is a potential race condition where it does not detect an auto-reset event, but it should work most of the time. As it is a nice-to-have, hopefully that is enough?
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
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,