browser icon
You are using an insecure version of your web browser. Please update your browser!
Using an outdated browser makes your computer unsafe. For a safer, faster, more enjoyable user experience, please update your browser today or try a newer browser.

“QQ反骚扰”开发手记

Posted by on 2002 年 10 月 04 日

你可以任意转载本文,但请在转载后的文章中注明作者和原始链接。
媒体约稿请联系 titilima_AT_163.com(把“_AT_”换成“@”)。

国庆七天,呆在家中上网聊天实在不是一件惬意的事:每一天打开QQ,迎接我的都是一串一串的广告……国庆黄金周,连广告也不放过!:(

无奈,打开Visual C++,开始了我的“反骚扰”之路。

首先我面对的问题是:QQ一共有几种广告,我能用什么方法消灭它们?

前半个问题很好回答,相信所有常Q的朋友都知道。QQ的广告有三种:第一种是在系统消息中的弹出式Flash广告,第二种是直接弹出的Flash广告(窗体非常花哨),第三种是以系统广播形式出现的文字式广告。

对于后半个问题,我给出的答案是:在广告对应的窗体上,都有相应的按钮可以将其关闭,点击即可。

不是吧,就这么简单?也许你要这么问。

是的,不过我是说,让我的“QQ反骚扰”帮助我点击这些按钮。即在取得这些按钮的句柄后,向该按钮发送一个单击消息,如下代码所示:

SendMessage( hButton, BM_CLICK, 0, 0 );

也许会有朋友问,为什么不直接将对话框消灭掉,即:

EndDialog( hDialog, TRUE );

问得好!具体原因是……呵呵,我也不知道:)但我能告诉你的是,你可以将我的代码换成上面那一句,效果可能不会很理想的,因为我试过。另外,有很多的共享软件点击器之所以叫“点击器”就是这个道理。单单消灭这个窗口,很可能由该窗口占用的一些系统资源就会流失,相比之下,还是使用点击的方法,让对话框自己调用它回调函数中的退出部分来消灭对话框,岂不是更加安全?

还有一个问题:什么时候让它去点击呢?或者说,它怎么知道什么时候去点击呢?

我的答案是:时刻监视。

是了,这就是我在软件的Readme.txt中所说的“计时器技术”了。很简单,只需在对话框的初始化中加入如下代码:

SetTimer( hDlg, 1, 100, NULL );

第一个参数是需要设置计时器的对话框句柄,使用MFC的朋友可以省略这个参数;第二个参数是计时器的ID;第三个是计时器事件的触发时间间隔(以微妙为单位);第四个参数可以指定响应事件的回调函数,这里用不着,为NULL。

这样,便可以实现初步的功能——时刻监视了。但是在最后处理程序退出部分的代码时,一定要将先前创建的计时器销毁,即:

KillTimer( hDlg, 1 );

因为计时器是一个耗费系统资源的东西,所以在程序结束的时候,必须销毁它以释放系统资源。

下面我来开始介绍如何来在内存中寻找QQ的三种广告窗口。以下的代码我均摘自“QQ反骚扰”的SDK源代码,请使用MFC的朋友们自行做出相应的改动。

在内存中有很多窗口,那么“QQ反骚扰”又是如何知道哪一个窗口是QQ的广告窗口呢?很简单,从窗口所具备的众多特征中取出两到三个来作为“过滤器”即可。比如对于系统消息的弹出式广告,它的“过滤器”就是它的标题——“腾讯QQ系统广播”和它的“关闭”按钮。

这样,在处理计时器事件时的代码如下:

HWND hWndCap, hBtnClose1; // 窗口句柄和“关闭”按钮句柄
hWndCap = FindWindow( NULL, "腾讯QQ系统广播" ); // 查找窗口
if ( hWndCap != NULL ) // 如果窗口存在
{
    hBtnClose1 = FindWindowEx( hWndCap, NULL, "Button", "关闭" ); // 继续过滤,找“关闭”按钮
    if ( hBtnClose1 != NULL ) // 如果这个按钮也存在,则基本可以确定是QQ的广告了
    {
        EnableWindow( hBtnClose1, TRUE ); // 将按钮生效
        SendMessage( hBtnClose1, BM_CLICK, 0, 0 ); // 发送单击消息
    }
}

在此我要说明一下将按钮生效的那行代码。QQ的早期版本中(譬如我目前在家使用的版本),Flash广告是必须得看完一遍后,“关闭”按钮才会生效,所以我必须在找到后立即使它生效以关闭窗口。当然,对于较新版本的QQ来说,完全可以去掉这一行。

对于自动弹出的Flash广告,就没有上面的那个那么容易了。因为它采用的是图形界面,从外表看是得不到我所谓的“过滤器”的,这就需要其它软件的帮助了。我使用的软件是我写的“对话框查看器”测试版v2.SVTF.00(有兴趣的朋友可以mail我titilima@163.com索取这个软件),这是一个能够即时获取窗口标题、窗口ID和窗口类名的工具。我在它的帮助下得到了这种广告的“关闭”按钮的标题——“CLOSE”。于是我的代码如下:

HWND hWndNo, hBtnClose2;
hWndNo = FindWindowEx( NULL, NULL, "#32770", "" ); // #32770是对话框的类名
do // 在找到的无标题对话框中反复查找“CLOSE”这个按钮
{
    hBtnClose2 = FindWindowEx( hWndNo, NULL, "Button", "CLOSE" );
    if ( hBtnClose2 != NULL )
        break// 若找到按钮则跳出循环
    hWndNo = FindWindowEx( NULL, hWndNo, "#32770", "" ); // 否则继续查找无标题窗口
while ( hWndNo != NULL );
if ( hBtnClose2 != NULL )
{
    EnableWindow( hBtnClose2, TRUE ); // 同上,若不需要请将此行自行删除
    SendMessage( hBtnClose2, BM_CLICK, 0, 0 );
}

就这样,这个广告也被我征服了。其实最困扰我的是第三种广告——QQ号为10000的广告。我之所以把它称为“QQ号为10000的广告”,就是因为我的“过滤器”就是“10000”。这种广告和“用户????????将你列入好友名单”的系统信息是一样的,所以一不小心就会将重要的信息过滤掉。于是我选中了“10000”作为我的过滤器。

起先我从对话框的外观上判断,写有用户QQ号的控件是一个只读(ES_READONLY)的编辑框(Edit),后来我如法炮制代码并编译运行,发现无效!于是“QQ反骚扰”的版本号定为1.SVOF.02,共能消除两种的QQ广告。于是我似乎消沉了。不过偶然的一天,在我使用eXeScope研究另一个软件的时候,我才突然想出了用eXeScope这位专家来研究一下QQ的主程序的办法,然而能否成功,我心里没底。

我打开QQ的主程序,找到那个对话框,发现有很多的Static(静态文本,Delphi及C++ Builder中的Label)!我的天,我怎么没有想到那是改变了风格的Static呢?于是乎三下五除二,我的最后一段代码也问世了:

HWND hWndYw, hBtnClose3, hEdit;
hWndYw = FindWindow( NULL,"系统消息" );
if ( hWndYw != NULL )
{
    hBtnClose3 = FindWindowEx( hWndYw, NULL, "Button", "返回" );
    hEdit = FindWindowEx( hWndYw, NULL, "Static", "10000" );
    if ( hEdit != NULL && hBtnClose3 != NULL )
        SendMessage( hBtnClose3, BM_CLICK, 0, 0 );
}

你可以看到,在我的代码中,标识那个Static的句柄依然叫hEdit,那是因为我先前的判断失误。

“QQ反骚扰”v1.SVOF.12的核心代码就讲到这里了,不过还有一点,就是我的“QQ反骚扰”中存在着一个不大不小的Bug。大家注意到了吗?第三段代码中,如果碰到标题是10000的静态文本,就向“返回”按钮发送单击消息。这也就意味着如果一个昵称是10000的网友加你为好友,那么他的这条系统信息同样有可能被过滤掉。解决的办法是判断“加为好友”按钮的风格是否为可见(WS_VISIBLE),若为不可见,则可以向“返回”按钮发送单击消息了。但是由于我个人时间的问题,这段代码还没有来得及实现,就交给大家了,呵呵。

欢迎与我交流:titilima@163.com。另外,你也可以通过这个信箱向我索要“QQ反骚扰”的最新版本。

后记:和“反骚扰”说再见

“QQ反骚扰”是我的VC SDK处女作,我从去年10月份开始写这个软件,之后又经历了很多次升级,到这个“最终版本”——v1.37为止,我终于决定停手了。

原因很简单,QQ的版本不断升级,广告的花样也越来越多,这就决定了我不得不一次次地升级这个软件。而现在网上关于“反骚扰”的技巧又有很多,所以我觉得我这么做就有点多此一举了。既然我的目的——学习——达到了,那么再“升级”下去也就失去意义了。

我仍然感谢很多网友,感谢他们对我的信任和对我的关心。我无以回报,决定将这个处女作的源代码倾囊相授,而不再是“核心代码演示版”。是前我的代码是用C++写成的,主要包括了我封装的CheckBox类,现在看来那个类十分丑陋,唯恐给诸位带来误导的副作用,于是我花了一些时间,将它用纯C重写了一遍,希望能够满足和我一样的初学者的需要。顺便说一句,这个v1.37几乎对QQ2003无能为力。还有,Visual Studio中自带的工具Spy++比我的“对话框查看器”功能要强得多。

OK,那么再见了,我的“QQ反骚扰”。

李马 2003/9/10 于山西太原

点此下载“QQ反骚扰”v1.37及其源代码:qqantiad.zip

点此下载“对话框查看器”测试版v2.SVTF.00:dlgview.zip

订阅本站

一条评论

  • At 2007.08.10 11:41, U鱼 said:

    (Required)
    (Required, will not be published)