Winlogon.exe是Windows操作系统中负责用户登录和注销的关键进程。它能够处理多种事件,如锁定、解锁、注销、登录、启动、关闭、启动屏幕保护程序、停止屏幕保护程序和启动shell等。本文将介绍如何使用Winlogon通知包来处理这些事件,这种方法相比NT服务具有更好的用户活动处理能力和更轻量级的代码需求。
Winlogon通知包的主要优势在于它能够更有效地处理用户活动。与NT服务相比,Winlogon通知包不仅代码量更少,而且更加轻量级。通过创建一个DLL并注册特定的函数来响应Winlogon事件消息,可以构建一个非常健壮且灵活的解决方案,与服务和应用程序相结合。
创建一个Winlogon通知包非常简单。只需要创建一个包含特定函数的DLL,这些函数将在Winlogon事件消息期间运行。要让Winlogon.exe知道DLL,只需在注册表中添加几个适当的条目即可。
以下示例展示了如何在用户登录之前启动一个WIN32应用程序。由于该进程是由Winlogon启动的,因此它属于系统账户。用户不能通过“结束任务”来结束该进程,这与NT服务的行为完全相同。在示例中,注销通知将终止该进程。如果需要该进程保持活动状态,则应移除EndProcessAtWinlogoff
函数。如果希望该进程属于用户,可以在启动通知而不是登录通知期间使用CreateProcessAsUser
。
以下是DLL的示例代码:
#include <windows.h>
#include <Winwlx.h>
PROCESS_INFORMATION g_pi;
TCHAR g_szPath[] = _T("c:\\somepath\\execut.exe \"arguments\"");
// 安全终止进程的函数
// 允许它进行清理(例如,DLL分离)
// 可以在Windows开发者杂志中找到
SafeTerminateProcess(HANDLE hProcess, UINT uExitCode);
// DLL的入口函数
BOOL WINAPI LibMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved)
{
switch (dwReason)
{
case DLL_PROCESS_ATTACH:
DisableThreadLibraryCalls(hInstance);
break;
}
return TRUE;
}
// Winlogon登录事件的处理函数
VOID APIENTRY StartProcessAtWinLogon(PWLX_NOTIFICATION_INFO pInfo)
{
STARTUPINFO si;
si.cb = sizeof(STARTUPINFO);
si.lpReserved = NULL;
si.lpTitle = NULL;
si.lpDesktop = _T("WinSta0\\Default");
si.dwX = si.dwY = si.dwXSize = si.dwYSize = 0L;
si.dwFlags = 0;
si.wShowWindow = SW_SHOW;
si.lpReserved2 = NULL;
si.cbReserved2 = 0;
CreateProcess(NULL, g_szPath, NULL, NULL, FALSE, CREATE_NEW_CONSOLE,
NULL, NULL, &si, &g_pi);
}
// Winlogon注销事件的处理函数
VOID APIENTRY StopProcessAtWinlogoff(PWLX_NOTIFICATION_INFO pInfo)
{
// 终止进程
SafeTerminateProcess(g_pi.hProcess, 0xDEADBEEF);
}
// 其他事件处理函数
VOID APIENTRY YOUR_EVENT_HANDLERS(PWLX_NOTIFICATION_INFO pInfo)
{
// 代码
}
程序尚未导出任何函数。需要创建一个.def文件。
sample.def
EXPORTS
StartProcessAtWinLogon
StopProcessAtWinlogoff
现在将以下内容添加到VC6的链接选项中并构建。
/def:"sample.def"
如果一切顺利,将在输出文件夹中生成sample.dll和sample.exp文件。将这些文件移动到\%NTROOT%\system32。
HKEY_LOCAL_MACHINE
\Software
\Microsoft
\Windows NT
\CurrentVersion
\Winlogon
\Notify
\NameOfProject
\Asynchronous REG_DWORD 0
\Dllname REG_SZ NameOfDll.dll
\Impersonate REG_DWORD 0
\Logon REG_SZ StartProcessAtWinLogon
\Logoff REG_SZ StopProcessAtWinlogoff
\... REG_SZ NameOfFunction