首页
论坛
课程
招聘
[原创]利用钩子函数来注入DLL的一个具体应用:点击桌面不同图标,播放相应音符
2011-6-27 21:17 15604

[原创]利用钩子函数来注入DLL的一个具体应用:点击桌面不同图标,播放相应音符

2011-6-27 21:17
15604
最近看核心编程,看到DLL注入这一章,有一个Desktop Item Positon Saver(DIPS)的例子,这个例子是使用窗口挂钩来将一个DLL注入到Explorer.exe的地址空间中,来保存和恢复图标位置。
于是便想根据这个例子自己改造一下,正好前段时间看到在 Google 的首页上,谷歌为了纪念电吉他之父莱斯·保罗 96 周年诞辰,特意做了一个很有意思的Doodle,这个 谷歌电吉他Logo可以让用户在其上面弹奏吉他,于是便想利用桌面图标来编一个类似的程序,点击不同的图标,发出不同的吉他音色的音符。
下面把编程的大概思路说一下:
首先就是找到桌面ListView控件的窗口句柄,刚开始在这里就遇到了问题。
核心编程这本书上讲到Windows外壳有一个类别为ProgMan的窗口,这个ProgMan窗口有且只有一个类别为SHELLDLL_DefView的子窗口。这个子窗口同样有且只有一个子窗口,子窗口的类别为SysListView32,这个SysListView32窗口就是桌面的ListView控件窗口。
于是我便利用了它的代码:
HWND hWndLV =GetFirstChild(GetFirstChild(
      FindWindow(TEXT("ProgMan"), NULL)));
但发现运行不正确,于是便使用spy++查看,发现我的SysListView32窗口是位于类为WorkerW的窗口下。难道这是win7系统更改的?我也不清楚。因此,如果大家下载下来我的源代码后,如果运行不成功,最好用spy++查看一下窗口信息,看一看SysListView32控件到底是谁的子窗口,如果是ProgMan的子窗口,那么大家需要把MouseHookApp.cpp文件中的
HWND hWndLV;
   EnumWindows(EnumWindowsProc,(LPARAM)&hWndLV);

EnumWindowsProc函数注释掉,
取消HWND hWndLV =GetFirstChild(GetFirstChild(
      FindWindow(TEXT("ProgMan"), NULL)));这一代码的注释。
我发现类名为WorkerW的窗口不是唯一的,因此不能使用FindWindows了,改用了EnumWindows函数。
HWND hWndLV;
   EnumWindows(EnumWindowsProc,(LPARAM)&hWndLV);

其中的EnumWindowsProc函数实现如下:
BOOL CALLBACK EnumWindowsProc(HWND hwnd, LPARAM lParam){
	if(hwnd)
	{
		TCHAR classname[128];
		GetClassName(hwnd, classname, 128);
		if(!_tcscmp(classname, _T("WorkerW") ) )
		{
			HWND &hWndLV = *(HWND *)lParam;
			TCHAR childClassName[128];
			HWND hChildWnd = GetWindow(hwnd, GW_CHILD);
			while(hChildWnd)
			{
				GetClassName(hChildWnd, childClassName, 128);
				if(!_tcscmp(childClassName, _T("SHELLDLL_DefView")))
				hWndLV = GetFirstChild(hChildWnd);
				chASSERT(IsWindow(hWndLV));
				return false;
			}
		}
	}
	
	return true;
}


好了,现在得到桌面ListView控件的句柄了,下面就需要编写注入到Explorer.exe中的DLL文件了。遇到的问题主要有两个:
第一个就是注册了鼠标消息的钩子函数后,如何判断鼠标点击的是图标的哪一项,经过各方面查找资料并实验后发现以下一种可行方法:
 LVITEM lvi;
  LVHITTESTINFO lvh={0};
  int iIndexItem;
  long lx = pMouseHook->pt.x;//pMouseHook是指向MOUSEHOOKSTRUCT结构体的指针
  long ly = pMouseHook->pt.y;
        lvh.pt.x = lx;
  lvh.pt.y = ly;
        ScreenToClient(pMouseHook->hwnd, &(lvh.pt));
  ListView_HitTest(pMouseHook->hwnd, &lvh);
        iIndexItem = lvh.iItem;
  if(iIndexItem !=-1)
  {
    ZeroMemory(&lvi, sizeof(lvi));
    lvi.mask = LVIF_TEXT;
    lvi.iItem = iIndexItem;
    lvi.pszText = szBuff;
    lvi.cchTextMax = _countof(szBuff);

    if(ListView_GetItem(pMouseHook->hwnd, &lvi))
    {
      wsprintf(szDebug, TEXT("item text = '%s'"), szBuff);
      OutputDebugString (szDebug); 
    }

遇到的第二个问题主要是音符播放问题,由于以前没接触过这方面的知识,所以刚开始没有什么头绪,后来发现应该使用MIDI方面的知识。
主要用到的函数有midiOutOpen和midiOutShortMsg函数,具体该函数的用法,大家可以参考一下MSDN。
函数GetSelectedItem的主要代码如下:
LVHITTESTINFO lvh={0};
	int iIndexItem;
	int keyNo, iOctave, iNote ;
	long lx = lmhs->pt.x;
	long ly = lmhs->pt.y;
	lvh.pt.x = lx;
	lvh.pt.y = ly;

	ScreenToClient(lmhs->hwnd, &(lvh.pt));
	ListView_HitTest(lmhs->hwnd, &lvh);
	iIndexItem = lvh.iItem;
	if(iIndexItem !=-1)
	{
		POINT ItemPt;
		ListView_GetItemPosition(lmhs->hwnd, iIndexItem, &ItemPt);
               /*wsprintf(szDebug, TEXT("item coordinate = '%d, %d'"), ItemPt.x, ItemPt.y);
		OutputDebugString (szDebug); */
		int lineNo = ItemPt.x/75;
		int colNo = ItemPt.y/86;
		keyNo = lineNo*10+colNo;
		if (keyNo >= NUMSCANS)                       // No scan codes over 53
          return ;
     
		if ((iOctave = notes[keyNo].iOctave) == -1)    // Non-music key
          return ;
		iNote = notes[keyNo].iNote ;
		if(keyNo <30)
		MidiNoteOn (hMidiOut, 0, iOctave, iNote, iVelocity) ; // Note on
		else
		{
			MidiSetPatch (hMidiOut, 9, 0) ;
			MidiNoteOn (hMidiOut, 9, iOctave, iNote, iVelocity) ; // Note on
		}

主要的部分就是这些,关于如何安装钩子函数,截取鼠标消息等等,这里我就不再赘述了,网上有很多具体资料,也可以查看我的源代码。
大家在运行源代码是,还有一个问题,就是屏幕分辨率问题,因为图标在桌面上的位置与间隔随着屏幕分辨率的不同会有差别,而我程序中判断图标位置的代码,
int lineNo = ItemPt.x/75;
int colNo = ItemPt.y/86;
其中的75和86分别是我自己屏幕分辨率的情况下(1440x900)一个图标与上下图标和左右图标之间上下和左右的距离。我这里为了省事,就直接写死了,没有对其进行程序上的判段,嘿嘿,今后为了通用性,肯定还是会改进的,现在先凑合着用吧。
如果大家想知道自己屏幕分辨率下的图标之间的距离,可以把上述GetSelectedItem函数代码中的
/*wsprintf(szDebug, TEXT("item coordinate = '%d, %d'"), ItemPt.x, ItemPt.y);
                OutputDebugString (szDebug); */
注释取消掉,然后运行程序,点击图标,使用debugview软件查看输出地坐标信息,自己计算出相邻图标的距离,把75 和86替换掉即可。

程序运行后点击MusicHook按钮就可以了,这是点击桌面图标就可以发出音符声音了。取消hook点击UnHook按钮。
大致情况就是这样。最后把收集到的一些吉他的曲谱附上供大家参考玩耍,嘿嘿。
小星星:1155665 4433221 5544332 5544332 1155665 4433221;
卖报歌:555 555 35653 235 53532 132 332 612 665 365 53235 5323 5323 61231
月亮之上:3686 3675 53686565326553 3686 89865 36865326656
团子大家族:325 56 67 52 325 565 325 56 67 52 325 565 8753 5635 235 8753 5635 235 251
两只老虎: 1231|1231|345|345|565431|565431|151|151||  (最爱,哈哈)
童年:35553 6676 66588886865 355536676 66658888668 9~
上海滩:356666,352222,356865132

第五届安全开发者峰会(SDC 2021)议题征集正式开启!

上传的附件:
收藏
点赞0
打赏
分享
最新回复 (19)
雪    币: 551
活跃值: 活跃值 (360)
能力值: (RANK:400 )
在线值:
发帖
回帖
粉丝
莫灰灰 活跃值 9 2011-6-28 10:28
2
0
核心编程我也看过, 但是没写出像LZ那么好玩的程序, 失败啊。
希望LZ以后能改进通用性的同时能分享你的学习心得。
雪    币: 210
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
lmhmylsq 活跃值 2011-6-28 12:31
3
0
看过,很好,感谢楼主分享!
雪    币: 677
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
hezhang 活跃值 2011-6-28 13:42
4
0
只装了vc6  鸭梨很大
雪    币: 271
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
wep 活跃值 2011-6-28 14:41
5
0
不错,挺好的应用。
雪    币: 220
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
广海混沌 活跃值 2011-6-28 20:18
6
0
嗯 曾经谷歌的这个小动作我也留意过
雪    币: 324
活跃值: 活跃值 (15)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
shwsf 活跃值 1 2011-6-28 21:07
7
0
上班的电脑,只装了vc6。今晚是不能试玩了!
雪    币: 301
活跃值: 活跃值 (23)
能力值: ( LV7,RANK:110 )
在线值:
发帖
回帖
粉丝
kkmylove 活跃值 2 2011-6-28 22:05
8
0
恩 那个电吉他很赞 不知道怎么做的 谁可以讲讲啊
雪    币: 252
活跃值: 活跃值 (11)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
superkofzx 活跃值 1 2011-6-28 23:26
9
0
对啊,我也想看看google的那个电吉他的原理。是不是用ajax实现的?
雪    币: 252
活跃值: 活跃值 (11)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
superkofzx 活跃值 1 2011-6-28 23:31
10
0
多谢斑竹,以后会分享的
雪    币: 123
活跃值: 活跃值 (10)
能力值: ( LV5,RANK:70 )
在线值:
发帖
回帖
粉丝
weizehua 活跃值 1 2011-6-29 07:24
11
0
如果楼主学过WINDOWS GDI那这个软件肯定更出色^_^
雪    币: 1602
活跃值: 活跃值 (13)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
panti 活跃值 2011-7-1 05:30
12
0
没放bin啊,一时之间找不到编译器``
鼠标钩子,学以致用啊
雪    币: 203
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
foolpanda 活跃值 2011-7-2 09:44
13
0
LZ挺有创意,从来没有想过这么玩。佩服。
雪    币: 149
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
xungege 活跃值 2011-7-2 10:21
14
0
厉害啊,我也看过核心编程,就没有这么多的想法。向楼主学习
雪    币: 13
活跃值: 活跃值 (94)
能力值: ( LV5,RANK:60 )
在线值:
发帖
回帖
粉丝
叁毛 活跃值 1 2011-7-3 23:56
15
0
编码风格不错。
既然win32下,就用大写FALSE替代false吧。
雪    币: 174
活跃值: 活跃值 (22)
能力值: ( LV10,RANK:160 )
在线值:
发帖
回帖
粉丝
zouzhiyong 活跃值 3 2011-7-4 17:36
16
0
mark~~,有点意思~~
雪    币: 254
活跃值: 活跃值 (63)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
hacker一疒亻 活跃值 2011-7-6 08:32
17
0
very very very good!
好!
能否指点一下在linux下如何运行你这个程序?
手头已经没有windows的机器了,可否书写一份linux下的源码?
雪    币: 252
活跃值: 活跃值 (11)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
superkofzx 活跃值 1 2011-7-6 14:46
18
0
多谢回复。现在还是个菜,linux没接触过,以后又机会一定要学习一下linux
雪    币: 49
活跃值: 活跃值 (30)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
菜菜默 活跃值 2011-7-6 19:24
19
0
鼠标钩子!!! 正好能用上!
雪    币: 777
活跃值: 活跃值 (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
lnheart 活跃值 2011-7-13 11:27
20
0
看起来蛮有创意的。
游客
登录 | 注册 方可回帖
返回