Windows Logon Password: (Win2K only)
It sounds a little crazy, but please look at the following figure:

Figure 5: SuperPasswordSpy++'s Peeking "Change Your Password" on WinLogon Screen of Win2K Server
I have only the Japanese Win2K server at hand, so there is some Japanese here, but I think you can see, that the window is obtained from "Ctrl+Alt-Del" and then pressing the "Change Password" button. PasswordSpy++ has been launched under the SYSTEM context on the Winlogon Desktop of this Win2K, and it works. I mean, it can read the password from the "Change Password" dialog. Oh, by the way, you will never know the current password because it is never shown.
To conduct this experiment, you have to use some tool to launch a program on the Windows Winlogon Desktop. You can go here to get my "GUI RunAs" program. You have to choose Winlogon desktop, make the user name edit box blank to use SYSTEM identity, and remember you must have Administrator rights to do so. Follow the article's instructions and you may need to log off the current session once (only once) to enable some privileges if you do not already have them. Some readers sent me e-mail saying there is already a "Runas" command line tool in Windows OS. I know, but with this MS-brand RunAs command-line tool, you can not choose the Desktop to launch the program while my tool works. If you have problems with the tool (for example, the launched program's GUI is blocked), please launch the tool itself as SYSTEM first, and then launch the program you use.
The last word: to get the screenshot, press "Print Screen" when you are on the Winlogon desktop, go to the default desktop, and paste it into MS Paint. You can also use the RunAs tool to launch MS Paint onto the Winlogon screen too, and do your job there without switching back and forth. And, you may find this RunAs GUI tool is a good way to launch a task manager as SYSTEM and kill some stubborn processes (including NT Service).
Anti-peeking edit and crack anti-peeking edit ( -* - = +)
I noticed someone asked how to do anti-peeking. Well, it does not cost too much to implement anti-peeking. Following is a code example using MFC. First, derive an edit class from CEdit. My first idea was to override its PreTranslate, this way:
BOOL CAntiPeekEdit::PreTranslateMessage(MSG* pMsg)
{
if(pMsg->message == WM_GETTEXT)
{
if(pMsg->wParam == 1024) {
}
else
{
::lstrcpy((LPTSTR)(pMsg->lParam), _T("Nothing"));
return TRUE;
}
}
return CEdit::PreTranslateMessage(pMsg);
}
Unfortunately, the inside if clause will never be called. Why? MFC team guys know. Well, I have to turn to the virtual function WindowsProc; this time it works:
LRESULT CAntiPeekEdit::WindowProc( UINT message,
WPARAM wParam,
LPARAM lParam)
{
if(message == WM_GETTEXT)
{
if(wParam == 1024) {
return CEdit::WindowProc(message, wParam, lParam);
}
else
{
::lstrcpy((LPTSTR)(lParam), _T("Nothing"));
return 7;
}
}
return CEdit::WindowProc(message, wParam, lParam);
}
In your own program, when you want to get the password text, you must do the following:
TCHAR sz[1024];
::SendMessage(hPasswordEdit, WM_GETTEXT, 1024, (LPARAM)sz);
If other routines call to retrieve the password, WM_GETTEXTLENGTH will tell them the correct length, but when the correct length buffer is asked by our AntiPeekEdit, we know it is called from some un-secure source, so we can just send back junk. Well, you can also abandon WM_GETTEXT completely and use a WM_USER + 123 message to get the text out.
Let's go back to how to counterstrike this kind of AntiPeekEdit. Well, we know the reason why we use hook DLL and query password from inside the remote process is because the Win2K password-style edit will not accept WM_GETTEXT from outside the process boundary. And, the above strategy replaces the standard Edit class Windows procedure with a user-defined one. So, how about replacing this user-defined procedure back to the standard Edit class Windows procedure when our lovely SuperPasswordSpy++ peeks it:
HWND hParent = ::GetParent(g_hTarget);
HWND hwndEdit = CreateWindow(
_T("EDIT"), NULL, WS_CHILD | WS_VISIBLE | WS_VSCROLL |
ES_LEFT | ES_MULTILINE | ES_AUTOVSCROLL,
0, 0, 0, 0, hParent, (HMENU)123,
(HINSTANCE) GetWindowLong(g_hTarget, GWL_HINSTANCE),
NULL); LONG_PTR lpNewEdit = GetWindowLongPtr(hwndEdit, GWLP_WNDPROC);
LONG_PTR lp = ::SetWindowLongPtr(g_hTarget,
GWLP_WNDPROC,(LONG_PTR)lpNewEdit);
SendMessage(g_hTarget, WM_GETTEXT, sizeof(szBuffer) /
sizeof(TCHAR), (LPARAM)szBuffer);
::SetWindowLongPtr(g_hTarget, GWLP_WNDPROC, (LONG_PTR)lp);
Please note the Control ID parameter when creating the fake edit; it must be unique among its siblings. Well, I use 123 as a placeholder here. You can write additional code to enumerate the sibling windows and get a unique ID, and remember to destroy the fake edit in the end.
But, it is really an overkill in most cases, so I did not include the above code in SuperPasswordSpy++ to keep performance and stability high. But, once you really meet such an anti-peek password edit, uncomment the additional code in the SuperPasswordSpy++ source code, and keep an eye on keeping the fake edit control ID unique.
If someone is mad asking if we have a way to anti- anti- anti-peeking, well, maybe you can add a global variable flag; before you fetch the password set this flag, and after reading, reset it.... Then why not use some algorithm to encode the text in WM_GETTEXT handler? Faint...