在Windows GUI程序开发和安全研究中,密码框控件的处理一直是个有趣的技术点。标准的密码框会以星号(*)或圆点(•)隐藏用户输入,这是基础的安全设计。但当我们进行自动化测试、密码恢复或安全审计时,可能需要获取这些被隐藏的字符内容。
用高级语言实现这个功能相对容易,但用汇编语言直接操作GUI控件则能让我们更深入理解Windows消息机制和内存管理。这个项目将展示如何用纯汇编代码获取密码框中的明文密码,涉及Windows API调用、消息派发和内存操作等核心概念。
Windows GUI程序的核心是消息循环。当用户在密码框中输入时,系统会发送WM_GETTEXT等消息到控件。常规情况下,密码框处理WM_GETTEXT消息时会返回掩码字符,但实际文本仍存储在内存中。
关键API函数:
标准Edit控件在设置ES_PASSWORD样式后会有以下行为变化:
通过发送EM_GETPASSWORDCHAR消息可以获取当前使用的掩码字符(默认0x25CF)。
推荐使用MASM32开发包,包含:
基础代码框架:
asm复制.386
.model flat, stdcall
option casemap:none
include \masm32\include\windows.inc
include \masm32\include\user32.inc
includelib \masm32\lib\user32.lib
.data
targetWindow db "目标窗口标题",0
targetClass db "Edit",0
.code
start:
; 主逻辑代码
invoke ExitProcess, 0
end start
分步查找目标窗口:
asm复制find_target:
; 查找顶级窗口
invoke FindWindow, NULL, addr targetWindow
cmp eax, NULL
je not_found
; 查找Edit控件
invoke FindWindowEx, eax, NULL, addr targetClass, NULL
cmp eax, NULL
je not_found
mov hTarget, eax ; 保存目标句柄
jmp found_target
三种实现方案对比:
asm复制invoke SendMessage, hTarget, WM_GETTEXT, sizeof buffer, addr buffer
asm复制invoke GetWindowTextLength, hTarget
inc eax ; 为null终止符加1
invoke VirtualAlloc, NULL, eax, MEM_COMMIT, PAGE_READWRITE
mov pMemory, eax
; 获取文本缓冲区地址
invoke SendMessage, hTarget, EM_GETHANDLE, 0, 0
mov hText, eax
; 复制内存内容
invoke RtlMoveMemory, pMemory, hText, eax
asm复制; 安装子类化过程
invoke SetWindowLong, hTarget, GWL_WNDPROC, addr NewEditProc
; 在新窗口过程中
NewEditProc proc hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM
cmp uMsg, WM_GETTEXT
jne @default
; 绕过密码掩码处理
invoke CallWindowProc, lpOldEditProc, hWnd, uMsg, wParam, lParam
ret
@default:
invoke CallWindowProc, lpOldEditProc, hWnd, uMsg, wParam, lParam
ret
NewEditProc endp
asm复制.386
.model flat, stdcall
option casemap:none
include \masm32\include\windows.inc
include \masm32\include\user32.inc
include \masm32\include\kernel32.inc
includelib \masm32\lib\user32.lib
includelib \masm32\lib\kernel32.lib
.data
targetWindow db "密码输入窗口",0
targetClass db "Edit",0
successMsg db "获取的密码: %s",0
failMsg db "找不到目标窗口",0
buffer db 256 dup(0)
.data?
hTarget dd ?
pMemory dd ?
.code
start:
invoke FindWindow, NULL, addr targetWindow
cmp eax, NULL
je fail
invoke FindWindowEx, eax, NULL, addr targetClass, NULL
cmp eax, NULL
je fail
mov hTarget, eax
; 方法1:直接获取(掩码)
; invoke SendMessage, hTarget, WM_GETTEXT, sizeof buffer, addr buffer
; 方法2:内存读取
invoke GetWindowTextLength, hTarget
inc eax
invoke VirtualAlloc, NULL, eax, MEM_COMMIT, PAGE_READWRITE
mov pMemory, eax
invoke SendMessage, hTarget, EM_GETHANDLE, 0, 0
invoke RtlMoveMemory, pMemory, eax, sizeof buffer
invoke wsprintf, addr buffer, addr successMsg, pMemory
invoke MessageBox, NULL, addr buffer, NULL, MB_OK
invoke VirtualFree, pMemory, 0, MEM_RELEASE
jmp exit
fail:
invoke MessageBox, NULL, addr failMsg, NULL, MB_OK
exit:
invoke ExitProcess, 0
end start
现代系统对密码框的保护措施:
应对方案:
在UI自动化测试中,可以用此技术验证密码输入:
asm复制; 测试用例示例
test_case:
invoke SetWindowText, hTarget, "test123"
invoke GetPasswordText
cmp eax, "test123"
jne test_failed
构建密码恢复工具的关键步骤:
在安全审计中的注意事项:
重要提示:此技术仅限合法用途,如测试自有软件或取证调查。未经授权获取他人密码可能涉及法律问题。
asm复制; 首次查找后保存句柄
mov hCachedWnd, eax
asm复制enum_controls:
invoke FindWindowEx, hParent, hLast, addr targetClass, NULL
cmp eax, NULL
je enum_done
mov hLast, eax
; 处理当前控件
jmp enum_controls
enum_done:
asm复制; 使用PostMessage避免阻塞
invoke PostMessage, hTarget, WM_GETTEXT, sizeof buffer, addr buffer
不同Windows版本的行为差异:
| 版本 | 密码存储方式 | 保护机制 |
|---|---|---|
| XP | 明文存储 | 无 |
| 7 | 部分加密 | 基础 |
| 10 | 完全加密 | 强 |
适配方案:
asm复制check_os_version:
invoke GetVersion
cmp eax, 6 ; Vista+
jge new_os
; XP处理逻辑
jmp done
new_os:
; 现代系统处理逻辑
done:
当目标程序有防护措施时:
asm复制invoke CheckRemoteDebuggerPresent, -1, addr isDebugged
cmp isDebugged, TRUE
je debugger_detected
asm复制; 使用ReadProcessMemory代替直接访问
invoke OpenProcess, PROCESS_VM_READ, FALSE, targetPID
invoke ReadProcessMemory, hProcess, pRemote, addr buffer, size, NULL
asm复制invoke GetTickCount
and eax, 0FFh ; 随机延迟
invoke Sleep, eax
对于实际项目应用:
asm复制error_handler:
invoke GetLastError
mov lastError, eax
; 记录错误日志
jmp cleanup
asm复制log_message:
invoke GetLocalTime, addr systemTime
invoke wsprintf, addr logBuffer, addr logFormat,
systemTime.wHour, systemTime.wMinute, systemTime.wSecond,
logMessage
invoke WriteFile, hLogFile, addr logBuffer, eax, NULL, NULL
ret
asm复制; 密码获取模块
GetPasswordText proc hWnd:HWND, pBuffer:PTR BYTE
; 实现代码
ret
GetPasswordText endp
这个项目展示了汇编语言在Windows系统编程中的强大能力。通过直接操作GUI控件和内存,我们可以实现高级语言难以完成的底层操作。但在实际应用中,务必遵守道德规范和法律法规。