PostThreadMessage函数
将一个队列消息放入(寄送)到指定线程的消息队列里,不等待线程处理消息就返回。
BOOLPostThreadMessage( DWORDidThread, UINTMsg, WPARAMwParam, LPARAMIParam );
idThread
:其消息将被寄送的线程的线程标识符。如果线程没有消息队列,此函数将失败。当线程第一次调用一个Win 32 USER或GDI函数时,系统创建线程的消息队列。要得到更多的信息,参见备注。
Msg
:指定将被寄送的消息的类型。
wParam
:指定附加的消息特定信息。
IParam
:指定附加的消息特定信息。
返回值
:返回线程号。
GetMessage函数
从调用线程的消息队列里取得一个消息并将其放于指定的结构。此函数可取得与指定窗口联系的消息和由PostThreadMessage寄送的线程消息。此函数接收一定范围的消息值。GetMessage不接收属于其他线程或应用程序的消息。获取消息成功后,线程将从消息队列中删除该消息。函数会一直等待直到有消息到来才有返回值。
GetMessage( LPMSG lpMsg, HWND hWnd, UINT wMsgFilterMin, UINT wMsgFilterMax )
lpMsg
:指向MSG结构的指针,该结构从线程的消息队列里接收消息信息。
hWnd
:取得其消息的窗口的句柄。当其值取NULL时,GetMessage为任何属于调用线程的窗口检索消息,线程消息通过PostThreadMessage寄送给调用线程。
wMsgFilterMin
:指定被检索的最小消息值的整数。
wMsgFilterMax
:指定被检索的最大消息值的整数。
返回值
:如果函数取得WM_QUIT之外的其他消息,返回非零值。如果函数取得WM_QUIT消息,返回值是零。如果出现了错误,返回值是-1。例如,当hWnd是无效的窗口句柄或lpMsg是无效的指针时。若想获得更多的错误信息,请调用GetLastError函数。
SendMessage函数
将指定的消息发送到一个或多个窗口。此函数为指定的窗口调用窗口程序,直到窗口程序处理完消息再返回。
LRESULT SendMessage( HWND hWnd, UINT Msg, WPARAM wParam, LPARAM IParam )
hWnd
:指定要接收消息的窗口的句柄。如果此参数为HWND_BROADCAST,则消息将被发送到系统中所有顶层窗口,包括无效或不可见的非自身拥有的窗口、被覆盖的窗口和弹出式窗口,但消息不被发送到子窗口。
Msg
:指定被发送的消息。
wParam
:指定附加的消息特定信息。
IParam
:指定附加的消息特定信息。
返回值
:返回值指定消息处理的结果,依赖于所发送的消息。
GetFirstChild宏
GetFirstChild()函数其实是一个宏定义:
#define GetFirstChild(hwnd) GetTopWindow(hwnd)\
GetTopWindow函数
GetTopWindow函数检查与特定父窗口相联的子窗口z序,并返回在z序顶部的子窗口的句柄。
HWND GetTopWindow(HWND hWnd);
hWnd
:被查序的父窗口的句柄。如果该参数为NULL,函数返回Z序顶部的窗口句柄。
返回值
;如果函数成功,返回值为在Z序顶部的子窗口句柄。如果指定的窗口无子窗口,返回值为NULL。
FindWindow函数
FindWindow这个函数检索处理顶级窗口的类名和窗口名称匹配指定的字符串。这个函数不搜索子窗口。
HWND FindWindow(LPCSTR lpClassName,LPCSTR lpWindowName);
lpClassName
:指向一个以NULL字符结尾的、用来指定类名的字符串或一个可以确定类名字符串的原子。如果这个参数是一个原子,那么它必须是一个在调用此函数前已经通过GlobalAddAtom函数创建好的全局原子。这个原子(一个16bit的值),必须被放置在lpClassName的低位字节中,lpClassName的高位字节置零。如果该参数为null时,将会寻找任何与lpWindowName参数匹配的窗口。
lpWindowName
:指向一个以NULL字符结尾的、用来指定窗口名(即窗口标题)的字符串。如果此参数为NULL,则匹配所有窗口名。
返回值
:
如果函数执行成功,则返回值是拥有指定窗口类名或窗口名的窗口的句柄。
如果函数执行失败,则返回值为 NULL 。
挂载调用
HHO0K hHook = SetWindowsHookEx( WH_GETMESSAGE, GetMsgProc, hinstDll, 0 );
- 进程B中的一个线程准备将一条消息发送到一个窗口。
- 系统查看该线程上是否已经安装了WH_GETMESSAGE挂钩。
- 系统查看包含GetMsgProc函数的DLL是否被映射到进程B的地址空间中。
- 如果该DLL尚未被映射,系统将强制该 DLL映射到进程B的地址空间,并且将进程 B中 的DLL映像的自动跟踪计数递增1。
- 当D L L的hinstDll用于进程B时,系统查看该函数,并检查该 D L L的hinstDll是否与它用于进程A时所处的位置相同。
- 系统将进程B中的D L L映像的自动跟踪计数递增1。
- 系统调用进程B的地址空间中的GetMsgProc函数。
- 当GetMsgProc函数返回时,系统将进程B中的D L L映像的自动跟踪计数递减1。
3.1 桌面项目位置保存器实用程序 DIPS
桌面项目位置保存器实用程序 DIPS。
当你将 S 作为命令行参数传递给 DIPS时,它就创建下面这个注册表子
关键字,并且给桌面窗口上的每个项目添加一个值:
HKEY_CURRENT_USER\Software\Richter\Desktop Item Position Saver
每个项目都有一个与它一起保存的位置值。当改变屏幕分辨率以便玩游戏之前,运行 DIPS的S。当玩完游戏后,将屏幕的分辨率改为原来的状态,并且运行 DIPS R。这使得DIPS打开注册表子关键字,对于桌面上与注册表中保存的项目相匹配的每个项目来说,当运行 DIPS S时,项目的位置将被重新设置为原来的值。
原理
DIPS应用程序使用窗口挂钩将一个DIPSLib.dll插入Explorer.exe的地址空间。
Explorer.exe进程用于管理Windows的图形界面,包括开始菜单、任务栏、桌面和文件管理,如果结束这个该程序会导致Windows图形界面无法使用,就是电脑只会剩下一张壁纸,其他的东西统统消失。所以这个Explorer.exe进程的正常运行对系统的稳定性有很大的帮助。如果用户发现任务管理器中有两个或多个Explorer.exe进程,那么就要检查是否中了远控了,最好用木马专杀工具扫扫。
windows下使用Hook实现对远程进程注入DLL技术,通过共用操作系统下同一份DLL,实现对目标进程的特定消息传输,甚至达到控制的技术。
DIPS功能
DIPS主要调用DIPSLib,DIPSLib主要实现Hook以及保存屏幕信息至注册表。
DIPS主要功能:
- 界面显示 save、resave等
- 获取ProgMan的线程ID
- 调用SetDPISHook和UnHook
- 作为客户端像DIPSLib发送WM_APP消息
ProgMan是显示出来的总桌面,也是总程序,如果你向Progman窗口发送一个WM_CLOSE消息,Windows就会提醒你是否要关机。
参考 编写Windows动态壁纸(关于Windows10桌面的了解)(一)
可以通过spy++ 查看
DIPSLib功能
DIPSLib主要功能:
- 导出SetDIPSHook接口用来Hook线程
- 保存DIPS信息到注册表。(SaveListViewItemPositions/RestoreListViewItemPositions)
- 共享数据段g_hHook、g_dwThreadIdDIPS
#pragma data_seg("Shared") HHOOK g_hHook = NULL; DWORD g_dwThreadIdDIPS = 0; #pragma data_seg()
- 作为服务端 接受处理WM_APP消息
过程
- 首先通过
ProgMan
进程,得到桌面的ListView控件的窗口句柄
HWND hWndLV = GetFirstChild(GetFirstChild( FindWindow(TEXT("ProgMan"), NULL)));
- 通过调用
GetWindowThreadProcessId
函数,就能够确定创建窗口的线程的ID。将这个ID传递给SetDIPSHook
函数(在DIPSLib.cpp中实现)。SetDIPSHook
负责在该线程上安装一个WH_GETMESSAGE
挂钩,然后调用PostThreadMessage
函数,以强制Windows Explorer的线程醒来。
// Install the hook on the specified thread g_hHook = SetWindowsHookEx(WH_GETMESSAGE, GetMsgProc, g_hInstDll, dwThreadId); bOk = (g_hHook != NULL); if (bOk) { // The hook was installed successfully; force a benign message to // the thread's queue so that the hook function gets called. bOk = PostThreadMessage(dwThreadId, WM_NULL, 0, 0); }
- 由于已经在该线程上安装了一个
WH_GETMESSAGE
挂钩,因此操作系统能够自动将DIPSLib. dll 文件插入Explorer.exe
的地址空间,并且调用GetMsgProc函数。该函数首先查看它是否是初次被调用,如果是,那么它就创建一个隐藏的窗口,其标题是Wintellect DIPS
,请记住,Explorer的线程正在创建这个隐藏窗口。
// The DLL just got injected. bFirstTime = FALSE; // Uncomment the line below to invoke the debugger // on the process that just got the injected DLL. // ForceDebugBreak(); // Create the DIPS Server window to handle the client request. CreateDialog(g_hInstDll, MAKEINTRESOURCE(IDD_DIPS), NULL, Dlg_Proc); // Tell the DIPS application that the server is up // and ready to handle requests. PostThreadMessage(g_dwThreadIdDIPS, WM_NULL, 0, 0);
- 调用GetMessage函数,这次函数调用将使线程进入睡眠状态,直到队列中显示一条消息为止。
- 服务端DIPS.dll隐藏窗口Wintellect DIPS创建完成后,客户端DIPS.exe 通过FindWindow其标题
Wintellect DIPS
获得其句柄,向其发送消息WM_APP,让服务端 DIPS.dll 此时处理S、R操作。 - 客户端DIPS.exe 发送消息
WM_CLOSE
SetDIPSHook(0)
,卸载挂钩,Explorer的地址空间中卸载DIPSLib.dll。