利用鼠标钩子获得Win2000密码框密码

下载本节例子程序和源代码 (5.93 KB)

获得Windows下的密码框密码,似乎是很多人感兴趣的话题,CSDN上问这类问题的人不计其数……这样看来,老罗也不能免俗啦,今天就让我跟大家探讨一下如何实现这一功能吧。^_^

我们知道,Windows下有一条功能很强劲的函数——SendMessage(),利用它能够实现很多意想不到的功能,例如获得密码框的密码就是其中一例。我们可以这样做:

char szPsw[255];
SendMessage(hWnd, WM_GETTEXT, 255, (LPARAM)(LPCTSTR)szPsw);

通过发送消息 WM_GETTEXT 给目标窗口句柄,我们就能够获得密码框的密码了,可是它还有一点不足,就是无法在 Win2000/WinXP 里面获得密码。这是因为 Win2000 对这个方法作了防范(当然啦,老比因为这个问题已经业界被骂死了),只要你是对其他进程进行这个操作,就会失效。呵呵,这也就是为什么很多同类的软件到了 Win2000 就死翘翘的原因。 :)

那么是否就毫无办法了呢?当然不是!我们已经知道了失败的原因,就是不能在别的进程中使用这一函数……嗯?……聪明的你是不是已经想到了什么?

对了,只要我们能够在同一个进程中使用它,就可以实现了!如何做到“同一个进程”?呵呵,这又是一个问题。《Windows核心编程》的大牛 Jeffrey Richter 告诉我们,实现“同一进程”的办法有很多种,例如有通过注册表来插入DLL、使用远程线程插入DLL、使用特洛伊DLL来插入DLL、通过内存映射文件插入DLL……方法真的是有很多种,它们都能实现“同一个进程”这一目的,不过老罗觉得都不太理想,例如,使用远程线程是通过 CreateRemoteThread() 来插入DLL,但是这个 CreateRemoteThread() 在MSDN中是明确指出了不能在 Win9X 中使用的,也就是说,通用性要大打折扣。所以最后我决定使用鼠标钩子函数来实现!

聪明的读者可能还会问道:为什么用鼠标钩子就能实现了?其实答案很简单,因为密码框是一个 EDIT 控件,它肯定能够接收到鼠标消息,这样,我们的鼠标钩子函数就能够注入到远程的目标进程,这时的 SendMessage() 就是跟目标进程在同一个进程里面,是可以取出密码的。而且它有个非常好的地方:就是通用性强,理论上任何一个版本的 Windows 都能使用!!(我没有 WinXP ,所以只好说“理论上”啦,请有装 XP 的朋友帮忙试试,OK?)

明白了吧?最后还有一个细节问题——密码是在鼠标钩子函数里面获得的,那么如何返回给我们的主程序?老罗的做法是把密码作为全局共享变量,这样就可以在两个进程里面共享,我们的主程序就可以输出结果啦!

说了一大通废话,希望大家不要介意。下面我给出一个完整的例子,通过鼠标钩子函数注入远程进程获得任何一个版本 Windows 的密码框密码。(呵呵,好拗口啊!啊!别扔番茄!!)


---------- 鼠标钩子函数的DLL ----------
文件名: HookDll.asm
--------------------------------------


;******************************************************
;程序名称:获取密码框的密码,适用于Win9x/WinMe/Win2000/WinXP
;作者:罗聪
;日期:2002-10-8
;出处:http://www.luocong.com(老罗的缤纷天地)
;注意事项:如欲转载,请保持本程序的完整,并注明:
;转载自“老罗的缤纷天地”(http://www.luocong.com)
;******************************************************

.386
.model flat, stdcall
option casemap:none

include \masm32\include\windows.inc
include \masm32\include\user32.inc
includelib \masm32\lib\user32.lib

DllEntry        proto :HINSTANCE, :DWORD, :DWORD
MouseProc       proto :DWORD, :DWORD, :DWORD
GetPsw          proto
InstallHook     proto :DWORD
UninstallHook   proto

.const
WM_MOUSEHOOK    equ    WM_USER + 6

;共享段:
.data?
hHook           dd    ?
hWnd            dd    ?
szPsw           db    255 dup(?)        ;关键语句!!!共享这个变量szPsw,以便在主程序中也能得到密码!

.data
hInstance        HINSTANCE    0

.code
DllEntry    proc    hInst:HINSTANCE, reason:DWORD, reserved1:DWORD
    .if reason == DLL_PROCESS_ATTACH
        push hInst
        pop hInstance
    .endif
    mov eax, TRUE
    ret
DllEntry    endp

GetPsw        proc
    ;关键!!返回密码!(前提是密码必须放在共享段!)
    lea eax, szPsw
    ret
GetPsw        endp

MouseProc    proc    uses edx    nCode:DWORD, wParam:DWORD, lParam:DWORD
    invoke CallNextHookEx, hHook, nCode, wParam, lParam
    mov edx, lParam
    assume edx: PTR MOUSEHOOKSTRUCT
        ;获得当前鼠标位置的窗口句柄:
        invoke WindowFromPoint, [edx].pt.x, [edx].pt.y
        ;发送一个消息给当前窗口,获得它的标题:
        invoke SendMessage, eax, WM_GETTEXT, 255, addr szPsw
        ;发送一个消息给主程序,以便在主程序中能处理鼠标钩子函数:
        invoke PostMessage, hWnd, WM_MOUSEHOOK, 0, 0
    assume edx: nothing
    xor eax, eax
    ret
MouseProc    endp

InstallHook    proc    hwnd:DWORD
    ;启动鼠标钩子函数:
    push hwnd
    pop hWnd
    invoke SetWindowsHookEx, WH_MOUSE, addr MouseProc, hInstance, NULL
    mov hHook, eax
    ret
InstallHook    endp

UninstallHook    proc
    ;卸载鼠标钩子函数:
    invoke UnhookWindowsHookEx, hHook
    ret
UninstallHook    endp

end DllEntry
;********************    over    ********************
;by LC


编译这个DLL的时候记住要这样:(否则会失败哦!)
ml /c /coff HookDll.asm
link /section:.bss,S /DLL /subsystem:windows /def:HookDll.def HookDll.obj


---------- 主程序调用 ----------
文件名: GetPsw.asm
-------------------------------


;******************************************************
;程序名称:获取密码框的密码,适用于Win9x/WinMe/Win2000/WinXP
;作者:罗聪
;日期:2002-10-8
;出处:http://www.luocong.com(老罗的缤纷天地)
;注意事项:如欲转载,请保持本程序的完整,并注明:
;转载自“老罗的缤纷天地”(http://www.luocong.com)
;******************************************************

.386
.model flat, stdcall
option casemap:none

include \masm32\include\windows.inc
include \masm32\include\kernel32.inc
include \masm32\include\user32.inc
include HookDll.inc
includelib \masm32\lib\kernel32.lib
includelib \masm32\lib\user32.lib
includelib HookDll.lib

WndProc            proto :DWORD, :DWORD, :DWORD, :DWORD

.const
IDC_EDIT_OUTPUT      equ    3000
WM_MOUSEHOOK         equ    WM_USER + 6

.data
szDlgName            db    "lc_dialog", 0
szPsw                db    255 dup(0)

.code
main:
    invoke GetModuleHandle, NULL
    invoke DialogBoxParam, eax, offset szDlgName, 0, WndProc, 0
    invoke ExitProcess, eax

WndProc proc hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM
    LOCAL rect: RECT

    .if uMsg == WM_CLOSE
        ;卸载鼠标钩子:
        invoke UninstallHook
        invoke EndDialog, hWnd, 0

    .elseif uMsg == WM_INITDIALOG
        ;获得主程序的rect:
        invoke GetWindowRect, hWnd, addr rect
        ;把主程序设置成“始终在最前面”:
        invoke SetWindowPos, hWnd, HWND_TOPMOST, rect.left, rect.top, rect.right, rect.bottom, SWP_SHOWWINDOW
        ;鼠标钩子函数启动:
        invoke InstallHook, hWnd

    ;处理鼠标钩子函数的消息:
    .elseif uMsg == WM_MOUSEHOOK
        ;获得密码:
        invoke GetPsw
        ;输出:
        invoke SetDlgItemText, hWnd, IDC_EDIT_OUTPUT, eax
        
    .else
        mov eax, FALSE
        ret
    .endif
    mov eax, TRUE
    ret
WndProc endp

end main
;********************    over    ********************
;by LC


---------- 主程序的资源文件 ----------
文件名: GetPsw.rc
-------------------------------------


#include "resource.h"

#define IDC_EDIT_OUTPUT        3000
#define IDC_STATIC             -1

LC_DIALOG DIALOGEX 0, 0, 195, 30
STYLE DS_SETFONT | WS_MINIMIZEBOX | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
CAPTION "Get Password by LC, 2002-10-8"
FONT 9, "宋体", 0, 0, 0x0
BEGIN
    LTEXT           "看看有什么:", IDC_STATIC, 5, 12, 50, 12
    EDITTEXT        IDC_EDIT_OUTPUT, 60, 10, 130, 12, ES_AUTOHSCROLL | NOT WS_BORDER, WS_EX_STATICEDGE
END


怎么样?看明白了吗?如果你还不太懂得鼠标钩子函数的编写,请先参考 Iczelion 的教程,到处都有哦!
假如还有什么疑问,那是我的水平问题,没跟大家解释得足够清楚,到时还请来信与我探讨!lcother@163.net

老罗
2002-10-8