背景:
博主去年在國內某知名互聯網公司做URL安全檢測時寫的一份草稿。
最後卻沒用到項目上。
當時主要想用於URL網址安全的入庫以及更新,需要建立下載文件以及URL的安全屬性關聯。
邏輯大致是這樣的:
若下載的文件報毒則拉黑該URL,認定URL為危險,若不報毒了,則恢復該URL為安全。
當時找了不少資料都不理想,特別是針對不同版本的IE浏覽器,網上前人的思路幾乎已經都失效了。
最後無奈操刀,逆向了IE浏覽器的這部分函數,才算是達到目標,具體實現代碼如下:
#include <WinInet.h> #pragma comment(lib,"wininet.lib") HRESULT getIeDownloadCache(HANDLE &hEnumHandle, LPINTERNET_CACHE_ENTRY_INFOA &lpCache, DWORD &nEntrySize) { HRESULT hr; DWORD nError; DWORD dwSize; LPINTERNET_CACHE_ENTRY_INFOA lpCacheEntry; HANDLE hHandle; DWORD dwEntrySize; dwEntrySize = 0; hr = E_INVALIDARG; if ( !FindFirstUrlCacheEntryExA("iedownload:", 0, 0xFFFFFFFF, 0, NULL, &dwEntrySize, NULL, NULL, NULL) ) { if ( GetLastError() != ERROR_INSUFFICIENT_BUFFER ) goto FailExit; dwSize = dwEntrySize; lpCacheEntry = (LPINTERNET_CACHE_ENTRY_INFOA)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwSize); if ( !lpCacheEntry ) return E_OUTOFMEMORY; hHandle = FindFirstUrlCacheEntryExA("iedownload:",0,0xFFFFFFFF,0,lpCacheEntry,&dwEntrySize,NULL,NULL,NULL); if ( hHandle ) { hr = 0; lpCache = lpCacheEntry; nEntrySize = dwEntrySize; hEnumHandle = hHandle; } else { FailExit: nError = GetLastError(); hr = nError; if ( (signed int)nError > 0 ) hr = (unsigned __int16)nError | 0x80070000; } } return hr; } HRESULT FindNextCache(HANDLE &hEnumHandle, LPINTERNET_CACHE_ENTRY_INFOA &lpCache, DWORD &dwEntrySize) { HRESULT hr; DWORD nSize; LPINTERNET_CACHE_ENTRY_INFOA lpCacheEntry; DWORD nError; DWORD cbCacheEntryInfo; cbCacheEntryInfo = 0; hr = E_INVALIDARG; if ( !FindNextUrlCacheEntryA(hEnumHandle, NULL, &cbCacheEntryInfo) ) { if ( GetLastError() != ERROR_INSUFFICIENT_BUFFER ) goto FailExit; nSize = cbCacheEntryInfo; lpCacheEntry = (LPINTERNET_CACHE_ENTRY_INFOA)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, nSize); if ( !lpCacheEntry ) return E_OUTOFMEMORY; if ( FindNextUrlCacheEntryA(hEnumHandle, lpCacheEntry, &cbCacheEntryInfo) ) { hr = 0; lpCache = lpCacheEntry; dwEntrySize = cbCacheEntryInfo; } else { FailExit: nError = GetLastError(); hr = nError; if ( (signed int)nError > 0 ) hr = (unsigned __int16)nError | 0x80070000; } } return hr; } void __cdecl myHeapFree(LPVOID lpMem) { HANDLE hHeap; if ( lpMem ) { hHeap = GetProcessHeap(); HeapFree(hHeap, 0, lpMem); } } int GetIEVersion() { HKEY hKey = NULL; DWORD dwType = 0; CHAR szData[16] = {0}; DWORD dwDataSize = 15; int nVersion = 0; if(RegOpenKeyExA(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Internet Explorer", 0, KEY_READ, &hKey) != ERROR_SUCCESS) { goto Exit0; } CHAR szVersion[MAX_PATH] = {0}; DWORD dwVersionSize = MAX_PATH-1; LONG lRet = RegQueryValueExA(hKey, "svcVersion", NULL, &dwType, (BYTE*)szVersion, &dwVersionSize); if (ERROR_SUCCESS == lRet && REG_SZ == dwType) { PCHAR pFind = strstr(szVersion, "."); if (pFind != NULL) { *pFind = 0; int nVer = atoi(szVersion); if (9 == nVer || 10 == nVer || 11 == nVer) { nVersion = nVer; goto Exit0; } } } if (ERROR_SUCCESS != RegQueryValueExA(hKey, "Build", NULL, &dwType, (BYTE*)szData, &dwDataSize)) { goto Exit0; } nVersion = atoi(szData); while (nVersion >= 15) { nVersion = nVersion / 10; } if (nVersion < 6) { nVersion = 0; goto Exit0; } Exit0: if (hKey != NULL) { RegCloseKey(hKey); } return nVersion; } BOOL GetIeDownloadHistoryFormCache(wstring & DestFile,wstring & refUrl, wstring &downloadUrl) { unsigned int i; LPINTERNET_CACHE_ENTRY_INFOA lpCache; BOOL bRet = FALSE; HANDLE hEnumHandle; DWORD dwSize; DWORD IEURL_BUFFER_OFFSET = 0; LPINTERNET_CACHE_ENTRY_INFOA lpCacheEntry; DWORD IEVer=GetIEVersion(); wstring strRefUrl,strMIMEType,strSrcFile,strDownloadUrl,strDestFile; hEnumHandle = NULL; lpCacheEntry = NULL; dwSize = 0; for ( i = getIeDownloadCache( hEnumHandle, lpCacheEntry, dwSize); (i & 0x80000000u) == 0; i = FindNextCache(hEnumHandle, lpCacheEntry, dwSize) ) { lpCache = lpCacheEntry; if ( strnicmp(lpCache->lpszSourceUrlName, "iedownload:", 11) == 0 ) { if (lpCache->lpHeaderInfo) { bRet = TRUE; DWORD dwLimitSize = 0x200; for ( DWORD n = 0; n < dwLimitSize; n++) { BYTE http[] = { 0x68, 0x00, 0x74, 0x00, 0x74, 0x00 ,0x70, 0x00, 0x3a, 0x00 ,0x2f ,0x00 ,0x2f }; BYTE https[] = { 0x68, 0x00, 0x74, 0x00, 0x74, 0x00 ,0x70, 0x00, 0x73, 0x00, 0x3a, 0x00 ,0x2f ,0x00 ,0x2f }; BYTE ftp[] = { 0x66, 0x00, 0x74, 0x00 ,0x70, 0x00, 0x3a, 0x00 ,0x2f ,0x00 ,0x2f }; if( (memcmp(lpCache->lpHeaderInfo+n, (PBYTE)http,sizeof(http) ) == 0) || (memcmp(lpCache->lpHeaderInfo+n, (PBYTE)ftp,sizeof(ftp) ) == 0) || (memcmp(lpCache->lpHeaderInfo+n, (PBYTE)https,sizeof(https) ) == 0)) { IEURL_BUFFER_OFFSET = n; break; } } wprintf(L"------------------------------------------\n"); LPWSTR lpRefUrl; LPWSTR lpMIMEType; LPWSTR lpSrcFile; LPWSTR lpDownloadUrl; LPWSTR lpDestFile; if (IEVer == 9) { lpRefUrl = (LPWSTR)((LPBYTE)lpCache->lpHeaderInfo+IEURL_BUFFER_OFFSET); strRefUrl = lpRefUrl; if (!strRefUrl.empty()) { wprintf(L"RefUrl[%s]\n",strRefUrl.c_str()); lpDownloadUrl = (LPWSTR)((LPBYTE)lpRefUrl+((wcslen(lpRefUrl)+1)*2)); strDownloadUrl = lpDownloadUrl; if (!strDownloadUrl.empty()) { wprintf(L"DownloadUrl[%s]\n",strDownloadUrl.c_str()); lpDestFile= (LPWSTR)((LPBYTE)lpDownloadUrl+((wcslen(lpDownloadUrl)+1)*2)); strDestFile = lpDestFile; wprintf(L"DestFile[%s]\n",strDestFile.c_str()); } } } else if (IEVer == 11||IEVer == 10) { lpRefUrl = (LPWSTR)((LPBYTE)lpCache->lpHeaderInfo+IEURL_BUFFER_OFFSET); strRefUrl = lpRefUrl; if (!strRefUrl.empty()) { wprintf(L"RefUrl[%s]\n",strRefUrl.c_str()); lpMIMEType = (LPWSTR)((LPBYTE)lpRefUrl+((wcslen(lpRefUrl)+1)*2)); } strMIMEType = lpMIMEType; if ( strMIMEType.find(L"tp:/")== wstring::npos ) { if (!strMIMEType.empty()) { wprintf(L"MIMEType[%s]\n",strMIMEType.c_str()); lpSrcFile = (LPWSTR)((LPBYTE)lpMIMEType+((wcslen(lpMIMEType)+1)*2)); } strSrcFile = lpSrcFile; if (!strSrcFile.empty()) { wprintf(L"SrcFile[%s]\n",strSrcFile.c_str()); lpDownloadUrl= (LPWSTR)((LPBYTE)lpSrcFile+((wcslen(lpSrcFile)+1)*2)); } strDownloadUrl = lpDownloadUrl; if (!strDownloadUrl.empty()) { wprintf(L"DownloadUrl[%s]\n",strDownloadUrl.c_str()); lpDestFile= (LPWSTR)((LPBYTE)lpDownloadUrl+((wcslen(lpDownloadUrl)+1)*2)); wprintf(L"DestFile[%s]\n",lpDestFile); strDestFile = lpDestFile; } } //兼容從IE9升級到IE10以上版本 else { lpDownloadUrl = (LPWSTR)((LPBYTE)lpRefUrl+((wcslen(lpRefUrl)+1)*2)); strDownloadUrl = lpDownloadUrl; if (!strDownloadUrl.empty()) { wprintf(L"DownloadUrl[%s]\n",strDownloadUrl.c_str()); lpDestFile= (LPWSTR)((LPBYTE)lpDownloadUrl+((wcslen(lpDownloadUrl)+1)*2)); strDestFile = lpDestFile; wprintf(L"DestFile[%s]\n",strDestFile.c_str()); } } } wprintf(L"------------------------------------------\n"); } } else //ie9以下版本 { strDownloadUrl=CA2W(lpCache->lpszSourceUrlName); strDestFile=CA2W(lpCache->lpszLocalFileName); transform(strDestFile.begin(), strDestFile.end(), strDestFile.begin(), towlower); //過濾目標文件目錄是臨時目錄 if (strDestFile.find(L"content.ie5")==std::string::npos) { wprintf(L"------------------------------------------\n"); wprintf(L"lpszSourceUrl[%s]\n",strDownloadUrl.c_str()); wprintf(L"lpszLocalFile[%s]\n",strDestFile.c_str()); wprintf(L"------------------------------------------\n"); } } //DeleteUrlCacheEntryA(lpCache->lpszSourceUrlName); myHeapFree(lpCache); transform(strDestFile.begin(), strDestFile.end(), strDestFile.begin(), towlower); transform(DestFile.begin(), DestFile.end(), DestFile.begin(), towlower); if (strDestFile.find(DestFile.c_str())!=wstring::npos) { refUrl=strRefUrl; downloadUrl = strDownloadUrl; return bRet; } } return bRet; } ------------------------------------------------------------------------------------------------- BOOL GetIEDownloadFileUrl(wstring& strCacheFilePath, wstring& RefUrl,wstring& FileUrl) { unsigned int i; LPINTERNET_CACHE_ENTRY_INFOA lpCache; BOOL bRet = FALSE; HANDLE hEnumHandle; DWORD dwSize; DWORD IEURL_BUFFER_OFFSET = 0; LPINTERNET_CACHE_ENTRY_INFOA lpCacheEntry; wstring strRefUrl,strMIMEType,strSrcFile,strDownloadUrl,strDestFile; hEnumHandle = NULL; lpCacheEntry = NULL; dwSize = 0; DEBUG_PUT(("------------------GetIeDownloadHistoryFormCache------------------------\n")); for ( i = getIeDownloadCache( hEnumHandle, lpCacheEntry, dwSize); (i & 0x80000000) == 0; i = FindNextCache(hEnumHandle, lpCacheEntry, dwSize) ) { lpCache = lpCacheEntry; if ( strnicmp(lpCache->lpszSourceUrlName, "iedownload:", 11) == 0 ) { if (lpCache->lpHeaderInfo) { bRet = TRUE; DWORD dwLimitSize = 0x200; for ( DWORD n = 0; n < dwLimitSize; n++) { BYTE http[] = { 0x68, 0x00, 0x74, 0x00, 0x74, 0x00 ,0x70, 0x00, 0x3a, 0x00 ,0x2f ,0x00 ,0x2f }; BYTE https[] = { 0x68, 0x00, 0x74, 0x00, 0x74, 0x00 ,0x70, 0x00, 0x73, 0x00, 0x3a, 0x00 ,0x2f ,0x00 ,0x2f }; BYTE ftp[] = { 0x66, 0x00, 0x74, 0x00 ,0x70, 0x00, 0x3a, 0x00 ,0x2f ,0x00 ,0x2f }; if( (memcmp(lpCache->lpHeaderInfo+n, (PBYTE)http,sizeof(http) ) == 0) || (memcmp(lpCache->lpHeaderInfo+n, (PBYTE)ftp,sizeof(ftp) ) == 0) || (memcmp(lpCache->lpHeaderInfo+n, (PBYTE)https,sizeof(https) ) == 0)) { IEURL_BUFFER_OFFSET = n; break; } } DEBUG_PUT(("------------------------------------------\n")); LPWSTR lpRefUrl; LPWSTR lpMIMEType; LPWSTR lpSrcFile; LPWSTR lpDownloadUrl; LPWSTR lpDestFile; lpRefUrl = (LPWSTR)((LPBYTE)lpCache->lpHeaderInfo+IEURL_BUFFER_OFFSET); strRefUrl = lpRefUrl; if (!strRefUrl.empty()) { DEBUG_PUT(("RefUrl[%s]\n",strRefUrl.c_str())); lpMIMEType = (LPWSTR)((LPBYTE)lpRefUrl+((wcslen(lpRefUrl)+1)*2)); strMIMEType = lpMIMEType; } if ( strMIMEType.find(L"tp:/")== wstring::npos ) { if (!strMIMEType.empty()) { DEBUG_PUT(("MIMEType[%s]\n",strMIMEType.c_str())); lpSrcFile = (LPWSTR)((LPBYTE)lpMIMEType+((wcslen(lpMIMEType)+1)*2)); } strSrcFile = lpSrcFile; if (!strSrcFile.empty()) { DEBUG_PUT(("SrcFile[%s]\n",strSrcFile.c_str())); lpDownloadUrl= (LPWSTR)((LPBYTE)lpSrcFile+((wcslen(lpSrcFile)+1)*2)); } strDownloadUrl = lpDownloadUrl; if (!strDownloadUrl.empty()) { DEBUG_PUT(("DownloadUrl[%s]\n",strDownloadUrl.c_str())); lpDestFile= (LPWSTR)((LPBYTE)lpDownloadUrl+((wcslen(lpDownloadUrl)+1)*2)); DEBUG_PUT(("DestFile[%s]\n",lpDestFile)); strDestFile = lpDestFile; } } //兼容IE9 else { lpDownloadUrl = (LPWSTR)((LPBYTE)lpRefUrl+((wcslen(lpRefUrl)+1)*2)); strDownloadUrl = lpDownloadUrl; if (!strDownloadUrl.empty()) { DEBUG_PUT(("DownloadUrl[%s]\n",strDownloadUrl.c_str())); lpDestFile= (LPWSTR)((LPBYTE)lpDownloadUrl+((wcslen(lpDownloadUrl)+1)*2)); strDestFile = lpDestFile; DEBUG_PUT(("DestFile[%s]\n",strDestFile.c_str())); } } DEBUG_PUT(("------------------------------------------\n")); } } else { //兼容IE9以下版本 strDownloadUrl=CA2W(lpCache->lpszSourceUrlName); strDestFile=CA2W(lpCache->lpszLocalFileName); transform(strDestFile.begin(), strDestFile.end(), strDestFile.begin(), towlower); } //清除記錄 //DeleteUrlCacheEntryA(lpCache->lpszSourceUrlName); myHeapFree(lpCache); transform(strDestFile.begin(), strDestFile.end(), strDestFile.begin(), towlower); transform(strCacheFilePath.begin(), strCacheFilePath.end(), strCacheFilePath.begin(), towlower); if (strDestFile.find(strCacheFilePath)!=wstring::npos) { RefUrl=strRefUrl; FileUrl = strDownloadUrl; return TRUE; } } return bRet; }