#include "viruspch.h" #include "vrsscan.h" #include "util.h" #include "viruschk.h" #include "resource.h" #include "virusmn.h" #include "richedit.h" // List of virus scanner providers #define SCANNER_KEY "Software\\Microsoft\\Virus Check\\Scanners" #define SCANNER_VIRUSCHECK "Software\\Microsoft\\Virus Check" #define SCANNER_COOKIE "Cookie" #define SCANNER_STARTDATE "StartDate" // Keys for accessing virus scanner engine #define SCANNER_CLSID_REG "CLSID\\%s\\InprocServer32" #define VENDOR_REG "CLSID\\%s\\VirusScanner" // Keys stored under VENDOR_REG #define VENDOR_DESC "VendorDescription" #define VENDOR_CONTACT "VendorContactInfo" #define VENDOR_FLAGS "VendorFlags" #define VENDOR_ICON "VendorIcon" #define STR_UNKNOWN L"" #define STR_NONE L"None" extern TCHAR g_szTitle[]; //REVIEW: We support Apartment model only so only 1 thread at a time can enter us. static CVirusScanProvider *g_pvp; // Used for DLGPROC callback procedure CVirusCheck::CVirusCheck(IUnknown *punkOuter, IUnknown **punkRet) { // Initilize members vars m_uNumProviders = 0; m_provList = NULL; m_cObjRef = 0; g_pvp = NULL; *punkRet = NULL; if(punkOuter != NULL) *punkRet = NULL; // Do not support aggregation else *punkRet = (IVirusScanner *)this; AddRef(); LoadProviders(); } void CVirusCheck::LoadProviders() { DWORD dwSubKeys; DWORD dwSize; LPWSTR pwsz; char szCLSID[GUID_STR_LEN]; char szBuf[MAX_STRING]; DWORD dwFlags; CLSID clsid; IVirusScanEngine *pvs; HKEY hVendorKey = NULL; HKEY hKey= NULL; HKEY hSubKey = NULL; ULONG ulCRC = 0; DWORD dwCookie; CVirusScanProvider *curProv = NULL; // Open the branch that contains providers if(RegOpenKeyExA(HKEY_LOCAL_MACHINE, SCANNER_KEY, 0, KEY_READ, &hKey) != ERROR_SUCCESS) return; // Find out how many providers we have if(RegQueryInfoKey(hKey, NULL, NULL, NULL, &dwSubKeys, NULL, NULL, NULL, NULL, NULL, NULL, NULL) != ERROR_SUCCESS) dwSubKeys = 0; // We will loop thru each key for( DWORD i = 0; i < dwSubKeys; i++ ) { dwSize = sizeof(szCLSID); if(RegEnumKeyExA(hKey, i, szCLSID, &dwSize, NULL, NULL, NULL, NULL) == ERROR_SUCCESS) { // We probably do any validatition right about here... if ( !DoCheckSum( szCLSID, &ulCRC ) ) { // skip the un-signed scanner continue; } // verify the scanner checksum //REVIEW: How should error be reported if virus scanner engine fails check? if ( RegOpenKeyExA( hKey, szCLSID, 0, KEY_READ, &hSubKey ) == ERROR_SUCCESS ) { dwSize = sizeof(DWORD); dwCookie = -1; if (RegQueryValueExA( hSubKey, SCANNER_COOKIE, NULL, NULL, (BYTE *)&dwCookie, &dwSize) == ERROR_SUCCESS) { RegCloseKey( hSubKey ); if ( ulCRC != (ULONG)dwCookie ) { continue; } } else continue; } else continue; // Open the \HKCR\CLSID\xxx\VirusScanner key wsprintf(szBuf, VENDOR_REG, szCLSID); if(RegOpenKeyExA(HKEY_CLASSES_ROOT, szBuf, 0, KEY_READ, &hVendorKey) == ERROR_SUCCESS) { // MakeWideStrFromAnsi allocs memory using CoMemTaskAlloc (so we better free it later!) pwsz = MakeWideStrFromAnsi(szCLSID); if ( pwsz != NULL && SUCCEEDED(CLSIDFromString(pwsz, &clsid)) ) { if ( SUCCEEDED(CoCreateInstance(clsid, NULL, CLSCTX_INPROC_SERVER, IID_IVirusScanEngine,(void **) &pvs)) ) { // Only know do we know we a) a key existed b) it was a clsid c) it was creatable and has // a IVirusScanner interface. Yea! Add it to our list of providers if (curProv == NULL) { curProv = m_provList = new CVirusScanProvider(); } else { curProv->nextProv = new CVirusScanProvider(); curProv = curProv->nextProv; } curProv->clsid = clsid; curProv->pvs = pvs; //Get the description szBuf[0] = '\0'; dwSize = MAX_DESCRIPTION; RegQueryValueExA(hVendorKey, VENDOR_DESC, NULL, NULL, (BYTE *) szBuf, &dwSize); curProv->pwszDescription = MakeWideStrFromAnsi(szBuf); //Get the Flags dwFlags = 0; dwSize = sizeof(dwFlags); RegQueryValueExA(hVendorKey, VENDOR_FLAGS, NULL, NULL, (BYTE *) &dwFlags, &dwSize); curProv->dwFlags = (DWORD)dwFlags; // Everything is in place, bump our provider count m_uNumProviders++; } } CoTaskMemFree(pwsz); RegCloseKey(hVendorKey); } } // get enumerated subkey } // loop if (curProv != NULL) curProv->nextProv = NULL; if(hKey) RegCloseKey(hKey); } CVirusCheck::~CVirusCheck() { CVirusScanProvider *curProv = m_provList, *temp; if (m_provList != NULL) delete m_provList; } //IUnknown things STDMETHODIMP CVirusCheck::QueryInterface(REFIID riid, void **ppv) { *ppv = NULL; //IUnknown if((riid == IID_IUnknown) || (riid == IID_IVirusScanner)) *ppv = (IVirusScanner *)this; if(riid == IID_IRegisterVirusScanEngine) *ppv = (IRegisterVirusScanEngine *)this; // Sorry... if(*ppv == NULL) return ResultFromScode(E_NOINTERFACE); ((IUnknown *) *ppv)->AddRef(); return NOERROR; } STDMETHODIMP_(ULONG) CVirusCheck::AddRef(void) { m_cObjRef++; return m_cObjRef; } STDMETHODIMP_(ULONG) CVirusCheck::Release(void) { m_cObjRef--; if(m_cObjRef != 0) return m_cObjRef; delete this; return 0; } STDMETHODIMP CVirusCheck::ScanForVirus(HWND hwnd, STGMEDIUM *pstgmed, LPWSTR pwszItemDesc, DWORD dwFlags, LPVIRUSINFO pVrsInfo) { HRESULT hr; DWORD dwMedium; BOOL bOneCheckFailed = FALSE; BOOL bOneCheckWorked = FALSE; LPWSTR pwsz = NULL; LPTSTR psz; LPVIRUSINFO pvrsinfo; LPSTREAM pIStream = NULL; LARGE_INTEGER li; g_pvp = m_provList; // Temporarily disable all Virus Scan UI dwFlags |= SFV_DONTDOUI; // No providers, not much to do if(m_provList == NULL || m_uNumProviders == 0) return VSCAN_E_NOPROVIDERS; if(pstgmed == NULL) return E_POINTER; if(pstgmed->tymed == TYMED_FILE) dwMedium = VSC_LIKESFILE; else if(pstgmed->tymed == TYMED_ISTREAM) dwMedium = VSC_LIKESISTREAM; else if(pstgmed->tymed == TYMED_HGLOBAL) dwMedium = VSC_LIKESHGLOBAL; else return E_INVALIDARG; if( !pVrsInfo || (pVrsInfo->cbSize != sizeof(VIRUSINFO)) ) return E_INVALIDARG; pvrsinfo = pVrsInfo; // Need to be careful about Couldn't check vs virus found! for(UINT i = 0; i < m_uNumProviders; i++) { // Clear all fields // This is put here as a precaution to ensure one provider can't interfere another. pvrsinfo->wszVendorDescription[0] = '\0'; pvrsinfo->wszVendorContactInfo[0] = '\0'; pvrsinfo->hVendorIcon = NULL; pvrsinfo->wszVirusName[0] = '\0'; pvrsinfo->wszVirusDescription[0] = '\0'; if( g_pvp->dwFlags & dwMedium ) { // make sure the starting date is set // RegisterStartDate( pvp[i].clsid ); if (pstgmed->tymed == TYMED_ISTREAM) { LISet32(li, 0); // Set the seek pointer to the beginning, just in case pstgmed->pstm->Seek(li, STREAM_SEEK_SET, NULL); } if (FAILED(hr = g_pvp->pvs->ScanForVirus(hwnd, pstgmed, pwszItemDesc, GetScannerEngineFlags(dwFlags), 0, pvrsinfo))) { // We should do different things depending on the hr. // If the virus provider returns (VSE_E_UNSUPPORTEDINPUTTYPE) // We might want to return this to the caller. Specialy if // this is the only one. if ((hr == VSE_E_UNSUPPORTEDINPUTTYPE) && (pstgmed->tymed == TYMED_ISTREAM)) { // Convert to file and try again. pwsz = ConvertIStreamToFile(pstgmed->pstm); if (pwsz != NULL) { STGMEDIUM stgMed; stgMed.tymed = TYMED_FILE; stgMed.lpszFileName = pwsz; hr = g_pvp->pvs->ScanForVirus(hwnd, &stgMed, pwszItemDesc, GetScannerEngineFlags(dwFlags), 0, pvrsinfo); // Delete temp file created by ConvertIStreamToFile psz = MakeAnsiStrFromWide(pwsz); DeleteFile(psz); CoTaskMemFree(pwsz); CoTaskMemFree(psz); } } } if(SUCCEEDED(hr)) { if(hr == S_FALSE) { // Found a virus!!! FillDefaultVirusInfo( pvrsinfo, g_pvp, dwFlags ); if(!(dwFlags & SFV_DONTDOUI)) { hr = DoVirusFoundDefaultUI(hwnd, pvrsinfo, pwszItemDesc, dwFlags); } // try to delete the file if((hr == S_FALSE) && (dwFlags & SFV_DELETE) && (pstgmed->tymed == TYMED_FILE)) { #ifdef UNICODE psz = pstgmed->lpszFileName; #else psz = MakeAnsiStrFromWide(pstgmed->lpszFileName); #endif if(!DeleteFile(psz)) hr = VSCAN_E_DELETEFAIL; #ifndef UNICODE CoTaskMemFree(psz); #endif } if (!(dwFlags & SFV_WANTVENDORICON) && pvrsinfo->hVendorIcon != NULL) { DestroyIcon(pvrsinfo->hVendorIcon); } return hr; } bOneCheckWorked = TRUE; } else { bOneCheckFailed = TRUE; } } } if(bOneCheckFailed) if(bOneCheckWorked) return VSCAN_E_CHECKPARTIAL; else return VSCAN_E_CHECKFAIL; return S_OK; } HRESULT CVirusCheck::DoVirusFoundDefaultUI(HWND hwnd, LPVIRUSINFO pvrsinfo, LPWSTR pwszDesc, DWORD dwFlags) { VIRUSDLGPARAM vrsDlgParam; HRESULT hr; INT_PTR ret; vrsDlgParam.pwszDesc = pwszDesc; vrsDlgParam.pvrsinfo = pvrsinfo; ret = DialogBoxParam(g_hinst, MAKEINTRESOURCE(IDD_FOUNDVIRUS), hwnd, VirusFoundDlg, (LPARAM) &vrsDlgParam); if(ret == IDNO) hr = S_OK; else hr = S_FALSE; return hr; } void CVirusCheck::FillDefaultVirusInfo(LPVIRUSINFO pvrsinfo, CVirusScanProvider *vsp, DWORD dwFlags) { // description if(pvrsinfo->wszVendorDescription[0] == '\0') CopyWideStr(pvrsinfo->wszVendorDescription, vsp->pwszDescription); // Contact info if( (pvrsinfo->wszVendorContactInfo[0] == '\0') || (pvrsinfo->hVendorIcon == NULL) ) { LPSTR pszCLSID; char szVendorRegPath[MAX_STRING]; LPWSTR pwszTmp = NULL; HKEY hVendorKey; DWORD dwSize; // Open the \HKCR\CLSID\xxx\VirusScanner key StringFromCLSID(vsp->clsid, &pwszTmp); pszCLSID = MakeAnsiStrFromWide(pwszTmp); CoTaskMemFree(pwszTmp); // Free the CLSID wsprintf(szVendorRegPath, VENDOR_REG, pszCLSID); CoTaskMemFree( pszCLSID ); if( RegOpenKeyExA(HKEY_CLASSES_ROOT, szVendorRegPath, 0, KEY_READ, &hVendorKey) == ERROR_SUCCESS ) { if ( pvrsinfo->wszVendorContactInfo[0] == '\0' ) { char szBuf[MAX_URL_LENGTH]; dwSize = MAX_URL_LENGTH; if (RegQueryValueExA( hVendorKey, VENDOR_CONTACT, NULL, NULL, (BYTE *)szBuf, &dwSize ) == ERROR_SUCCESS) { MultiByteToWideChar(CP_ACP, 0, szBuf, -1, pvrsinfo->wszVendorContactInfo, ARRAYSIZE(pvrsinfo->wszVendorContactInfo)); } } // very dangouse thing ! if ( pvrsinfo->hVendorIcon == NULL ) { char szBuf[MAX_STRING]; LPSTR pArg; HINSTANCE hDll; dwSize = MAX_STRING; RegQueryValueExA(hVendorKey, VENDOR_ICON, NULL, NULL, (BYTE *) szBuf, &dwSize); if ( szBuf[0] ) { pArg = strtok( szBuf, "," ); if ( pArg ) { if ( hDll = LoadLibraryA( pArg ) ) { if ( pArg = strtok( NULL, "," ) ) { pvrsinfo->hVendorIcon = LoadIcon( hDll, MAKEINTRESOURCE(atoi(pArg)) ); } FreeLibrary( hDll ); } } } } RegCloseKey( hVendorKey ); } } if(pvrsinfo->wszVirusName[0] == 0) CopyWideStr(pvrsinfo->wszVirusName, STR_UNKNOWN); if( (pvrsinfo->wszVirusDescription[0] == 0) || (lstrcmpiW(pvrsinfo->wszVirusDescription, L"NONE" ) == 0) ) CopyWideStr(pvrsinfo->wszVirusDescription, STR_UNKNOWN); pvrsinfo->cbSize = sizeof(VIRUSINFO); } STDMETHODIMP CVirusCheck::RegisterScanEngine(REFCLSID rclsid, LPWSTR pwszDescription, DWORD dwFlags, DWORD dwReserved, DWORD *pdwCookie) { char szSubKey[MAX_STRING]; char szValue[MAX_STRING]; HKEY hKeyScanner; ULONG ulSize; ULONG ulCRC = 0; LPOLESTR pwszClsid = NULL; LPSTR pszCLSID = NULL; LPSTR psz; UINT idErr = 0; HRESULT hr = E_FAIL; // Get confirmation from user before register the scanner if ( (dwFlags & SFV_DONTDOUI) || DialogBoxParam(g_hinst, MAKEINTRESOURCE(IDD_REGISTER_VSCANNER), NULL, (DLGPROC)RegisterVirusScannerDlg, (LPARAM) pwszDescription) == IDYES ) { StringFromCLSID(rclsid, &pwszClsid); pszCLSID = MakeAnsiStrFromWide(pwszClsid); CoTaskMemFree(pwszClsid); // Free the CLSID // checking code sign if ( (dwFlags & SFV_DONTDOUI) || (IsScannerSigned(pszCLSID) != E_FAIL) ) { // want to make sure the vendor's reg entries are set properly // such as VendorContactInfo and VendorDescription. wsprintf( szSubKey, VENDOR_REG, pszCLSID ); if ( RegOpenKeyExA(HKEY_CLASSES_ROOT, szSubKey, 0, KEY_READ, &hKeyScanner) == ERROR_SUCCESS ) { // Compare Vendor Description ulSize = sizeof(szValue); if ( (RegQueryValueExA(hKeyScanner, VENDOR_DESC, NULL, NULL, (LPBYTE)szValue, &ulSize) == ERROR_SUCCESS) && (RegQueryValueExA(hKeyScanner, VENDOR_CONTACT, NULL, NULL, NULL, &ulSize) == ERROR_SUCCESS) && (ulSize>0) ) { psz = MakeAnsiStrFromWide(pwszDescription); if ( lstrcmpi(psz, szValue) == 0 ) { // Generate/Store and set cookie if ( DoCheckSum( pszCLSID, &ulCRC ) ) { // Add Registry key to Virus Check\Scanners if ( SUCCEEDED(AddScanner(pszCLSID, psz, &ulCRC, TRUE)) ) { if (pdwCookie) *pdwCookie = ulCRC; hr = S_OK; } } } else { // Description not the same. idErr = IDS_ERR_MISMHVENDORDESC; } CoTaskMemFree(psz); } else idErr = IDS_ERR_NOVENDORINFO; RegCloseKey(hKeyScanner); } else idErr = IDS_ERR_NOVENDOR; } else idErr = IDS_ERR_CODESIGN; CoTaskMemFree(pszCLSID); // Free the ANSI version of the CLSID if ( idErr ) { ErrMsgBox( idErr, g_szTitle, MB_OK ); } } return hr; } STDMETHODIMP CVirusCheck::UnRegisterScanEngine(REFCLSID rclsid, LPWSTR pwszDescription, DWORD dwFlags, DWORD dwReserved, DWORD dwCookie ) { return( RemoveScanner( rclsid, pwszDescription, dwCookie ) ); } inline DWORD CVirusCheck::GetScannerEngineFlags(DWORD dwFlags) { return (dwFlags & 0xFFFF0000); }; CVirusScanProvider::CVirusScanProvider() { pwszDescription = NULL; dwFlags = 0; pvs = NULL; nextProv = NULL; } CVirusScanProvider::~CVirusScanProvider() { if(pwszDescription) CoTaskMemFree(pwszDescription); if(pvs) pvs->Release(); if (nextProv != NULL) delete nextProv; } INT_PTR CALLBACK VirusFoundDlg(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { static RECT rctDlg; switch(uMsg) { case WM_INITDIALOG: { VIRUSDLGPARAM *pvs; pvs = (VIRUSDLGPARAM *)lParam; GetWindowRect(hwnd, &rctDlg); if ( pvs->pvrsinfo->hVendorIcon ) { SendDlgItemMessage( hwnd, IDC_VENDORICON, STM_SETICON, (WPARAM)(HICON)pvs->pvrsinfo->hVendorIcon, 0L ); } SetWindowLongPtr(hwnd, DWLP_USER, (LONG_PTR)pvs); InitVirusFoundDlg(hwnd, pvs, rctDlg); } break; case WM_COMMAND: switch(wParam) { case IDYES: EndDialog(hwnd, wParam); break; case IDNO: { TCHAR szBuf[MAX_STRING]; TCHAR szTitle[MAX_STRING]; szBuf[0] = szTitle[0] = '\0'; LoadString(g_hinst, IDS_IGNOREWARNCONFIRM, szBuf, ARRAYSIZE(szBuf) ); LoadString(g_hinst, IDS_WARNING, szTitle, ARRAYSIZE(szTitle) ); if ( szBuf[0] && szTitle[0]) { if ( MessageBox( hwnd, szBuf, szTitle, MB_ICONWARNING|MB_YESNO ) == IDNO ) break; } EndDialog(hwnd, wParam); } break; case IDC_VENDORINFO: if (g_pvp != NULL) g_pvp->pvs->DisplayCustomInfo(); break; case IDC_DETAILS: { LONG lBaseUnit; VIRUSDLGPARAM *pvrs; LPTSTR lpBuf, lpTmpName, lpTmpDesc; TCHAR szBuf[MAX_STRING], szTmp[MAX_STRING], szTmp2[MAX_STRING]; szBuf[0] = szTmp[0] = szTmp2[0] = '\0'; lpBuf = (LPTSTR) CoTaskMemAlloc( MAX_URL_LENGTH+1024 ); if ( !lpBuf ) { ErrMsgBox( IDS_ERR_OUTMEM, g_szTitle, MB_OK ); break; } pvrs = (VIRUSDLGPARAM *)GetWindowLongPtr(hwnd, DWLP_USER); SetWindowPos(hwnd, HWND_NOTOPMOST, 0, 0, (rctDlg.right - rctDlg.left), (rctDlg.bottom - rctDlg.top), SWP_NOMOVE | SWP_NOZORDER); SendDlgItemMessage( hwnd, IDC_DETAIL_GROUP, EM_SETMARGINS, EC_LEFTMARGIN, MAKELONG(10, 10) ); // SendDlgItemMessage( hwnd, IDC_DETAIL_GROUP, EM_SETBKGNDCOLOR, 0, RGB(256,256,256) ); lBaseUnit = (GetDialogBaseUnits()&0x0000FFFF)*4 ; SendDlgItemMessage( hwnd, IDC_DETAIL_GROUP, EM_SETTABSTOPS, 1, (LPARAM)(LPDWORD)&lBaseUnit); if ( *pvrs->pvrsinfo->wszVirusDescription && lstrcmpiW(pvrs->pvrsinfo->wszVirusDescription, STR_UNKNOWN) ) { TCHAR szTmp3[MAX_STRING]; szTmp3[0] = '\0'; #ifdef UNICODE lpTmpDesc = pvrs->pvrsinfo->wszVirusDescription; #else lpTmpDesc = MakeAnsiStrFromWide( pvrs->pvrsinfo->wszVirusDescription ); #endif LoadString(g_hinst, IDS_VIRUSDESC, szTmp3, ARRAYSIZE(szTmp)); if (szTmp3[0]) { wsprintf(szTmp2,szTmp3,lpTmpDesc); } #ifndef UNICODE CoTaskMemFree( lpTmpDesc ); #endif } #ifdef UNICODE lpTmpName = pvrs->pvrsinfo->wszVirusName; lpTmpDesc = pvrs->pvrsinfo->wszVendorDescription; #else lpTmpName = MakeAnsiStrFromWide( pvrs->pvrsinfo->wszVirusName ); lpTmpDesc = MakeAnsiStrFromWide( pvrs->pvrsinfo->wszVendorDescription ); #endif LoadString(g_hinst, IDS_VIRUSNAME, szTmp, ARRAYSIZE(szBuf)); if (szTmp[0]) { wsprintf(szBuf, szTmp, lpTmpName, lpTmpDesc, szTmp2); } #ifndef UNICODE CoTaskMemFree( lpTmpName ); CoTaskMemFree( lpTmpDesc ); #endif SetDlgItemText( hwnd, IDC_DETAIL_GROUP, szBuf); CoTaskMemFree( lpBuf ); } break; default: return FALSE; } break; default: return FALSE; } return TRUE; } void InitVirusFoundDlg(HWND hwnd, VIRUSDLGPARAM *pvrs, RECT rctDlg ) { RECT rctDetails; INT cx, cy; TCHAR szBuf[MAX_STRING]; TCHAR szMessBuf[MAX_STRING]; TCHAR *psz; // Fill in the header szBuf[0] = 0; szMessBuf[0] = 0; if(pvrs->pwszDesc != NULL) { LoadString(g_hinst, IDS_VIRUSFOUND, szBuf, ARRAYSIZE(szBuf) ); if(szBuf[0] != 0) { #ifdef UNICODE psz = pvrs->pwszDesc; #else psz = MakeAnsiStrFromWide(pvrs->pwszDesc); #endif wsprintf(szMessBuf, szBuf, psz); #ifndef UNICODE CoTaskMemFree(psz); #endif } } else LoadString(g_hinst, IDS_VIRUSFOUND_NODESC, szMessBuf, ARRAYSIZE(szMessBuf) ); SetDlgItemText(hwnd, IDC_TEXT_FOUNDVIRUS, szMessBuf); GetWindowRect(GetDlgItem(hwnd, IDC_DETAIL_GROUP), &rctDetails); cx = rctDlg.right - rctDlg.left; cy = rctDetails.top - rctDlg.top; SetWindowPos(hwnd, HWND_NOTOPMOST, 0, 0, cx, cy, SWP_NOMOVE | SWP_NOZORDER); } #define BUFFERSIZE 1024 LPWSTR ConvertIStreamToFile(LPSTREAM pIStream ) { HANDLE fh; LPWSTR pwsz = NULL; char szTempFile[MAX_PATH]; LPVOID lpv = NULL; LARGE_INTEGER li; DWORD dwl; ULONG ul; HRESULT hr; if (GetTempPath(sizeof(szTempFile), szTempFile) > 0) { if (GetTempFileName(szTempFile, "~VS", 0, szTempFile) != 0) { fh = CreateFile(szTempFile, GENERIC_READ|GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); if (fh != INVALID_HANDLE_VALUE) { lpv = (LPSTR)LocalAlloc(LPTR, BUFFERSIZE); if (lpv) { LISet32(li, 0); pIStream->Seek(li, STREAM_SEEK_SET, NULL); // Set the seek pointer to the beginning do { hr = pIStream->Read(lpv, BUFFERSIZE, &ul); if(SUCCEEDED(hr)) { if (!WriteFile(fh, lpv, ul, &dwl, NULL)) hr = E_FAIL; } } while ((SUCCEEDED(hr)) && (ul == BUFFERSIZE)); } CloseHandle(fh); if (SUCCEEDED(hr)) { // Convert from ANSI to UNICODE pwsz = MakeWideStrFromAnsi(szTempFile); } else { // Failed during read or write, delete the file. DeleteFile(szTempFile); } } } } return pwsz; } void InitRegisterVirusScannerDlg(HWND hwnd, LPWSTR pwszDesc) { TCHAR *psz; if(pwszDesc != NULL) { #ifdef UNICODE psz = pvrs->pwszDesc; #else psz = MakeAnsiStrFromWide(pwszDesc); #endif SetDlgItemText(hwnd, IDC_SCANNER_DESC, psz); } #ifndef UNICODE CoTaskMemFree(psz); #endif } BOOL CALLBACK RegisterVirusScannerDlg(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { switch(uMsg) { case WM_INITDIALOG: InitRegisterVirusScannerDlg(hwnd, (LPWSTR)lParam); break; case WM_COMMAND: switch(wParam) { case IDYES: case IDNO: EndDialog(hwnd, wParam); break; default: return FALSE; } break; default: return FALSE; } return TRUE; } HRESULT IsScannerSigned(LPSTR pszCLSID) { HKEY hKey; char szSubKey[MAX_STRING]; char szValue[MAX_STRING]; ULONG ulSize; HRESULT hr = E_FAIL; // Need to get the path for the scanner from the registry "InprocServer32" wsprintf(szSubKey, SCANNER_CLSID_REG, pszCLSID); if (RegOpenKeyExA(HKEY_CLASSES_ROOT, szSubKey, 0, KEY_READ, &hKey) == ERROR_SUCCESS) { ulSize = sizeof(szValue); // Get the default value, this should contain the full qualified path of the DLL if (RegQueryValueExA(hKey, "", NULL, NULL, (LPBYTE)szValue, &ulSize) == ERROR_SUCCESS) { hr = CheckTrust((LPSTR) szValue); } RegCloseKey(hKey); } return hr; } HRESULT AddScanner(LPSTR pszCLSID, LPSTR psz, LPDWORD pdwCookie, BOOL bNewEntry) { HRESULT hr = E_FAIL; HKEY hKey; HKEY hKeyScanner; DWORD dwDisposition; // make sure the parent keys exist if ( FAILED( MakeSureKeyExist( HKEY_LOCAL_MACHINE, SCANNER_VIRUSCHECK ) ) ) { return hr; } if ( FAILED( MakeSureKeyExist( HKEY_LOCAL_MACHINE, SCANNER_KEY ) ) ) { return hr; } if ( RegOpenKeyExA(HKEY_LOCAL_MACHINE, SCANNER_KEY, 0, KEY_READ, &hKey) == ERROR_SUCCESS ) { if ( RegCreateKeyExA( hKey, pszCLSID, 0, "", REG_OPTION_NON_VOLATILE, KEY_READ|KEY_WRITE, NULL, &hKeyScanner, &dwDisposition) == ERROR_SUCCESS ) { if ( bNewEntry && (dwDisposition == REG_OPENED_EXISTING_KEY) ) { // want to create new key but key already exists. Clear it up and recreate it. RegCloseKey(hKeyScanner); RegDeleteKeyA(hKey, pszCLSID); if ( RegCreateKeyExA( hKey, pszCLSID, 0, "", REG_OPTION_NON_VOLATILE, KEY_READ|KEY_WRITE, NULL, &hKeyScanner, &dwDisposition) != ERROR_SUCCESS) { // this just try to skip the next if() { } goto done; } } RegSetValueExA( hKeyScanner, "", 0, REG_SZ, (CONST BYTE *)psz, lstrlen(psz)+1 ); RegSetValueExA( hKeyScanner, SCANNER_COOKIE, 0, REG_DWORD, (CONST BYTE *)pdwCookie, sizeof(DWORD) ); RegCloseKey( hKeyScanner ); hr = S_OK; } done: RegCloseKey(hKey); } return hr; } HRESULT RemoveScanner( REFCLSID rclsid, LPWSTR pDesc, DWORD dwCookie ) { HRESULT hr = E_FAIL; HKEY hKey, hSubKey; LPOLESTR pwszCLSID; LPSTR pszCLSID; LPSTR pszInDesc; DWORD dwTmp; DWORD dwRegCookie; char szDesc[MAX_PATH]; StringFromCLSID(rclsid, &pwszCLSID); pszCLSID = MakeAnsiStrFromWide(pwszCLSID); pszInDesc = MakeAnsiStrFromWide(pDesc); CoTaskMemFree(pwszCLSID); // Free the CLSID if ( (RegOpenKeyExA(HKEY_LOCAL_MACHINE, SCANNER_KEY, 0, KEY_ALL_ACCESS, &hKey) == ERROR_SUCCESS) && (RegOpenKeyExA(hKey, pszCLSID, 0, KEY_ALL_ACCESS, &hSubKey) == ERROR_SUCCESS) ) { // check the cookie and description before remove the scanner dwTmp = sizeof(szDesc); if ( (RegQueryValueExA(hSubKey, "", NULL, NULL, (LPBYTE)szDesc, &dwTmp) == ERROR_SUCCESS) && (lstrcmpi(szDesc, pszInDesc) == 0 ) ) { dwTmp = sizeof(DWORD); if ( (RegQueryValueExA(hSubKey, SCANNER_COOKIE, NULL, NULL, (LPBYTE)&dwRegCookie, &dwTmp) == ERROR_SUCCESS) && (dwCookie == dwRegCookie ) ) { if ( DeleteKeyAndSubKeys(hKey, pszCLSID) ) hr = S_OK; else hr = S_FALSE; } } RegCloseKey(hSubKey); RegCloseKey(hKey); } CoTaskMemFree(pszCLSID); CoTaskMemFree(pszInDesc); return hr; } #if 0 void RegisterStartDate( CLSID clsid ) { HKEY hKey; LPOLESTR pwszCLSID; LPSTR pszCLSID; DWORD dwSize; char szSubKey[MAX_STRING]; char szTime[MAX_DESCRIPTION]; StringFromCLSID( clsid, &pwszCLSID ); pszCLSID = MakeAnsiStrFromWide(pwszCLSID); CoTaskMemFree(pwszCLSID); lstrcpy( szSubKey, SCANNER_KEY ); lstrcat( szSubKey, "\\" ); lstrcat( szSubKey, pszCLSID ); if ( RegOpenKeyExA(HKEY_LOCAL_MACHINE, szSubKey, 0, KEY_READ, &hKey) == ERROR_SUCCESS ) { dwSize = sizeof(szTime); if ( RegQueryValueExA(hKey, SCANNER_STARTDATE, NULL, NULL, (LPBYTE)szTime, &dwSize) != ERROR_SUCCESS ) { SYSTEMTIME systemTime; GetSystemTime( &systemTime ); dwSize = sizeof(SYSTEMTIME); RegSetValueExA(hKey, SCANNER_STARTDATE, NULL, REG_BINARY, (LPBYTE)&systemTime, dwSize); } RegCloseKey( hKey ); } CoTaskMemFree( pszCLSID ); } #endif BOOL DoCheckSum( LPSTR pszCLSID, ULONG *pulCRC ) { ULONG ulCRC = 0; HKEY hKey; char szSubKey[MAX_STRING]; char szValue[MAX_PATH]; HANDLE hFile; DWORD dwSize; // Need to get the path for the scanner from the registry "InprocServer32" wsprintf(szSubKey, SCANNER_CLSID_REG, pszCLSID); if (RegOpenKeyExA(HKEY_CLASSES_ROOT, szSubKey, 0, KEY_READ, &hKey) == ERROR_SUCCESS) { dwSize = sizeof(szValue); // Get the default value, this should contain the full qualified path of the DLL if (RegQueryValueExA(hKey, "", NULL, NULL, (LPBYTE)szValue, &dwSize) == ERROR_SUCCESS) { hFile = CreateFile( szValue, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL ); if ( hFile != INVALID_HANDLE_VALUE ) { dwSize = GetFileSize( hFile, NULL ); } } RegCloseKey(hKey); } else return FALSE; ulCRC = CRC32Compute( (BYTE *)&dwSize, sizeof(DWORD), ulCRC ); ulCRC = CRC32Compute( (BYTE *)pszCLSID, lstrlen(pszCLSID), ulCRC ); *pulCRC = ulCRC; return TRUE; }