minifilter send message to r3 - windows

I'm writing a minifilter, which wants to notify the r3 application to popup a messagebox in some cases. I used fltsendmessage in minifilter and filtergetmessage in r3. In r3 application, I wrote like:
while (INVALID_HANDLE_VALUE == s_portWorker.m_clientPort)
{
hResult = FilterConnectCommunicationPort(SERVER_PORTNAME_POPUP, 0, NULL, 0, NULL, &s_portWorker.m_clientPort);
if (IS_ERROR(hResult)) {
Sleep(1000);
}
while (true)
{
ZeroMemory(&getStruct, sizeof(GET_STRUCT));
hResult = FilterGetMessage(s_portWorker.m_clientPort, (PFILTER_MESSAGE_HEADER)&getStruct, sizeof(GET_STRUCT), NULL);
}
}
It works fine. But when I stop my minifilter, calling FltCloseCommunicationPort() in driver unload. The port has been closed, but the connection is still in, my r3 process will blocks on FilterGetMessage and never return.
I want to stop waiting the messagew when port close, and try to reconnect to my minifilter. What should I do? Since that FilterGetMessage() routine doesn't support a timeout mechanism, Do I have to create a event to notify the r3 when stop the filter?

You can implement a timeout mechanism by using lpOverlapped parameter.
HANDLE hWait = CreateEvent(NULL, TRUE, FALSE, NULL);
OVERLAPPED op = {0};
op.hEvent = hWait;
HRESULT hResult = FilterGetMessage(s_portWorker.m_clientPort, (PFILTER_MESSAGE_HEADER)&getStruct, sizeof(GET_STRUCT), &op);
if (hResult == HRESULT_FROM_WIN32(ERROR_IO_PENDING))
{
HANDLE phHandles[2] = { hWait, g_hTerm };
WaitForMultipleObjects(2, phHandles, TIME_OUT_VALUE);
}
And you can stop listenning by calling SetEvent(g_hTerm);

Related

Blue screen when rewriting packets at DATAGRAM_DATA layer in WFP

I've been trying to modify outgoing DNS packets via the DATAGRAM_DATA layer in WFP, however i get blue screen errors when rewriting the destination ip in the outgoing packet. What am i doing wrong?
I admit i found the parameters for FwpsInjectTransportSendAsync a bit confusing, and was unsure exactly what to put in for the sendParams arg - though i think what i have looks right.
RtlIpv4StringToAddressExW(
L"1.1.1.1", // hard-coding the new (rewritten) dns server for now
FALSE,
&sin4.sin_addr,
&sin4.sin_port);
RtlIpv4StringToAddressExW(
L"8.8.8.8", // hard-coding the original dns server for now
FALSE,
&origSin4.sin_addr,
&origSin4.sin_port);
if ((Direction == FWP_DIRECTION_OUTBOUND) && (PacketInjectionState == FWPS_PACKET_NOT_INJECTED) && (RemotePort == 53) && (RemoteAddress == origSin4.sin_addr.S_un.S_addr))
{
UINT32 IpHeaderSize = inMetaValues->ipHeaderSize;
UINT32 TransportHeaderSize = inMetaValues->transportHeaderSize;
UINT64 endpointHandle = inMetaValues->transportEndpointHandle;
PNET_BUFFER NetBuffer = NET_BUFFER_LIST_FIRST_NB((PNET_BUFFER_LIST)layerData);
NdisRetreatNetBufferDataStart(NetBuffer, IpHeaderSize + TransportHeaderSize, 0, NULL);
PNET_BUFFER_LIST NetBufferList = NULL;
NTSTATUS Status = FwpsAllocateCloneNetBufferList(layerData, NULL, NULL, 0, &NetBufferList);
if (!NT_SUCCESS(Status))
{
return;
}
NdisAdvanceNetBufferDataStart(NetBuffer, IpHeaderSize + TransportHeaderSize, FALSE, NULL);
if (!NetBufferList)
{
return;
}
NetBuffer = NET_BUFFER_LIST_FIRST_NB(NetBufferList);
PIPV4_HEADER IpHeader = NdisGetDataBuffer(NetBuffer, sizeof(IPV4_HEADER), NULL, 1, 0);
// Rewriting the dest ip
IpHeader->DestinationAddress = sin4.sin_addr.S_un.S_addr;
// Updating the IP checksum
UpdateIpv4HeaderChecksum(IpHeader, sizeof(IPV4_HEADER));
// not 100% sure the sendParams argument is setup correctly, the docs are slightly unclear
FWPS_TRANSPORT_SEND_PARAMS sendParams = {
.remoteAddress = (UCHAR*)IpHeader->DestinationAddress,
.remoteScopeId = inMetaValues->remoteScopeId,
.controlData = inMetaValues->controlData,
.controlDataLength = inMetaValues->controlDataLength,
.headerIncludeHeader = inMetaValues->headerIncludeHeader,
.headerIncludeHeaderLength = inMetaValues->headerIncludeHeaderLength
};
Status = FwpsInjectTransportSendAsync(g_InjectionHandle, NULL, endpointHandle, 0, &sendParams, AF_INET, inMetaValues->compartmentId, NetBufferList, DriverDatagramDataInjectComplete, NULL);
if (!NT_SUCCESS(Status))
{
FwpsFreeCloneNetBufferList(NetBufferList, 0);
}
classifyOut->actionType = FWP_ACTION_BLOCK;
classifyOut->rights &= ~FWPS_RIGHT_ACTION_WRITE;
classifyOut->flags |= FWPS_CLASSIFY_OUT_FLAG_ABSORB;
}
Two things stand out to me, both in the sendParams.
First, remoteAddress is incorrect. It needs to a pointer to the address, so it should be (UCHAR*)&IpHeader->DestinationAddress.
Second, FwpsInjectTransportSendAsync() is asynchronous so any parameters you pass to it need to stay valid until it completes which may be after your calling function returns. Typically you allocate some context structure that contains sendParams and deep copies of relevant members (remoteAddress and controlData). You pass this as the context to the completion routine where you free it.

Persistently write to a file from windows kernel driver

Hi I'm new to kernel level programming and trying to build a simple log writing driver. What I'm trying to achieve is to have a persistent driver will write referred text every predefined interval to a file in system path. (I'm not familiar IRQ hooking yet)
I have following globals for timing
// Timer
PKTIMER pTimer = NULL; // Pointer to the timer
PKDPC pDpcObject = NULL; // Pointer to the DPC
#define IDLE_INTERVAL (10000)
I call following code in the DriverEntry (However, problem with following code is its writing feature fails when computer restarted) Could someone suggest a fix ? Should it be called by IRQ Major call ?
while(1)
{
if (pTimer == NULL) // if timer object does not exist:
{
// Allocate memory for the object timer
pTimer = (PKTIMER) ExAllocatePool (NonPagedPool, sizeof (KTIMER));
KeInitializeTimer (pTimer); // Initialize the timer object
// Allocate memory for the DPC object and initialize it
pDpcObject = (PKDPC) ExAllocatePool (NonPagedPool, sizeof (KDPC));
KeInitializeDpc (pDpcObject, MyDeferredRoutine, pTimer);
}
LARGE_INTEGER dueTime;
dueTime.QuadPart = -10000 * IDLE_INTERVAL; // 10000 * 10000 * 1 ns
// "Platoon" timer:
KeSetTimerEx (pTimer,
dueTime, // latency relative interval
(IDLE_INTERVAL / 2), // period of 5 seconds, i.e. 5000 * 1 ms
pDpcObject);
if (KeReadStateTimer (pTimer))
{
//DbgPrint ("- Example- KeReadStateTimer returns TRUE.");
}
else
{
// DbgPrint ("- Example- KeReadStateTimer returns FALSE.");
}
}
Status = KeWaitForSingleObject (pTimer,
Executive, // IN KWAIT_REASON WaitReason,
KernelMode, // IN KPROCESSOR_MODE WaitMode,
FALSE, // IN BOOLEAN Alertable,
NULL); // IN PLARGE_INTEGER Timeout OPTIONAL
RtlInitUnicodeString(&TestName, L"\\??\\C:\\log.txt");
InitializeObjectAttributes(&ObjAttr, &TestName,
OBJ_CASE_INSENSITIVE,
0, NULL);
Status = NtCreateFile(&TestFile,
FILE_WRITE_DATA + SYNCHRONIZE,
&ObjAttr,
&IoStatus, NULL,
FILE_ATTRIBUTE_NORMAL,
FILE_SHARE_WRITE,
FILE_OVERWRITE_IF,
FILE_SYNCHRONOUS_IO_NONALERT,
NULL, 0);
if(Status == STATUS_SUCCESS)
{
Status = NtWriteFile(TestFile,
0, NULL, NULL,
&IoStatus,
(PCHAR)"OUR LOG STORED TO LOG FILE",
22,
NULL, NULL);
}
NtClose(TestFile);
}

Opening COM1 port using CreateFile is returning invalide handle

i have connected my wince device with pc.now from my code i am using following code to open COM1 port and write on it. but it is not opening.Why?
WCHAR* m_PortNam = L"COM1";
m_hCOM = CreateFile(m_PortName, // Specify port device: default "COM1"
GENERIC_WRITE, // Specify mode that open device.
0, // the devide isn't shared.
NULL, // the object gets a default security.
OPEN_EXISTING, // Specify which action to take on file.
0, // default.
NULL);
// default.
if(m_hCOM != INVALID_HANDLE_VALUE)
{
}
else
{
//always going here
}
In Windows CE, the port name must include the colon:
TCHAR *m_PortName = _T("COM1:");

Get windows session's user name in c++

I am trying to understand better how Windows sessions (TS sessions and log on sessions) works (currently in XP), so maybe my whole question or what I am trying to do is impossible.
I am running a Windows service (in XP), which runs in session 0, and I am trying to get the username attached to this session using WTSQueryUserToken().
Now, in session 0 there are several usernames: SYSTEM, theuser (logged on user),NETWORK SERVICE, LOCAL SERVICE.
When I use WTSQueryUserToken() I get "theuser" (which is the Active session), but I am trying to get the username of my service (which is SYSTEM).
Is that possible or did I simply get it all wrong?
I use the following code to get user token for my process
HANDLE GetProcessOwnerToken(DWORD pid)
{
if (!pid) return NULL;
HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);
if (!hProcess) return NULL;
HANDLE hToken = NULL;
if(OpenProcessToken(hProcess, MAXIMUM_ALLOWED, &hToken))
{
HANDLE result = INVALID_HANDLE_VALUE;
if(DuplicateTokenEx(hToken, TOKEN_ASSIGN_PRIMARY | TOKEN_ALL_ACCESS, NULL, SecurityImpersonation, TokenPrimary, &result))
{
if(result != INVALID_HANDLE_VALUE)
{
CloseHandle(hToken);
CloseHandle(hProcess);
return result;
}
}
CloseHandle(hToken);
}
CloseHandle(hProcess);
return NULL;
}
I have no idea if it works for services as well, I think it should.

Multithreaded IOCP Client Issue

I am writing a multithreaded client that uses an IO Completion Port.
I create and connect the socket that has the WSA_FLAG_OVERLAPPED attribute set.
if ((m_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == INVALID_SOCKET)
{
throw std::exception("Failed to create socket.");
}
if (WSAConnectByName(m_socket, L"server.com", L"80", &localAddressLength, reinterpret_cast<sockaddr*>(&localAddress), &remoteAddressLength, &remoteAddress, NULL, NULL) == FALSE)
{
throw std::exception("Failed to connect.");
}
I associate the IO Completion Port with the socket.
if ((m_hIOCP = CreateIoCompletionPort(reinterpret_cast<HANDLE>(m_socket), m_hIOCP, NULL, 8)) == NULL)
{
throw std::exception("Failed to create IOCP object.");
}
All appears to go well until I try to send some data over the socket.
SocketData* socketData = new SocketData;
socketData->hEvent = 0;
DWORD bytesSent = 0;
if (WSASend(m_socket, socketData->SetBuffer(socketData->GenerateLoginRequestHeader()), 1, &bytesSent, NULL, reinterpret_cast<OVERLAPPED*>(socketData), NULL) == SOCKET_ERROR && WSAGetLastError() != WSA_IO_PENDING)
{
throw std::exception("Failed to send data.");
}
Instead of returning SOCKET_ERROR with the last error set to WSA_IO_PENDING, WSASend returns immediately.
I need the IO to pend and for it's completion to be handled in my thread function which is also my worker thread.
unsigned int __stdcall MyClass::WorkerThread(void* lpThis)
{
}
I've done this before but I don't know what is going wrong in this case, I'd greatly appreciate any efforts in helping me fix this problem.
It's not a problem unless you make it so.
As long as you're not calling SetFileCompletionNotificationModes() and setting the flag to skip completion port processing on success then even if WSARecv (or whatever) returns SUCCESS an IO Completion Packet is queued to the IOCP the same as if ERROR_IO_PENDING was returned. Thus you need no special handling for the non error return case.
See http://support.microsoft.com/default.aspx?scid=kb;en-us;Q192800 for details.
First of all break the call into more clear logic:
int nRet = WSASend(m_socket, socketData->SetBuffer(socketData->GenerateLoginRequestHeader()), 1, NULL, NULL, reinterpret_cast<OVERLAPPED*>(socketData), NULL);
if (nRet == SOCKET_ERROR)
{
if ((WSAGetLastError()) == WSA_IO_PENDING)
nRet = 0; // ok
else
throw std::exception("Failed to send data."); // failed
}
Also, as you can see in my code, you should NOT pass the "&bytesSent" parameter according to WSASend:
Use NULL for this parameter if the
lpOverlapped parameter is not NULL to
avoid potentially erroneous results.
Besides that your call to WSASend() looks fine.

Resources