通过Patch DLL修正QQ的状态推送

升级了Win10 TH2,感觉良好,赶紧备份一波。开始菜单的各种BUG得到了很好的修复,不过DPI貌似又变得与之前不一样了。

 

趁备份和清理文件的时候写写这个问题。

在QQ7.5版及之前,我们通过调用QQCPHelper这个COM库的PutRSInfo函数,可以向QQ推送状态,比如QZone的浏览器插件使用这个东西来推送你正在QZone中播放的歌曲。不过目前的QZone已经不使用这个了,因为Chrome等浏览器已经不支持NPAPI这种插件了。现在的QZone和QQ音乐都是直接向服务器发消息,服务器再向QQ客户端通知改状态。

这个东西当然可以用在其他地方,比如osuPlayer。比如我的小工具Sync2(把网易云音乐和千千静听正在播放的歌曲同步到QQ状态,当然是他人可见的)。

不知道是否是因为这个API已经不再使用了,在QQ7.6之后的版本,这个API函数的实现貌似出现了微妙的变化。(我还是觉得比起BUG,这更像是TX故意为之)

以前的PutRSInfo是可以正常接收Unicode字符串的。事实上我们调用COM库,传入的是BSTR(.NET有一层自动包装,传入.NET类型String即可),理论上都是Unicode编码。一直以来都没问题。但是更新之后,它反而会认为你传入的编码是ANSI(GBK),并尝试转为UTF8。这就导致你推送的消息中的中文全部乱码,当然英文是没事的。

关于这个问题的讨论

一个首先会想到的方案是将UTF8字符串强行编码成GBK字符串再传过去(于是实际上传的是内容是UTF8、却由GBK编码的乱码字符串)。但这样会由于UTF8用3个字节表示汉字、GBK用2个字节,导致奇数个汉字的最后一个字不能正确显示。关于这个问题的探讨

于是我们还是要寻找其他办法。虽然目前还没有搞出完美的解决方案,不过还是将这个可行方案的研究过程记录一下。

打开QQ目录下的CPHelper.dll,找到PutRSInfo这个函数的具体实现(这是一个内部函数,并非导出函数,下图中的名字是我自己加的)。

我们可以看到它构造字符串的时候调用的函数是CTXStringA::CTXStringA(tagGBK, wchar_t const *, int)。tagGBK已经明显透露出它是把输入的字符串看做GBK了。

再去看CTXStringA的实现库Common.dll,可以看到它的构造函数有三种,分别是针对纯英文(ASCII?)、GBK和UTF8的。于是想到把这个函数的调用换成UTF8版的构造函数是否能解决问题。

但是,查看CPHelper.dll的导入表(Import Table),发现它根本没导入UTF8版本的函数,只导入了一个GBK版。那我们把导入表里GBK版的函数名改成UTF8版就好(可以使用LordPE或者CFF Explorer)。如果真的能这样改的话,那还算是相当方便了。但是!UTF8版的导出函数名比GBK版多了1个字!!!而这个导入表改名的操作显然是不能变长的!(要是这帮人起名的时候,一个叫tagGBK,一个叫tagUTF,那估计就没这么多问题了)没办法,我们必须要在CPHelper.dll的导入表中添加这个UTF8版函数。

这个过程同样可以使用LordPE或是CFF Explorer。添加完后,查看函数的地址,然后再找到PutRSInfo函数的call调用指令处,将原本GBK版的地址换成UTF8版的地址(16进制直接改就好,当然你要写汇编指令应该也可以)。保存,收工。

测试一下,确实是可以了。

但是一旦QQ版本更新,这个就失效了,还得重新Patch。所以可能还是需要一个更稳定的方案才行。目前就先这样吧。

添加评论

Loading