简介本资源为Windows安全研究领域经典的WinlogonHack核心DLL源码包面向逆向工程初学者、系统安全研究人员及底层编程学习者聚焦Windows登录机制剖析与Gina层Hook技术实践。压缩包共11个文件含2个核心CPP实现文件Hookmsgina.cpp、StdAfx.cpp、2个头文件resource.h、StdAfx.h支撑模块化结构另有DSP/DSP工程配置、DEF导出定义、RC资源脚本及NCB/OPT等VC6开发环境辅助文件完整保留原始编译调试上下文包体仅11KB轻量但信息密度高。已有141人下载学习适合通过源码级分析理解msgina.dll劫持原理、登录凭据捕获逻辑及XP时代Gina接口扩展机制。读者可直接编译调试、对照博文逐函数跟踪Hook注入流程并结合ReadMe.txt掌握内存替换时机与关键API拦截点是深入Windows认证子系统与实战Hook技术的优质教学样本。1. WinlogonHack 不是“黑盒后门”而是 Windows 登录层 Hook 的教科书级拆解样本去年在复现一个某高校实验室的模拟项目X时我本想快速验证 GINA 替换机制的兼容性边界结果卡在 winlogon.exe 加载 msgina.dll 的符号解析阶段整整三天——调试器进不去、断点全失效、日志无输出。直到翻出这份名为WinlogonHack核心dll源码的资源才真正看清它根本不是网上流传的“免杀后门模板”而是一份完整暴露了 Windows XP/2003 登录子系统底层交互契约的逆向工程笔记。它用最朴素的 C Win32 API 实现了对 msgina.dll 的 inline hook、函数指针劫持与结构体偏移重定位所有关键逻辑都写在 .cpp 文件里连WlxDisplaySASNotice这种冷门回调的参数校验都加了注释。如果你正面临登录界面定制、域控策略绕过分析、或想搞懂 Windows 身份认证链最前端的控制权争夺逻辑这份源码就是你该亲手编译、单步跟进去的第一块“登陆跳板”。它不教你写木马但教会你怎么让系统在用户敲下 CtrlAltDel 的瞬间先听你的话。2. 从加载时机到函数劫持WinlogonHack 如何精准卡在登录流程咽喉处2.1 Winlogon.exe 的加载生命周期为什么必须在 Session 0 中注入Winlogon 是 Windows 登录会话的守门人运行在 Session 0系统会话且以 LocalSystem 权限启动。它在系统初始化后期加载msgina.dll并通过硬编码的导出函数名如WlxInitialize、WlxDisplaySASNotice调用其接口。WinlogonHack 的核心 DLL 并非通过 CreateRemoteThread 注入而是利用注册表HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon\GinaDLL键值强制替换 GINA 模块路径——这是 Windows 原生支持的合法扩展机制。但注意该机制仅在 Classic 模式非 Fast User Switching下生效且从 Windows Vista 起已被 Credential Providers 取代。因此这份源码的适用场景明确限定在 XP/2003 测试环境或遗留系统加固分析中。源码中DllMain的DLL_PROCESS_ATTACH分支会立即调用SetThreadDesktop(NULL)确保线程绑定到 winlogon 的 WinSta0\Default 桌面否则 GUI 函数如MessageBox将因桌面句柄无效而静默失败。2.2 msgina.dll 导出函数劫持的三重锚点WinlogonHack 并未使用 IAT/EAT Hook而是采用更底层的 inline hook 技术针对三个关键函数实施跳转覆盖WlxDisplaySASNotice用户按下 CtrlAltDel 后首个被调用的函数用于显示安全注意提示SAS。源码在此处插入自定义 UI并通过GetAsyncKeyState(VK_LCONTROL)等组合键检测实现“隐藏触发入口”。WlxLoggedOutSAS用户未登录状态下响应 SAS 的主逻辑。源码在此处 patch 了g_WlxFuncsTable函数指针表将WlxDisplaySASNotice地址替换为自定义函数地址完成控制流接管。WlxActivateUserShell登录成功后启动用户 shell如 explorer.exe前的最后钩子。源码在此处注入进程监控逻辑可拦截 shell 启动参数或延迟执行。提示所有 inline hook 均使用VirtualProtectEx修改代码段内存属性为PAGE_EXECUTE_READWRITE并严格遵循 x86 指令边界如避免截断mov eax, [ebx0x10]这类多字节指令。源码中HookFunction函数内嵌了反调试检查IsDebuggerPresent()返回真时跳过 hook这是为避免在分析环境中被误判为恶意行为。2.3 结构体偏移的硬编码陷阱为什么WLX_DISPATCH_VERSION_1_0必须手动计算msgina.dll 的函数表WLX_DISPATCH_VERSION_1_0并非导出符号而是由 winlogon 在运行时通过GetProcAddress获取其地址后再按固定偏移读取函数指针。WinlogonHack 源码中g_WlxFuncsTable的初始化代码如下// 偏移计算依据WLX_DISPATCH_VERSION_1_0 结构体定义MSDN 文档 IDA 反编译交叉验证 // 成员顺序pWlxUseCtrlAltDel, pWlxSetContextPointer, ..., pWlxActivateUserShell // 每个指针占 4 字节x86pWlxDisplaySASNotice 位于第 3 个位置索引 2 DWORD* pDispatchTable (DWORD*)GetProcAddress(hMsgina, WlxInitialize); if (pDispatchTable) { g_pOriginalDisplaySAS (PFN_WLXDISPLAYSASNOTICE)(pDispatchTable[2]); // 索引 2 WlxDisplaySASNotice DWORD dwOldProtect; VirtualProtect((LPVOID)pDispatchTable, 4, PAGE_EXECUTE_READWRITE, dwOldProtect); pDispatchTable[2] (DWORD)MyWlxDisplaySASNotice; // 覆盖函数指针 VirtualProtect((LPVOID)pDispatchTable, 4, dwOldProtect, dwOldProtect); }这段代码的关键在于WlxInitialize的返回值即为WLX_DISPATCH_VERSION_1_0*指针而该结构体在不同 Windows 版本中成员数量可能变化如 1.0 vs 1.1因此硬编码索引[2]仅对目标版本有效。源码注释明确标注了测试环境为 Windows XP SP3若在 2003 上运行需重新确认结构体布局。3. 编译与调试避坑那些让你在 winlogon 里“失联”的致命细节3.1 现象DLL 加载后 winlogon.exe 立即崩溃0xC0000005原因源码中MyWlxDisplaySASNotice函数未正确处理hWlx参数传递。winlogon 调用此函数时传入的是其内部维护的上下文句柄而原始 msgina.dll 会将其作为WLX_DISPATCH_VERSION_1_0*解析。若 hook 函数直接将该句柄转发给原函数但原函数期望的是经过WlxInitialize初始化后的有效结构体则会导致访问非法内存。解决在MyWlxDisplaySASNotice开头添加句柄有效性校验if (!hWlx || IsBadReadPtr(hWlx, sizeof(WLX_DISPATCH_VERSION_1_0))) { return FALSE; // 防御性退出避免崩溃 } // 正确转发确保 hWlx 是 WlxInitialize 返回的有效指针 return g_pOriginalDisplaySAS(hWlx, pWlxWindowManager, pWlxSasInfo);3.2 现象自定义 UI 窗口无法显示CreateWindowEx返回 NULL原因winlogon 运行在 Session 0其桌面对象WinSta0\Default与用户会话桌面隔离。若未显式指定hWndParent为 winlogon 的主窗口句柄可通过FindWindow(Shell_TrayWnd, NULL)获取失败因其不存在于 Session 0或未调用SetThreadDesktop(GetThreadDesktop(GetCurrentThreadId()))则窗口创建会因桌面句柄无效而失败。解决在MyWlxDisplaySASNotice中强制切换线程桌面HDESK hDesk OpenDesktop(Default, 0, FALSE, DESKTOP_ENUMERATE | DESKTOP_WRITEOBJECTS); if (hDesk) { SetThreadDesktop(hDesk); CloseDesktop(hDesk); } // 此后调用 CreateWindowEx 才能成功3.3 现象Hook 成功但WlxActivateUserShell中无法获取用户 token原因WlxActivateUserShell被调用时用户会话尚未完全初始化OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, hToken)可能返回ERROR_NO_TOKEN。源码中直接调用DuplicateTokenEx会因缺少有效 token 而失败。解决改用WTSQueryUserToken获取当前登录会话 tokenDWORD sessionId; if (ProcessIdToSessionId(GetCurrentProcessId(), sessionId)) { HANDLE hUserToken; if (WTSQueryUserToken(sessionId, hUserToken)) { // 使用 hUserToken 创建进程 CreateProcessAsUser(hUserToken, ...); CloseHandle(hUserToken); } }3.4 现象编译后 DLL 在目标机上加载失败错误 0x7E原因源码项目配置为 Unicode 字符集但msgina.dll本身是 ANSI 编译。当DllMain中调用LoadLibrary(user32.dll)后若后续GetProcAddress获取MessageBoxA失败转而调用MessageBoxW则因字符集不匹配导致函数解析失败。解决统一使用 ANSI 版本 API在stdafx.h中定义#define UNICODE #define _UNICODE // 改为 #undef UNICODE #undef _UNICODE #pragma comment(lib, user32.lib) // 所有 MessageBox 调用显式使用 MessageBoxA4. 安全分析视角如何用这份源码反向验证 GINA 类攻击的检测盲区4.1 内存特征提取从 inline hook 到 YARA 规则生成WinlogonHack 的 inline hook 在WlxDisplaySASNotice函数头部写入JMP指令0xE9 4 字节相对偏移这是典型的代码段 patch 行为。我们可基于此生成 YARA 规则检测异常 GINA 模块rule GINA_inline_hook_jmp { meta: description Detects JMP instruction at start of WlxDisplaySASNotice-like function author analyst strings: $jmp_prefix { E9 [4] } // JMP rel32 $func_name WlxDisplaySASNotice wide ascii condition: $jmp_prefix at 0 and $func_name }但需注意该规则易误报因合法 GINA 也可能包含 JMP。更可靠的方式是结合内存扫描——在 winlogon 进程中搜索msgina.dll模块基址 WlxDisplaySASNoticeRVA 处是否被修改。源码中HookFunction的 patch 地址可作为基准偏移如0x1234实际检测时用ReadProcessMemory读取该地址 5 字节比对是否为0xE9开头。4.2 进程行为建模winlogon 异常子进程的判定逻辑WinlogonHack 在WlxActivateUserShell中可能启动cmd.exe或notepad.exe等进程。正常情况下winlogon 启动的子进程应为explorer.exe或logonui.exe。我们可构建如下判定树若 winlogon 创建的子进程ImageFileName不在白名单explorer.exe,logonui.exe,lsass.exe中且该进程的父进程CreateTime与 winlogon 的CreateTime时间差 5 秒且该进程的TokenElevationType为TokenElevationTypeFull表明拥有高权限则标记为高风险。源码中CreateProcessAsUser的调用位置MyWlxActivateUserShell函数末尾即为此类行为的典型植入点。4.3 日志取证线索注册表与文件系统联动分析WinlogonHack 的持久化依赖注册表键GinaDLL但攻击者常配合文件替换如将msgina.dll备份为msgina.bak再放自己的 DLL。因此EDR 应关联以下事件注册表HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon\GinaDLL值被修改同一时间点%SystemRoot%\System32\msgina.dll文件大小/签名/哈希发生变化winlogon.exe 进程加载了非微软签名的 DLL通过GetModuleInformation获取模块签名状态。源码中DllMain的DLL_PROCESS_ATTACH分支会记录日志到%SystemRoot%\Temp\winlogonhack.log这恰好成为溯源关键——若发现该日志文件被创建即可反向定位注册表修改时间。5. 从源码到实战一份可落地的 GINA Hook 安全加固检查清单5.1 环境准备三步建立可复现的测试沙箱系统选择使用 Windows XP SP3 虚拟机VMware Workstation 16 VMware Tools禁用自动更新与防火墙确保msgina.dll未被 KB 补丁修改验证方法sigcheck -i %SystemRoot%\System32\msgina.dll应显示Verified: Signed且Publisher: Microsoft Corporation。调试配置安装 WinDbg 10设置符号路径为SRV*c:\symbols*https://msdl.microsoft.com/download/symbols在虚拟机中启用内核调试bcdedit /debug onbcdedit /dbgsettings serial debugport:1 baudrate:115200主机用串口连接调试。源码编译用 Visual Studio 2010兼容 XP 运行时打开项目配置为Release|Win32在Project Properties Configuration Properties General中设置Platform Toolset为v100Character Set为Not SetANSI输出目录设为%SystemRoot%\System32\winlogonhack.dll。5.2 动态验证五步确认 Hook 是否生效步骤操作预期结果关键命令/工具1修改注册表GinaDLL值为C:\Windows\System32\winlogonhack.dllwinlogon 重启后加载新 DLLreg add HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon /v GinaDLL /t REG_SZ /d C:\Windows\System32\winlogonhack.dll /f2触发 CtrlAltDel观察是否弹出自定义 SAS 窗口显示 “WinlogonHack Active” 标题栏目视确认3在 WinDbg 中附加 winlogon.exe执行lm m msgina*列出winlogonhack.dll模块而非msgina.dlllm m winlogonhack*4在WlxDisplaySASNotice入口下断点bp winlogonhack!MyWlxDisplaySASNotice断点命中r查看寄存器eax应为有效上下文地址bpg5检查内存 patchdb msgina!WlxDisplaySASNotice L5首字节为E9JMP非原始55PUSH EBPdb命令5.3 加固建议三道防线阻断 GINA 类攻击注册表防护通过组策略Computer Configuration Windows Settings Security Settings Registry将HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon键设置为Administrators: Full Control; SYSTEM: Full Control; Everyone: Read禁止普通用户修改GinaDLL。文件完整性监控使用 Sysmon v13.9配置Event ID 11FileCreate监控%SystemRoot%\System32\msgina.dll及其备份文件*.bak,*.old并启用Hash字段记录文件哈希。进程行为审计部署 ETWEvent Tracing for Windows跟踪winlogon.exe的ProcessCreate事件过滤ParentProcessId winlogon PID且ImageName NOT IN (explorer.exe, logonui.exe)的进程实时告警。从那以后我每次做登录层安全评估都会先用这份源码编译一个最小化 DLL在测试机上跑通全流程再对照它的内存 patch 方式、注册表操作、进程创建逻辑去反推真实环境中可能存在的同类攻击痕迹。它逼着我把 Windows 登录链的每个环节都亲手拧开看过——不是为了复刻而是为了认出那些藏在合法接口背后的异样脉搏。希望帮到你。本文还有配套的精品资源点击获取
阅读完成 · 觉得有帮助?