Keyboard Filter Driver BSOD - windows

I do not understand why my source code is not working properly.
My source code is just a simple driver that just drops the IRP.
#include <wdm.h>
typedef struct
{
PDEVICE_OBJECT NextLayerDeviceObject;
} DEVICE_EXTENSION, *PDEVICE_EXTENSION;
const WCHAR next_device_name[] = L"\\Device\\KeyboardClass0";
const char dbg_name[] = "[Test]";
NTSTATUS IrpSkip(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
{
NTSTATUS ret = STATUS_SUCCESS;
PIO_STACK_LOCATION Stack = IoGetCurrentIrpStackLocation(Irp);
DbgPrint("%s IrpSkip() Start\n", dbg_name);
DbgPrint("%s IrpSkip() - MajorFunction %d\n", dbg_name, Stack->MajorFunction);
IoSkipCurrentIrpStackLocation(Irp);
ret = IoCallDriver(((PDEVICE_EXTENSION)(DeviceObject->DeviceExtension))->NextLayerDeviceObject, Irp);
DbgPrint("%s IrpSkip() End\n", dbg_name);
return ret;
}
NTSTATUS Unload(IN PDRIVER_OBJECT DriverObject)
{
NTSTATUS ret = STATUS_SUCCESS;
IoDetachDevice(((PDEVICE_EXTENSION)(DriverObject->DeviceObject->DeviceExtension))->NextLayerDeviceObject);
IoDeleteDevice(DriverObject->DeviceObject);
DbgPrint("%s Unload()...\n", dbg_name);
return ret;
}
NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath)
{
NTSTATUS ret=STATUS_SUCCESS;
UNICODE_STRING _next_device_name;
DbgSetDebugFilterState(DPFLTR_DEFAULT_ID, DPFLTR_INFO_LEVEL, TRUE);
DbgPrint("%s DriverEntry() Start\n", dbg_name);
RtlInitUnicodeString(&_next_device_name, next_device_name);
for (int i = 0; i < IRP_MJ_MAXIMUM_FUNCTION ; i++)
{
DriverObject->MajorFunction[i] = IrpSkip;
}
DriverObject->DriverUnload = Unload;
//DriverObject->MajorFunction[IRP_MJ_READ] = Read;
PDEVICE_OBJECT DeviceObject = 0;
PDEVICE_EXTENSION DeviceExtension;
ret = IoCreateDevice(DriverObject, sizeof(DEVICE_EXTENSION), 0, FILE_DEVICE_KEYBOARD, 0, TRUE, &DeviceObject);
if (ret == STATUS_SUCCESS)
{
DbgPrint("%s DriverEntry() - IoCreateDevice() Success\n", dbg_name);
}
else
{
DbgPrint("%s DriverEntry() - IoCreateDevice() Fail\n", dbg_name);
return ret;
}
DeviceExtension = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;
DeviceObject->Flags |= (DO_BUFFERED_IO | DO_POWER_PAGABLE);
DeviceObject->Flags &= DO_DEVICE_INITIALIZING;
ret = IoAttachDevice(DeviceObject, &_next_device_name, &DeviceExtension->NextLayerDeviceObject);
if (ret == STATUS_SUCCESS)
{
DbgPrint("%s DriverEntry() - IoAttachDevice() Success\n", dbg_name);
}
else
{
DbgPrint("%s DriverEntry() - IoAttachDevice() Fail\n", dbg_name);
IoDeleteDevice(DriverObject->DeviceObject);
return ret;
}
DbgPrint("%s DriverEntry() End\n", dbg_name);
return ret;
}
Below are the results from WinDbg
[Test] DriverEntry() Start
[Test] DriverEntry() - IoCreateDevice() Success
[Test] IrpSkip() Start
[Test] IrpSkip() - MajorFunction 2
[Test] IrpSkip() End
[Test] DriverEntry() - IoAttachDevice() Success
[Test] DriverEntry() End
[Test] IrpSkip() Start
[Test] IrpSkip() - MajorFunction 3
[Test] IrpSkip() End
*** Fatal System Error: 0x0000000a
(0x00000000,0x00000002,0x00000001,0x82E41C24)
Break instruction exception - code 80000003 (first chance)
A fatal system error has occurred.
Debugger entered on first try; Bugcheck callbacks have not been invoked.
A fatal system error has occurred.
nt!RtlpBreakWithStatusInstruction:
82e83110 cc int 3
0: kd> k
# ChildEBP RetAddr
00 82f30634 82ee7083 nt!RtlpBreakWithStatusInstruction
01 82f30684 82ee7b81 nt!KiBugCheckDebugBreak+0x1c
02 82f30a48 82e495cb nt!KeBugCheck2+0x68b
03 82f30a48 82e41c24 nt!KiTrap0E+0x2cf
04 82f30ae4 8fba3588 nt!memmove+0x124
05 82f30b14 8fb8fb74 kbdclass!KeyboardClassServiceCallback+0xe0
06 82f30b78 82e801b5 i8042prt!I8042KeyboardIsrDpc+0x18c
07 82f30bd4 82e80018 nt!KiExecuteAllDpcs+0xf9
08 82f30c20 82e7fe38 nt!KiRetireDpcList+0xd5
09 82f30c24 00000000 nt!KiIdleLoop+0x38
It seems that CallBack is not working properly.
I do not know where the problem occurred.
I just dropped the IRP and I do not know why this is happening.
I have been searching for driver 's books and internet for two days but have not found the cause.
When the blue screen comes up, the message 'iRQL_NOT_LESS_OR_EQUAL' appears.
Help plz.
P.S. I do not speak English well. And that's the first question. I hope you understand if my question is strange.

Related

How to hook DNS query request in windows?

I want to hook DNS query request in windows, I use IAThook to hook "gethostbyname","getaddrinfo","GetAddrInfoW", "GetAddrInfoExA","GetAddrInfoExW","WSAAsyncGetHostByName", but seems most app didn't link the ws2_32.dll statically at all. So I also hook "GetProcAddress" in kernel32.dll, but them also don't use "gethostbyname"...at all(but the DNS query request actually be sent). I test this with MsEdge explorer and many other apps. I do this in LSP.
Do these apps not usr such as "gethostbyname" function to send a DNS request? How can I do?
Can somebody give me some help?
my code like this:
long hookGetProcAddress()
{
long ret = 0;
FUNCBEGINLOG
if (g_hHook_GetProcAddressFunc != NULL)
{
dbgprint("%s hookGetProcAddress already hooked!", moduleBaseName);
return ret;
}
ret = IATHook(GetModuleHandleW(NULL), "kernel32.dll", "GetProcAddress",
LSPGetProcAddress, &g_hHook_GetProcAddressFunc);
dbgprint("%s hookGetProcAddress func ret %d!", moduleBaseName, ret);
FUNCFINISHLOG
return ret;
}
long hookgethostbyname()
{
long ret = 0;
FUNCBEGINLOG
if (g_hHook_gethostbynameFunc != NULL)
{
dbgprint("%s hookgethostbyname already hooked!", moduleBaseName);
return ret;
}
ret = IATHook(GetModuleHandleW(NULL), "Ws2_32.dll", "gethostbyname",
LSPgethostbyname,
&g_hHook_gethostbynameFunc);
dbgprint("%s hookgethostbyname func ret %d!", moduleBaseName, ret);
FUNCFINISHLOG
return ret;
}
long hookgetaddrinfo()
{
long ret = 0;
FUNCBEGINLOG
if (g_hHook_getaddrinfoFunc != NULL)
{
dbgprint("%s hookgetaddrinfo already hooked!", moduleBaseName);
return ret;
}
ret = IATHook(GetModuleHandleW(NULL), "Ws2_32.dll", "getaddrinfo", LSPgetaddrinfo, &g_hHook_getaddrinfoFunc);
dbgprint("%s hookgetaddrinfo func ret %d!", moduleBaseName, ret);
FUNCFINISHLOG
return ret;
}

winsock time loop send message does not work

Using winsock, I got a client and a server, when connect is done and i send a message the first time i can recv it in the server but after that when I do a time loop i can not show them on the screen. the send message inside the time loop does not return an error. I know this is a weird problem but if you take a look at timerCb that's where the send function is, it does not return an error but in my server i cannot print it. I have also tried making a new while loop with a parameter of recv it still did not work.
This is my client,
char receivingMessage[1000];
char messageInitiation[90] = "Hello YUMATKARA, conn pls bro hhhasf7sasflljh89";
VOID CALLBACK timerCb(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime);
//main
SetTimer(NULL, 0, 3600, timerCb);
if(WSAStartup(MAKEWORD(2, 2), &ws) != 0){
printf("WSA err %d \n", GetLastError());
}else{
}
if((s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == INVALID_SOCKET){
printf("Invalid Socket \n");
}else{
printf("socket binded \n");
}
rmtServer.sin_addr.s_addr = inet_addr("127.0.0.1");
rmtServer.sin_port = htons(4743);
rmtServer.sin_family = AF_INET;
if((connect(s, (struct sockaddr*)&rmtServer, sizeof(struct sockaddr_in))) != 0){
printf("\n err %d", GetLastError());
}else{
printf("\n connected");
send(s, messageInitiation, strlen(messageInitiation), 0);
recv(s, receivingMessage, 1000, 0);
printf("\n %s", receivingMessage);
int liop;
liop = strcmp(receivingMessage, "I got you!!");
if(liop == 0){
connectedYet = TRUE;
}
printf("\n is it true: ? %d\n", connectedYet);
}
while(GetMessage(&message, NULL, 0, 0) > 0){
TranslateMessage(&message);
DispatchMessage(&message);
}
//outside main
VOID CALLBACK timerCb(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime){
char *msgg = "Hello YUMATKARA, conn pls bro hhhasf7sasflljh89";
printf("\n%s\n", "timing");
if(send(s, msgg, strlen(msgg), 0) == SOCKET_ERROR){
printf("err :%d\n", GetLastError());
}
}
And this is my server
#include <windows.h>
#include <winsock2.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdParam, int iCmdShow) {
MSG message;
WSADATA ws;
SOCKET s, incomingSocket;
struct sockaddr_in server, client;
char incomingMessage[1800];
int recvState;
WSAStartup(MAKEWORD(2, 2), &ws);
s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
server.sin_port = htons(4743);
server.sin_addr.s_addr = inet_addr("127.0.0.1");
server.sin_family = AF_INET;
bind(s, (struct sockaddr *)&server, sizeof(server));
listen(s, 1300);
int g = sizeof(struct sockaddr_in);
while((incomingSocket = accept(s, (struct sockaddr *)&client, &g)) != INVALID_SOCKET){
printf("%s\n", inet_ntoa(client.sin_addr));
printf("conn\n");
if((recvState = recv(incomingSocket, incomingMessage, 2500, 0)) == SOCKET_ERROR){
}else{
int as;
if((as = strcmp(incomingMessage, "Hello YUMATKARA, conn pls bro hhhasf7sasflljh89")) == 0){
printf("\n identical");
send(incomingSocket, "I got you!!", 11, 0);
}
printf("\n :%s\n", incomingMessage);
}
}
if(incomingSocket == INVALID_SOCKET){
printf("invalid socket");
}
return 0;
}
UPDATE
I have added this in my server code, before return 0 it does not display anything at all.
while((recvState = recv(incomingSocket, incomingMessage, 50, 0)) > 0) {
printf("\n new msg %s\n", incomingMessage);
}
TCP is a byte stream, not message-oriented like you are expecting.
recv() is not guaranteed to return complete messages. It could return as little as 1 byte, or it could return partial bytes from a message, or even bytes from multiple messages. You have to handle buffering and message framing in your code logic. And pay attention to its return value so you know how much it actually read. If you are expecting more data than is read, you have to call recv() again to read the rest, potentially many times. So use a loop.
So, either:
Have the sender send a string's length as a fixed-length value before then sending the actual characters. Then have the receiver read the length to know how many characters to read.
Have the sender send a unique terminator after each string, like a nul character or even a CRLF, then the receiver can keep reading until it encounters the terminator.
As for send(), it is not guaranteed to send complete data, either. It could send as few as 1 byte, or at least less than what you requested. So you have to pay attention to its return value, too, to know how much it actually sent. If it doesn't send everything in one go, you have to call it again to send any remaining data, potentially many times. So use a loop.
For example, try something more like this:
Client:
const char messageInitiation* = "Hello YUMATKARA, conn pls bro hhhasf7sasflljh89";
char* readStr(SOCKET s)
{
char *str = NULL;
char buffer[100], ch;
int buf_len = 0, str_len = 0, ret;
do
{
ret = recv(s, &ch, 1, 0);
if (ret == SOCKET_ERROR)
{
printf("recv err %d\n", WSAGetLastError());
return SOCKET_ERROR;
}
if (ch == '\0')
break;
if (buf_len == sizeof(buffer))
{
char *newstr = (char*) realloc(str, str_len + buf_len + 1);
if (!newstr)
{
printf("memory err\n");
free(str);
return NULL;
}
str = newstr;
memcpy(str + str_len, buffer, buf_len);
str_len += buf_len;
buf_len = 0;
}
buffer[buf_len++] = ch;
}
while (true);
if (buf_len > 0)
{
char *newstr = (char*) realloc(str, str_len + buf_len + 1);
if (!newstr)
{
printf("memory err\n");
free(str);
return NULL;
}
str = newstr;
memcpy(str, buffer, buf_len);
str_len += buf_len;
}
str[str_len] = '\0';
return str;
}
int sendStr(SOCKET s, const char *str)
{
const unsigned char *pstr = (const unsigned char*) str;
int len = strlen(str) + 1, ret;
do
{
ret = send(s, pstr, len, 0);
if (ret == SOCKET_ERROR)
{
printf("send err %d\n", WSAGetLastError());
return SOCKET_ERROR;
}
pstr += ret;
len -= ret;
}
while (len > 0);
return 0;
}
/* alternatively:
int readAll(SOCKET s, void *data, int len)
{
unsigned char *pdata = (unsigned char *) data;
int ret;
while (len > 0)
{
ret = recv(s, pdata, len, 0);
if (ret == SOCKET_ERROR)
{
printf("recv err %d\n", WSAGetLastError());
return SOCKET_ERROR;
}
pdata += ret;
len -= ret;
}
return 0;
}
int readStr(SOCKET s)
{
int32_t len = 0;
if (readAll(s, &len, sizeof(len)) == SOCKET_ERROR)
return NULL;
char *str = (char*) malloc(len + 1);
if (!str)
{
printf("memory err\n");
return NULL;
}
if (readAll(s, str, len) == SOCKET_ERROR)
{
free(str);
return NULL;
}
str[len] = '\0';
return str;
}
int sendAll(SOCKET s, const void *data, int len)
{
const unsigned char *pdata = (const unsigned char*) data;
int ret;
while (len > 0)
{
ret = send(s, pdata, len, 0);
if (ret == SOCKET_ERROR)
{
printf("send err %d\n", WSAGetLastError());
return SOCKET_ERROR;
}
pdata += ret;
len -= ret;
}
return 0;
}
int sendStr(SOCKET s, const char *str)
{
int32_t len = strlen(str) + 1;
int ret = sendAll(s, &len, sizeof(len));
if (ret == 0)
ret = sendAll(s, str, len);
return ret;
}
*/
VOID CALLBACK timerCb(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime)
{
printf("\n%s\n", "timing");
if (!sendStr(s, messageInitiation))
PostQuitMessage(0);
}
int main()
{
WSADATA ws;
int ret = WSAStartup(MAKEWORD(2, 2), &ws);
if (ret != 0)
{
printf("WSA err %d\n", ret);
return -1;
}
SOCKET s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (s == INVALID_SOCKET)
{
printf("socket err %d\n", WSAGetLastError());
WSACleanup();
return -1;
}
printf("socket created\n");
struct sockaddr_in rmtServer = {};
rmtServer.sin_family = AF_INET;
rmtServer.sin_addr.s_addr = inet_addr("127.0.0.1");
rmtServer.sin_port = htons(4743);
if (connect(s, (struct sockaddr*)&rmtServer, sizeof(struct sockaddr_in)) == SOCKET_ERROR)
{
printf("connect err %d\n", WSAGetLastError());
closesocket(s);
WSACleanup();
return -1;
}
printf("connected\n");
if (sendStr(s, messageInitiation) != 0)
{
closesocket(s);
WSACleanup();
return -1;
}
char *receivingMessage = recvStr(s);
if (!receivingMessage)
{
closesocket(s);
WSACleanup();
return -1;
}
printf("%s\n", receivingMessage);
BOOL connectedYet = (strcmp(receivingMessage, "I got you!!") == 0);
printf("is it true: ? %d\n", connectedYet);
free(receivingMessage);
SetTimer(NULL, 0, 3600, timerCb);
MSG message;
while (GetMessage(&message, NULL, 0, 0) > 0)
{
TranslateMessage(&message);
DispatchMessage(&message);
}
closesocket(s);
WSACleanup();
return 0;
}
Server:
#include <windows.h>
#include <winsock2.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// see client code above
char* readStr(SOCKET s);
int sendStr(SOCKET s, const char *str);
int main()
{
struct sockaddr_in server = {0}, client;
WSADATA ws;
int ret = WSAStartup(MAKEWORD(2, 2), &ws);
if (ret != 0)
{
printf("WSA err %d\n", ret);
return -1;
}
SOCKET s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (s == INVALID_SOCKET)
{
printf("socket err %d\n", WSAGetLasatError());
WSACleanup();
return -1;
}
struct sockaddr_in server = {};
server.sin_family = AF_INET;
server.sin_addr.s_addr = inet_addr("127.0.0.1");
server.sin_port = htons(4743);
ret = bind(s, (struct sockaddr *)&server, sizeof(server));
if (ret == SOCKET_ERROR)
{
printf("bind err %d\n", WSAGetLastError());
closesocket(s);
WSACleanup();
return -1;
}
if (listen(s, 10) == SOCKET_ERROR)
{
printf("listen err %d\n", WSAGetLastError());
closesocket(s);
WSACleanup();
return -1;
}
int g, iResult;
struct sockaddr_in client;
do
{
g = sizeof(client);
SOCKET incomingSocket = accept(s, (struct sockaddr *)&client, &g);
if (incomingSocket == INVALID_SOCKET)
{
printf("accept err %d\n", WSAGetLastError());
closesocket(s);
WSACleanup();
return -1;
}
printf("%s conn\n", inet_ntoa(client.sin_addr));
char *incomingMessage = recvStr(incomingSocket);
if (incomingMessage)
{
printf("%s\n", incomingMessage);
if (incomingMessage, "Hello YUMATKARA, conn pls bro hhhasf7sasflljh89") == 0)
{
printf("identical\n");
sendStr(incomingSocket, "I got you!!");
}
}
closesocket(incomingSocket);
}
while (true);
return 0;
}

Keyboard filter driver unload BSOD

I have developed a keyboard filter driver that changes the keyboard button '1' (above the Q button) to '2'.
This driver works fine.
However, after Unload is executed, pressing the keyboard button causes BSOD.
If the driver is loaded and unloaded without pressing the keyboard button, it will be unloaded normally.
When I check it with Windbg, my driver's ReadCompletion () function is called even after it is unloaded.
I do not know why this is happening even though I've called IoDetachDevice () and IoDeleteDevice ().
In addition, after loading the driver, if you press the keyboard button '1' at the beginning, it does not change to '2'.
And then it changes very well.
I do not know what this is related to.
I hope you will find a solution to this problem.
please answer about my question.
Below is the source code.
#include <wdm.h>
typedef struct
{
PDEVICE_OBJECT NextLayerDeviceObject;
} DEVICE_EXTENSION, *PDEVICE_EXTENSION;
const WCHAR next_device_name[] = L"\\Device\\KeyboardClass0";
const char dbg_name[] = "[Test]";
NTSTATUS IrpSkip(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
{
NTSTATUS ret = STATUS_SUCCESS;
PIO_STACK_LOCATION Stack = IoGetCurrentIrpStackLocation(Irp);
DbgPrint("%s IrpSkip() Start\n", dbg_name);
DbgPrint("%s IrpSkip() - MajorFunction %d\n", dbg_name, Stack->MajorFunction);
IoSkipCurrentIrpStackLocation(Irp);
ret = IoCallDriver(((PDEVICE_EXTENSION)(DeviceObject->DeviceExtension))->NextLayerDeviceObject, Irp);
DbgPrint("IoCallDriver return %x\n", ret);
DbgPrint("%s IrpSkip() End\n", dbg_name);
return ret;
}
NTSTATUS ReadCompletion(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PVOID Context)
{
NTSTATUS ret = STATUS_SUCCESS;
PIO_STACK_LOCATION Stack;
unsigned char key[32];
DbgPrint("%s ReadCompletion() Start\n", dbg_name);
if (Irp->IoStatus.Status == STATUS_SUCCESS)
{
DbgPrint("%s ReadCompletion() - Success\n", dbg_name);
RtlCopyMemory(key, Irp->AssociatedIrp.SystemBuffer, 32);
DbgPrint("%s Data : %d %d %d %d %d %d %d %d\n", dbg_name, key[0], key[1], key[2], key[3], key[4], key[5], key[6], key[7]);
if (key[2] == 2)
{
key[2] = 3;
RtlCopyMemory(Irp->AssociatedIrp.SystemBuffer, key, 32);
DbgPrint("%s Key '1' changed '2'\n", dbg_name);
}
}
//else if (Irp->IoStatus.Status == STATUS_PENDING)
else
{
DbgPrint("%s ReadCompletion() - Fail... %x\n", Irp->IoStatus.Status);
}
if (Irp->PendingReturned)
{
IoMarkIrpPending(Irp);
}
DbgPrint("%s ReadCompletion() End\n", dbg_name);
return Irp->IoStatus.Status;
}
NTSTATUS Read(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
{
NTSTATUS ret = STATUS_SUCCESS;
PIO_STACK_LOCATION Stack = IoGetCurrentIrpStackLocation(Irp);
DbgPrint("%s Read() Start\n", dbg_name);
PDEVICE_EXTENSION device_extension = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;
//IoCopyCurrentIrpStackLocationToNext(Irp);
PIO_STACK_LOCATION current_irp = IoGetCurrentIrpStackLocation(Irp);
PIO_STACK_LOCATION next_irp = IoGetNextIrpStackLocation(Irp);
*next_irp = *current_irp;
IoSetCompletionRoutine(Irp, ReadCompletion, DeviceObject, TRUE, TRUE, TRUE);
ret=IoCallDriver(((PDEVICE_EXTENSION)device_extension)->NextLayerDeviceObject, Irp);
DbgPrint("%s Read() End\n", dbg_name);
return ret;
}
NTSTATUS Unload(IN PDRIVER_OBJECT DriverObject)
{
NTSTATUS ret = STATUS_SUCCESS;
IoDetachDevice(((PDEVICE_EXTENSION)(DriverObject->DeviceObject->DeviceExtension))->NextLayerDeviceObject);
IoDeleteDevice(DriverObject->DeviceObject);
DbgPrint("%s Unload()...\n", dbg_name);
return ret;
}
NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath)
{
NTSTATUS ret=STATUS_SUCCESS;
UNICODE_STRING _next_device_name;
DbgSetDebugFilterState(DPFLTR_DEFAULT_ID, DPFLTR_INFO_LEVEL, TRUE);
DbgPrint("%s DriverEntry() Start\n", dbg_name);
RtlInitUnicodeString(&_next_device_name, next_device_name);
for (int i = 0; i < IRP_MJ_MAXIMUM_FUNCTION ; i++)
{
DriverObject->MajorFunction[i] = IrpSkip;
}
DriverObject->DriverUnload = Unload;
DriverObject->MajorFunction[IRP_MJ_READ] = Read;
PDEVICE_OBJECT DeviceObject = 0;
PDEVICE_EXTENSION DeviceExtension;
ret = IoCreateDevice(DriverObject, sizeof(DEVICE_EXTENSION), 0, FILE_DEVICE_KEYBOARD, 0, TRUE, &DeviceObject);
if (ret == STATUS_SUCCESS)
{
DbgPrint("%s DriverEntry() - IoCreateDevice() Success\n", dbg_name);
}
else
{
DbgPrint("%s DriverEntry() - IoCreateDevice() Fail\n", dbg_name);
return ret;
}
DeviceExtension = (PDEVICE_EXTENSION)DeviceObject->DeviceExtension;
DeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
DeviceObject->Flags |= (DO_BUFFERED_IO | DO_POWER_PAGABLE);
ret = IoAttachDevice(DeviceObject, &_next_device_name, &DeviceExtension->NextLayerDeviceObject);
if (ret == STATUS_SUCCESS)
{
DbgPrint("%s DriverEntry() - IoAttachDevice() Success\n", dbg_name);
}
else
{
DbgPrint("%s DriverEntry() - IoAttachDevice() Fail\n", dbg_name);
IoDeleteDevice(DriverObject->DeviceObject);
return ret;
}
DbgPrint("%s DriverEntry() End\n", dbg_name);
return ret;
}
Below is Windbg Call Stack.
0: kd> k
# ChildEBP RetAddr
00 82f33604 82eea083 nt!RtlpBreakWithStatusInstruction
01 82f33654 82eeab81 nt!KiBugCheckDebugBreak+0x1c
02 82f33a1c 82e4c5cb nt!KeBugCheck2+0x68b
03 82f33a1c 975e36e0 nt!KiTrap0E+0x2cf
WARNING: Frame IP not in any known module. Following frames may be wrong.
04 82f33aac 82e83933 <Unloaded_Test.sys>+0x16e0
05 82f33af0 8efed7a2 nt!IopfCompleteRequest+0x128
06 82f33b14 8eea7b74 kbdclass!KeyboardClassServiceCallback+0x2fa
07 82f33b78 82e831b5 i8042prt!I8042KeyboardIsrDpc+0x18c
08 82f33bd4 82e83018 nt!KiExecuteAllDpcs+0xf9
09 82f33c20 82e82e38 nt!KiRetireDpcList+0xd5
0a 82f33c24 00000000 nt!KiIdleLoop+0x38
The CallBack function does not seem to be released properly.
How do I solve this problem?
if you pass pointer to own driver body (ReadCompletion in your case) - driver must not be unloaded until this pointer is used (ReadCompletion called and returned your case)
as notified Harry Johnston need use IoSetCompletionRoutineEx - but documentation for this is bad and not explain all details. absolute mandatory study windows src files (WRK-v1.2 for example) and binary windows code. if you look for implementation of IoSetCompletionRoutineEx - you can view that this routine nothing do for prevent you driver for unloading. it simply allocate small memory block, save here your DeviceObject, Context and CompletionRoutine and set IopUnloadSafeCompletion as completion and pointer to allocated memory block as context.
what is IopUnloadSafeCompletion doing ?
NTSTATUS
IopUnloadSafeCompletion(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN PVOID Context
)
{
PIO_UNLOAD_SAFE_COMPLETION_CONTEXT Usc = Context;
NTSTATUS Status;
ObReferenceObject (Usc->DeviceObject);
Status = Usc->CompletionRoutine (DeviceObject, Irp, Usc->Context);
ObDereferenceObject (Usc->DeviceObject);
ExFreePool (Usc);
return Status;
}
but this assume that Usc->DeviceObject IS VALID at calling IopUnloadSafeCompletion time. you can delete/de-reference DeviceObject inside CompletionRoutine , do some task which cause your driver unload - and will be no crash, because your CompletionRoutine protected by adding reference to your device. but if IopUnloadSafeCompletion will be called when your device already destroyed and driver unloaded - any way will be crash.
partial solution will be call ObfReferenceObject(DeviceObject) in your dispatch routine and ObfDereferenceObject(DeviceObject) in completion routine. this on practice resolve problem. so code must be next
NTSTATUS OnComplete(PDEVICE_OBJECT DeviceObject, PIRP Irp, PVOID /*Context*/)
{
ObfDereferenceObject(DeviceObject);// !!!
PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
if (Irp->PendingReturned)
{
IrpSp->Control |= SL_PENDING_RETURNED;
}
if (IrpSp->MajorFunction == IRP_MJ_READ &&
Irp->IoStatus.Status == STATUS_SUCCESS &&
(Irp->Flags & IRP_BUFFERED_IO))
{
if (ULONG n = (ULONG)Irp->IoStatus.Information / sizeof(KEYBOARD_INPUT_DATA))
{
PKEYBOARD_INPUT_DATA pkid = (PKEYBOARD_INPUT_DATA)Irp->AssociatedIrp.SystemBuffer;
do
{
DbgPrint("Port%x> %x %x\n", pkid->UnitId, pkid->MakeCode, pkid->Flags);
} while (pkid++, --n);
}
}
return ContinueCompletion;
}
NTSTATUS KbdDispatch(PDEVICE_OBJECT DeviceObject, PIRP Irp)
{
IoCopyCurrentIrpStackLocationToNext(Irp);
if (0 > IoSetCompletionRoutineEx(DeviceObject, Irp, OnComplete, NULL, TRUE, TRUE, TRUE))
{
IoSkipCurrentIrpStackLocation(Irp);
}
else
{
ObfReferenceObject(DeviceObject);// !!!
}
return IofCallDriver(
reinterpret_cast<DEVICE_EXTENSION*>(DeviceObject->DeviceExtension)->_NextDeviceObject, Irp);
}
call ObfReferenceObject(DeviceObject); in KbdDispatch prevent unload your driver until ObfDereferenceObject(DeviceObject); called inside OnComplete.
you can ask for what in this case IoSetCompletionRoutineEx at all, if we yourself call ObfReferenceObject / ObfDereferenceObject ? because if DriverUnload already called - all your code hold only on single reference on DeviceObject - so when you call ObfDereferenceObject(DeviceObject); from OnComplete - your device will be deleted and driver unloaded inside ObfDereferenceObject and finally this routine returned to your unloaded code. so sense of IoSetCompletionRoutineEx is protect your completion routine.
but need understand that this is anyway not 100% correct solution. call IoDetachDevice/IoDeleteDevice for attached device not correct from DriverUnload. ( this must be called from IRP_MN_REMOVE_DEVICE or FAST_IO_DETACH_DEVICE callback)
assume next scenario - somebody call NtReadFile for device A to which your B device is attached. NtReadFile get pointer to your B device via IoGetRelatedDeviceObject. internally this routine call IoGetAttachedDevice. read this:
IoGetAttachedDevice does not increment the reference count on the
device object. (Thus no matching call to ObDereferenceObject is
required.) Callers of IoGetAttachedDevice must ensure that no device
objects are added to or removed from the stack while
IoGetAttachedDevice is executing. Callers that cannot do this must use
IoGetAttachedDeviceReference instead.
assume that while NtReadFile using pointer to your B device, another thread called your DriverUnload which delete B device and unload driver. handle/file object exist on device A - this hold it and prevent from unloading. but your attached B device not hold nothing. as result if NtReadFile or any another I/O subsystem routine which use your device execute in concurrent with DriverUnload where you call detach/delete device - system can crash already inside NtReadFile code. and you nothing can do with this. only one way after call IoDetachDevice some(how many ?!) time wait before call IoDeleteDevice. fortunately possibility of this case very low usual.
so try understand - system can crash in NtReadFile already. even if your Dispatch called - your DeviceObject can be deleted/not valid already or driver unloaded during dispatch routine. only after you call ObfReferenceObject(DeviceObject) all become ok. and all this problem because you try detach attached device in DriverUnload (windows not designed for this).
also can noted many another errors in your code. say completion routine must not return Irp->IoStatus.Status it must return or StopCompletion (i.e STATUS_MORE_PROCESSING_REQUIRED ) or any another value - usual ContinueCompletion (i.e STATUS_CONTINUE_COMPLETION or 0) also need not hardcode "\\Device\\KeyboardClass0" but use IoRegisterPlugPlayNotification with GUID_CLASS_KEYBOARD if you not wdm driver. also for xp need special handler for IRP_MJ_POWER ( Passing Power IRPs ) but may be this is already not actual if xp support not actual.
code example can be look like:
struct DEVICE_EXTENSION
{
PDEVICE_OBJECT _NextDeviceObject;
};
NTSTATUS KbdPower(PDEVICE_OBJECT DeviceObject, PIRP Irp)
{
PoStartNextPowerIrp(Irp);
IoSkipCurrentIrpStackLocation(Irp);
return PoCallDriver(
reinterpret_cast<DEVICE_EXTENSION*>(DeviceObject->DeviceExtension)->_NextDeviceObject, Irp);
}
NTSTATUS OnComplete(PDEVICE_OBJECT DeviceObject, PIRP Irp, PVOID /*Context*/)
{
ObfDereferenceObject(DeviceObject);
PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
if (Irp->PendingReturned)
{
IrpSp->Control |= SL_PENDING_RETURNED;
}
if (IrpSp->MajorFunction == IRP_MJ_READ &&
Irp->IoStatus.Status == STATUS_SUCCESS &&
(Irp->Flags & IRP_BUFFERED_IO))
{
if (ULONG n = (ULONG)Irp->IoStatus.Information / sizeof(KEYBOARD_INPUT_DATA))
{
PKEYBOARD_INPUT_DATA pkid = (PKEYBOARD_INPUT_DATA)Irp->AssociatedIrp.SystemBuffer;
do
{
DbgPrint("Port%x> %x %x\n", pkid->UnitId, pkid->MakeCode, pkid->Flags);
} while (pkid++, --n);
}
}
return ContinueCompletion;
}
NTSTATUS KbdDispatch(PDEVICE_OBJECT DeviceObject, PIRP Irp)
{
IoCopyCurrentIrpStackLocationToNext(Irp);
if (0 > IoSetCompletionRoutineEx(DeviceObject, Irp, OnComplete, NULL, TRUE, TRUE, TRUE))
{
IoSkipCurrentIrpStackLocation(Irp);
}
else
{
ObfReferenceObject(DeviceObject);
}
return IofCallDriver(
reinterpret_cast<DEVICE_EXTENSION*>(DeviceObject->DeviceExtension)->_NextDeviceObject, Irp);
}
NTSTATUS KbdNotifyCallback(PDEVICE_INTERFACE_CHANGE_NOTIFICATION Notification, PDRIVER_OBJECT DriverObject)
{
if (::RtlCompareMemory(&Notification->Event, &GUID_DEVICE_INTERFACE_ARRIVAL, sizeof(GUID)) == sizeof(GUID))
{
DbgPrint("++%wZ\n", Notification->SymbolicLinkName);
HANDLE hFile;
OBJECT_ATTRIBUTES oa = { sizeof(oa), 0, Notification->SymbolicLinkName, OBJ_CASE_INSENSITIVE };
IO_STATUS_BLOCK iosb;
if (0 <= IoCreateFile(&hFile, SYNCHRONIZE, &oa, &iosb, 0, 0, FILE_SHARE_VALID_FLAGS, FILE_OPEN, 0, 0, 0, CreateFileTypeNone, 0, IO_ATTACH_DEVICE))
{
PFILE_OBJECT FileObject;
NTSTATUS status = ObReferenceObjectByHandle(hFile, 0, 0, 0, (void**)&FileObject, 0);
NtClose(hFile);
if (0 <= status)
{
PDEVICE_OBJECT DeviceObject, TargetDevice = IoGetAttachedDeviceReference(FileObject->DeviceObject);
ObfDereferenceObject(FileObject);
if (0 <= IoCreateDevice(DriverObject, sizeof(DEVICE_EXTENSION), 0,
TargetDevice->DeviceType,
TargetDevice->Characteristics & (FILE_REMOVABLE_MEDIA|FILE_DEVICE_SECURE_OPEN),
FALSE, &DeviceObject))
{
DeviceObject->Flags |= TargetDevice->Flags &
(DO_BUFFERED_IO|DO_DIRECT_IO|DO_SUPPORTS_TRANSACTIONS|DO_POWER_PAGABLE|DO_POWER_INRUSH);
DEVICE_EXTENSION* pExt = (DEVICE_EXTENSION*)DeviceObject->DeviceExtension;
if (0 > IoAttachDeviceToDeviceStackSafe(DeviceObject, TargetDevice, &pExt->_NextDeviceObject))
{
IoDeleteDevice(DeviceObject);
}
else
{
DeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
DbgPrint("++DeviceObject<%p> %x\n", DeviceObject, DeviceObject->Flags);
}
}
ObfDereferenceObject(TargetDevice);
}
}
}
return STATUS_SUCCESS;
}
PVOID NotificationEntry;
void KbdUnload(PDRIVER_OBJECT DriverObject)
{
DbgPrint("KbdUnload(%p)\n", DriverObject);
if (NotificationEntry) IoUnregisterPlugPlayNotification(NotificationEntry);
PDEVICE_OBJECT NextDevice = DriverObject->DeviceObject, DeviceObject;
while (DeviceObject = NextDevice)
{
NextDevice = DeviceObject->NextDevice;
DbgPrint("--DeviceObject<%p>\n", DeviceObject);
IoDetachDevice(reinterpret_cast<DEVICE_EXTENSION*>(DeviceObject->DeviceExtension)->_NextDeviceObject);
IoDeleteDevice(DeviceObject);
}
}
NTSTATUS KbdInit(PDRIVER_OBJECT DriverObject, PUNICODE_STRING /*RegistryPath*/)
{
DbgPrint("KbdInit(%p)\n", DriverObject);
DriverObject->DriverUnload = KbdUnload;
#ifdef _WIN64
__stosq
#else
__stosd
#endif
((PULONG_PTR)DriverObject->MajorFunction, (ULONG_PTR)KbdDispatch, RTL_NUMBER_OF(DriverObject->MajorFunction));
ULONG MajorVersion;
PsGetVersion(&MajorVersion, 0, 0, 0);
if (MajorVersion < 6) DriverObject->MajorFunction[IRP_MJ_POWER] = KbdPower;
IoRegisterPlugPlayNotification(
EventCategoryDeviceInterfaceChange,
PNPNOTIFY_DEVICE_INTERFACE_INCLUDE_EXISTING_INTERFACES,
(void*)&GUID_CLASS_KEYBOARD, DriverObject,
(PDRIVER_NOTIFICATION_CALLBACK_ROUTINE)KbdNotifyCallback,
DriverObject, &NotificationEntry);
return STATUS_SUCCESS;
}
This sounds like it explains your problem:
Note Only a driver that can guarantee it will not be unloaded before its completion routine finishes can use IoSetCompletionRoutine. Otherwise, the driver must use IoSetCompletionRoutineEx, which prevents the driver from unloading until its completion routine executes.
(From the MSDN documentation for IoSetCompletionRoutine.)
PS: the one-keystroke delay in the functionality taking effect is to be expected, because your driver isn't hooked into the read operation that was already in progress when it was loaded. I'm not sure whether there's any reasonable way to do that.

Why my threaded winsock server won't crash?

I have implemented a c++ winsock (win 32) with intention of crashing using an strcpy command. The socket itself is instantiated inside a thread. However, when I put the strcpy inside the recv loop, it does not seem to crash.
I know there is nothing wrong with the compiler since writing one with just strcpy crashes, I am thinking it is related to recv since it initiates a block on the process.
Here is the full code below for the sever, the crash I am trying to implement is in the form of strcpy(a, "AAAA..."); in regular circumstances it should crash, but here it does not. I would like to know why.
#define WIN32_LEAN_AND_MEAN
#include<windows.h>
#include<winsock2.h>
#include<stdlib.h>
#include<stdio.h>
#include<ws2tcpip.h>
#include <iostream.h>
#include <conio.h>
#define DEFAULT_PORT "1133"
#define DEFAULT_BUFLEN 512
struct thread_data
{
int m_id;
thread_data(int id) : m_id(id){}
};
char a[10];
DWORD WINAPI ServerThread (LPVOID pParam){
WSADATA wsaData;
struct addrinfo *result =NULL;
struct addrinfo hints;
SOCKET ListenSocket = INVALID_SOCKET;
do{
ZeroMemory(&hints, sizeof(hints));
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
hints.ai_flags = AI_PASSIVE;
int iResult;
iResult = WSAStartup(MAKEWORD(2,2), &wsaData);
iResult = getaddrinfo(NULL,DEFAULT_PORT,&hints, &result);
if (iResult != 0 ){
printf("get addrinfo failed with error %d\n", iResult);
WSACleanup();
return 1;
} //end if
ListenSocket = socket(result->ai_family, result->ai_socktype, result->ai_protocol);
if (ListenSocket ==0){
printf("socket creation failed with error %d\n", WSAGetLastError());
}
//bind socket
iResult= bind( ListenSocket , result->ai_addr, (int)result->ai_addrlen);
if(iResult == SOCKET_ERROR){
printf("bind failed with error %d\n", WSAGetLastError());
freeaddrinfo(result);
closesocket(ListenSocket);
WSACleanup();
return 1;
}
printf ("initializing socket\n ");
iResult= listen(ListenSocket,SOMAXCONN);
if (iResult== SOCKET_ERROR){
printf("listen failed with %d\n",WSAGetLastError());
closesocket(ListenSocket);
WSACleanup();
return 1;
}
SOCKET client ;
sockaddr_in from;
int fromlen=sizeof(from);
char temp[1024];
char temp_to_send[1024];
char temp_to_send_vuln[512];
printf("accepting client request\n");
client=accept(ListenSocket, (struct sockaddr*) &from, &fromlen);
printf("accepted socket\n");
iResult =1;
int iSendResult =1;
char c;
//start receiving from client
while( (iResult = recv(client,temp,1024,0 )) > 0 ){
c = temp[0];
temp[iResult] = '\0';
if(c!=13)
strcat(temp_to_send,temp);
//if enter is hit echo sent data to client
if(c ==13 ){
printf("sending %s \n",temp_to_send);
//I WANT TO CRASH THE PGORAM HERE!!
strcpy(a,"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA");
strcat(temp_to_send_vuln,temp_to_send);
strcat(temp_to_send_vuln,"\r\n");
iSendResult = send(client,temp_to_send,strlen(temp_to_send),0);
//if user types "exit" the client socket would terminate
if (strcmp(temp_to_send,"exit") ==0){
printf("exit entered\n");
closesocket(client);
WSACleanup();
break;
}
re-initialize variables for next input
temp[0] = '\0';
temp_to_send[0] = '\0';
}//end if(ch ==13)
}//end recv
printf("termination of socket with error %d and buffer length is ", WSAGetLastError());
printf("client said %s\n", temp) ;
if (iResult == SOCKET_ERROR){
printf("receiving failed with error %d",WSAGetLastError());
}
if (iSendResult == SOCKET_ERROR){
printf("seding failed with error %d", WSAGetLastError());
closesocket(client);
WSACleanup();
exit(1);
}
} while(1);
closesocket(ListenSocket);
WSACleanup();
printf("program ended\n");
return 0;
}
//the main function that calls the thread
int main(void)
{
//create thread here
CreateThread(NULL, 0 ,ServerThread, new thread_data(0), 0,0);
//terminate program when escape character is hit
while(_getch()!=27);
return 0;
}
Your strcpy() call is just trashing a and then whatever else happens to be after it in global memory; it's undefined whether it'll crash or not. If you really want to crash out, just call strcpy( NULL, "whatever" ).

Filter hook driver: dispatch routine isn't called

I'm trying to write legacy filter-hook driver, firewall-like: look for dst port and block it.
But when packets are sent, dispatcher routine isn't called.
Register dispatch:
DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = DrvDispatch;
Start ipfilter driver:
C:\Users\unnamed>net start ipfilterdriver
After that, launch debug driver via Visual DDK. Driver load successfully, but breakpoint in dispatcher isn't reached. What am I doing wrong?
NTSTATUS DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath)
{
UNICODE_STRING DeviceName,Win32Device;
PDEVICE_OBJECT DeviceObject = NULL;
NTSTATUS status;
unsigned i;
RtlInitUnicodeString(&DeviceName,L"\\Device\\driver10");
RtlInitUnicodeString(&Win32Device,L"\\DosDevices\\driver10");
for (i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++)
DriverObject->MajorFunction[i] = driver1DefaultHandler;
/*
DriverObject->MajorFunction[IRP_MJ_CREATE] = driver1CreateClose;
DriverObject->MajorFunction[IRP_MJ_CLOSE] = driver1CreateClose;
DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = DrvDispatch;
*/
status = IoCreateDevice(DriverObject, 0, &DeviceName,
FILE_DEVICE_DRVFLTIP, 0, FALSE,
&DeviceObject);
if (NT_SUCCESS(status)) {
status = IoCreateSymbolicLink(&Win32Device, &DeviceName);
if (!NT_SUCCESS(status))
dprintf("DrvFltIp.SYS: IoCreateSymbolicLink failed\n");
DriverObject->MajorFunction[IRP_MJ_CREATE] =
DriverObject->MajorFunction[IRP_MJ_CLOSE] =
DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = DrvDispatch;
DriverObject->DriverUnload = driver1Unload;
}
if (!NT_SUCCESS(status)) {
dprintf("Error in initialization. Unloading...");
driver1Unload(DriverObject);
}
if (!DeviceObject)
return STATUS_UNEXPECTED_IO_ERROR;
/*
DeviceObject->Flags |= DO_DIRECT_IO;
DeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
DeviceObject->AlignmentRequirement = FILE_WORD_ALIGNMENT;
*/
DbgPrint("Driver started\n");
return status;
}
NTSTATUS DrvDispatch(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
{
dprintf("DrvDispatch called\n");
PIO_STACK_LOCATION irpStack;
PVOID ioBuffer;
ULONG inputBufferLength;
ULONG outputBufferLength;
ULONG ioControlCode;
NTSTATUS ntStatus;
Irp->IoStatus.Status = STATUS_SUCCESS;
Irp->IoStatus.Information = 0;
irpStack = IoGetCurrentIrpStackLocation(Irp);
switch (irpStack->MajorFunction) {
case IRP_MJ_CREATE:
dprintf("DrvFltIp.SYS: IRP_MJ_CREATE\n");
break;
case IRP_MJ_CLOSE:
dprintf("DrvFltIp.SYS: IRP_MJ_CLOSE\n");
break;
case IRP_MJ_DEVICE_CONTROL:
dprintf("DrvFltIp.SYS: IRP_MJ_DEVICE_CONTROL\n");
break;
}
ntStatus = Irp->IoStatus.Status;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return ntStatus;
}
Just forgot register filter-hook callback function in the DriverEntry:
Registering and Clearing a Filter Hook

Resources