How to receive message from kernel in user-mode in c? - c

Basically I want to get filepath of every file created in windows using File system minifilter driver on Post Operation and send the filepath to user-mode, I have achieved this using below code:
BOOLEAN
GetFullPath(
IN PFLT_FILE_NAME_INFORMATION nameInfo,
IN PFLT_CALLBACK_DATA FltCallBackData,
IN PCFLT_RELATED_OBJECTS FltObjects,
IN OUT PUNICODE_STRING pFullPathName){
UNREFERENCED_PARAMETER(nameInfo);
BOOLEAN bResult;
NTSTATUS status;
PDEVICE_OBJECT pDiskDeviceObject = NULL;
UNICODE_STRING VolumeName = { 0 };
PFLT_FILE_NAME_INFORMATION TempNameInfo = NULL;
PAGED_CODE();
__try{
VolumeName.Buffer = NULL;
// Get the associated file name
status = FltGetFileNameInformation(FltCallBackData, FLT_FILE_NAME_NORMALIZED
| FLT_FILE_NAME_QUERY_DEFAULT, &TempNameInfo);
if (!NT_SUCCESS(status)){
bResult = FALSE;
__leave;
}
status = FltParseFileNameInformation(TempNameInfo);
if (!NT_SUCCESS(status)){
bResult = FALSE;
__leave;
}
// Try to get the volume device object & convert this to the volume name
status = FltGetDiskDeviceObject(FltObjects->Volume, &pDiskDeviceObject);
if (!NT_SUCCESS(status)){
bResult = FALSE;
__leave;
}
// Get the volume name
status = IoVolumeDeviceToDosName(pDiskDeviceObject, &VolumeName);
if (!NT_SUCCESS(status)){
bResult = FALSE;
__leave;
}
// Store the filename in pFullPathName
RtlInitUnicodeString(pFullPathName, (PWSTR)NULL);
pFullPathName->MaximumLength = (USHORT)(VolumeName.Length +
TempNameInfo->Name.Length + sizeof(UNICODE_NULL));
//pFullPathName->Buffer = (PWSTR)ExAllocatePool2(PagedPool,
// pFullPathName->MaximumLength, AV_SCAN_CTX_TAG);
pFullPathName->Buffer = ExAllocatePool2(POOL_FLAG_PAGED, 100, '3331');
if (pFullPathName->Buffer == NULL){
AV_DBG_PRINTEX((0, AVDBG_TRACE_ZERO, "Failed to allocate memory\n"));
bResult = FALSE;
__leave;
}
status = RtlAppendUnicodeStringToString(pFullPathName, &VolumeName);
if (!NT_SUCCESS(status)){
ExFreePool(pFullPathName->Buffer);
bResult = FALSE;
__leave;
}
pFullPathName->MaximumLength = 100;
status = RtlAppendUnicodeStringToString(pFullPathName,
&TempNameInfo->ParentDir);
if (!NT_SUCCESS(status)){
bResult = FALSE;
__leave;
}
status = RtlAppendUnicodeStringToString(pFullPathName,
&TempNameInfo->FinalComponent);
if (!NT_SUCCESS(status)){
ExFreePool(pFullPathName->Buffer);
bResult = FALSE;
__leave;
}
//DbgPrint(" Full Path Name = %wZ\n", pFullPathName );
AV_DBG_PRINTEX((0, AVDBG_TRACE_ZERO, "<Fullpath> Full Path Name = %wZ, %d\n", pFullPathName, pFullPathName->Length));
LARGE_INTEGER timeout = { 0 };
timeout.QuadPart = 1;
//timeout.QuadPart = -(timeout.QuadPart * _1ms);
status = FltSendMessage(Globals.Filter,
&Globals.ScanClientPort,
pFullPathName,
pFullPathName->Length,
NULL,
NULL,
&timeout);
bResult = TRUE;
}
__finally{
// Free all allocated resources
if (pDiskDeviceObject)
ObDereferenceObject(pDiskDeviceObject);
if (VolumeName.Buffer)
ExFreePool(VolumeName.Buffer);
if (TempNameInfo)
FltReleaseFileNameInformation(TempNameInfo);
}
return bResult;
}
In my kernel debugger, I see the Full file path just as I want it, and then I basically receive that in user-mode as below:
int main() {
ULONG bytesReturned = 0;
AV_CONNECTION_CONTEXT connectionCtx = {0};
COMMAND_MESSAGE commandMessage = { 0 };
char* buffer = (char *)malloc(500);
HRESULT hResult = 0;
printf("Enter your request: ");
scanf_s("%s", buffer, max_buffer_length);
printf("Entered request is: %s:%d\n", buffer, strlen(buffer));
//strncpy_s(buffer,500, "status=sto", 11);
char recvbuffer[500] = { 0 };
if (port == NULL) {
connectionCtx.Type = AvConnectForScan;
hResult = FilterConnectCommunicationPort(L"\\NeehackAVScanPort", 0, &connectionCtx, sizeof(AV_CONNECTION_CONTEXT), NULL, &port);
printf("hresult: 0x%08x\n", hResult);
if (hResult) {
printf("Failed to Connect to Kernel\n");
return -1;
}
}
printf("Connected to kernel, sending: %s:%d\n", buffer, strlen(buffer));
/*
hr = FilterSendMessage( Context->ConnectionPort,
&commandMessage,
sizeof( COMMAND_MESSAGE ),
NULL,
0,
&bytesReturned);
*/
commandMessage.Command = AvCmdCreateSectionForDataScan;
hResult = FilterSendMessage(port, &commandMessage, sizeof(COMMAND_MESSAGE), recvbuffer, 500, &bytesReturned);
printf("sending data hresult: 0x%08x recv:%s\n", hResult, recvbuffer);
FILTER_MESSAGE_HEADER msg;
//connectionCtx.Type = AvConnectForScan;
while (true) {
hResult = FilterGetMessage(port,
&msg,
1024,
NULL);
printf("message is: %s:%wZ\n", msg, &msg);
}
if (FAILED(hResult)) {
printf("Failed to send data 0x%08x\n", hResult);
return -1;
}
printf("kernel said: %s\n", recvbuffer);
return 0;
}
The problem is on printf("message is: %s:%wZ\n", msg, &msg); I get null strings or message is: :(null) every time the message is sent by the kernel.
Can anyone tell me what am I doing wrong?

You need to have both ends of the port agree on the format of the message. Something along the lines of the following just to give an idea:
typedef struct _MY_MESSAGE {
FILTER_MESSAGE_HEADER Header;
WCHAR FullPathName[1024];
} MY_MESSAGE;
FltSendMessage(pFullPathName->Buffer, pFullPathName->Length)
MY_MESSAGE Message;
FilterGetMessage(&Message.Header, sizeof(Message));
printf("FullPathName: %ls\n", Message.FullPathName);

Related

FilterReplyMessage Not working in minifilter driver?

I have below code to send ever filename created in post operation in windows from kernel to user and then from user reply back with a simple string I.e "succeed" or whatever, in which case below it is basically replyMessage.passFLag.
User-Mode:
typedef struct _MY_MESSAGE {
FILTER_MESSAGE_HEADER Header;
WCHAR FullPathName[1024];
} MY_MESSAGE;
typedef struct _REPLY_MESSAGE_STRUCT {
// Message header.
FILTER_REPLY_HEADER header;
// Flag to be set
// by user mode.
int passFlag;
}REPLY_MESSAGE_STRUCT, * PREPLY_MESSAGE_STRUCT;
int main() {
ULONG bytesReturned = 0;
AV_CONNECTION_CONTEXT connectionCtx = {};
HRESULT hResult = 0;
if (port == NULL) {
connectionCtx.Type = AvConnectForScan;
hResult = FilterConnectCommunicationPort(L"\\ScanPort", 0, &connectionCtx, sizeof(AV_CONNECTION_CONTEXT), NULL, &port);
printf("hresult: 0x%08x\n", hResult);
if (hResult) {
printf("Failed to Connect to Kernel\n");
return -1;
}
}
printf("Connected to kernel\n");
while (true) {
MY_MESSAGE Message;
memcpy(Message.FullPathName, "\x00", 1024);
hResult = FilterGetMessage(port, &Message.Header, sizeof(Message), NULL);
if (FAILED(hResult)) {
printf("Failed to get message, [0x%08x]\n", hResult);
break;
}
REPLY_MESSAGE_STRUCT replyMessage;
ULONG replySize = sizeof(FILTER_REPLY_HEADER) + sizeof(int);
replyMessage.header.Status = 0;
replyMessage.header.MessageId = 12;
replyMessage.passFlag = 1;
hResult = FilterReplyMessage(port,
&replyMessage.header,
replySize);
printf("\nFullPathName: %ls, 0x%08x, %d\n", Message.FullPathName, hResult, replyMessage.passFlag);
}
return 0;
}
Kernel-Mode:
typedef struct _REPLY_MESSAGE_STRUCT {
// Message header.
FILTER_REPLY_HEADER header;
// Flag to be set
// by user mode.
int passFlag;
}REPLY_MESSAGE_STRUCT, * PREPLY_MESSAGE_STRUCT;
BOOLEAN
GetFullPath(
IN PFLT_FILE_NAME_INFORMATION nameInfo,
IN PFLT_CALLBACK_DATA FltCallBackData,
IN PCFLT_RELATED_OBJECTS FltObjects,
IN OUT PUNICODE_STRING pFullPathName){
UNREFERENCED_PARAMETER(nameInfo);
BOOLEAN bResult;
NTSTATUS status;
PDEVICE_OBJECT pDiskDeviceObject = NULL;
UNICODE_STRING VolumeName = { 0 };
PFLT_FILE_NAME_INFORMATION TempNameInfo = NULL;
PAGED_CODE();
__try{
VolumeName.Buffer = NULL;
// Get the associated file name
status = FltGetFileNameInformation(FltCallBackData, FLT_FILE_NAME_NORMALIZED
| FLT_FILE_NAME_QUERY_DEFAULT, &TempNameInfo);
if (!NT_SUCCESS(status)){
bResult = FALSE;
__leave;
}
status = FltParseFileNameInformation(TempNameInfo);
if (!NT_SUCCESS(status)){
bResult = FALSE;
__leave;
}
// Try to get the volume device object & convert this to the volume name
status = FltGetDiskDeviceObject(FltObjects->Volume, &pDiskDeviceObject);
if (!NT_SUCCESS(status)){
bResult = FALSE;
__leave;
}
// Get the volume name
status = IoVolumeDeviceToDosName(pDiskDeviceObject, &VolumeName);
if (!NT_SUCCESS(status)){
bResult = FALSE;
__leave;
}
// Store the filename in pFullPathName
RtlInitUnicodeString(pFullPathName, (PWSTR)NULL);
pFullPathName->MaximumLength = (USHORT)(VolumeName.Length +
TempNameInfo->Name.Length + sizeof(UNICODE_NULL));
//pFullPathName->Buffer = (PWSTR)ExAllocatePool2(PagedPool,
// pFullPathName->MaximumLength, AV_SCAN_CTX_TAG);
pFullPathName->Buffer = ExAllocatePool2(POOL_FLAG_PAGED, 100, '3331');
if (pFullPathName->Buffer == NULL){
AV_DBG_PRINTEX((0, AVDBG_TRACE_ZERO, "Failed to allocate memory\n"));
bResult = FALSE;
__leave;
}
status = RtlAppendUnicodeStringToString(pFullPathName, &VolumeName);
if (!NT_SUCCESS(status)){
ExFreePool(pFullPathName->Buffer);
bResult = FALSE;
__leave;
}
pFullPathName->MaximumLength = 100;
status = RtlAppendUnicodeStringToString(pFullPathName,
&TempNameInfo->ParentDir);
if (!NT_SUCCESS(status)){
bResult = FALSE;
__leave;
}
status = RtlAppendUnicodeStringToString(pFullPathName,
&TempNameInfo->FinalComponent);
if (!NT_SUCCESS(status)){
ExFreePool(pFullPathName->Buffer);
bResult = FALSE;
__leave;
}
//DbgPrint(" Full Path Name = %wZ\n", pFullPathName );
/*
typedef struct _MY_REPLY {
FILTER_MESSAGE_HEADER Header;
WCHAR FullPathNameReply[1024];
} MY_REPLY;
*/
LARGE_INTEGER timeout = { 0 };
timeout.QuadPart = 30000;
//timeout.QuadPart = -(timeout.QuadPart * _1ms);
REPLY_MESSAGE_STRUCT replyBuffer;
ULONG replySize = sizeof(FILTER_REPLY_HEADER) + sizeof(int);
status = FltSendMessage(Globals.Filter,
&Globals.ScanClientPort,
pFullPathName->Buffer,
pFullPathName->Length,
(PVOID)&replyBuffer,
&replySize,
&timeout);
AV_DBG_PRINTEX((0, AVDBG_TRACE_ZERO, "<Fullpath> Full Path Name = %wZ, %d, %wZ, %lu\n", pFullPathName, pFullPathName->Length, replyBuffer, replyBuffer.passFlag));
bResult = TRUE;
}
__finally{
// Free all allocated resources
if (pDiskDeviceObject)
ObDereferenceObject(pDiskDeviceObject);
if (VolumeName.Buffer)
ExFreePool(VolumeName.Buffer);
if (TempNameInfo)
FltReleaseFileNameInformation(TempNameInfo);
}
return bResult;
}
The code compile files but in the kernel I get incorrect passFlag value or <Fullpath> Full Path Name = C:\Users\Dev\Desktop\OSRLOADER - Shortcut.lnk, 90, (null), 2485861544
2485861544 is passFlag.
Can anyone tell me what is wrong here?
Also, or even better how do I reply back to kernel with a string I.e "Got it".

Serial number enumeration failed when we cast Descriptor+Descriptor->SerialNumberOffset

I have a kernel driver which is used to find the serial number of storage devices, but there is an issue with the driver.
Descriptor->SerialNumberOffset is 103
but (LPCSTR)(UINT_PTR)Descriptor+(DWORD32)Descriptor->SerialNumberOffset is NULL
here is my code
NTSTATUS GetDeviceTypeAndUniqueID(IN PDEVICE_OBJECT StorageStackDeviceObject, cwDevices *lDeviceTypeArg, char *pszUidArg)
{
DWORRD lDeviceType=0;
STORAGE_PROPERTY_QUERY Query;
STORAGE_DEVICE_DESCRIPTOR Buffer[4];
NTSTATUS Status = STATUS_SUCCESS;
ULONG uBusType=BusTypeUnknown;
PSTORAGE_DEVICE_DESCRIPTOR Descriptor=NULL;
PIRP NewIrp2=NULL;
PIO_STACK_LOCATION NextIrpStack=NULL;
IO_STATUS_BLOCK IoStatus;
char szSptr[2]={'_','\0'};
Query.PropertyId = StorageDeviceProperty;// first set the query properties
Query.QueryType = PropertyStandardQuery;
lDeviceType=0;
if (KeGetCurrentIrql() > PASSIVE_LEVEL)
{
return STATUS_SUCCESS;
}
if(StorageStackDeviceObject == NULL)
{
return STATUS_SUCCESS;
}
if((StorageStackDeviceObject->DeviceType != FILE_DEVICE_DISK) &&
(StorageStackDeviceObject->DeviceType != FILE_DEVICE_CD_ROM)&&
(StorageStackDeviceObject->DeviceType != FILE_DEVICE_DVD)&&
(StorageStackDeviceObject->DeviceType !=FILE_DEVICE_TAPE) )
{
return STATUS_SUCCESS;
}
KeInitializeEvent(&WaitEvent_newIrp, NotificationEvent, TRUE);// initialize the waitable event
__try
{
NewIrp2=IoBuildDeviceIoControlRequest(IOCTL_STORAGE_QUERY_PROPERTY, StorageStackDeviceObject,
(PVOID)&Query,sizeof(STORAGE_PROPERTY_QUERY),
(PVOID)Buffer,sizeof(STORAGE_DEVICE_DESCRIPTOR)*4,
FALSE,&WaitEvent_newIrp,&IoStatus);
if(NewIrp2==NULL)
{
return STATUS_SUCCESS;
}
Status = IoCallDriver(StorageStackDeviceObject, NewIrp2);// send this irp to the storage device
if (Status == STATUS_PENDING)
{
KeWaitForSingleObject(&WaitEvent_newIrp, Executive, KernelMode, FALSE, NULL);
Status =IoStatus.Status;
}
}
__finally
{
if(NT_SUCCESS(Status))
{
if (NT_SUCCESS(Status))
{
if(Buffer!=NULL)
{
char szStart[256];
Descriptor = (PSTORAGE_DEVICE_DESCRIPTOR)Buffer;
uBusType = Descriptor->BusType; //Get the bus type.
if(Descriptor->SerialNumberOffset!=0)//Is Valid SerialNumberOffset, returns 103
{
strcpy(szStart,(char*)(UINT_PTR)Descriptor+(DWORD32)Descriptor->SerialNumberOffset);
//szStart is null
}
}
NewIrp2 = NULL;
}
}
}
}
please share how to solve this
you mistake in OutputBufferLength - why you decide that sizeof(STORAGE_DEVICE_DESCRIPTOR)*4 is enough ? why not 5* sizeof(STORAGE_DEVICE_DESCRIPTOR) for example ? really what OutputBufferLength must be is unknown - you need call this query in loop and compare your current OutputBufferLength with STORAGE_DEVICE_DESCRIPTOR.Size - if OutputBufferLength < STORAGE_DEVICE_DESCRIPTOR.Size - you must again send IOCTL_STORAGE_QUERY_PROPERTY with OutputBufferLength = STORAGE_DEVICE_DESCRIPTOR.Size. the code can be look like.
STORAGE_PROPERTY_QUERY spq = { StorageDeviceProperty, PropertyStandardQuery };
union {
PVOID buf;
PSTR psz;
PSTORAGE_DEVICE_DESCRIPTOR psdd;
};
ULONG size = sizeof(STORAGE_DEVICE_DESCRIPTOR) + 0x100;
NTSTATUS status = STATUS_INSUFFICIENT_RESOURCES;
do
{
status = STATUS_INSUFFICIENT_RESOURCES;
if (buf = ExAllocatePool(PagedPool, size))
{
switch (status = (NtDeviceIoControlFile(hFile, 0, 0, 0, &iosb,
IOCTL_STORAGE_QUERY_PROPERTY, &spq, sizeof(spq), buf, size)))
{
case STATUS_SUCCESS:
case STATUS_BUFFER_OVERFLOW:
if (psdd->Version == sizeof(STORAGE_DEVICE_DESCRIPTOR))
{
if (psdd->Size > size)
{
size = psdd->Size;
status = STATUS_BUFFER_OVERFLOW;
}
else
{
if (psdd->SerialNumberOffset)
{
DbgPrint("SerialNumber = %s\n", psz + psdd->SerialNumberOffset);
}
}
}
else
{
status = STATUS_INVALID_PARAMETER;
}
break;
}
ExFreePool(buf);
}
} while (status == STATUS_BUFFER_OVERFLOW);
in place NtDeviceIoControlFile we of course can use IoBuildDeviceIoControlRequest + IoCallDriver - this nothing change and unrelated to problem

monitor session change event in c

I try to build a service that monitor user sessions activity. currently focusing on logon and lock of user.
i am using http://msdn.microsoft.com/en-us/library/bb540475(v=VS.85).aspx example
my code :
#include <windows.h>
#include <tchar.h>
#include <strsafe.h>
#pragma comment(lib, "advapi32.lib")
#define SVCNAME TEXT("SvcName")
#define SVC_ERROR 4
SERVICE_STATUS gSvcStatus;
SERVICE_STATUS_HANDLE gSvcStatusHandle;
HANDLE ghSvcStopEvent = NULL;
VOID SvcInstall(void);
DWORD WINAPI SvcCtrlHandler(DWORD , DWORD , LPVOID , LPVOID );
VOID WINAPI SvcMain(DWORD, LPTSTR *);
VOID ReportSvcStatus(DWORD, DWORD, DWORD);
VOID SvcInit(DWORD, LPTSTR *);
VOID SvcReportEvent(LPTSTR);
void __cdecl _tmain(int argc, TCHAR *argv[])
{
if (lstrcmpi(argv[1], TEXT("install")) == 0)
{
SvcInstall();
return;
}
SERVICE_TABLE_ENTRY DispatchTable[] =
{
{ SVCNAME, (LPSERVICE_MAIN_FUNCTION)SvcMain },
{ NULL, NULL }
};
if (!StartServiceCtrlDispatcher(DispatchTable))
{
SvcReportEvent(TEXT("StartServiceCtrlDispatcher"));
}
}
VOID SvcInstall()
{
SC_HANDLE schSCManager;
SC_HANDLE schService;
TCHAR szPath[MAX_PATH];
if (!GetModuleFileName(NULL, szPath, MAX_PATH))
{
printf("Cannot install service (%d)\n", GetLastError());
return;
}
schSCManager = OpenSCManager(
NULL, // local computer
NULL, // ServicesActive database
SC_MANAGER_ALL_ACCESS); // full access rights
if (NULL == schSCManager)
{
printf("OpenSCManager failed (%d)\n", GetLastError());
return;
}
// Create the service
schService = CreateService(
schSCManager, // SCM database
SVCNAME, // name of service
SVCNAME, // service name to display
SERVICE_ALL_ACCESS, // desired access
SERVICE_WIN32_OWN_PROCESS, // service type
SERVICE_AUTO_START, // start type
SERVICE_ERROR_NORMAL, // error control type
szPath, // path to service's binary
NULL, // no load ordering group
NULL, // no tag identifier
NULL, // no dependencies
NULL, // LocalSystem account
NULL); // no password
if (schService == NULL)
{
printf("CreateService failed (%d)\n", GetLastError());
CloseServiceHandle(schSCManager);
return;
}
else printf("Service installed successfully\n");
CloseServiceHandle(schService);
CloseServiceHandle(schSCManager);
}
VOID WINAPI SvcMain(DWORD dwArgc, LPTSTR *lpszArgv)
{
gSvcStatusHandle = RegisterServiceCtrlHandler(SVCNAME,SvcCtrlHandler,NULL);
OutputDebugString(L"\n***SVCMAIN");
if (!gSvcStatusHandle)
{
SvcReportEvent(TEXT("RegisterServiceCtrlHandler"));
return;
}
gSvcStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
gSvcStatus.dwServiceSpecificExitCode = 0;
ReportSvcStatus(SERVICE_START_PENDING, NO_ERROR, 3000);
SvcInit(dwArgc, lpszArgv);
}
VOID SvcInit(DWORD dwArgc, LPTSTR *lpszArgv)
{
FILE *f = fopen("c:\\test\\file.txt", "a");
OutputDebugString(L"\n***SVCINIT");
fprintf(f, "init\n");
fclose(f);
ghSvcStopEvent = CreateEvent(
NULL, // default security attributes
TRUE, // manual reset event
FALSE, // not signaled
NULL); // no name
if (ghSvcStopEvent == NULL)
{
ReportSvcStatus(SERVICE_STOPPED, NO_ERROR, 0);
return;
}
ReportSvcStatus(SERVICE_RUNNING, NO_ERROR, 0);
while (WaitForSingleObject(ghSvcStopEvent, 3000) != WAIT_OBJECT_0){
OutputDebugString(L"\n***BEEP");
f = fopen("c:\\test\\file.txt", "a");
fprintf(f, "beep\n");
fclose(f);
Beep(1000, 100);
}
ReportSvcStatus(SERVICE_STOPPED, NO_ERROR, 0);
}
VOID ReportSvcStatus(DWORD dwCurrentState,
DWORD dwWin32ExitCode,
DWORD dwWaitHint)
{
static DWORD dwCheckPoint = 1;
DWORD my_error = 0;
// Fill in the SERVICE_STATUS structure.
gSvcStatus.dwCurrentState = dwCurrentState;
gSvcStatus.dwWin32ExitCode = dwWin32ExitCode;
gSvcStatus.dwWaitHint = dwWaitHint;
gSvcStatus.dwControlsAccepted = SERVICE_ACCEPT_SESSIONCHANGE | SERVICE_ACCEPT_STOP;
if ((dwCurrentState == SERVICE_RUNNING) ||
(dwCurrentState == SERVICE_STOPPED)){
gSvcStatus.dwCheckPoint = 0;
}
else gSvcStatus.dwCheckPoint = dwCheckPoint++;
// Report the status of the service to the SCM.
SetServiceStatus(gSvcStatusHandle, &gSvcStatus);
my_error = GetLastError();
FILE *f = fopen("c:\\test\\file.txt", "a");
fprintf(f, "last error %d \n",my_error);
fprintf(f, "\n***controls accepted %d ***\n", gSvcStatus.dwControlsAccepted);
fclose(f);
}
DWORD WINAPI SvcCtrlHandler(DWORD dwControl, DWORD dwEventType, LPVOID lpEventData, LPVOID lpContext)
{
DWORD dwErrorCode = NO_ERROR;
FILE *f = fopen("c:\\test\\file.txt", "a");
// Handle the requested control code.
fprintf(f, "dwCtrl is = %d \n", dwControl);
fclose(f);
switch (dwControl)
{
case SERVICE_CONTROL_TIMECHANGE:
f = fopen("c:\\test\\file.txt", "a");
fprintf(f, "time\n");
fclose(f);
OutputDebugString(L"\n****GOT time!!!\n\n");
SetEvent(ghSvcStopEvent);
ReportSvcStatus(gSvcStatus.dwCurrentState, NO_ERROR, 0);
break;
case SERVICE_CONTROL_SESSIONCHANGE:
f = fopen("c:\\test\\file.txt", "a");
fprintf(f, "session\n");
fclose(f);
OutputDebugString(L"\n****GOT Session!\n\n");
SetEvent(ghSvcStopEvent);
ReportSvcStatus(gSvcStatus.dwCurrentState, NO_ERROR, 0);
break;
case SERVICE_CONTROL_STOP:
OutputDebugString(L"\n****GOT STOP!\n\n");
f = fopen("c:\\test\\file.txt", "a");
fprintf(f, "stop\n");
fclose(f);
ReportSvcStatus(SERVICE_STOP_PENDING, NO_ERROR, 0);
SetEvent(ghSvcStopEvent);
ReportSvcStatus(gSvcStatus.dwCurrentState, NO_ERROR, 0);
return;
case SERVICE_CONTROL_INTERROGATE:
break;
default:
break;
}
}
VOID SvcReportEvent(LPTSTR szFunction)
{
HANDLE hEventSource;
LPCTSTR lpszStrings[2];
TCHAR Buffer[80];
hEventSource = RegisterEventSource(NULL, SVCNAME);
if (NULL != hEventSource)
{
StringCchPrintf(Buffer, 80, TEXT("%s failed with %d"), szFunction, GetLastError());
lpszStrings[0] = SVCNAME;
lpszStrings[1] = Buffer;
ReportEvent(hEventSource, // event log handle
EVENTLOG_ERROR_TYPE, // event type
0, // event category
SVC_ERROR, // event identifier
NULL, // no security identifier
2, // size of lpszStrings array
0, // no binary data
lpszStrings, // array of strings
NULL); // no binary data
DeregisterEventSource(hEventSource);
}
}
any ideas why i am not getting any "case SERVICE_CONTROL_SESSIONCHANGE" and only stop?
in my log file i see the beep log and controls accepted - 129 (stop + session change)
this is my log file content :
last error 0
***controls accepted 129 ***
init
last error 0
***controls accepted 129 ***
beep
beep
beep
beep
beep
gSvcStatusHandle = RegisterServiceCtrlHandler(SVCNAME,SvcCtrlHandler,NULL);
should be :
gSvcStatusHandle = RegisterServiceCtrlHandlerEx(SVCNAME,SvcCtrlHandler,NULL);

How does HidD_GetAttributes retrieve the attributes from a Device Object?

I'm working on creating a virtual HID device in Windows 10. To prepare myself for writing the drivers, I've been analyzing the sample provided here: https://github.com/Microsoft/Windows-driver-samples/tree/master/hid/vhidmini2.
In the file app/testvhid.c, HidD_GetAttributes is used to retrieve the attributes of the HID device. It appears that the attributes are initialized in driver/vhidmini.c (hidAttributes in the EvtDeviceAdd function). However, hidAttributes is stored inside of a DEVICE_CONTEXT structure, which (from my understanding) is defined by the driver.
If hidAttributes is a user defined attribute, then how does HidD_GetAttributes know to retrieve it from the device?
I've tried to replicate this for myself by creating a KMDF driver which is based mostly on the sample given. The relevant driver code is as follows (The majority of this was taken from the sample, with the exception of the call to WdfDeviceCreateDeviceInterface):
NTSTATUS
kmdfTest2CreateDevice(
_Inout_ PWDFDEVICE_INIT DeviceInit
)
{
WDF_OBJECT_ATTRIBUTES deviceAttributes;
PDEVICE_CONTEXT deviceContext;
WDFDEVICE device;
NTSTATUS status;
PHID_DEVICE_ATTRIBUTES hidAttributes;
WdfFdoInitSetFilter(DeviceInit);
WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&deviceAttributes, DEVICE_CONTEXT);
status = WdfDeviceCreate(&DeviceInit, &deviceAttributes, &device);
if (NT_SUCCESS(status)) {
deviceContext = DeviceGetContext(device);
deviceContext->Device = device;
deviceContext->DeviceData = 0;
hidAttributes = &deviceContext->HidDeviceAttributes;
RtlZeroMemory(hidAttributes, sizeof(HID_DEVICE_ATTRIBUTES));
hidAttributes->Size = sizeof(HID_DEVICE_ATTRIBUTES);
hidAttributes->VendorID = HIDMINI_VID;
hidAttributes->ProductID = HIDMINI_PID;
hidAttributes->VersionNumber = HIDMINI_VERSION;
if (NT_SUCCESS(status)) {
status = kmdfTest2QueueInitialize(device);
}
deviceContext->HidDescriptor = G_DefaultHidDescriptor;
deviceContext->ReportDescriptor = G_DefaultReportDescriptor;
status = WdfDeviceCreateDeviceInterface(
device,
&GUID_DEVINTERFACE_HID,
NULL // ReferenceString
);
}
return status;
}
The relevant section of code in the user mode test application is as follows (this code is virtually entirely from the given sample):
BOOLEAN
CheckIfOurDevice(
HANDLE file)
{
PHIDP_PREPARSED_DATA Ppd; // The opaque parser info describing this device
HIDP_CAPS Caps; // The Capabilities of this hid device.
HIDD_ATTRIBUTES attr; // Device attributes
if (!HidD_GetAttributes(file, &attr))
{
printf("Error: HidD_GetAttributes failed \n");
return FALSE;
}
printf("Device Attributes - PID: 0x%x, VID: 0x%x \n", attr.ProductID, attr.VendorID);
if ((attr.VendorID != HIDMINI_VID) || (attr.ProductID != HIDMINI_PID))
{
printf("Device attributes doesn't match the sample \n");
return FALSE;
}
if (!HidD_GetPreparsedData(file, &Ppd))
{
printf("Error: HidD_GetPreparsedData failed \n");
return FALSE;
}
if (!HidP_GetCaps(Ppd, &Caps))
{
printf("Error: HidP_GetCaps failed \n");
HidD_FreePreparsedData(Ppd);
return FALSE;
}
if ((Caps.UsagePage == g_MyUsagePage) && (Caps.Usage == g_MyUsage)) {
printf("Success: Found my device.. \n");
return TRUE;
}
else {
printf("failed: UsagePage: %d, Usage: %d \n", Caps.UsagePage, Caps.Usage);
}
return FALSE;
}
BOOLEAN
GetHidInterface(_Out_ HANDLE* Handle) {
CONFIGRET cr = CR_SUCCESS;
*Handle = INVALID_HANDLE_VALUE;
ULONG deviceInterfaceListLength = 0;
GUID InterfaceGuid;
PSTR deviceInterfaceList = NULL;
HANDLE devHandle = INVALID_HANDLE_VALUE;
if (NULL == Handle) {
printf("Error: Invalid device handle parameter\n");
return FALSE;
}
HidD_GetHidGuid(&InterfaceGuid);
cr = CM_Get_Device_Interface_List_Size(
&deviceInterfaceListLength,
&InterfaceGuid,
NULL,
CM_GET_DEVICE_INTERFACE_LIST_PRESENT);
if (cr != CR_SUCCESS) {
printf("Error 0x%x retrieving device interface list size.\n", cr);
return FALSE;
}
if (deviceInterfaceListLength <= 1) {
printf("Error: No active device interfaces found.\n"
" Is the sample driver loaded?");
return FALSE;
}
deviceInterfaceList = (PSTR)malloc(deviceInterfaceListLength * sizeof(WCHAR));
if (deviceInterfaceList == NULL) {
printf("Error allocating memory for device interface list.\n");
return FALSE;
}
ZeroMemory(deviceInterfaceList, deviceInterfaceListLength * sizeof(WCHAR));
cr = CM_Get_Device_Interface_List(
&InterfaceGuid,
NULL,
deviceInterfaceList,
deviceInterfaceListLength,
CM_GET_DEVICE_INTERFACE_LIST_PRESENT);
if (cr != CR_SUCCESS) {
printf("Error 0x%x retrieving device interface list.\n", cr);
return FALSE;
}
printf("\n....looking for our HID device (with UP=0x%04X "
"and Usage=0x%02X)\n", g_MyUsagePage, g_MyUsage);
PSTR currentInterface;
for (currentInterface = deviceInterfaceList;
*currentInterface;
currentInterface += strlen(currentInterface) + 1) {
devHandle = CreateFile(currentInterface,
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL, // no SECURITY_ATTRIBUTES structure
OPEN_EXISTING, // No special create flags
0, // No special attributes
NULL); // No template file
if (INVALID_HANDLE_VALUE == devHandle) {
printf("Warning: CreateFile failed: %d\n", GetLastError());
continue;
}
if (CheckIfOurDevice(devHandle)) {
*Handle = devHandle;
return TRUE;
}
else {
CloseHandle(devHandle);
}
}
return FALSE;
}
The HidD_GetAttributes function passes, but the CheckIfOurDevice function fails when checking the device attributes ("Device attributes doesn't match the sample"). I've checked some of the attribute values that are being set by HidD_GetAttributes, but they don't match up with the ones set by the driver. Is the sample making some other call that I'm missing?

How to set l2tp preshared key?

I need to create RASENTRY for L2TP with pre-shared key set. So far, I can see that entry has somewhat correct flags, but no key is set, unfortunately.
Here is code:
int common_ras_manager_create_entry(const char* server_address, const char* username, const char* password, MY_VPN_CONNECTION_TYPE connection_type, const char* preshared_key)
{
DWORD EntryInfoSize = 0;
DWORD DeviceInfoSize = 0;
DWORD Ret;
LPRASENTRY lpRasEntry;
LPBYTE lpDeviceInfo;
// Get buffer sizing information for a default phonebook entry
if ((Ret = RasGetEntryProperties(NULL, "", NULL, &EntryInfoSize, lpDeviceInfo, &DeviceInfoSize)) != 0)
{
if (Ret != ERROR_BUFFER_TOO_SMALL)
{
printf("RasGetEntryProperties sizing failed with error %d\n", Ret);
return Ret;
}
}
lpRasEntry = (LPRASENTRY) GlobalAlloc(GPTR, EntryInfoSize);
if (DeviceInfoSize == 0)
lpDeviceInfo = NULL;
else
lpDeviceInfo = (LPBYTE) GlobalAlloc(GPTR, DeviceInfoSize);
// Get default phonebook entry
lpRasEntry->dwSize = sizeof(RASENTRY);
if ((Ret = RasGetEntryProperties(NULL, "", lpRasEntry, &EntryInfoSize, lpDeviceInfo, &DeviceInfoSize)) != 0)
{
printf("RasGetEntryProperties failed with error %d\n", Ret);
return Ret;
}
// Validate new phonebook name "Testentry"
if ((Ret = RasValidateEntryName(NULL, APP_NAME)) != ERROR_SUCCESS)
{
printf("RasValidateEntryName failed with error %d\n", Ret);
if (Ret != ERROR_ALREADY_EXISTS)
return Ret;
}
LPRASDEVINFO ras_devices;
DWORD cb =sizeof(RASDEVINFO);
DWORD cbDevices = 0;
ras_devices = (LPRASDEVINFO)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, cb);
if (NULL == ras_devices)
{
printf("HeapAlloc failed.\n");
return ERROR_OUTOFMEMORY;
}
ras_devices->dwSize = sizeof(RASDEVINFO);
if ((Ret = RasEnumDevices(ras_devices, &cb, &cbDevices)) != ERROR_SUCCESS)
{
printf("RasEnumDevices failed with error %d\n", Ret);
switch(Ret)
{
case ERROR_BUFFER_TOO_SMALL:
printf("buffer too small");
HeapFree(GetProcessHeap(), 0, (LPVOID)ras_devices);
ras_devices = (LPRASDEVINFO)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, cb);
if (NULL == ras_devices)
{
printf("HeapAlloc failed.\n");
return ERROR_OUTOFMEMORY;
}
ras_devices->dwSize = sizeof(RASDEVINFO);
Ret = RasEnumDevices(ras_devices, &cb, &cbDevices);
if (ERROR_SUCCESS == Ret)
{
//fSuccess = TRUE;
}
else
{
printf("RasEnumDevices failed again: Error = %d\n", Ret);
return Ret;
//goto done;
}
break;
case ERROR_NOT_ENOUGH_MEMORY:
printf("ERROR_NOT_ENOUGH_MEMORY");
return Ret;
break;
case ERROR_INVALID_PARAMETER:
printf("ERROR_INVALID_PARAMETER");
return Ret;
break;
case ERROR_INVALID_USER_BUFFER:
printf("ERROR_INVALID_USER_BUFFER");
return Ret;
break;
}
}
DWORD dwVpnStrategy = 0;
char device_name_mask[5];
strcpy(device_name_mask, "");
gboolean preshared_key_valid = 0;
switch(connection_type)
{
case PPTP:
strcpy(device_name_mask, "PPTP");
dwVpnStrategy = VS_PptpOnly;
break;
case L2TP:
if (preshared_key == 0 || strlen(preshared_key) == 0)
{
printf("CRITICAL: preshared key not set.");
return 1;
}
else
{
preshared_key_valid = TRUE;
}
strcpy(device_name_mask, "L2TP");
dwVpnStrategy = VS_L2tpOnly;
break;
}
int i =0;
for (i = 0; i < cbDevices; i++)
{
RASDEVINFO r = ras_devices[i];
if (strstr(r.szDeviceName, device_name_mask))
{
break;
}
}
//lpRasEntry->dwfOptions |= RASEO_SpecificIpAddr;
//lpRasEntry->szLocalPhoneNumber = RASDT_Vpn;
lpRasEntry->dwfNetProtocols |= RASNP_Ip;
lpRasEntry->dwFramingProtocol = RASFP_Ppp;
lstrcpy(lpRasEntry->szDeviceType, RASDT_Vpn);
lstrcpy(lpRasEntry->szDeviceName, ras_devices[i].szDeviceName);
lstrcpy(lpRasEntry->szLocalPhoneNumber, server_address);
lpRasEntry->dwVpnStrategy = dwVpnStrategy; // VS_PptpOnly; VS_SstpOnly
if (preshared_key_valid)
{
L2TP_CONFIG_DATA* data = GlobalAlloc(GPTR, sizeof(L2TP_CONFIG_DATA));
lpRasEntry->dwfOptions2 |= RASEO2_UsePreSharedKey;
data->dwOffsetKey = 16;
memcpy((PBYTE)data + data->dwOffsetKey, preshared_key, strlen(preshared_key));
data->dwAuthType =L2TP_IPSEC_AUTH_PRESHAREDKEY;
RasSetCustomAuthData(NULL, APP_NAME, data, sizeof(L2TP_CONFIG_DATA));
}
if ((Ret = RasSetEntryProperties(NULL, APP_NAME, lpRasEntry, EntryInfoSize, lpDeviceInfo, DeviceInfoSize)) != 0)
{
printf("RasSetEntryProperties failed with error %d\n", Ret);
return Ret;
}
//if ((Ret = RasSetCredentials(NULL, lpRasEntry.))
}
I cant find where is buffer to fill for pre-shared key.
Following code works fine.
// l2tp
if (preshared_key_valid)
{
RASCREDENTIALS ras_cre_psk = {0};
ras_cre_psk.dwSize = sizeof(ras_cre_psk);
ras_cre_psk.dwMask = 0x00000010; //RASCM_PreSharedKey;
wcscpy(ras_cre_psk.szPassword, preshared_key);
if ((Ret = RasSetCredentials(NULL, APP_NAME, &ras_cre_psk, FALSE)))
{
printf("RasSetCredentials failed with error %d\n", Ret);
return Ret;
}
}

Resources