QQ密码输入框(防键盘钩子)原理分析

1.网上看到的一些防星号查看器的代码大多是在后台维护一个字符串(真实的密码),界面则不显示真实的密码,这样做,维护那个字符串很费事,就因为我之前那样做过,我才在看到WM_GETTEXT后想要重做一个
2.防键盘钩子,在做上面的功能是,突然想到,如果自己模拟发一些乱七八糟的按键消息,然后自己区分哪些是垃圾哪些是用户真正的按键,那钩子就到不取密码了,所以又加了这个功能.后来自己做了一个钩子看了一下效果不错,试了试QQ的竟然也是这样,开始以为QQ用了什么高科技
3.自我感觉貌似实现了QQ密码框的功能,不知道会有什么问题,所以帖出来,谁有兴趣自己看吧
//
#pragma once

//safeedit.h
// CSafeEdit

class CSafeEdit : public CEdit
{
public:
    //设置取密码时用的KEY(大于5)
    BOOL SetPassWordKey(CString & astrKey);//取密码时用的KEY
    DECLARE_DYNAMIC(CSafeEdit)
    int GetWindowTextEx(CString & astrText);//astrText 传入KEY 传出密码
public:
    CSafeEdit();
    virtual ~CSafeEdit();

protected:
    DECLARE_MESSAGE_MAP()
    LRESULT OnGetText(WPARAM wParam, LPARAM lParam);

private:
    BOOL mbCanGetText;//GetWindowTextEx:astrText == mstrKey ? TRUE : FALSE
    CString mstrKey;
    char mcLastVKey;//Timer 模拟的键
public:
    afx_msg void OnChar(UINT nChar, UINT nRepCnt, UINT nFlags);
    afx_msg void OnTimer(UINT nIDEvent);
    afx_msg void OnSetFocus(CWnd* pOldWnd);
    afx_msg void OnKillFocus(CWnd* pNewWnd);
};
//

// SafeEdit.cpp : 实现文件
//

#include "stdafx.h"
#include "DlgTemp2.h"
#include "SafeEdit.h"
#include ".\safeedit.h"


// CSafeEdit

IMPLEMENT_DYNAMIC(CSafeEdit, CEdit)
CSafeEdit::CSafeEdit()
{
    mstrKey = "jiawei@hotmail.com";
    mbCanGetText = FALSE;
    mcLastVKey = 0;
}

CSafeEdit::~CSafeEdit()
{
}


BEGIN_MESSAGE_MAP(CSafeEdit, CEdit)
    ON_MESSAGE(WM_GETTEXT, OnGetText)
    ON_WM_CHAR()
    ON_WM_TIMER()
    ON_WM_SETFOCUS()
    ON_WM_KILLFOCUS()
END_MESSAGE_MAP()


// CSafeEdit 消息处理程序

LRESULT CSafeEdit::OnGetText(WPARAM wParam, LPARAM lParam)
{
    long lnStyle = GetWindowLong(GetSafeHwnd(),GWL_STYLE);
    if(lnStyle & ES_PASSWORD)
    {
        if(mbCanGetText)
            return DefWindowProc(WM_GETTEXT,wParam,lParam);
        else
            return -1;
    }

    return DefWindowProc(WM_GETTEXT,wParam,lParam);
}
//************************************
// Method:    SetPassWordKey
// FullName: CSafeEdit::SetPassWordKey
// Access:    public 
// Returns:   BOOL
// Qualifier: 设置取密码时用到的KEY,长度大于五
// Parameter: CString & astrKey
//************************************
BOOL CSafeEdit::SetPassWordKey(CString & astrKey)
{
    if(astrKey.GetLength() < 5)
        return FALSE;
    mstrKey = astrKey;
    return TRUE;
}

//************************************
// Method:    GetWindowTextEx
// FullName: CSafeEdit::GetWindowTextEx
// Access:    public 
// Returns:   int
// Qualifier:
// Parameter: CString & astrText 传入取密码用的KEY,如果成功返回密码
//************************************
int CSafeEdit::GetWindowTextEx(CString & astrText)
{
    if(astrText != mstrKey)
        return -1;

    astrText = "";
    DWORD ldwLen = ::SendMessage(GetSafeHwnd(),WM_GETTEXTLENGTH,0,0);
    if(ldwLen <= 0)
        return 0;
    char *lpszBuf = new char[ldwLen+1];
    if(lpszBuf == NULL)
        return 0;
    mbCanGetText = TRUE;
     ldwLen = ::SendMessage(GetSafeHwnd(),WM_GETTEXT,ldwLen+1,(LPARAM)lpszBuf);
    mbCanGetText = FALSE;
    astrText = lpszBuf;
    delete [] lpszBuf;
    return ldwLen;
}
void CSafeEdit::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags)
{
    if(mcLastVKey != nChar)
        CEdit::OnChar(nChar, nRepCnt, nFlags);
}

void CSafeEdit::OnTimer(UINT nIDEvent)
{
    //随机生成按键
    UINT lnVKey = '0' + (rand()%('Z'-'0'+1));
    UINT lnScan = MapVirtualKeyEx(lnVKey,0,NULL);
    mcLastVKey = MapVirtualKeyEx(lnVKey,2,NULL);
    if(mcLastVKey >= 'A' && mcLastVKey <= 'Z')
    {
        BOOL lbLowercase = TRUE;
        if(GetKeyState(VK_CAPITAL) & 0x01 != 0)//CapsLock ON
            lbLowercase = !lbLowercase;
        if((GetKeyState(VK_LSHIFT) & 0x80) != 0 || (GetKeyState(VK_RSHIFT) & 0x80) != 0)//Shift DOWN
            lbLowercase = !lbLowercase;
        if(lbLowercase)
            mcLastVKey += 'a' - 'A';
    }
    keybd_event(lnVKey,lnScan,KEYEVENTF_EXTENDEDKEY,0);
    CEdit::OnTimer(nIDEvent);
    keybd_event(lnVKey,lnScan,KEYEVENTF_KEYUP,0);
}

void CSafeEdit::OnSetFocus(CWnd* pOldWnd)
{
    CEdit::OnSetFocus(pOldWnd);
    long lnStyle = GetWindowLong(GetSafeHwnd(),GWL_STYLE);
    if(lnStyle & ES_PASSWORD)
        SetTimer(1,500,NULL);
}

void CSafeEdit::OnKillFocus(CWnd* pNewWnd)
{
    CEdit::OnKillFocus(pNewWnd);
    long lnStyle = GetWindowLong(GetSafeHwnd(),GWL_STYLE);
    if(lnStyle & ES_PASSWORD)
        KillTimer(1);
}

相关评论:qq好象不是这样做的 因为我在截取QQ密码的时候发现QQ密码输入框输入的内容什么都截取不到 而不是截取到一大片乱七八遭的数据

这几天好好地研究了一下QQ2010登陆窗口的密码输入框,细节没有完全弄清楚, 不过还是看出了大致的原理了。在这里发表一下我的看法,和有兴趣的朋友一起讨论。菜鸟水平,认识问题的程度很有限,大牛们就飘过吧。
我首先想到的,是要搞清楚,他的保护原始是基于R0还是R3?
这个问题的答案是:R3。理由很简单,因为找不到QQ有驱动啊,所以自然就是在R3进行的保护了。这个没什么好说的,不讲了。
接着是,QQ究竟如何在应用层实现密码输入保护的呢?
这个问题一开始我想来想去都不明白。我的运气很好,后来无意中看到了QQ2010安装了两个很特别的windows消息钩子:WH_DEBUG和WH_KEYBOARD_LL,于是线索出来了。QQ密码输入框(防键盘钩子)原理分析 - darkbus@126 - darkbus@126的博客
看到这两个钩子,好特别啊,它们是做什么用的呢?为什么要安装这两个钩子呢?
我马上翻了一下MSDN,找到答案了。QQ密码输入框(防键盘钩子)原理分析 - darkbus@126 - darkbus@126的博客
原来,WH_DEBUG可以用来管理很多种类型的钩子,有这么多种:
WH_CALLWNDPROC 
WH_CALLWNDPROCRET 
WH_CBT 
WH_DEBUG 
WH_JOURNALPLAYBACK 
WH_JOURNALRECORD 
WH_KEYBOARD 
WH_MOUSE 
WH_MSGFILTER 
WH_SHELL 
WH_SYSMSGFILTER 
WH_DEBUG能管理这些类型的钩子,在这些钩子的钩子过程将要被系统调用的时候,系统总是先执行调试钩子的钩子过程。而MS的这个调试钩子,允许我们决定是否执行这些被管理的钩子。
我扫了一眼以上列表,在其中发现了WH_KEYBOARD钩子。原来普通键盘钩子是被调式钩子所管理的,也就是说,如果一个程序装上了调式钩子,那么在它上面的普通键盘钩子的钩子过程在执行之前,先要执行调式钩子,而在这个调式钩子里就可以拒绝执行即将执行的普通键盘钩子。
想到这里我恍然大悟了,难怪QQ装有一个调式钩子呢,难怪有全局键盘钩子记录不到QQ的密码呢!QQ密码输入框(防键盘钩子)原理分析 - darkbus@126 - darkbus@126的博客QQ密码输入框(防键盘钩子)原理分析 - darkbus@126 - darkbus@126的博客
还有一个低级键盘钩子,这个比较难一点,QQ保护原理核心都在这里面。
想贴一下这个钩子的钩子过程的反汇编代码,想想还是算了,太太长了。还是说一下我理解出来的意思吧,不全面,没有完全弄懂。
首先要知道的是,低级键盘钩子和普通简单钩子执行的先后顺序。
如果一个程序,同时被装有这两种钩子的话。在按键消息到来的时候,这两个钩子的执行顺序是:
低级键盘钩子 -》普通键盘钩子
为什么是这样的呢?我是看MSDN悟出来的,有疑问的话你也看看吧。
既然低级键盘钩子在普通键盘钩子的前面执行,自然它也有防御普通键盘钩子的能力了。
看到前面两个钩子,都是能够防御普通键盘钩子的。我自然想到,如果盗号者采用的是低级键盘钩子呢?是不是就能取得QQ的密码了呢?
带着好奇,我自己做了一个低级键盘钩子的测试程序。结果发现:
当我用鼠标点击密码输入框,把输入焦点定在这里时(并没有按键盘),测试程序就不停地输出按键信息。奇怪,我还没有开始输入密码啊,一个键都还没按呢!QQ密码输入框(防键盘钩子)原理分析 - darkbus@126 - darkbus@126的博客
后来冷静下来想了一想,这一定是TX为了防止盗号木马使用低级键盘钩子取走QQ的密码,而故意设置的虚假的按键信息,这样即使你用低级钩子记录到了某个正确的按键,其中必然混杂了很多虚假的按键信息,形成了干扰。
最后还有一点很重要的东西,可能大家很容易忘记,我在这里提醒一下大家。
细细地回想一下以前学习windows钩子学到的东西,记忆里会想起这么一个规律:
如果一个程序上被装上了多了同一类型的钩子,那么这些钩子的执行顺序是,先安装的后执行,
后安装的先执行。
也就是说,如果给某个程序同时装上两个低级键盘钩子A和B,安装的顺序是:A -》B,那么这个钩子的钩子过程执行的顺序就是:B -》A。
所以说,如果我们给QQ安装上一个低级键盘钩子,因为我门是在后面安装的,所以我们的钩子应该先执行,然后才执行QQ自己安装的低级键盘钩子。这不是成了QQ键盘保护的弱点了吗?我一边想着,一边在怀疑。
这个问题QQ是处理的呢?我在实践中探索到了答案,原来QQ会通过一个定时器,不停地对它的调式钩子和低级键盘钩子进行Unhook,然后马上再Hook。这样,不是就保证了QQ的钩子安装在盗号木马的钩子之后,从而先于木马的钩子执行了吗?哈哈 QQ密码输入框(防键盘钩子)原理分析 - darkbus@126 - darkbus@126的博客
最后用一句话概括QQ自己的低级键盘钩子吧,尽管细节我也没有完全看明白,但还是能猜出来了。
QQ通过给自己在应用层设置这个低级键盘钩子,并不断脱钩、挂钩,来保证自己在应用层上是最先得到键盘消息的。既然是最先得到了,那么接下来要进行保护就容易了,自然就是先取得正确的按键信息,然后阻止这个消息继续传递下来给别人,就算传下去交给别人,也要修改按键信息,传一个错误的下去。:)
仔细回想一下整个过程,发现也不是很高深嘛,以前把QQ的键盘保护看得太神秘了 QQ密码输入框(防键盘钩子)原理分析 - darkbus@126 - darkbus@126的博客
我知道的就这么多了,希望有深入理解的朋友继续报料啊

相关评论:


我想了一个在应用层实现的办法:
先把QQ进程里的SetWindowsHookEx和UnhookWindowsHookEx废了,然后再安装低级键盘钩子来记录
实验了一翻这个办法是成功的,可是不知道为什么后来QQ的进程崩溃了。

不错。QQ的密码框还会产生干扰,按了的键会变成另一个键信息,会生成一些随机的按键信息


QQ用了一个定时器,不停得卸载自己的钩子,又马上重新安装,如此来保证自己的钩子总是在最前面执行的,所以只要把SetWindowsHookEx和UnhookWindowsHookEx废了,那它就没办法了


自己装个键盘过滤驱动不就得了?反正是从下面传上来的。或者挂csrss.exe的win32k!RawInputThread
  • 3
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值