- 帖子
- 3852
- 积分
- 13044
- 威望
- 16780
- 金钱
- 36761
- 在线时间
- 1139 小时
|
4楼
发表于 2009-2-15 20:44
| 只看该作者
到QQ2008为至,可爱的珊瑚版本显IP显隐身的QQ已经不能用了,前几天下载了比特版本,传美版本,极速版本用了一下,感觉没有珊瑚虫的版本好用,总之用习惯了一种版本,不乐意改变太多.于是抱着这种心态,我于前天下午认真研究了QQ显IP显隐身的原理,自己成功编译出了一款比较满意的显IP显隐身的QQ2008贺岁版本,以满足自己工作和学习的需要.下面我来谈一下显IP显隐身的基本原理.
最初我认为当前的一些显IP的工具,包括大名鼎鼎的FINEPLUS这类软件是在QQ工作时可以拦截了底层的Socket通讯,后来发现,没那么复杂,但我认为如果做成这样子,肯定是一种最有效的办法.
大家的思路是这样子的,由于如果你现在需要和一个QQ好友传输文件或者进行语音聊天或者发送了图片或自定义表情。那么QQ必须知道对方的IP地址和端口信息,这样才能把数据传给对方。所以,QQ内部已经实现了获取IP地址和其他信息的相关函数了。的确如此。而我们只要想办法调用QQ内部的函数。
经过反编译QQ组件之一的CQQApplication.dll中的汇编代码:
027832C7 8B45 F0 mov eax,dword ptr ss:[ebp-10]
027832CA 53 push ebx
027832CB 68 38558302 push CQQAppli.02835538 ; ASCII dwIP
027832D0 50 push eax
027832D1 8B08 mov ecx,dword ptr ds:[eax]
027832D3 FF51 18 call dword ptr ds:[ecx+18]
027832D6 8B45 F0 mov eax,dword ptr ss:[ebp-10]
027832D9 53 push ebx
027832DA 68 40558302 push CQQAppli.02835540 ; ASCII wPort
027832DF 50 push eax
027832E0 8B08 mov ecx,dword ptr ds:[eax]
027832E2 FF51 14 call dword ptr ds:[ecx+14]
从上面的汇编来看,显然是调用了2个thiscall规范的函数,也就是我们所说的C++类成员函数。2个成员函数的大致形式是this->Func(void *ptr1,char *cmd,DWORD *ptr2);其中cmd就是上面dwIP、wPort这些字符串,而ptr2也很容易知道是函数返回值得存储指针。现在关键是要获取this指针,也就是ecx寄存器的数据和ptr1这个神秘指针的数据。
所以问题在这里就变得比较简单了,我们只要想办法获得这个数据,就可以成功实现显IP的功能,这里一般可以有以下三种方案可供选择:
直接修改QQ本身的程序文件->不具备版本无关性,容易引发法律纠纷
使用外部exe进程->必须采用调试进程的办法,效率低且浪费系统资源
编写dll文件让QQ加载->效率高,稳定
所以我们都选择了第三种编写DLL注入的方法,一般目前显IP的版本下面都有两个这样的文件,FINEPLUS.exe和fineplus.dll,我们一般通过fineplus.exe来启动QQ,从而实现显IP的目的,大家可能以为主要的功能部分一定在fineplus.exe这个文件中,其实是不对的,fineplus.exe这个文件就做了一件事,就是在启动QQ的过程中把fineplus.dll注入到QQ中去.
将dll文件注入到程序的方法有2种:
1.首先通过CreateProcess创建进程,然后模拟windows加载一个dll的全过程,在加载程序主体
2.采用远程线程植入技术,即使用CreateRemoteThread
我也只是参考了明日帝国的教程,大家可以去看看,最后列出获取IP的源程序(不涉及加载,拦截,替换的过程)
char *szwProcotol = wProcotol;
char *szRecentip=dwRecentIP;
char *szwRecentPort=wRecentPort;
char *szdwC2CIP=dwC2CIP;
char *szwC2CPort=wC2CPort;
char *szdwIP=dwIP;
char *szwPort=wPort;
bool GetDestIPInfo(DWORD ptrClassHandle,DWORD *ptrDestIp,DWORD *ptrDestPort)
{
if (ptrClassHandle==NULL || ptrDestIp==NULL || ptrDestPort==NULL) return false;
//Using Std Info Buffer
_asm
{
pushad
pushf
mov eax,ptrClassHandle
mov ecx,[eax]
mov edx,ptrDestIp
push edx
push szRecentip
push eax
mov eax,[ecx+34h]
call eax
mov eax,ptrClassHandle
mov ecx,[eax]
mov edx,ptrDestPort
push edx
push szwRecentPort
push eax
mov eax,[ecx+30h]
call eax
popf
popad
}
(*ptrDestPort) &= 0xFFFF;
if ((*ptrDestIp) != NULL && (*ptrDestPort) != NULL) return true;
_asm
{
pushad
pushf
mov eax,ptrClassHandle
mov ecx,[eax]
mov edx,ptrDestIp
push edx
push szdwC2CIP
push eax
mov eax,[ecx+34h]
call eax
mov eax,ptrClassHandle
mov ecx,[eax]
mov edx,ptrDestPort
push edx
push szwC2CPort
push eax
mov eax,[ecx+30h]
call eax
popf
popad
}
(*ptrDestPort) &= 0xFFFF;
if ((*ptrDestIp) != NULL && (*ptrDestPort) != NULL) return true;
_asm
{
pushad
pushf
mov eax,ptrClassHandle
mov ecx,[eax]
mov edx,ptrDestIp
push edx
push szdwIP
push eax
mov eax,[ecx+34h]
call eax
mov eax,ptrClassHandle
mov ecx,[eax]
mov edx,ptrDestPort
push edx
push szwPort
push eax
mov eax,[ecx+30h]
call eax
popf
popad
}
(*ptrDestPort) &= 0xFFFF;
return ((*ptrDestIp) != NULL && (*ptrDestPort) != NULL);
}
这样一个通过注入DLL方式的显IP插件就可以实现了,目前我觉得fineplus就做得很好.最后再谈一下显隐身的基本原理.以fineplus为例.
我们在反编译的过程中,注意到了这样一个函数,IQQDATA,从他的的参数来看,IQQData *,很有可能就是存放着一个用户相关信息的结构,所以开启QQ的显隐身功能原理在于QQ本身的这个部分,只要我们拦截到IQQDATA中关于本身状态的数据就可以了.QQ外挂程序Fineplus能够将该结果利用通过外挂的显隐身逻辑运算式就能将暗藏的显隐身功能开启,其实这个很简单,学过C语言选择语句的同学应该都可以写得出来.
能打开FinePlus程序内隐藏的显隐身逻辑运算格式,不过只对QQ开启后比你后隐身登录的人有效:
"('{状态}'/10-1#'[在线]':(('{IP}'==0)#'':(('{版本}'==0)#'[隐身]':'[离线]')):'[离开]':'[隐身]':'[忙碌]':'[Q我]':'[静音]':'[其他]')"
"('{状态}'/10-1#'[在线]':'[离线]':'[离开]':'[隐身]':'[忙碌]':'[Q我]':'[静音]':'[其他]')"
下面有三种能开启FinePlus隐藏的显隐身功能逻辑运算格式,请替换上面{状态}中[离线]的地方为以下逻辑运算格式即可:
(('{IP}'&&'{版本}')?'':('{版本}'?'[隐身]':'[离线]'))
('{IP}'?'':('{版本}'?'[隐身]':'[离线]'))
(('{IP}'==0)#'':(('{版本}'==0)#'[隐身]':'[离线]'))
以上逻辑运算式已经经小辉测试过是正确的。其功能就是为了判断在离线状态下,是否隐身或者离线.
到这里为止,一个可以显示IP地址和隐身与否的QQ版本就制作成功了,我再把IP数据包更新到了3月1日,再花了点时间做个安装包,手动DIY soft QQ2008贺岁版本显IP显隐身完整版本就这样做出来了.考虑版权问题,暂不提供下载.
欢迎大家阅读本教程,参考明日帝国等高手教程,表示感谢.朋友们可以与我讨论技术性细节问题. |
|