标 题:原创】另类得到QQ聊天信息,支持所有的QQ版本
作 者:fbbttfbb
时 间: 2012-03-31,17:30:40
目 的:只是研究,无其它 得到QQ聊天内容的有许多方法,有通过QQ接口得到,也可以通过COM接口得到,现在用另一种方法得到QQ聊天信息,我们知道QQ2008版本的聊天信息我们可以通过向QQ聊天对话
框的rich窗口发送消息得到内容,但2009聊天内容,就不能了,因为并不是标准的控件。所以我们现在用HOOK ExtTextOutW API来得到QQ聊天内容,经过逆向QQ,发现新版本的QQ(
包括QQ2010,2011,2012)的聊天内容,都是放在一块内存块里,那么我们只要得到了这个内存地址,就可以得到聊天内容了,至于如何得到这块内存址址,这时就用到了HOOK
ExtTextOutW做为入口,在QQ聊天窗口每次显示时,都会调用ExtTextOutW函数,并且会传入这块内存地址,并且从ExtTextOutW里也可以得到聊天对象的QQ号等,现在我们QQ聊天内容
和聊天对象的QQ号都知道了。接着我们可以通过HOOK Shell_NotifyIconW来得到本机的QQ号和昵称,有了本机的QQ信息,这样信息基本上是完整了好了,废话不多说直接上代码 #include "stdafx.h"
#include <windows.h>
#include <shellapi.h>
#include <shlwapi.h>
#include <stdio.h>
#include <string>
#include <AtlBase.h>
#include <assert.h>
using namespace std; //---------------inline hook Shell_NotifyIconW--------------------------
BOOL WINAPI MyShell_NotifyIconW( DWORD dwMessage,
PNOTIFYICONDATAW lpdata
);
typedef BOOL (WINAPI *PFNMyShell_NotifyIconW)(DWORD,PNOTIFYICONDATAW);
char szOldShell_NotifyIconW[5] = {0};
char szJmpMyShell_NotifyIconW[5] = {(char)0xe9};
PFNMyShell_NotifyIconW pShell_NotifyIconW = NULL;
//----------------------------------------------------------------------- //------------------------inline hook SetForegroundWindow-------------------------
BOOL WINAPI MySetForegroundWindow(
HWND hWnd
);
typedef BOOL (WINAPI *PFNSetForegroundWindow)(HWND);
char szOldSetForegroundWindow[5] = {0};
char szJmpMySetForegroundWindow[5] = {(char)0xe9};
PFNSetForegroundWindow pSetForegroundWindow = NULL;
//--------------------------------------------------------------------------
//------------------------inline hook ShowWindow-------------------------
BOOL WINAPI MyShowWindow(
HWND hWnd,
int nCmdShow
);
typedef BOOL (WINAPI *PFNShowWindow)(HWND,int);
char szOldShowWindow[5] = {0};
char szJmpMyShowWindow[5] = {(char)0xe9};
PFNShowWindow pShowWindow = NULL;
//-------------------------------------------------------------------------- //------------------------inline hook ExtTextOutW---------------------------------
BOOL WINAPI MyExtTextOutW( HDC hdc, // handle to DC
int X, // x-coordinate of reference point
int Y, // y-coordinate of reference point
UINT fuOptions, // text-output options
CONST RECT* lprc, // optional dimensions
LPCWSTR lpString, // string
UINT cbCount, // number of characters in string
CONST INT* lpDx // array of spacing values
);
typedef BOOL (WINAPI *PFNExtTextOutW)( HDC hdc, // handle to DC
int X, // x-coordinate of reference point
int Y, // y-coordinate of reference point
UINT fuOptions, // text-output options
CONST RECT* lprc, // optional dimensions
LPCWSTR lpString, // string
UINT cbCount, // number of characters in string
CONST INT* lpDx // array of spacing values
);
char szOldExtTextOutW[5] = {0};
char szJmpMyExtTextOutW[5] = {(char)0xe9};
PFNExtTextOutW pExtTextOutW= NULL;
//---------------------------------------------------------------------------------- wstring g_wstrlocaluserinfo;//本地用户信息
bool g_bETOLastTime = false; DWORD dwlaststringaddr=0;
DWORD dwLaststringLen = 0;
DWORD dwRectLeft = -1;
DWORD dwRectRight = -1; HWND GetForeGroundWindowTitle(wstring &wstrtitle); BOOL APIENTRY DllMain( HANDLE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
{
/*
inline hook ExtTextOutW 得到聊天内容,和聊天对象QQ号
*/
DWORD dwJmpAddr = 0;
HMODULE hModule = LoadLibrary("gdi32.Dll");
pExtTextOutW = (PFNExtTextOutW)GetProcAddress(hModule, "ExtTextOutW");
if(pExtTextOutW)
{
dwJmpAddr = (DWORD)MyExtTextOutW - (DWORD)pExtTextOutW - 5;
memcpy(szJmpMyExtTextOutW + 1, &dwJmpAddr, 4);
FreeLibrary(hModule);
ReadProcessMemory((void*)-1, pExtTextOutW, szOldExtTextOutW, 5, NULL);//读出原来的前5个字节
WriteProcessMemory((void*)-1, pExtTextOutW, szJmpMyExtTextOutW, 5, NULL);//写入我们处理后的5个字节
}
/*
inline hook Shell_NotifyIconW 得到本机QQ信息
*/
dwJmpAddr = 0;
hModule = LoadLibrary("Shell32.Dll");
pShell_NotifyIconW = (PFNMyShell_NotifyIconW)GetProcAddress(hModule, "Shell_NotifyIconW");
if(pShell_NotifyIconW)
{
dwJmpAddr = (DWORD)MyShell_NotifyIconW - (DWORD)pShell_NotifyIconW - 5;
memcpy(szJmpMyShell_NotifyIconW + 1, &dwJmpAddr, 4);
FreeLibrary(hModule);
ReadProcessMemory((void*)-1, pShell_NotifyIconW, szOldShell_NotifyIconW, 5, NULL);//读出原来的前5个字节
WriteProcessMemory((void*)-1, pShell_NotifyIconW, szJmpMyShell_NotifyIconW, 5, NULL);//写入我们处理后的5个字节
}
/*
inline hook SetForegroundWindow
*/
dwJmpAddr = 0;
hModule = LoadLibrary("User32.Dll");
pSetForegroundWindow = (PFNSetForegroundWindow)GetProcAddress(hModule, "SetForegroundWindow");
if(pSetForegroundWindow)
{
dwJmpAddr = (DWORD)MySetForegroundWindow - (DWORD)pSetForegroundWindow - 5;
memcpy(szJmpMySetForegroundWindow + 1, &dwJmpAddr, 4);
FreeLibrary(hModule);
ReadProcessMemory((void*)-1, pSetForegroundWindow, szOldSetForegroundWindow, 5, NULL);//读出原来的前5个字节
WriteProcessMemory((void*)-1, pSetForegroundWindow, szJmpMySetForegroundWindow, 5, NULL);//
}
/*
inline hook ShowWindow
*/
dwJmpAddr = 0;
hModule = LoadLibrary("User32.Dll");
pShowWindow = (PFNShowWindow)GetProcAddress(hModule, "ShowWindow");
if(pShowWindow)
{
dwJmpAddr = (DWORD)MyShowWindow - (DWORD)pShowWindow - 5;
memcpy(szJmpMyShowWindow + 1, &dwJmpAddr, 4);
FreeLibrary(hModule);
ReadProcessMemory((void*)-1, pShowWindow, szOldShowWindow, 5, NULL);//读出原来的前5个字节
WriteProcessMemory((void*)-1, pShowWindow, szJmpMyShowWindow, 5, NULL);//
}
}
case DLL_THREAD_ATTACH:
break;
case DLL_THREAD_DETACH:
break;
case DLL_PROCESS_DETACH:
break;
}
return TRUE;
}
BOOL WINAPI MyShell_NotifyIconW( DWORD dwMessage,
PNOTIFYICONDATAW lpdata
)
{
//取QQ本地用户的QQ号
DWORD dwWritten = 0;
DWORD dwUnicode = 0xFEFF;
HANDLE hFile=NULL;
if(lstrlenW(lpdata->szTip)>10)
{
g_wstrlocaluserinfo = wstring(lpdata->szTip); OutputDebugStringW(L"本机QQ如下:\r\n");
OutputDebugStringW(g_wstrlocaluserinfo.c_str());
OutputDebugStringW(L"\r\n");
}
WriteProcessMemory((void*)-1, pShell_NotifyIconW, szOldShell_NotifyIconW, 5, NULL);
BOOL bRet = Shell_NotifyIconW(dwMessage,lpdata);
WriteProcessMemory((void*)-1, pShell_NotifyIconW, szJmpMyShell_NotifyIconW, 5, NULL);
return bRet;
} DWORD g_dwLastCount=0;
DWORD g_ELTime = 2000;//时间间隔默认为2秒
wstring g_strforegwintitle;
HWND g_hLastWnd = NULL;
bool g_bsetforegwin = false;
HWND g_hWnd = NULL;
struct st_HWND_COUNT//打开QQ聊天窗口时,QQ调用SetForeGroundWindow与ShowWindow进行绑定
{
HWND hWnd;
bool bSetForeGWin;
st_HWND_COUNT()
{
hWnd=NULL;
bSetForeGWin=false; //未调用SetForeGroundWindow
}
};
st_HWND_COUNT g_st_hwnd_count; BOOL WINAPI MyShowWindow(
HWND hWnd,
int nCmdShow
)
{
BOOL bRet=FALSE;
//
//为了,如果有多个QQ聊天窗口同时弹出,就慢慢的显示,这样QQ聊天对象和QQ号不会混淆
//
bool bQQChatWin = false;
//判断是否是QQ聊天窗口
char szClassName[255]={0};
GetClassName(hWnd,szClassName,255);
if(stricmp(szClassName,"TXGuiFoundation")==0)
{
long lstyle = GetWindowLong(hWnd,GWL_STYLE);
if(lstyle==0x960f0000)
{
char szTitle[255]={0};
GetWindowText(hWnd,szTitle,255);
if((stricmp(szTitle,"消息盒子")!=0)&&(stricmp(szTitle,"消息管理器")!=0))
{
char*lpstr = strstr(szTitle,"QQ20");
if(lpstr==NULL)
{
bQQChatWin = true;
}
}
}
}
if(bQQChatWin)
{
if(g_st_hwnd_count.hWnd!=NULL)
{
if(g_st_hwnd_count.hWnd==hWnd&&g_st_hwnd_count.bSetForeGWin)
{
DWORD dwTime = GetTickCount()-g_dwLastCount;
if(dwTime<=g_ELTime)
{
WriteProcessMemory((void*)-1, pShowWindow, szOldShowWindow, 5, NULL);
bRet = ShowWindow(hWnd,SW_SHOWMINIMIZED);
WriteProcessMemory((void*)-1, pShowWindow, szJmpMyShowWindow, 5, NULL);
FLASHWINFO falshinfo;
falshinfo.dwFlags = FLASHW_ALL;
falshinfo.hwnd = hWnd;
falshinfo.uCount = 3;
falshinfo.dwTimeout = 1000;
falshinfo.cbSize = sizeof(falshinfo);
FlashWindowEx(&falshinfo);
}
else
{
WriteProcessMemory((void*)-1, pShowWindow, szOldShowWindow, 5, NULL);
bRet = ShowWindow(hWnd,nCmdShow);
WriteProcessMemory((void*)-1, pShowWindow, szJmpMyShowWindow, 5, NULL);
}
g_st_hwnd_count.hWnd=NULL;
g_st_hwnd_count.bSetForeGWin=false;
g_dwLastCount=::GetTickCount();
return bRet;
}
}
}
WriteProcessMemory((void*)-1, pShowWindow, szOldShowWindow, 5, NULL);
bRet = ShowWindow(hWnd,nCmdShow);
WriteProcessMemory((void*)-1, pShowWindow, szJmpMyShowWindow, 5, NULL);
return bRet;
}
BOOL WINAPI MySetForegroundWindow( HWND hWnd)
{
BOOL bRet = FALSE;
bool bQQChatWin = false;
//判断是否是QQ聊天窗口
char szClassName[255]={0};
GetClassName(hWnd,szClassName,255);
if(stricmp(szClassName,"TXGuiFoundation")==0)
{
long lstyle = GetWindowLong(hWnd,GWL_STYLE);
if(lstyle==0x960f0000)
{
char szTitle[255]={0};
GetWindowText(hWnd,szTitle,255);
if((stricmp(szTitle,"消息盒子")!=0)&&(stricmp(szTitle,"消息管理器")!=0))
{
char*lpstr = strstr(szTitle,"QQ20");
if(lpstr==NULL)
bQQChatWin = true;
}
}
}
if(bQQChatWin)
{
if(g_hLastWnd!=hWnd)//去掉重复
{
g_st_hwnd_count.hWnd = hWnd;
g_st_hwnd_count.bSetForeGWin = true;
}
}
g_hLastWnd = hWnd;
WriteProcessMemory((void*)-1, pSetForegroundWindow, szOldSetForegroundWindow, 5, NULL);
bRet = bRet = SetForegroundWindow(hWnd);
WriteProcessMemory((void*)-1, pSetForegroundWindow, szJmpMySetForegroundWindow, 5, NULL);
return bRet;
} BOOL WINAPI MyExtTextOutW( HDC hdc, // handle to DC
int X, // x-coordinate of reference point
int Y, // y-coordinate of reference point
UINT fuOptions, // text-output options
CONST RECT* lprc, // optional dimensions
LPCWSTR lpString, // string
UINT cbCount, // number of characters in string
CONST INT* lpDx // array of spacing values
)
{
BOOL bRet=FALSE;
//
//取QQ聊天消息内容
//
try
{
if(dwRectLeft!=-1&&dwRectRight!=-1)
{
if(lprc)
if((dwRectLeft!=lprc->left)||(dwRectRight!=lprc->right))
{
//Rect发生变化,这时可以输出数据
if(dwlaststringaddr!=0)
{
DWORD dwBaseAddress = (DWORD)dwlaststringaddr;
DWORD dwBaseAddressStringLenbytes = dwLaststringLen*2;
dwBaseAddress-=6;
dwBaseAddressStringLenbytes+=6;
DWORD dwLastCount = ::GetTickCount();
while(1)
{
if(GetTickCount()-dwLastCount>=1000)//超时就退出
break;
WCHAR*pwtr = (WCHAR*)(dwBaseAddress);
assert(pwtr!=NULL);
WCHAR*pp=NULL;
WCHAR* pstr=NULL;
//向上查找地址内容,找到"易拨打"就结束,超时为1秒
try
{
// int len = lstrlenW(pwtr);
int len = dwBaseAddressStringLenbytes/2;
if(len>0)
{
pstr = new WCHAR[len+1];
StrCpyNW(pstr,pwtr,len+1);
// pp = StrStrW(pstr,L"易拨打");
pp = StrStrW(pstr,L"交谈中");
}
}catch(...)
{
WriteProcessMemory((void*)-1, pExtTextOutW, szOldExtTextOutW, 5, NULL);
bRet = ExtTextOutW(hdc,X,Y,fuOptions,lprc,lpString,cbCount,lpDx);
WriteProcessMemory((void*)-1, pExtTextOutW, szJmpMyExtTextOutW, 5, NULL);
return bRet;
}
if(pp!=NULL)//找到了,就退出
{
wstring wstrTitle;
GetForeGroundWindowTitle(wstrTitle);
USES_CONVERSION;
OutputDebugStringW(L"聊天内容如下:\r\n");
OutputDebugStringW(pstr);
OutputDebugStringW(L"\r\n"); OutputDebugStringW(L"聊天对象如下:\r\n");
OutputDebugStringW(wstrTitle.c_str());
OutputDebugStringW(L"\r\n");
break;
}//if(pp!=NULL)
dwBaseAddress-=6;
dwBaseAddressStringLenbytes+=6;
if(pstr)
delete []pstr;
pstr=NULL;
}//while(1)
dwlaststringaddr=0;
dwRectLeft = -1;
dwRectRight=-1;
dwLaststringLen = 0;
}
dwRectLeft=-1;
dwRectRight=-1;
}
}
//
//取QQ号
//
if(cbCount>0)
{
WCHAR*pWmsg = NULL;
try
{
pWmsg = new WCHAR[cbCount+2];
lstrcpynW(pWmsg,lpString ,cbCount+1);
}
catch(...)
{
WriteProcessMemory((void*)-1, pExtTextOutW, szOldExtTextOutW, 5, NULL);
BOOL bRet = ExtTextOutW(hdc,X,Y,fuOptions,lprc,lpString,cbCount,lpDx);
WriteProcessMemory((void*)-1, pExtTextOutW, szJmpMyExtTextOutW, 5, NULL);
return bRet;
}
assert(pWmsg!=NULL);
wstring wstrMSG(pWmsg);
//消息记录格式1 用户名 19:20:20
//消息记录格式2 用户名(QQ号) 19:20:20
//消息记录格式3 用户名(QQ号) 2009-04-09 19:20:20
int pos1 = wstrMSG.find(L":");
int pos2 = wstrMSG.rfind(L":");
int len = pos2-pos1;
if((pos1!=-1)&&(pos2!=-1)&&(len==3))
{
g_bETOLastTime = true;
dwRectLeft = lprc->left;
dwRectRight = lprc->right;
}
else
{
if(g_bETOLastTime)
{
g_bETOLastTime=false;
}
else
{
//
//检测是不是QQ号或者群号
//QQ号有两种形式(761677111)和<xfege9@163.com>
//
//(761677111) <xfege9@163.com>形式
wstring wstr(pWmsg);
pos1 = wstr.find_first_of(L"(");
if(pos1==-1)
pos1 = wstr.find_first_of(L"<");
pos2 = wstr.find_last_of(L")");
if(pos2==-1)
pos2 = wstr.find_last_of(L">");
if(pos1!=-1&&pos2!=-1)
{
wstring wstrtemp = wstr;
wstrtemp=wstrtemp.substr(pos1+1,pos2-pos1-1);
if(wstrtemp.size()>=6&&wstrtemp.size()<=30)
{
//QQ号是由0-9数字组成的
bool bqqhao = true;
for(int i = 0; i<wstrtemp.size();i++)
{
if(wstrtemp.at(i)<'0'&&wstrtemp.at(i)>'9')
{
bqqhao=false;
break;
}
}
if(!bqqhao)
{
for(int i = 0; i<wstrtemp.size();i++)
{
if(wstrtemp.at(i)=='@')
{
bqqhao=true;
break;
}
}
}
if(bqqhao)
{
OutputDebugStringW(L"聊天对象QQ号如下:\r\n");
OutputDebugStringW(wstrtemp.c_str());
OutputDebugStringW(L"\r\n");
}
}
}
}
}
dwlaststringaddr = (DWORD)lpString;
dwLaststringLen = cbCount+1;
if(pWmsg)
delete []pWmsg;
pWmsg=NULL;
}
}catch(...)
{
}
WriteProcessMemory((void*)-1, pExtTextOutW, szOldExtTextOutW, 5, NULL);
bRet = ExtTextOutW(hdc,X,Y,fuOptions,lprc,lpString,cbCount,lpDx);
WriteProcessMemory((void*)-1, pExtTextOutW, szJmpMyExtTextOutW, 5, NULL);
return bRet;
} HWND GetForeGroundWindowTitle(wstring &wstrtitle)
{
HWND hTargetHwnd = ::GetForegroundWindow();
if(hTargetHwnd)
{
//判断是否是QQ聊天窗口
char szClassName[255]={0};
GetClassName(hTargetHwnd,szClassName,255);
if(stricmp(szClassName,"TXGuiFoundation")==0)
{
long lstyle = GetWindowLong(hTargetHwnd,GWL_STYLE);
if((lstyle==0x960f0000)||(lstyle==0x970f0000))
{
char szTitle[255]={0};
GetWindowText(hTargetHwnd,szTitle,255);
if((stricmp(szTitle,"消息盒子")!=0)&&(stricmp(szTitle,"消息管理器")!=0))
{
char*lpstr = strstr(szTitle,"QQ20");
if(lpstr==NULL)
{
//去掉窗口名称里的" - 正在输入"字符串
USES_CONVERSION;
//wstrtitle=A2W(szTitle);
wstrtitle=A2W(szTitle);
int pos = wstrtitle.find(L" - 正在输入");
if(pos!=-1)
wstrtitle=wstrtitle.substr(0,pos);
return hTargetHwnd;
}
}
}
}
}
return NULL;
}
[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课
上传的附件: