Win32k(2) 报文驱动的通信机制
来源:互联网 发布:notepad pro mac 编辑:程序博客网 时间:2024/05/20 22:38
一.应用层的api
int APIENTRY _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine,intnCmdShow){ WNDCLASSEXwcex; wcex.lpfnWndProc = WndProc; wcex.cbClsExtra = 0;RegisterClassEx(&wcex); hWnd= CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,CW_USEDEFAULT, 0,CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL); while(GetMessage(&msg, NULL, 0, 0))//NtUserGetMessage {// NtUserGetMessage目的是循环获取一个普通报文,在这个循环中会检查被发送的报文,对方send过来的message会由NtUserGetMessage内部直接调用wndproc立即响应//如果没有普通报文(post 硬件报文定时器报文等)就睡眠循环等待 if(!TranslateAccelerator(msg.hwnd, hAccelTable, &msg)) { TranslateMessage(&msg);//键盘扫描码变成unicode DispatchMessage(&msg);//对wndproc的调用 } }
然后在WndProc函数中还能调用到SendMessage、PostQuitMessage等等函数
应用层消息的结构是
struct MSG{ HWND hwnd; UINT message; WPARAM wParam; LPARAM lParam; DWORD time; POINT pt;};
二.创建窗口NtUserCreateWindowEx
控件什么也都算window。
创建好的窗口对应的是window_object返回句柄。
Window_object里面包含了许多字段,里面就有用户填充的WndProc地址,消息队列结构
三.接收报文NtUserGetMessage
根据HWNDhWnd在全局句柄表中找到窗口
主要关注co_IntPeekMessage这个调用,他从w32thread里面拆取消息队列中的消息
Win下
typedefstruct _tagTHREADINFO // 156 elements, 0x208 bytes (sizeof){/*0x0BC*/ struct _tagQ* pq;// input queue/*0x0E0*/ struct _tagSMS* psmsSent;// send queue (sent)/*0x0E4*/ struct _tagSMS* psmsCurrent;// send queue (current)/*0x0E8*/ struct _tagSMS* psmsReceiveList;// send queue (received)/*0x174*/ struct _tagMLISTmlPost;// post queue} tagTHREADINFO, *PtagTHREADINFO;
Ros下
typedef struct _USER_MESSAGE_QUEUE{/* Reference counter, only access this variable with interlocked functions! */LONGReferences;/* Owner of the message queue */struct _ETHREAD *Thread;/* Queue of messages sent to the queue. */LIST_ENTRYSentMessagesListHead;/* Queue of messages posted to the queue. */LIST_ENTRYPostedMessagesListHead;/* Queue of sent-message notifies for the queue. */LIST_ENTRYNotifyMessagesListHead;/* Queue for hardware messages for the queue. */LIST_ENTRYHardwareMessagesListHead;/* List of timers, sorted on expiry time (earliest first) */LIST_ENTRYTimerListHead; /* messages that are currently dispatched by other threads */LIST_ENTRYDispatchingMessagesHead;/* messages that are currently dispatched by this message queue, required for cleanup */LIST_ENTRYLocalDispatchingMessagesHead;
(1)获取send报文:
同步方式的消息传递
发送方要把消息挂入发送方的DispatchingMessagesHead,也挂入接收方的SentMessagesListHead,等待Message->CompletionEvent
接收方从SentMessagesListHead提出消息挂入自己的LocalDispatchingMessagesHead,调用窗口的wndproc或者其消息钩子,完成后摘除,用Message->CompletionEvent通知发送方
BOOLFASTCALLco_IntPeekMessage(PUSER_MESSAGEMsg,PWINDOW_OBJECTWindow,UINTMsgFilterMin,UINTMsgFilterMax,UINTRemoveMsg){ 。。。。。。while (co_MsqDispatchOneSentMessage(ThreadQueue));这一句从循环摘消息发送消息 BOOLEAN FASTCALLco_MsqDispatchOneSentMessage(PUSER_MESSAGE_QUEUE MessageQueue){。。。。。 //SentMessagesListHead中获取消息 Entry = RemoveHeadList(&MessageQueue->SentMessagesListHead); Message = CONTAINING_RECORD(Entry, USER_SENT_MESSAGE, ListEntry); //放入LocalDispatchingMessagesHeadInsertTailList(&MessageQueue->LocalDispatchingMessagesHead,&Message->ListEntry);//消息钩子另行处理if (Message->HookMessage == MSQ_ISHOOK) { Result = co_HOOK_CallHooks(。。。); }elseif (Message->HookMessage == MSQ_ISEVENT) { Result = co_EVENT_CallEvents(。。。); }else {//调用应用层窗口函数wndproc Result = co_IntSendMessage(。。。); }//已经送达就可以删除了RemoveEntryList(&Message->ListEntry); /* remove the message from the dispatching list, so lock the sender's message queue */SenderReturned = (Message->DispatchingListEntry.Flink == NULL);if(!SenderReturned) {//从DispatchingListEntry中移除RemoveEntryList(&Message->DispatchingListEntry); }/* Let the sender know the result. */if (Message->Result != NULL) {//返回wndproc执行的结果 *Message->Result = Result; } /* Notify the sender. */if (Message->CompletionEvent != NULL) {//通知发送方可以唤醒KeSetEvent(Message->CompletionEvent, IO_NO_INCREMENT, FALSE); } //对方回调函数的处理,略/* Notify the sender if they specified a callback. */if (!SenderReturned&& Message->CompletionCallback != NULL) {。。。 }。。。/* free the message */ExFreePool(Message);return(TRUE);}
这里面的co_IntSendMessage最终调用co_IntCallWindowProc
在调用KeUserModeCallback(USER32_CALLBACK_WINDOWPROC。。。返回r3
此处暂略
(2)获取其他报文
NtUserGetMessage -co_IntPeekMessage
BOOLFASTCALLco_IntPeekMessage(PUSER_MESSAGEMsg,PWINDOW_OBJECTWindow,UINTMsgFilterMin,UINTMsgFilterMax,UINTRemoveMsg){ 。。。。。。//sent报文的处理,已经分析过while (co_MsqDispatchOneSentMessage(ThreadQueue))//接下来看其他报文,伪代码 一般的post报文/* Now check for normal messages. */Present = co_MsqFindMessage(ThreadQueue,if (Present){gotoMessageFound;}硬件报文/* Check for hardware events. */Present = co_MsqFindMessage(ThreadQueue,if (Present){gotoMessageFound;}再次检查sent报文/* Check for sent messages again. */while (co_MsqDispatchOneSentMessage(ThreadQueue))paint报文/* Check for paint messages. */if (IntGetPaintMessage(Window, MsgFilterMin, MsgFilterMax, pti, &Msg->Msg, RemoveMessages)){Msg->FreeLParam = FALSE;gotoMsgExit;}定时器报文(包括鼠标)Present = MsqGetTimerMessage(ThreadQueue, Window, MsgFilterMin, MsgFilterMax,&Msg->Msg, RemoveMessages);if (Present){Msg->FreeLParam = FALSE;gotoMessageFound;}
报文可以来自于其他窗口、程序发送的,也可能是鼠标键盘线程投递的
(3)DispatchMessage对应NtUserDispatchMessage这个也简单了,就是把消息派发出去,调用wndproc或者hook
四.发送视窗报文
(1)Post message
Post很简单,插入链表发送消息根据Wnd找到对应window object,然后插入其post链表并且时间通知有消息了
NtUserPostMessage–UserPostMessage - UserPostThreadMessage - MsqPostMessage
VOIDFASTCALLMsqPostMessage(PUSER_MESSAGE_QUEUEMessageQueue, MSG* Msg, BOOLEANFreeLParam,DWORDMessageBits){PUSER_MESSAGEMessage; if(!(Message = MsqCreateMessage(Msg, FreeLParam))) {return; }InsertTailList(&MessageQueue->PostedMessagesListHead,&Message->ListEntry);MessageQueue->QueueBits |= MessageBits;MessageQueue->ChangedBits |= MessageBits;if (MessageQueue->WakeMask&MessageBits)KeSetEvent(MessageQueue->NewMessages, IO_NO_INCREMENT, FALSE);}
(2)send message
如果是向自身线程发送消息,就不用send了,直接回调本线程wndproc
否则的话就调用co_MsqSendMessage
co_MsqSendMessage(PUSER_MESSAGE_QUEUE MessageQueue,//接收方队列 HWND Wnd, UINT Msg, WPARAM wParam, LPARAM lParam, UINT uTimeout, BOOL Block, INT HookMessage, ULONG_PTR *uResult){……if(!(Message = ExAllocatePoolWithTag(PagedPool, sizeof(USER_SENT_MESSAGE), TAG_USRMSG)))…… KeInitializeEvent(&CompletionEvent, NotificationEvent, FALSE); pti = PsGetCurrentThreadWin32Thread();ThreadQueue = pti->MessageQueue; //发送方队列 Timeout.QuadPart = (LONGLONG) uTimeout * (LONGLONG) -10000; ……//初始化Message结构 /* 挂入两个队列自己进程的DispatchingListEntry,对方进程的SentMessagesListHead* /InsertTailList(&ThreadQueue->DispatchingMessagesHead, &Message->DispatchingListEntry);InsertTailList(&MessageQueue->SentMessagesListHead, &Message->ListEntry); ……//如果对方正在等待报文,将其唤醒if (MessageQueue->WakeMask&QS_SENDMESSAGE)KeSetEvent(MessageQueue->NewMessages, IO_NO_INCREMENT, FALSE); //if(Block)//阻塞方式,单纯等待这个消息被完成的事件CompletionEvent {……/* 等待这个报文得到处理*/WaitStatus = KeWaitForSingleObject(&CompletionEvent, UserRequest, UserMode, FALSE, (uTimeout ?&Timeout : NULL)); ……//超时的话if(WaitStatus == STATUS_TIMEOUT) {/* 从对方的sent链表里面消除消息*/ Entry = MessageQueue->SentMessagesListHead.Flink;while (Entry != &MessageQueue->SentMessagesListHead) {if ((PUSER_SENT_MESSAGE) CONTAINING_RECORD(Entry, USER_SENT_MESSAGE, ListEntry) == Message) { Message->CompletionEvent = NULL; Message->Result = NULL;break; } Entry = Entry->Flink; } /*从自己的Dispatching消除消息 */ Entry = ThreadQueue->DispatchingMessagesHead.Flink;while (Entry != &ThreadQueue->DispatchingMessagesHead) {if ((PUSER_SENT_MESSAGE) CONTAINING_RECORD(Entry, USER_SENT_MESSAGE, DispatchingListEntry) == Message) { Message->CompletionEvent = NULL; Message->Result = NULL;RemoveEntryList(&Message->DispatchingListEntry); Message->DispatchingListEntry.Flink = NULL;break; } Entry = Entry->Flink; } }//这里要捎带脚吧发过来的消息处理一下while (co_MsqDispatchOneSentMessage(ThreadQueue)); }else//非阻塞方式,等待这个消息被完成的事件CompletionEvent以及有对方的报文被贴过来时短暂唤醒,但并不处理这些 { PVOID WaitObjects[2]; WaitObjects[0] = &CompletionEvent;WaitObjects[1] = ThreadQueue->NewMessages;do {IdlePing(); UserLeaveCo(); WaitStatus = KeWaitForMultipleObjects(2, WaitObjects, WaitAny, UserRequest,UserMode, FALSE, (uTimeout ?&Timeout : NULL), NULL); ……//超时的话和上面一样,移除两个链表中的消息,处理sent链表上对方发送过来的消息 }while (NT_SUCCESS(WaitStatus) && STATUS_WAIT_0 != WaitStatus); //只要CompletionEvent不满足就要等待 } if(WaitStatus != STATUS_TIMEOUT) *uResult = (STATUS_WAIT_0 == WaitStatus ?Result : -1); returnWaitStatus;}
- Win32k(2) 报文驱动的通信机制
- win32k.sys驱动的注入与利用漏洞
- java socket报文通信-报文的封装
- Win32K里的死循环
- java socket报文通信(二)报文的封装
- java socket报文通信(二)报文的封装
- java socket报文通信(二)报文的封装
- java socket报文通信(二)报文的封装
- java socket报文通信(二)报文的封装
- java socket报文通信(二)报文的封装
- C#的反射机制(定制报文)
- linux下的数据报文截获机制
- 【消息通信】Android消息驱动机制
- Win32k(1) 图形线程的初始化
- CHtmlView的通信机制
- CHtmlView的通信机制
- CHtmlView的通信机制
- Larbin的通信机制
- ios开发之从输入流里读入数据
- 第十六周实验报告3
- 重建索引
- iocomp winform 类型的使用笔记
- Win32k(1) 图形线程的初始化
- Win32k(2) 报文驱动的通信机制
- 删除索引
- 在水晶报表中怎样显示页合计
- WebApplication(Web应用程序)和WebSite(网站)的区别
- 注册消息码
- Win32k(3) R0 to R3,键盘鼠标输入
- Xcode 开发 控件如何和代码配合使用
- Get和post的区别
- Win32k(4) 视窗钩子