欢迎来到 黑吧安全网 聚焦网络安全前沿资讯,精华内容,交流技术心得!

Windows调试艺术——从真实病毒学习消息机制

来源:本站整理 作者:佚名 时间:2019-04-09 TAG: 我要投稿

之前的时候偶然在某网站拿到一款很简单的病毒程序,虽然分析的难度不高,但是它巧妙的利用了Windows的消息机制实现了恶意功能,正好可以用它做个例子来学习一下Windows的消息机制。
 
Windows 消息结构
每一个程序猿都应该知道Windows是一个消息驱动的系统,可是真正提到什么是消息,消息又是如何组织的就一头雾水了。实际上Windows的应用内部的各个线程、各个应用、应用与操作系统之间都会通过消息来传递。消息就是一个信号,应用会根据收到的信号做出不同的反应,比如我们点击了窗口的关闭按钮,那么就会传递给应用一个”关闭”的消息,然后窗体关闭。
Windows以窗口作为基础实现了可视化的交互,窗口是基于线程实现的,一个线程又维护着一个消息队列,每一个传递给这个窗口的消息都要依次进入队列进行”先进先出”的操作,不分轻重缓急,再紧急的情况也只能老老实实排队。
消息
一个消息说白了就是一段数据,消息在Windows的定义如下
typedef struct tagMsg
{
HWND hwnd;    //目标的窗口句柄
UINT message; //消息的标识符
WPARAM wParam;//附加信息,与消息标识符有关
LPARAM lParam;//附加信息,与消息标识符有关
DWORD time;   //消息产生的时间
POINT pt;     //消息发生产生时的按屏幕坐标表示的鼠标光标的位置
}MSG,*PMSG;
消息按照用途可以分为:
窗口消息,比如WM_PAINT窗口绘制、WM_CREATE窗口创建等等
命令消息,一般是指WM_COMMAND,表示用户执行了一个命令,产生的对象一般是菜单或是控件
通知消息,一般是指WM_NOTIFY,由公用控件发出
反射消息,处理需要经过”反射”机制的消息,之后会详细说明
消息按照区段可分为:
标识符由0x0000到0x03ff的系统消息
 0x0001-0x0087    窗口消息。
 0x00A0-0x00A9    非客户区消息
 0x0100-0x0108    键盘消息
 0x0111-0x0126    菜单消息
 0x0132-0x0138    颜色控制消息
 0x0200-0x020A    鼠标消息
 0x0211-0x0213    菜单循环消息
 0x0220-0x0230    多文档消息
 0x03E0-0x03E8    DDE消息
标识符由0x0400到0x7FFF的用户自定义消息,以VM_USER(0x0400)为基址,自定义偏移所对应的消息
标识符由0x8000到0xBFFF的用户自定语消息,一般是基于某一个窗口类。用作应用之间的通信
标识符由0xC000到0xFFFF的来自于RegisterWindowMessage函数,它会将传入的字符串注册成一个信息
消息队列
Windows维护了两种类型的队列,一种是系统消息队列,它是唯一的,用户的输入通过驱动程序转化为消息后会进入该队列,然后再将消息放入对应线程(窗口)的消息队列;另外一种是线程消息队列,在调用User或者GDI的函数时创建,队列中的消息会经过消息泵传递给窗口回调函数。
消息也不都是这么”听话”,比如一下的几种
WM_PAINT、WM_TIMER等,它们只有在队列中没有其他消息的时候才会处理,而VM_PAINT甚至还会进行合并来提高效率,这其实是因为它们消息的优先级较低
WM_ACTIVATE、WM_SETFOCUS等,它们会绕过消息队列直接被目标窗口处理
来自其他线程的消息,处理上还是一样,但是它们的优先级较高一些,在下边消息处理中会有所体现
 
消息的处理过程
消息首先由系统或应用产生,由于应用的消息可定制化程度太高,所以我们这里选择系统的消息来作为例子。
消息的传递对应大体有两种方式,一种是POST,一种是SEND,涉及到了各种各样的发送形式
postMessage //消息进入消息队列中后立即返回,消息可能不被处理。
PostThreadMessage //消息放入指定线程的消息队列中后立即返回,消息可能不被处理。
SendMessage //消息进入消息队列中,处理后才返回,如果消息不被处理,发送消息的线程将一直处于阻塞状态,等待消息返回。
SendNotifyMessage//如果消息进入本线程,则为SendMessage(),不是则采取postMessage(),当目标线程仍然依send处理
SendMessageTimeout //消息进入消息队列,处理或超时则返回,实际上SendMessage()就是建立在该函数上的
SendMessageCallback //在本线程再指定一个回调函数,当处理完后再次处理
BroadcastSystemMessage //发送目标为系统组件,比如驱动程序
消息发送处理时会先判定消息的目标是不是在同一线程而产生不同的结果
是,SendMessage()发送的消息不进入消息队列直接处理,而postMessage()进入消息队列
否,SendMessage()发送消息至目标线程的队列,然后监视直至处理,PostThreadMessage()进入队列后返回
其实真正处理消息的就是一个窗口过程函数,它的参数实际上就是一个简化的MSG结构,包括了:对应窗口的句柄、消息的ID、消息的参数
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
当我们创建一个窗口的时候有一个注册窗口的过程,代码如下:
ATOM MyRegisterClass(HINSTANCE hInstance) 

   WNDCLASSEX wcex; 
   wcex.cbSize = sizeof(WNDCLASSEX); 
   wcex.style   = CS_HREDRAW | CS_VREDRAW; 
   wcex.lpfnWndProc = WndProc;
   wcex.cbClsExtra  = 0; 
   wcex.cbWndExtra  = 0; 
   wcex.hInstance  = hInstance; 
   wcex.hIcon   = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_WINDOWSP)); 
   wcex.hCursor  = LoadCursor(NULL, IDC_ARROW); 
   wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); 

[1] [2] [3] [4]  下一页

【声明】:黑吧安全网(http://www.myhack58.com)登载此文出于传递更多信息之目的,并不代表本站赞同其观点和对其真实性负责,仅适于网络安全技术爱好者学习研究使用,学习中请遵循国家相关法律法规。如有问题请联系我们,联系邮箱admin@myhack58.com,我们会在最短的时间内进行处理。
  • 最新更新
    • 相关阅读
      • 本类热门
        • 最近下载