deleting temp files
This commit is contained in:
@@ -1,373 +0,0 @@
|
||||
#ifndef CHECK_DIR_CPP
|
||||
#define CHECK_DIR_CPP
|
||||
#include "check_dir.h"
|
||||
#include "well_known.h"
|
||||
#include "log.h"
|
||||
#include "md5hash.h"
|
||||
#include "scan.h"
|
||||
#include "app_ctrl.h"
|
||||
#include "virus_ctrl.h"
|
||||
#include "scan.h"
|
||||
#include "settings.h"
|
||||
/* old implementation. used up a lot of resource and did not work properly.
|
||||
void add_to_temp_db(const char*hash) {
|
||||
//PERIODIC_FOLDER_SCAN_TEMP_DB
|
||||
FILE*fp;
|
||||
if (fopen_s(&fp, PERIODIC_FOLDER_SCAN_TEMP_DB, "a") != 0) {
|
||||
log(LOGLEVEL::ERR, "[add_to_temp_db()]: Error opening temp db: ", PERIODIC_FOLDER_SCAN_TEMP_DB);
|
||||
return;
|
||||
}
|
||||
else {
|
||||
//log(LOGLEVEL::INFO, "[add_to_temp_db()]: Adding hash: ", hash, " to temp db: ", PERIODIC_FOLDER_SCAN_TEMP_DB);
|
||||
fprintf_s(fp, "%s\n", hash);
|
||||
fclose(fp);
|
||||
}
|
||||
}
|
||||
void scan_folder_recursive(const std::string& directory, int thread_id,const std::string&db_file) {
|
||||
std::string search_path = directory + "\\*.*";
|
||||
WIN32_FIND_DATA find_file_data;
|
||||
HANDLE hFind = FindFirstFile(search_path.c_str(), &find_file_data);
|
||||
|
||||
if (hFind == INVALID_HANDLE_VALUE) {
|
||||
//std::cerr << "Error opening directory: " << directory << std::endl;
|
||||
log(LOGLEVEL::ERR, "[scan_folder_recursive()]: Error opening directory: ", directory ," while scanning folder for new files");
|
||||
return;
|
||||
}
|
||||
|
||||
do {
|
||||
if (strcmp(find_file_data.cFileName, ".") == 0 || strcmp(find_file_data.cFileName, "..") == 0) {
|
||||
continue; // Skip the current and parent directories
|
||||
}
|
||||
|
||||
|
||||
std::string full_path = directory + "\\" + find_file_data.cFileName;
|
||||
if (find_file_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
|
||||
// If it's a directory, recurse into it
|
||||
scan_folder_recursive(full_path, thread_id,db_file);
|
||||
}
|
||||
else {
|
||||
// If it's a file, check if it is in db, else scan it and add it to db
|
||||
char*hash = new char[300];
|
||||
md5_file(full_path.c_str(), hash);
|
||||
//now find hash in db
|
||||
if (scan_hash(db_file.c_str(), hash)==1) {
|
||||
//file is allready in db, skipping
|
||||
//in order to not keep hashes that are not present anymore in the db, we have to write this hash into a temp dir, which is at the end copied into the main db
|
||||
add_to_temp_db(hash);
|
||||
}
|
||||
else {
|
||||
//scan the file and add it to db
|
||||
//scan for virus
|
||||
|
||||
switch (scan_hash(hash)) {
|
||||
case 1:
|
||||
//virus found
|
||||
//log it
|
||||
log(LOGLEVEL::VIRUS, "[scan_folder_recursive()]: Virus found in file: ", full_path, " while scanning ", directory, " for new files");
|
||||
//virus_ctrl_store(full_path.c_str(), hash, "fs");
|
||||
break;
|
||||
case 2:
|
||||
//error
|
||||
log(LOGLEVEL::ERR, "[scan_folder_recursive()]: Error while scanning file: ", full_path, " while scanning ", directory, " for new files");
|
||||
break;
|
||||
default:
|
||||
//not a virus
|
||||
add_to_temp_db(hash);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
} while (FindNextFile(hFind, &find_file_data) != 0);
|
||||
|
||||
FindClose(hFind);
|
||||
}
|
||||
int check_scan_dir(char*dirpath,char*dirname) {
|
||||
if (can_scan_folder()) {
|
||||
scan_folder_init();
|
||||
//FOLDER_DATABASE_DIR <= the folder where the database for folder checking is stored
|
||||
//the database is stored in the following format:
|
||||
/* a file per folder (and its subfolders)
|
||||
in this db file the hashes of all the files in the folder (and its subfolders) are stored
|
||||
If a file is detected, which hash is not known, it gets scanned and added to the db. if a hash is inside the db, which is not present in the folder, the hash is rempved from the db
|
||||
|
||||
*/
|
||||
/*
|
||||
FILE* fp;
|
||||
char* path = new char[300];
|
||||
path[0] = '\0';
|
||||
//build up the path for the db file.
|
||||
strcpy_s(path, 295, FOLDER_DATABASE_DIR);
|
||||
strcat_s(path, 295, "\\");
|
||||
strcat_s(path, 295, dirname);
|
||||
strcat_s(path, 295, ".jdbf");
|
||||
|
||||
//check if the file exists. else we cannot scan the folder
|
||||
if ((fopen_s(&fp, path, "r")) != 0) {
|
||||
log(LOGLEVEL::ERR, "[check_scan_dir()]: Error opening database: ", path, " while scanning folder for new files; aborting");
|
||||
//try to create the file
|
||||
if (fopen_s(&fp, path, "w") != 0) {
|
||||
log(LOGLEVEL::ERR, "[check_scan_dir()]: Error creating new database: ", path, " while scanning folder for new files; aborting");
|
||||
}
|
||||
else {
|
||||
fprintf_s(fp, "%s\n", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA");//write A 32 times A into the file. So the algorithm ha ssomething to map into memory. else it might throw an error
|
||||
fclose(fp);
|
||||
}
|
||||
scan_folder_shutdown();
|
||||
return 1;
|
||||
}
|
||||
else {
|
||||
fclose(fp);
|
||||
//process the files of the folder.
|
||||
//first: calculate hash of file
|
||||
//second: check if hash is in db
|
||||
//if not, scan file and add it to db (only add it if it is not detected as a virus)
|
||||
scan_folder_recursive(dirpath, 0,path);
|
||||
//process the found viruses
|
||||
virus_ctrl_process("fs");
|
||||
}
|
||||
delete[] path;
|
||||
scan_folder_shutdown();
|
||||
return 0;
|
||||
}
|
||||
else {
|
||||
|
||||
//there is already a folder scan happening
|
||||
}
|
||||
}
|
||||
|
||||
*/
|
||||
bool is_directory(const std::string& path) {
|
||||
DWORD attributes = GetFileAttributes(path.c_str());
|
||||
|
||||
if (attributes == INVALID_FILE_ATTRIBUTES) {
|
||||
// Handle the error, e.g., by printing an error message
|
||||
return false;
|
||||
}
|
||||
|
||||
return (attributes & FILE_ATTRIBUTE_DIRECTORY) != 0;
|
||||
}
|
||||
void process_changes(const FILE_NOTIFY_INFORMATION* pInfo) {
|
||||
// Allocate a buffer for the file name and copy the content
|
||||
std::wstring fileName(pInfo->FileName, pInfo->FileNameLength / sizeof(wchar_t));
|
||||
|
||||
//convert wstring to string
|
||||
std::string filename_str(fileName.begin(), fileName.end());
|
||||
filename_str = "c:\\" + filename_str;
|
||||
//scan the file and send it to virus_ctrl if it is a virus and then process it
|
||||
std::transform(filename_str.begin(), filename_str.end(), filename_str.begin(), ::tolower);
|
||||
if (!is_folder_included(filename_str.c_str()) or is_directory(filename_str.c_str()) or is_folder_excluded(filename_str.c_str())) {
|
||||
//dont scan excluded files or folders
|
||||
return;
|
||||
}
|
||||
else {
|
||||
std::thread scan_thread(scan_file_t, filename_str);
|
||||
scan_thread.detach();
|
||||
}
|
||||
//log(LOGLEVEL::INFO, "[process_changes()]: File change: ", filename_str.c_str(), " while monitoring directory for changes");
|
||||
}
|
||||
/* this was the old algorithm. it was slower and used up more resources, because it used a database to track which files have been modified instead of using the windows internal functions
|
||||
void monitor_directory(LPCSTR directory) {
|
||||
// Open the directory for monitoring
|
||||
HANDLE hDir = CreateFile(
|
||||
directory,
|
||||
FILE_LIST_DIRECTORY,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
|
||||
NULL,
|
||||
OPEN_EXISTING,
|
||||
FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED,
|
||||
NULL
|
||||
);
|
||||
|
||||
if (hDir == INVALID_HANDLE_VALUE) {
|
||||
log(LOGLEVEL::ERR, "[monitor_directory()]: Error opening directory: ", directory, " while monitoring directory for changes");
|
||||
return;
|
||||
}
|
||||
|
||||
// Create a buffer for file change notifications
|
||||
constexpr DWORD bufferSize = 4096;
|
||||
BYTE buffer[bufferSize];
|
||||
|
||||
// Monitor the directory for changes
|
||||
OVERLAPPED overlapped;
|
||||
memset(&overlapped, 0, sizeof(overlapped));
|
||||
overlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
|
||||
|
||||
if (ReadDirectoryChangesW(
|
||||
hDir,
|
||||
buffer,
|
||||
bufferSize,
|
||||
TRUE,
|
||||
FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_SIZE,
|
||||
NULL,
|
||||
&overlapped,
|
||||
NULL) == 0) {
|
||||
log(LOGLEVEL::ERR, "[monitor_directory()]: Error reading directory changes: ", GetLastError(), " while monitoring directory for changes");
|
||||
CloseHandle(hDir);
|
||||
return;
|
||||
}
|
||||
|
||||
log(LOGLEVEL::INFO, "[monitor_directory()]: Monitoring directory: ", directory, " for changes");
|
||||
//print_exclusions();
|
||||
|
||||
// Wait for changes
|
||||
while (true) {
|
||||
DWORD bytesReturned;
|
||||
if (GetOverlappedResult(hDir, &overlapped, &bytesReturned, TRUE)) {
|
||||
// Process the changes in the buffer
|
||||
FILE_NOTIFY_INFORMATION* pInfo = reinterpret_cast<FILE_NOTIFY_INFORMATION*>(buffer);
|
||||
|
||||
do {
|
||||
process_changes(pInfo);
|
||||
|
||||
pInfo = reinterpret_cast<FILE_NOTIFY_INFORMATION*>(
|
||||
reinterpret_cast<BYTE*>(pInfo) + pInfo->NextEntryOffset);
|
||||
|
||||
} while (pInfo->NextEntryOffset != 0);
|
||||
|
||||
// Reset the event for the next wait
|
||||
ResetEvent(overlapped.hEvent);
|
||||
|
||||
// Continue monitoring
|
||||
if (ReadDirectoryChangesW(
|
||||
hDir,
|
||||
buffer,
|
||||
bufferSize,
|
||||
TRUE,
|
||||
FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_SIZE,
|
||||
NULL,
|
||||
&overlapped,
|
||||
NULL) == 0) {
|
||||
log(LOGLEVEL::ERR, "[monitor_directory()]: Error reading directory changes: ", GetLastError(), " while monitoring directory for changes");
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
DWORD error = GetLastError();
|
||||
if (error != ERROR_IO_PENDING) {
|
||||
log(LOGLEVEL::ERR, "[monitor_directory()]: Error reading directory changes: ", error, " while monitoring directory for changes");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Wait for the event to be signaled (infinite timeout)
|
||||
WaitForSingleObject(overlapped.hEvent, INFINITE);
|
||||
}
|
||||
|
||||
// Cleanup
|
||||
CloseHandle(overlapped.hEvent);
|
||||
CloseHandle(hDir);
|
||||
}
|
||||
*/
|
||||
|
||||
void monitor_directory(LPCSTR directory) {
|
||||
// Open the directory for monitoring
|
||||
HANDLE hDir = CreateFile(
|
||||
directory,
|
||||
FILE_LIST_DIRECTORY,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
|
||||
NULL,
|
||||
OPEN_EXISTING,
|
||||
FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED,
|
||||
NULL
|
||||
);
|
||||
|
||||
if (hDir == INVALID_HANDLE_VALUE) {
|
||||
log(LOGLEVEL::ERR, "[monitor_directory()]: Error opening directory: ", directory, " while monitoring directory for changes");
|
||||
return;
|
||||
}
|
||||
|
||||
// Create a buffer for file change notifications
|
||||
constexpr DWORD bufferSize = 4096;
|
||||
BYTE buffer[bufferSize];
|
||||
|
||||
// Monitor the directory for changes
|
||||
OVERLAPPED overlapped;
|
||||
memset(&overlapped, 0, sizeof(overlapped));
|
||||
memset(buffer, 0, bufferSize);
|
||||
overlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
|
||||
|
||||
if (ReadDirectoryChangesW(
|
||||
hDir,
|
||||
buffer,
|
||||
bufferSize,
|
||||
TRUE,
|
||||
FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_LAST_WRITE,
|
||||
NULL,
|
||||
&overlapped,
|
||||
NULL) == 0) {
|
||||
log(LOGLEVEL::ERR, "[monitor_directory()]: Error reading directory changes: ", GetLastError(), " while monitoring directory for changes");
|
||||
CloseHandle(hDir);
|
||||
return;
|
||||
}
|
||||
|
||||
log(LOGLEVEL::INFO, "[monitor_directory()]: Monitoring directory: ", directory, " for changes");
|
||||
|
||||
// Wait for changes
|
||||
while (!app_stop()) {
|
||||
DWORD bytesReturned;
|
||||
DWORD waitStatus = WaitForSingleObject(overlapped.hEvent, INFINITE);
|
||||
|
||||
if (waitStatus == WAIT_OBJECT_0) {
|
||||
if (GetOverlappedResult(hDir, &overlapped, &bytesReturned, FALSE)) {
|
||||
// Process the changes in the buffer
|
||||
FILE_NOTIFY_INFORMATION* pInfo = reinterpret_cast<FILE_NOTIFY_INFORMATION*>(buffer);
|
||||
|
||||
do {
|
||||
process_changes(pInfo);
|
||||
|
||||
pInfo = reinterpret_cast<FILE_NOTIFY_INFORMATION*>(
|
||||
reinterpret_cast<BYTE*>(pInfo) + pInfo->NextEntryOffset);
|
||||
|
||||
} while (pInfo->NextEntryOffset != 0);
|
||||
|
||||
// Reset the event for the next wait
|
||||
ResetEvent(overlapped.hEvent);
|
||||
memset(buffer, 0, bufferSize);
|
||||
|
||||
// Continue monitoring
|
||||
if (ReadDirectoryChangesW(
|
||||
hDir,
|
||||
buffer,
|
||||
bufferSize,
|
||||
TRUE,
|
||||
FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_LAST_WRITE,
|
||||
NULL,
|
||||
&overlapped,
|
||||
NULL) == 0) {
|
||||
log(LOGLEVEL::ERR, "[monitor_directory()]: Error reading directory changes: ", GetLastError(), " while monitoring directory for changes");
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
log(LOGLEVEL::ERR, "[monitor_directory()]: GetOverlappedResult failed: ", GetLastError());
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
log(LOGLEVEL::ERR, "[monitor_directory()]: WaitForSingleObject failed: ", GetLastError());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Cleanup
|
||||
CloseHandle(overlapped.hEvent);
|
||||
CloseHandle(hDir);
|
||||
}
|
||||
|
||||
void folder_scanner() {
|
||||
|
||||
//we are in a completely seperate thread then the main thread; unlimited resources wuhuii
|
||||
FILE*fp;
|
||||
char* path = new char[300];
|
||||
char* foldername = new char[300];
|
||||
|
||||
//start the watch dir function used to monitor the dir for new files
|
||||
monitor_directory("C:\\");
|
||||
|
||||
|
||||
delete[] path;
|
||||
delete[] foldername;
|
||||
}
|
||||
|
||||
#endif // !CHECK_DIR_CPP
|
||||
@@ -1,373 +0,0 @@
|
||||
#ifndef CHECK_DIR_CPP
|
||||
#define CHECK_DIR_CPP
|
||||
#include "check_dir.h"
|
||||
#include "well_known.h"
|
||||
#include "log.h"
|
||||
#include "md5hash.h"
|
||||
#include "scan.h"
|
||||
#include "app_ctrl.h"
|
||||
#include "virus_ctrl.h"
|
||||
#include "scan.h"
|
||||
#include "settings.h"
|
||||
/* old implementation. used up a lot of resource and did not work properly.
|
||||
void add_to_temp_db(const char*hash) {
|
||||
//PERIODIC_FOLDER_SCAN_TEMP_DB
|
||||
FILE*fp;
|
||||
if (fopen_s(&fp, PERIODIC_FOLDER_SCAN_TEMP_DB, "a") != 0) {
|
||||
log(LOGLEVEL::ERR, "[add_to_temp_db()]: Error opening temp db: ", PERIODIC_FOLDER_SCAN_TEMP_DB);
|
||||
return;
|
||||
}
|
||||
else {
|
||||
//log(LOGLEVEL::INFO, "[add_to_temp_db()]: Adding hash: ", hash, " to temp db: ", PERIODIC_FOLDER_SCAN_TEMP_DB);
|
||||
fprintf_s(fp, "%s\n", hash);
|
||||
fclose(fp);
|
||||
}
|
||||
}
|
||||
void scan_folder_recursive(const std::string& directory, int thread_id,const std::string&db_file) {
|
||||
std::string search_path = directory + "\\*.*";
|
||||
WIN32_FIND_DATA find_file_data;
|
||||
HANDLE hFind = FindFirstFile(search_path.c_str(), &find_file_data);
|
||||
|
||||
if (hFind == INVALID_HANDLE_VALUE) {
|
||||
//std::cerr << "Error opening directory: " << directory << std::endl;
|
||||
log(LOGLEVEL::ERR, "[scan_folder_recursive()]: Error opening directory: ", directory ," while scanning folder for new files");
|
||||
return;
|
||||
}
|
||||
|
||||
do {
|
||||
if (strcmp(find_file_data.cFileName, ".") == 0 || strcmp(find_file_data.cFileName, "..") == 0) {
|
||||
continue; // Skip the current and parent directories
|
||||
}
|
||||
|
||||
|
||||
std::string full_path = directory + "\\" + find_file_data.cFileName;
|
||||
if (find_file_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
|
||||
// If it's a directory, recurse into it
|
||||
scan_folder_recursive(full_path, thread_id,db_file);
|
||||
}
|
||||
else {
|
||||
// If it's a file, check if it is in db, else scan it and add it to db
|
||||
char*hash = new char[300];
|
||||
md5_file(full_path.c_str(), hash);
|
||||
//now find hash in db
|
||||
if (scan_hash(db_file.c_str(), hash)==1) {
|
||||
//file is allready in db, skipping
|
||||
//in order to not keep hashes that are not present anymore in the db, we have to write this hash into a temp dir, which is at the end copied into the main db
|
||||
add_to_temp_db(hash);
|
||||
}
|
||||
else {
|
||||
//scan the file and add it to db
|
||||
//scan for virus
|
||||
|
||||
switch (scan_hash(hash)) {
|
||||
case 1:
|
||||
//virus found
|
||||
//log it
|
||||
log(LOGLEVEL::VIRUS, "[scan_folder_recursive()]: Virus found in file: ", full_path, " while scanning ", directory, " for new files");
|
||||
//virus_ctrl_store(full_path.c_str(), hash, "fs");
|
||||
break;
|
||||
case 2:
|
||||
//error
|
||||
log(LOGLEVEL::ERR, "[scan_folder_recursive()]: Error while scanning file: ", full_path, " while scanning ", directory, " for new files");
|
||||
break;
|
||||
default:
|
||||
//not a virus
|
||||
add_to_temp_db(hash);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
} while (FindNextFile(hFind, &find_file_data) != 0);
|
||||
|
||||
FindClose(hFind);
|
||||
}
|
||||
int check_scan_dir(char*dirpath,char*dirname) {
|
||||
if (can_scan_folder()) {
|
||||
scan_folder_init();
|
||||
//FOLDER_DATABASE_DIR <= the folder where the database for folder checking is stored
|
||||
//the database is stored in the following format:
|
||||
/* a file per folder (and its subfolders)
|
||||
in this db file the hashes of all the files in the folder (and its subfolders) are stored
|
||||
If a file is detected, which hash is not known, it gets scanned and added to the db. if a hash is inside the db, which is not present in the folder, the hash is rempved from the db
|
||||
|
||||
*/
|
||||
/*
|
||||
FILE* fp;
|
||||
char* path = new char[300];
|
||||
path[0] = '\0';
|
||||
//build up the path for the db file.
|
||||
strcpy_s(path, 295, FOLDER_DATABASE_DIR);
|
||||
strcat_s(path, 295, "\\");
|
||||
strcat_s(path, 295, dirname);
|
||||
strcat_s(path, 295, ".jdbf");
|
||||
|
||||
//check if the file exists. else we cannot scan the folder
|
||||
if ((fopen_s(&fp, path, "r")) != 0) {
|
||||
log(LOGLEVEL::ERR, "[check_scan_dir()]: Error opening database: ", path, " while scanning folder for new files; aborting");
|
||||
//try to create the file
|
||||
if (fopen_s(&fp, path, "w") != 0) {
|
||||
log(LOGLEVEL::ERR, "[check_scan_dir()]: Error creating new database: ", path, " while scanning folder for new files; aborting");
|
||||
}
|
||||
else {
|
||||
fprintf_s(fp, "%s\n", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA");//write A 32 times A into the file. So the algorithm ha ssomething to map into memory. else it might throw an error
|
||||
fclose(fp);
|
||||
}
|
||||
scan_folder_shutdown();
|
||||
return 1;
|
||||
}
|
||||
else {
|
||||
fclose(fp);
|
||||
//process the files of the folder.
|
||||
//first: calculate hash of file
|
||||
//second: check if hash is in db
|
||||
//if not, scan file and add it to db (only add it if it is not detected as a virus)
|
||||
scan_folder_recursive(dirpath, 0,path);
|
||||
//process the found viruses
|
||||
virus_ctrl_process("fs");
|
||||
}
|
||||
delete[] path;
|
||||
scan_folder_shutdown();
|
||||
return 0;
|
||||
}
|
||||
else {
|
||||
|
||||
//there is already a folder scan happening
|
||||
}
|
||||
}
|
||||
|
||||
*/
|
||||
bool is_directory(const std::string& path) {
|
||||
DWORD attributes = GetFileAttributes(path.c_str());
|
||||
|
||||
if (attributes == INVALID_FILE_ATTRIBUTES) {
|
||||
// Handle the error, e.g., by printing an error message
|
||||
return false;
|
||||
}
|
||||
|
||||
return (attributes & FILE_ATTRIBUTE_DIRECTORY) != 0;
|
||||
}
|
||||
void process_changes(const FILE_NOTIFY_INFORMATION* pInfo) {
|
||||
// Allocate a buffer for the file name and copy the content
|
||||
std::wstring fileName(pInfo->FileName, pInfo->FileNameLength / sizeof(wchar_t));
|
||||
|
||||
//convert wstring to string
|
||||
std::string filename_str(fileName.begin(), fileName.end());
|
||||
filename_str = "c:\\" + filename_str;
|
||||
//scan the file and send it to virus_ctrl if it is a virus and then process it
|
||||
std::transform(filename_str.begin(), filename_str.end(), filename_str.begin(), ::tolower);
|
||||
if (!is_folder_included(filename_str.c_str()) or is_directory(filename_str.c_str()) or is_folder_excluded(filename_str.c_str())) {
|
||||
//dont scan excluded files or folders
|
||||
return;
|
||||
}
|
||||
else {
|
||||
std::thread scan_thread(scan_file_t, filename_str);
|
||||
scan_thread.detach();
|
||||
}
|
||||
//log(LOGLEVEL::INFO, "[process_changes()]: File change: ", filename_str.c_str(), " while monitoring directory for changes");
|
||||
}
|
||||
/* this was the old algorithm. it was slower and used up more resources, because it used a database to track which files have been modified instead of using the windows internal functions
|
||||
void monitor_directory(LPCSTR directory) {
|
||||
// Open the directory for monitoring
|
||||
HANDLE hDir = CreateFile(
|
||||
directory,
|
||||
FILE_LIST_DIRECTORY,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
|
||||
NULL,
|
||||
OPEN_EXISTING,
|
||||
FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED,
|
||||
NULL
|
||||
);
|
||||
|
||||
if (hDir == INVALID_HANDLE_VALUE) {
|
||||
log(LOGLEVEL::ERR, "[monitor_directory()]: Error opening directory: ", directory, " while monitoring directory for changes");
|
||||
return;
|
||||
}
|
||||
|
||||
// Create a buffer for file change notifications
|
||||
constexpr DWORD bufferSize = 4096;
|
||||
BYTE buffer[bufferSize];
|
||||
|
||||
// Monitor the directory for changes
|
||||
OVERLAPPED overlapped;
|
||||
memset(&overlapped, 0, sizeof(overlapped));
|
||||
overlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
|
||||
|
||||
if (ReadDirectoryChangesW(
|
||||
hDir,
|
||||
buffer,
|
||||
bufferSize,
|
||||
TRUE,
|
||||
FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_SIZE,
|
||||
NULL,
|
||||
&overlapped,
|
||||
NULL) == 0) {
|
||||
log(LOGLEVEL::ERR, "[monitor_directory()]: Error reading directory changes: ", GetLastError(), " while monitoring directory for changes");
|
||||
CloseHandle(hDir);
|
||||
return;
|
||||
}
|
||||
|
||||
log(LOGLEVEL::INFO, "[monitor_directory()]: Monitoring directory: ", directory, " for changes");
|
||||
//print_exclusions();
|
||||
|
||||
// Wait for changes
|
||||
while (true) {
|
||||
DWORD bytesReturned;
|
||||
if (GetOverlappedResult(hDir, &overlapped, &bytesReturned, TRUE)) {
|
||||
// Process the changes in the buffer
|
||||
FILE_NOTIFY_INFORMATION* pInfo = reinterpret_cast<FILE_NOTIFY_INFORMATION*>(buffer);
|
||||
|
||||
do {
|
||||
process_changes(pInfo);
|
||||
|
||||
pInfo = reinterpret_cast<FILE_NOTIFY_INFORMATION*>(
|
||||
reinterpret_cast<BYTE*>(pInfo) + pInfo->NextEntryOffset);
|
||||
|
||||
} while (pInfo->NextEntryOffset != 0);
|
||||
|
||||
// Reset the event for the next wait
|
||||
ResetEvent(overlapped.hEvent);
|
||||
|
||||
// Continue monitoring
|
||||
if (ReadDirectoryChangesW(
|
||||
hDir,
|
||||
buffer,
|
||||
bufferSize,
|
||||
TRUE,
|
||||
FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_SIZE,
|
||||
NULL,
|
||||
&overlapped,
|
||||
NULL) == 0) {
|
||||
log(LOGLEVEL::ERR, "[monitor_directory()]: Error reading directory changes: ", GetLastError(), " while monitoring directory for changes");
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
DWORD error = GetLastError();
|
||||
if (error != ERROR_IO_PENDING) {
|
||||
log(LOGLEVEL::ERR, "[monitor_directory()]: Error reading directory changes: ", error, " while monitoring directory for changes");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Wait for the event to be signaled (infinite timeout)
|
||||
WaitForSingleObject(overlapped.hEvent, INFINITE);
|
||||
}
|
||||
|
||||
// Cleanup
|
||||
CloseHandle(overlapped.hEvent);
|
||||
CloseHandle(hDir);
|
||||
}
|
||||
*/
|
||||
|
||||
void monitor_directory(LPCSTR directory) {
|
||||
// Open the directory for monitoring
|
||||
HANDLE hDir = CreateFile(
|
||||
directory,
|
||||
FILE_LIST_DIRECTORY,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE
|
||||
NULL,
|
||||
OPEN_EXISTING,
|
||||
FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED,
|
||||
NULL
|
||||
);
|
||||
|
||||
if (hDir == INVALID_HANDLE_VALUE) {
|
||||
log(LOGLEVEL::ERR, "[monitor_directory()]: Error opening directory: ", directory, " while monitoring directory for changes");
|
||||
return;
|
||||
}
|
||||
|
||||
// Create a buffer for file change notifications
|
||||
constexpr DWORD bufferSize = 4096;
|
||||
BYTE buffer[bufferSize];
|
||||
|
||||
// Monitor the directory for changes
|
||||
OVERLAPPED overlapped;
|
||||
memset(&overlapped, 0, sizeof(overlapped));
|
||||
memset(buffer, 0, bufferSize);
|
||||
overlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
|
||||
|
||||
if (ReadDirectoryChangesW(
|
||||
hDir,
|
||||
buffer,
|
||||
bufferSize,
|
||||
TRUE,
|
||||
FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_LAST_WRITE,
|
||||
NULL,
|
||||
&overlapped,
|
||||
NULL) == 0) {
|
||||
log(LOGLEVEL::ERR, "[monitor_directory()]: Error reading directory changes: ", GetLastError(), " while monitoring directory for changes");
|
||||
CloseHandle(hDir);
|
||||
return;
|
||||
}
|
||||
|
||||
log(LOGLEVEL::INFO, "[monitor_directory()]: Monitoring directory: ", directory, " for changes");
|
||||
|
||||
// Wait for changes
|
||||
while (!app_stop()) {
|
||||
DWORD bytesReturned;
|
||||
DWORD waitStatus = WaitForSingleObject(overlapped.hEvent, INFINITE);
|
||||
|
||||
if (waitStatus == WAIT_OBJECT_0) {
|
||||
if (GetOverlappedResult(hDir, &overlapped, &bytesReturned, FALSE)) {
|
||||
// Process the changes in the buffer
|
||||
FILE_NOTIFY_INFORMATION* pInfo = reinterpret_cast<FILE_NOTIFY_INFORMATION*>(buffer);
|
||||
|
||||
do {
|
||||
process_changes(pInfo);
|
||||
|
||||
pInfo = reinterpret_cast<FILE_NOTIFY_INFORMATION*>(
|
||||
reinterpret_cast<BYTE*>(pInfo) + pInfo->NextEntryOffset);
|
||||
|
||||
} while (pInfo->NextEntryOffset != 0);
|
||||
|
||||
// Reset the event for the next wait
|
||||
ResetEvent(overlapped.hEvent);
|
||||
memset(buffer, 0, bufferSize);
|
||||
|
||||
// Continue monitoring
|
||||
if (ReadDirectoryChangesW(
|
||||
hDir,
|
||||
buffer,
|
||||
bufferSize,
|
||||
TRUE,
|
||||
FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_LAST_WRITE,
|
||||
NULL,
|
||||
&overlapped,
|
||||
NULL) == 0) {
|
||||
log(LOGLEVEL::ERR, "[monitor_directory()]: Error reading directory changes: ", GetLastError(), " while monitoring directory for changes");
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
log(LOGLEVEL::ERR, "[monitor_directory()]: GetOverlappedResult failed: ", GetLastError());
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
log(LOGLEVEL::ERR, "[monitor_directory()]: WaitForSingleObject failed: ", GetLastError());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Cleanup
|
||||
CloseHandle(overlapped.hEvent);
|
||||
CloseHandle(hDir);
|
||||
}
|
||||
|
||||
void folder_scanner() {
|
||||
|
||||
//we are in a completely seperate thread then the main thread; unlimited resources wuhuii
|
||||
FILE*fp;
|
||||
char* path = new char[300];
|
||||
char* foldername = new char[300];
|
||||
|
||||
//start the watch dir function used to monitor the dir for new files
|
||||
monitor_directory("C:\\");
|
||||
|
||||
|
||||
delete[] path;
|
||||
delete[] foldername;
|
||||
}
|
||||
|
||||
#endif // !CHECK_DIR_CPP
|
||||
@@ -1,157 +0,0 @@
|
||||
#ifndef CHECK_DIR_CPP
|
||||
#define CHECK_DIR_CPP
|
||||
#include "check_dir.h"
|
||||
#include "well_known.h"
|
||||
#include "log.h"
|
||||
#include "md5hash.h"
|
||||
#include "scan.h"
|
||||
#include "app_ctrl.h"
|
||||
#include "virus_ctrl.h"
|
||||
#include "settings.h"
|
||||
#include <mutex> // Include the mutex header
|
||||
#include <algorithm> // Include the algorithm header
|
||||
#include <string> // Include the string header
|
||||
#include <iostream> // Include the iostream header
|
||||
|
||||
// Define a mutex for thread synchronization
|
||||
std::mutex monitorMutex;
|
||||
|
||||
bool is_directory(const std::string& path) {
|
||||
DWORD attributes = GetFileAttributes(path.c_str());
|
||||
|
||||
if (attributes == INVALID_FILE_ATTRIBUTES) {
|
||||
// Handle the error, e.g., by printing an error message
|
||||
return false;
|
||||
}
|
||||
|
||||
return (attributes & FILE_ATTRIBUTE_DIRECTORY) != 0;
|
||||
}
|
||||
|
||||
void process_changes(const FILE_NOTIFY_INFORMATION* pInfo) {
|
||||
// Allocate a buffer for the file name and copy the content
|
||||
std::wstring fileName(pInfo->FileName, pInfo->FileNameLength / sizeof(wchar_t));
|
||||
|
||||
// Convert wstring to string
|
||||
std::string filename_str(fileName.begin(), fileName.end());
|
||||
filename_str = "c:\\" + filename_str;
|
||||
|
||||
// Scan the file and send it to virus_ctrl if it is a virus and then process it
|
||||
if (is_valid_path(filename_str)) { //filter out invalid paths and paths with weird characters
|
||||
std::transform(filename_str.begin(), filename_str.end(), filename_str.begin(), ::tolower);
|
||||
if (!is_folder_included(filename_str.c_str()) || is_directory(filename_str) || is_folder_excluded(filename_str.c_str())) {
|
||||
// Don't scan excluded files or folders
|
||||
return;
|
||||
}
|
||||
else {
|
||||
//log(LOGLEVEL::INFO_NOSEND, "[process_changes()]: File ", filename_str, " has been changed. Scanning it for viruses");
|
||||
std::thread scan_thread(scan_file_t, filename_str);
|
||||
scan_thread.detach();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void monitor_directory(LPCSTR directory) {
|
||||
// Open the directory for monitoring
|
||||
HANDLE hDir = CreateFile(
|
||||
directory,
|
||||
FILE_LIST_DIRECTORY,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
|
||||
NULL,
|
||||
OPEN_EXISTING,
|
||||
FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED,
|
||||
NULL
|
||||
);
|
||||
|
||||
if (hDir == INVALID_HANDLE_VALUE) {
|
||||
log(LOGLEVEL::ERR, "[monitor_directory()]: Error opening directory: ", directory, " while monitoring directory for changes");
|
||||
return;
|
||||
}
|
||||
|
||||
// Create a buffer for file change notifications
|
||||
constexpr DWORD bufferSize = 4096;
|
||||
BYTE buffer[bufferSize];
|
||||
|
||||
// Monitor the directory for changes
|
||||
OVERLAPPED overlapped;
|
||||
memset(&overlapped, 0, sizeof(overlapped));
|
||||
memset(buffer, 0, bufferSize);
|
||||
overlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
|
||||
|
||||
if (ReadDirectoryChangesW(
|
||||
hDir,
|
||||
buffer,
|
||||
bufferSize,
|
||||
TRUE,
|
||||
FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_LAST_WRITE,
|
||||
NULL,
|
||||
&overlapped,
|
||||
NULL) == 0) {
|
||||
log(LOGLEVEL::ERR, "[monitor_directory()]: Error reading directory changes: ", GetLastError(), " while monitoring directory for changes");
|
||||
CloseHandle(hDir);
|
||||
return;
|
||||
}
|
||||
|
||||
log(LOGLEVEL::INFO, "[monitor_directory()]: Monitoring directory: ", directory, " for changes");
|
||||
|
||||
// Wait for changes
|
||||
while (!app_stop()) {
|
||||
DWORD bytesReturned;
|
||||
DWORD waitStatus = WaitForSingleObject(overlapped.hEvent, INFINITE);
|
||||
|
||||
if (waitStatus == WAIT_OBJECT_0) {
|
||||
if (GetOverlappedResult(hDir, &overlapped, &bytesReturned, FALSE)) {
|
||||
// Process the changes in the buffer
|
||||
FILE_NOTIFY_INFORMATION* pInfo = reinterpret_cast<FILE_NOTIFY_INFORMATION*>(buffer);
|
||||
|
||||
do {
|
||||
process_changes(pInfo);
|
||||
|
||||
pInfo = reinterpret_cast<FILE_NOTIFY_INFORMATION*>(
|
||||
reinterpret_cast<BYTE*>(pInfo) + pInfo->NextEntryOffset);
|
||||
|
||||
} while (pInfo->NextEntryOffset != 0);
|
||||
|
||||
// Reset the event for the next wait
|
||||
ResetEvent(overlapped.hEvent);
|
||||
memset(buffer, 0, bufferSize);
|
||||
|
||||
// Continue monitoring
|
||||
if (ReadDirectoryChangesW(
|
||||
hDir,
|
||||
buffer,
|
||||
bufferSize,
|
||||
TRUE,
|
||||
FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_CREATION,
|
||||
NULL,
|
||||
&overlapped,
|
||||
NULL) == 0) {
|
||||
log(LOGLEVEL::ERR, "[monitor_directory()]: Error reading directory changes: ", GetLastError(), " while monitoring directory for changes");
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
log(LOGLEVEL::ERR, "[monitor_directory()]: GetOverlappedResult failed: ", GetLastError());
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
log(LOGLEVEL::ERR, "[monitor_directory()]: WaitForSingleObject failed: ", GetLastError());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Cleanup
|
||||
CloseHandle(overlapped.hEvent);
|
||||
CloseHandle(hDir);
|
||||
}
|
||||
|
||||
void folder_scanner() {
|
||||
// Lock access to the monitor function
|
||||
std::lock_guard<std::mutex> lock(monitorMutex);
|
||||
|
||||
// We are in a completely separate thread than the main thread; unlimited resources wuhuii
|
||||
// Start the watch dir function used to monitor the dir for new files
|
||||
monitor_directory("C:\\");
|
||||
}
|
||||
|
||||
#endif // !CHECK_DIR_CPP
|
||||
@@ -1,370 +0,0 @@
|
||||
#ifndef CHECK_DIR_CPP
|
||||
#define CHECK_DIR_CPP
|
||||
#include "check_dir.h"
|
||||
#include "well_known.h"
|
||||
#include "log.h"
|
||||
#include "md5hash.h"
|
||||
#include "scan.h"
|
||||
#include "app_ctrl.h"
|
||||
#include "virus_ctrl.h"
|
||||
#include "scan.h"
|
||||
#include "settings.h"
|
||||
/* old implementation. used up a lot of resource and did not work properly.
|
||||
void add_to_temp_db(const char*hash) {
|
||||
//PERIODIC_FOLDER_SCAN_TEMP_DB
|
||||
FILE*fp;
|
||||
if (fopen_s(&fp, PERIODIC_FOLDER_SCAN_TEMP_DB, "a") != 0) {
|
||||
log(LOGLEVEL::ERR, "[add_to_temp_db()]: Error opening temp db: ", PERIODIC_FOLDER_SCAN_TEMP_DB);
|
||||
return;
|
||||
}
|
||||
else {
|
||||
//log(LOGLEVEL::INFO, "[add_to_temp_db()]: Adding hash: ", hash, " to temp db: ", PERIODIC_FOLDER_SCAN_TEMP_DB);
|
||||
fprintf_s(fp, "%s\n", hash);
|
||||
fclose(fp);
|
||||
}
|
||||
}
|
||||
void scan_folder_recursive(const std::string& directory, int thread_id,const std::string&db_file) {
|
||||
std::string search_path = directory + "\\*.*";
|
||||
WIN32_FIND_DATA find_file_data;
|
||||
HANDLE hFind = FindFirstFile(search_path.c_str(), &find_file_data);
|
||||
|
||||
if (hFind == INVALID_HANDLE_VALUE) {
|
||||
//std::cerr << "Error opening directory: " << directory << std::endl;
|
||||
log(LOGLEVEL::ERR, "[scan_folder_recursive()]: Error opening directory: ", directory ," while scanning folder for new files");
|
||||
return;
|
||||
}
|
||||
|
||||
do {
|
||||
if (strcmp(find_file_data.cFileName, ".") == 0 || strcmp(find_file_data.cFileName, "..") == 0) {
|
||||
continue; // Skip the current and parent directories
|
||||
}
|
||||
|
||||
|
||||
std::string full_path = directory + "\\" + find_file_data.cFileName;
|
||||
if (find_file_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
|
||||
// If it's a directory, recurse into it
|
||||
scan_folder_recursive(full_path, thread_id,db_file);
|
||||
}
|
||||
else {
|
||||
// If it's a file, check if it is in db, else scan it and add it to db
|
||||
char*hash = new char[300];
|
||||
md5_file(full_path.c_str(), hash);
|
||||
//now find hash in db
|
||||
if (scan_hash(db_file.c_str(), hash)==1) {
|
||||
//file is allready in db, skipping
|
||||
//in order to not keep hashes that are not present anymore in the db, we have to write this hash into a temp dir, which is at the end copied into the main db
|
||||
add_to_temp_db(hash);
|
||||
}
|
||||
else {
|
||||
//scan the file and add it to db
|
||||
//scan for virus
|
||||
|
||||
switch (scan_hash(hash)) {
|
||||
case 1:
|
||||
//virus found
|
||||
//log it
|
||||
log(LOGLEVEL::VIRUS, "[scan_folder_recursive()]: Virus found in file: ", full_path, " while scanning ", directory, " for new files");
|
||||
//virus_ctrl_store(full_path.c_str(), hash, "fs");
|
||||
break;
|
||||
case 2:
|
||||
//error
|
||||
log(LOGLEVEL::ERR, "[scan_folder_recursive()]: Error while scanning file: ", full_path, " while scanning ", directory, " for new files");
|
||||
break;
|
||||
default:
|
||||
//not a virus
|
||||
add_to_temp_db(hash);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
} while (FindNextFile(hFind, &find_file_data) != 0);
|
||||
|
||||
FindClose(hFind);
|
||||
}
|
||||
int check_scan_dir(char*dirpath,char*dirname) {
|
||||
if (can_scan_folder()) {
|
||||
scan_folder_init();
|
||||
//FOLDER_DATABASE_DIR <= the folder where the database for folder checking is stored
|
||||
//the database is stored in the following format:
|
||||
/* a file per folder (and its subfolders)
|
||||
in this db file the hashes of all the files in the folder (and its subfolders) are stored
|
||||
If a file is detected, which hash is not known, it gets scanned and added to the db. if a hash is inside the db, which is not present in the folder, the hash is rempved from the db
|
||||
|
||||
*/
|
||||
/*
|
||||
FILE* fp;
|
||||
char* path = new char[300];
|
||||
path[0] = '\0';
|
||||
//build up the path for the db file.
|
||||
strcpy_s(path, 295, FOLDER_DATABASE_DIR);
|
||||
strcat_s(path, 295, "\\");
|
||||
strcat_s(path, 295, dirname);
|
||||
strcat_s(path, 295, ".jdbf");
|
||||
|
||||
//check if the file exists. else we cannot scan the folder
|
||||
if ((fopen_s(&fp, path, "r")) != 0) {
|
||||
log(LOGLEVEL::ERR, "[check_scan_dir()]: Error opening database: ", path, " while scanning folder for new files; aborting");
|
||||
//try to create the file
|
||||
if (fopen_s(&fp, path, "w") != 0) {
|
||||
log(LOGLEVEL::ERR, "[check_scan_dir()]: Error creating new database: ", path, " while scanning folder for new files; aborting");
|
||||
}
|
||||
else {
|
||||
fprintf_s(fp, "%s\n", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA");//write A 32 times A into the file. So the algorithm ha ssomething to map into memory. else it might throw an error
|
||||
fclose(fp);
|
||||
}
|
||||
scan_folder_shutdown();
|
||||
return 1;
|
||||
}
|
||||
else {
|
||||
fclose(fp);
|
||||
//process the files of the folder.
|
||||
//first: calculate hash of file
|
||||
//second: check if hash is in db
|
||||
//if not, scan file and add it to db (only add it if it is not detected as a virus)
|
||||
scan_folder_recursive(dirpath, 0,path);
|
||||
//process the found viruses
|
||||
virus_ctrl_process("fs");
|
||||
}
|
||||
delete[] path;
|
||||
scan_folder_shutdown();
|
||||
return 0;
|
||||
}
|
||||
else {
|
||||
|
||||
//there is already a folder scan happening
|
||||
}
|
||||
}
|
||||
|
||||
*/
|
||||
bool is_directory(const std::string& path) {
|
||||
DWORD attributes = GetFileAttributes(path.c_str());
|
||||
|
||||
if (attributes == INVALID_FILE_ATTRIBUTES) {
|
||||
// Handle the error, e.g., by printing an error message
|
||||
return false;
|
||||
}
|
||||
|
||||
return (attributes & FILE_ATTRIBUTE_DIRECTORY) != 0;
|
||||
}
|
||||
void process_changes(const FILE_NOTIFY_INFORMATION* pInfo) {
|
||||
// Allocate a buffer for the file name and copy the content
|
||||
std::wstring fileName(pInfo->FileName, pInfo->FileNameLength / sizeof(wchar_t));
|
||||
|
||||
//convert wstring to string
|
||||
std::string filename_str(fileName.begin(), fileName.end());
|
||||
filename_str = "c:\\" + filename_str;
|
||||
//scan the file and send it to virus_ctrl if it is a virus and then process it
|
||||
std::transform(filename_str.begin(), filename_str.end(), filename_str.begin(), ::tolower);
|
||||
if (is_folder_excluded(filename_str.c_str()) or is_directory(filename_str.c_str())) {
|
||||
//dont scan excluded files
|
||||
return;
|
||||
}else
|
||||
action_scanfile(filename_str.c_str());
|
||||
log(LOGLEVEL::INFO, "[process_changes()]: File change: ", filename_str.c_str(), " while monitoring directory for changes");
|
||||
}
|
||||
/*
|
||||
void monitor_directory(LPCSTR directory) {
|
||||
// Open the directory for monitoring
|
||||
HANDLE hDir = CreateFile(
|
||||
directory,
|
||||
FILE_LIST_DIRECTORY,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
|
||||
NULL,
|
||||
OPEN_EXISTING,
|
||||
FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED,
|
||||
NULL
|
||||
);
|
||||
|
||||
if (hDir == INVALID_HANDLE_VALUE) {
|
||||
log(LOGLEVEL::ERR, "[monitor_directory()]: Error opening directory: ", directory, " while monitoring directory for changes");
|
||||
return;
|
||||
}
|
||||
|
||||
// Create a buffer for file change notifications
|
||||
constexpr DWORD bufferSize = 4096;
|
||||
BYTE buffer[bufferSize];
|
||||
|
||||
// Monitor the directory for changes
|
||||
OVERLAPPED overlapped;
|
||||
memset(&overlapped, 0, sizeof(overlapped));
|
||||
overlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
|
||||
|
||||
if (ReadDirectoryChangesW(
|
||||
hDir,
|
||||
buffer,
|
||||
bufferSize,
|
||||
TRUE,
|
||||
FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_SIZE,
|
||||
NULL,
|
||||
&overlapped,
|
||||
NULL) == 0) {
|
||||
log(LOGLEVEL::ERR, "[monitor_directory()]: Error reading directory changes: ", GetLastError(), " while monitoring directory for changes");
|
||||
CloseHandle(hDir);
|
||||
return;
|
||||
}
|
||||
|
||||
log(LOGLEVEL::INFO, "[monitor_directory()]: Monitoring directory: ", directory, " for changes");
|
||||
//print_exclusions();
|
||||
|
||||
// Wait for changes
|
||||
while (true) {
|
||||
DWORD bytesReturned;
|
||||
if (GetOverlappedResult(hDir, &overlapped, &bytesReturned, TRUE)) {
|
||||
// Process the changes in the buffer
|
||||
FILE_NOTIFY_INFORMATION* pInfo = reinterpret_cast<FILE_NOTIFY_INFORMATION*>(buffer);
|
||||
|
||||
do {
|
||||
process_changes(pInfo);
|
||||
|
||||
pInfo = reinterpret_cast<FILE_NOTIFY_INFORMATION*>(
|
||||
reinterpret_cast<BYTE*>(pInfo) + pInfo->NextEntryOffset);
|
||||
|
||||
} while (pInfo->NextEntryOffset != 0);
|
||||
|
||||
// Reset the event for the next wait
|
||||
ResetEvent(overlapped.hEvent);
|
||||
|
||||
// Continue monitoring
|
||||
if (ReadDirectoryChangesW(
|
||||
hDir,
|
||||
buffer,
|
||||
bufferSize,
|
||||
TRUE,
|
||||
FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_SIZE,
|
||||
NULL,
|
||||
&overlapped,
|
||||
NULL) == 0) {
|
||||
log(LOGLEVEL::ERR, "[monitor_directory()]: Error reading directory changes: ", GetLastError(), " while monitoring directory for changes");
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
DWORD error = GetLastError();
|
||||
if (error != ERROR_IO_PENDING) {
|
||||
log(LOGLEVEL::ERR, "[monitor_directory()]: Error reading directory changes: ", error, " while monitoring directory for changes");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Wait for the event to be signaled (infinite timeout)
|
||||
WaitForSingleObject(overlapped.hEvent, INFINITE);
|
||||
}
|
||||
|
||||
// Cleanup
|
||||
CloseHandle(overlapped.hEvent);
|
||||
CloseHandle(hDir);
|
||||
}
|
||||
*/
|
||||
|
||||
void monitor_directory(LPCSTR directory) {
|
||||
// Open the directory for monitoring
|
||||
HANDLE hDir = CreateFile(
|
||||
directory,
|
||||
FILE_LIST_DIRECTORY,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
|
||||
NULL,
|
||||
OPEN_EXISTING,
|
||||
FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED,
|
||||
NULL
|
||||
);
|
||||
|
||||
if (hDir == INVALID_HANDLE_VALUE) {
|
||||
log(LOGLEVEL::ERR, "[monitor_directory()]: Error opening directory: ", directory, " while monitoring directory for changes");
|
||||
return;
|
||||
}
|
||||
|
||||
// Create a buffer for file change notifications
|
||||
constexpr DWORD bufferSize = 4096;
|
||||
BYTE buffer[bufferSize];
|
||||
|
||||
// Monitor the directory for changes
|
||||
OVERLAPPED overlapped;
|
||||
memset(&overlapped, 0, sizeof(overlapped));
|
||||
memset(buffer, 0, bufferSize);
|
||||
overlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
|
||||
|
||||
if (ReadDirectoryChangesW(
|
||||
hDir,
|
||||
buffer,
|
||||
bufferSize,
|
||||
TRUE,
|
||||
FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_LAST_WRITE,
|
||||
NULL,
|
||||
&overlapped,
|
||||
NULL) == 0) {
|
||||
log(LOGLEVEL::ERR, "[monitor_directory()]: Error reading directory changes: ", GetLastError(), " while monitoring directory for changes");
|
||||
CloseHandle(hDir);
|
||||
return;
|
||||
}
|
||||
|
||||
std::cout << "[monitor_directory()]: Monitoring directory: " << directory << " for changes" << std::endl;
|
||||
|
||||
// Wait for changes
|
||||
while (!app_stop()) {
|
||||
DWORD bytesReturned;
|
||||
DWORD waitStatus = WaitForSingleObject(overlapped.hEvent, INFINITE);
|
||||
|
||||
if (waitStatus == WAIT_OBJECT_0) {
|
||||
if (GetOverlappedResult(hDir, &overlapped, &bytesReturned, FALSE)) {
|
||||
// Process the changes in the buffer
|
||||
FILE_NOTIFY_INFORMATION* pInfo = reinterpret_cast<FILE_NOTIFY_INFORMATION*>(buffer);
|
||||
|
||||
do {
|
||||
process_changes(pInfo);
|
||||
|
||||
pInfo = reinterpret_cast<FILE_NOTIFY_INFORMATION*>(
|
||||
reinterpret_cast<BYTE*>(pInfo) + pInfo->NextEntryOffset);
|
||||
|
||||
} while (pInfo->NextEntryOffset != 0);
|
||||
|
||||
// Reset the event for the next wait
|
||||
ResetEvent(overlapped.hEvent);
|
||||
memset(buffer, 0, bufferSize);
|
||||
|
||||
// Continue monitoring
|
||||
if (ReadDirectoryChangesW(
|
||||
hDir,
|
||||
buffer,
|
||||
bufferSize,
|
||||
TRUE,
|
||||
FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_LAST_WRITE,
|
||||
NULL,
|
||||
&overlapped,
|
||||
NULL) == 0) {
|
||||
log(LOGLEVEL::ERR, "[monitor_directory()]: Error reading directory changes: ", GetLastError(), " while monitoring directory for changes");
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
log(LOGLEVEL::ERR, "[monitor_directory()]: GetOverlappedResult failed: ", GetLastError());
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
log(LOGLEVEL::ERR, "[monitor_directory()]: WaitForSingleObject failed: ", GetLastError());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Cleanup
|
||||
CloseHandle(overlapped.hEvent);
|
||||
CloseHandle(hDir);
|
||||
}
|
||||
|
||||
void folder_scanner() {
|
||||
|
||||
//we are in a completely seperate thread then the main thread; unlimited resources wuhuii
|
||||
FILE*fp;
|
||||
char* path = new char[300];
|
||||
char* foldername = new char[300];
|
||||
|
||||
//start the watch dir function used to monitor the dir for new files
|
||||
monitor_directory("C:\\");
|
||||
|
||||
|
||||
delete[] path;
|
||||
delete[] foldername;
|
||||
}
|
||||
|
||||
#endif // !CHECK_DIR_CPP
|
||||
@@ -1,360 +0,0 @@
|
||||
#ifndef CHECK_DIR_CPP
|
||||
#define CHECK_DIR_CPP
|
||||
#include "check_dir.h"
|
||||
#include "well_known.h"
|
||||
#include "log.h"
|
||||
#include "md5hash.h"
|
||||
#include "scan.h"
|
||||
#include "app_ctrl.h"
|
||||
#include "virus_ctrl.h"
|
||||
#include "scan.h"
|
||||
#include "settings.h"
|
||||
/* old implementation. used up a lot of resource and did not work properly.
|
||||
void add_to_temp_db(const char*hash) {
|
||||
//PERIODIC_FOLDER_SCAN_TEMP_DB
|
||||
FILE*fp;
|
||||
if (fopen_s(&fp, PERIODIC_FOLDER_SCAN_TEMP_DB, "a") != 0) {
|
||||
log(LOGLEVEL::ERR, "[add_to_temp_db()]: Error opening temp db: ", PERIODIC_FOLDER_SCAN_TEMP_DB);
|
||||
return;
|
||||
}
|
||||
else {
|
||||
//log(LOGLEVEL::INFO, "[add_to_temp_db()]: Adding hash: ", hash, " to temp db: ", PERIODIC_FOLDER_SCAN_TEMP_DB);
|
||||
fprintf_s(fp, "%s\n", hash);
|
||||
fclose(fp);
|
||||
}
|
||||
}
|
||||
void scan_folder_recursive(const std::string& directory, int thread_id,const std::string&db_file) {
|
||||
std::string search_path = directory + "\\*.*";
|
||||
WIN32_FIND_DATA find_file_data;
|
||||
HANDLE hFind = FindFirstFile(search_path.c_str(), &find_file_data);
|
||||
|
||||
if (hFind == INVALID_HANDLE_VALUE) {
|
||||
//std::cerr << "Error opening directory: " << directory << std::endl;
|
||||
log(LOGLEVEL::ERR, "[scan_folder_recursive()]: Error opening directory: ", directory ," while scanning folder for new files");
|
||||
return;
|
||||
}
|
||||
|
||||
do {
|
||||
if (strcmp(find_file_data.cFileName, ".") == 0 || strcmp(find_file_data.cFileName, "..") == 0) {
|
||||
continue; // Skip the current and parent directories
|
||||
}
|
||||
|
||||
|
||||
std::string full_path = directory + "\\" + find_file_data.cFileName;
|
||||
if (find_file_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
|
||||
// If it's a directory, recurse into it
|
||||
scan_folder_recursive(full_path, thread_id,db_file);
|
||||
}
|
||||
else {
|
||||
// If it's a file, check if it is in db, else scan it and add it to db
|
||||
char*hash = new char[300];
|
||||
md5_file(full_path.c_str(), hash);
|
||||
//now find hash in db
|
||||
if (scan_hash(db_file.c_str(), hash)==1) {
|
||||
//file is allready in db, skipping
|
||||
//in order to not keep hashes that are not present anymore in the db, we have to write this hash into a temp dir, which is at the end copied into the main db
|
||||
add_to_temp_db(hash);
|
||||
}
|
||||
else {
|
||||
//scan the file and add it to db
|
||||
//scan for virus
|
||||
|
||||
switch (scan_hash(hash)) {
|
||||
case 1:
|
||||
//virus found
|
||||
//log it
|
||||
log(LOGLEVEL::VIRUS, "[scan_folder_recursive()]: Virus found in file: ", full_path, " while scanning ", directory, " for new files");
|
||||
//virus_ctrl_store(full_path.c_str(), hash, "fs");
|
||||
break;
|
||||
case 2:
|
||||
//error
|
||||
log(LOGLEVEL::ERR, "[scan_folder_recursive()]: Error while scanning file: ", full_path, " while scanning ", directory, " for new files");
|
||||
break;
|
||||
default:
|
||||
//not a virus
|
||||
add_to_temp_db(hash);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
} while (FindNextFile(hFind, &find_file_data) != 0);
|
||||
|
||||
FindClose(hFind);
|
||||
}
|
||||
int check_scan_dir(char*dirpath,char*dirname) {
|
||||
if (can_scan_folder()) {
|
||||
scan_folder_init();
|
||||
//FOLDER_DATABASE_DIR <= the folder where the database for folder checking is stored
|
||||
//the database is stored in the following format:
|
||||
/* a file per folder (and its subfolders)
|
||||
in this db file the hashes of all the files in the folder (and its subfolders) are stored
|
||||
If a file is detected, which hash is not known, it gets scanned and added to the db. if a hash is inside the db, which is not present in the folder, the hash is rempved from the db
|
||||
|
||||
*/
|
||||
/*
|
||||
FILE* fp;
|
||||
char* path = new char[300];
|
||||
path[0] = '\0';
|
||||
//build up the path for the db file.
|
||||
strcpy_s(path, 295, FOLDER_DATABASE_DIR);
|
||||
strcat_s(path, 295, "\\");
|
||||
strcat_s(path, 295, dirname);
|
||||
strcat_s(path, 295, ".jdbf");
|
||||
|
||||
//check if the file exists. else we cannot scan the folder
|
||||
if ((fopen_s(&fp, path, "r")) != 0) {
|
||||
log(LOGLEVEL::ERR, "[check_scan_dir()]: Error opening database: ", path, " while scanning folder for new files; aborting");
|
||||
//try to create the file
|
||||
if (fopen_s(&fp, path, "w") != 0) {
|
||||
log(LOGLEVEL::ERR, "[check_scan_dir()]: Error creating new database: ", path, " while scanning folder for new files; aborting");
|
||||
}
|
||||
else {
|
||||
fprintf_s(fp, "%s\n", "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA");//write A 32 times A into the file. So the algorithm ha ssomething to map into memory. else it might throw an error
|
||||
fclose(fp);
|
||||
}
|
||||
scan_folder_shutdown();
|
||||
return 1;
|
||||
}
|
||||
else {
|
||||
fclose(fp);
|
||||
//process the files of the folder.
|
||||
//first: calculate hash of file
|
||||
//second: check if hash is in db
|
||||
//if not, scan file and add it to db (only add it if it is not detected as a virus)
|
||||
scan_folder_recursive(dirpath, 0,path);
|
||||
//process the found viruses
|
||||
virus_ctrl_process("fs");
|
||||
}
|
||||
delete[] path;
|
||||
scan_folder_shutdown();
|
||||
return 0;
|
||||
}
|
||||
else {
|
||||
|
||||
//there is already a folder scan happening
|
||||
}
|
||||
}
|
||||
|
||||
*/
|
||||
void process_changes(const FILE_NOTIFY_INFORMATION* pInfo) {
|
||||
// Allocate a buffer for the file name and copy the content
|
||||
std::wstring fileName(pInfo->FileName, pInfo->FileNameLength / sizeof(wchar_t));
|
||||
|
||||
// Print information about the changed file or directory
|
||||
|
||||
//convert wstring to string
|
||||
std::string filename_str(fileName.begin(), fileName.end());
|
||||
filename_str = "c:\\" + filename_str;
|
||||
//scan the file and send it to virus_ctrl if it is a virus and then process it
|
||||
std::transform(filename_str.begin(), filename_str.end(), filename_str.begin(), ::tolower);
|
||||
if (is_folder_excluded(filename_str.c_str())) {
|
||||
//dont scan excluded files
|
||||
return;
|
||||
}else
|
||||
action_scanfile(filename_str.c_str());
|
||||
log(LOGLEVEL::INFO, "[process_changes()]: File change: ", filename_str.c_str(), " while monitoring directory for changes");
|
||||
}
|
||||
/*
|
||||
void monitor_directory(LPCSTR directory) {
|
||||
// Open the directory for monitoring
|
||||
HANDLE hDir = CreateFile(
|
||||
directory,
|
||||
FILE_LIST_DIRECTORY,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
|
||||
NULL,
|
||||
OPEN_EXISTING,
|
||||
FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED,
|
||||
NULL
|
||||
);
|
||||
|
||||
if (hDir == INVALID_HANDLE_VALUE) {
|
||||
log(LOGLEVEL::ERR, "[monitor_directory()]: Error opening directory: ", directory, " while monitoring directory for changes");
|
||||
return;
|
||||
}
|
||||
|
||||
// Create a buffer for file change notifications
|
||||
constexpr DWORD bufferSize = 4096;
|
||||
BYTE buffer[bufferSize];
|
||||
|
||||
// Monitor the directory for changes
|
||||
OVERLAPPED overlapped;
|
||||
memset(&overlapped, 0, sizeof(overlapped));
|
||||
overlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
|
||||
|
||||
if (ReadDirectoryChangesW(
|
||||
hDir,
|
||||
buffer,
|
||||
bufferSize,
|
||||
TRUE,
|
||||
FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_SIZE,
|
||||
NULL,
|
||||
&overlapped,
|
||||
NULL) == 0) {
|
||||
log(LOGLEVEL::ERR, "[monitor_directory()]: Error reading directory changes: ", GetLastError(), " while monitoring directory for changes");
|
||||
CloseHandle(hDir);
|
||||
return;
|
||||
}
|
||||
|
||||
log(LOGLEVEL::INFO, "[monitor_directory()]: Monitoring directory: ", directory, " for changes");
|
||||
//print_exclusions();
|
||||
|
||||
// Wait for changes
|
||||
while (true) {
|
||||
DWORD bytesReturned;
|
||||
if (GetOverlappedResult(hDir, &overlapped, &bytesReturned, TRUE)) {
|
||||
// Process the changes in the buffer
|
||||
FILE_NOTIFY_INFORMATION* pInfo = reinterpret_cast<FILE_NOTIFY_INFORMATION*>(buffer);
|
||||
|
||||
do {
|
||||
process_changes(pInfo);
|
||||
|
||||
pInfo = reinterpret_cast<FILE_NOTIFY_INFORMATION*>(
|
||||
reinterpret_cast<BYTE*>(pInfo) + pInfo->NextEntryOffset);
|
||||
|
||||
} while (pInfo->NextEntryOffset != 0);
|
||||
|
||||
// Reset the event for the next wait
|
||||
ResetEvent(overlapped.hEvent);
|
||||
|
||||
// Continue monitoring
|
||||
if (ReadDirectoryChangesW(
|
||||
hDir,
|
||||
buffer,
|
||||
bufferSize,
|
||||
TRUE,
|
||||
FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_SIZE,
|
||||
NULL,
|
||||
&overlapped,
|
||||
NULL) == 0) {
|
||||
log(LOGLEVEL::ERR, "[monitor_directory()]: Error reading directory changes: ", GetLastError(), " while monitoring directory for changes");
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
DWORD error = GetLastError();
|
||||
if (error != ERROR_IO_PENDING) {
|
||||
log(LOGLEVEL::ERR, "[monitor_directory()]: Error reading directory changes: ", error, " while monitoring directory for changes");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Wait for the event to be signaled (infinite timeout)
|
||||
WaitForSingleObject(overlapped.hEvent, INFINITE);
|
||||
}
|
||||
|
||||
// Cleanup
|
||||
CloseHandle(overlapped.hEvent);
|
||||
CloseHandle(hDir);
|
||||
}
|
||||
*/
|
||||
|
||||
void monitor_directory(LPCSTR directory) {
|
||||
// Open the directory for monitoring
|
||||
HANDLE hDir = CreateFile(
|
||||
directory,
|
||||
FILE_LIST_DIRECTORY,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
|
||||
NULL,
|
||||
OPEN_EXISTING,
|
||||
FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED,
|
||||
NULL
|
||||
);
|
||||
|
||||
if (hDir == INVALID_HANDLE_VALUE) {
|
||||
std::cerr << "[monitor_directory()]: Error opening directory: " << directory << " while monitoring directory for changes" << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
// Create a buffer for file change notifications
|
||||
constexpr DWORD bufferSize = 4096;
|
||||
BYTE buffer[bufferSize];
|
||||
|
||||
// Monitor the directory for changes
|
||||
OVERLAPPED overlapped;
|
||||
memset(&overlapped, 0, sizeof(overlapped));
|
||||
overlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
|
||||
|
||||
if (ReadDirectoryChangesW(
|
||||
hDir,
|
||||
buffer,
|
||||
bufferSize,
|
||||
TRUE,
|
||||
FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_SIZE,
|
||||
NULL,
|
||||
&overlapped,
|
||||
NULL) == 0) {
|
||||
std::cerr << "[monitor_directory()]: Error reading directory changes: " << GetLastError() << " while monitoring directory for changes" << std::endl;
|
||||
CloseHandle(hDir);
|
||||
return;
|
||||
}
|
||||
|
||||
std::cout << "[monitor_directory()]: Monitoring directory: " << directory << " for changes" << std::endl;
|
||||
|
||||
// Wait for changes
|
||||
while (!app_stop()) {
|
||||
DWORD bytesReturned;
|
||||
DWORD waitStatus = WaitForSingleObject(overlapped.hEvent, INFINITE);
|
||||
|
||||
if (waitStatus == WAIT_OBJECT_0) {
|
||||
if (GetOverlappedResult(hDir, &overlapped, &bytesReturned, FALSE)) {
|
||||
// Process the changes in the buffer
|
||||
FILE_NOTIFY_INFORMATION* pInfo = reinterpret_cast<FILE_NOTIFY_INFORMATION*>(buffer);
|
||||
|
||||
do {
|
||||
process_changes(pInfo);
|
||||
|
||||
pInfo = reinterpret_cast<FILE_NOTIFY_INFORMATION*>(
|
||||
reinterpret_cast<BYTE*>(pInfo) + pInfo->NextEntryOffset);
|
||||
|
||||
} while (pInfo->NextEntryOffset != 0);
|
||||
|
||||
// Reset the event for the next wait
|
||||
ResetEvent(overlapped.hEvent);
|
||||
|
||||
// Continue monitoring
|
||||
if (ReadDirectoryChangesW(
|
||||
hDir,
|
||||
buffer,
|
||||
bufferSize,
|
||||
TRUE,
|
||||
FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_LAST_WRITE,
|
||||
NULL,
|
||||
&overlapped,
|
||||
NULL) == 0) {
|
||||
std::cerr << "[monitor_directory()]: Error reading directory changes: " << GetLastError() << " while monitoring directory for changes" << std::endl;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
std::cerr << "[monitor_directory()]: Error reading directory changes: " << GetLastError() << " while monitoring directory for changes" << std::endl;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
std::cerr << "[monitor_directory()]: WaitForSingleObject failed: " << GetLastError() << std::endl;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Cleanup
|
||||
CloseHandle(overlapped.hEvent);
|
||||
CloseHandle(hDir);
|
||||
}
|
||||
|
||||
void folder_scanner() {
|
||||
|
||||
//we are in a completely seperate thread then the main thread; unlimited resources wuhuii
|
||||
FILE*fp;
|
||||
char* path = new char[300];
|
||||
char* foldername = new char[300];
|
||||
|
||||
//start the watch dir function used to monitor the dir for new files
|
||||
monitor_directory("C:\\");
|
||||
|
||||
|
||||
delete[] path;
|
||||
delete[] foldername;
|
||||
}
|
||||
|
||||
#endif // !CHECK_DIR_CPP
|
||||
@@ -1,76 +0,0 @@
|
||||
#include "check_process.h"
|
||||
#include "log.h"
|
||||
#include "well_known.h"
|
||||
#include "scan.h"
|
||||
#include "app_ctrl.h"
|
||||
#include "settings.h"
|
||||
#include "scan.h"
|
||||
|
||||
void monitor_processes() {
|
||||
static DWORD previousProcessIds[1024] = { 0 }; // Previous snapshot of process IDs
|
||||
DWORD processIds[1024];
|
||||
DWORD bytesReturned;
|
||||
|
||||
// Get the list of process IDs
|
||||
if (EnumProcesses(processIds, sizeof(processIds), &bytesReturned)) {
|
||||
// Calculate how many process IDs were returned
|
||||
DWORD numProcesses = bytesReturned / sizeof(DWORD);
|
||||
|
||||
// Check for new processes
|
||||
log(LOGLEVEL::INFO_NOSEND, "[monitor_processes()]: Checking for new processes; having ",numProcesses, " currently running");
|
||||
for (DWORD i = 0; i < numProcesses; ++i) {
|
||||
DWORD processId = processIds[i];
|
||||
BOOL isNewProcess = TRUE;
|
||||
|
||||
// Check if the process is new
|
||||
for (DWORD j = 0; j < 1024; ++j) {
|
||||
if (processId == previousProcessIds[j]) {
|
||||
isNewProcess = FALSE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// If the process is new, get its executable path and print it
|
||||
if (isNewProcess) {
|
||||
// Open the process
|
||||
HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, processId);
|
||||
if (hProcess != NULL) {
|
||||
// Get the full path of the executable
|
||||
TCHAR exePath[MAX_PATH];
|
||||
char path[MAX_PATH+1];
|
||||
if (GetModuleFileNameEx(hProcess, NULL, exePath, MAX_PATH) > 0) {
|
||||
// Print the full path of the executable
|
||||
strcpy_s(path, MAX_PATH, exePath);
|
||||
//convert to lower case
|
||||
for(int z=0;z<strlen(path);z++)
|
||||
path[z] = tolower(path[z]);
|
||||
//scan the file
|
||||
if (!is_folder_included(path) or is_folder_excluded(path)) {
|
||||
//dont scan excluded files or folders
|
||||
}
|
||||
else {
|
||||
//log(LOGLEVEL::INFO, "[monitor_processes()]: New Process to scan: ", path, " while monitoring processes");
|
||||
std::thread scan_thread(scan_process_t, path);
|
||||
scan_thread.detach();
|
||||
}
|
||||
}
|
||||
// Close the process handle
|
||||
CloseHandle(hProcess);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Update the previous snapshot of process IDs
|
||||
memcpy(previousProcessIds, processIds, sizeof(DWORD) * 1024);
|
||||
}
|
||||
else {
|
||||
log(LOGLEVEL::ERR, "[monitor_processes()]: Error enumerating processes");
|
||||
}
|
||||
}
|
||||
void process_scanner() {
|
||||
//we are in a thread so we can do this, unlimited resources wuhuiii
|
||||
while (!app_stop()) {
|
||||
monitor_processes();
|
||||
Sleep(1000); // Sleep for 1 second
|
||||
}
|
||||
}
|
||||
@@ -1,106 +0,0 @@
|
||||
#pragma warning(disable:4996)
|
||||
#include <iostream>
|
||||
#include <thread>
|
||||
#include <curl/curl.h>
|
||||
#include <openssl/md5.h>
|
||||
//#include <yara.h>
|
||||
#include "app_ctrl.h"
|
||||
#include "md5hash.h"
|
||||
#include "connect.h"
|
||||
#include "scan.h"
|
||||
#include "queue_ctrl.h"
|
||||
#include "well_known.h"
|
||||
#include "local_com.h"
|
||||
#include "local_schedule.h"
|
||||
#include "log.h"
|
||||
#include "thread_ctrl.h"
|
||||
#include "settings.h"
|
||||
#include "check_dir.h"
|
||||
#include "virus_ctrl.h"
|
||||
int main() {
|
||||
log(LOGLEVEL::INFO, "[main()]:Starting main thread.");
|
||||
printf("welcome to the jakach security tool main thread\n");
|
||||
load_settings();
|
||||
initialize(DB_DIR);
|
||||
//start a second thread which will scan for new files
|
||||
if (get_setting("rtp:status") == 1) {
|
||||
log(LOGLEVEL::INFO, "[main()]:Starting real time protection.");
|
||||
std::thread folder_scannner_thread(folder_scanner);
|
||||
folder_scannner_thread.detach();
|
||||
}
|
||||
|
||||
//main thread:
|
||||
/* watches for notifications on bus
|
||||
* start threads (scans etc); only one at a time may run
|
||||
* updates settings etc
|
||||
* start scheduled tasks
|
||||
|
||||
|
||||
*/
|
||||
while (!app_stop()) {
|
||||
//run all the tasks described above
|
||||
//check for tasks in com
|
||||
//check for scheduled tasks
|
||||
//execute tasks
|
||||
//call_srv("8.8.8.8","","");
|
||||
auto start = std::chrono::high_resolution_clock::now();
|
||||
// printf("check_from_com:%d\n",check_for_com_tasks(MAIN_COM, MAIN_COM_PATH));
|
||||
check_for_com_tasks(MAIN_COM, MAIN_COM_PATH);
|
||||
check_for_sched_tasks(SCHED, SCHED_PATH);
|
||||
// printf("check_from_task:%d\n", check_for_sched_tasks(SCHED,SCHED_PATH));
|
||||
//unlock_task("tsk1"); else it will only be executed once. but this function has to be called at the end of the task. else it will nvr be executed again. this would be bad :(
|
||||
//start a thread that executes check_scan_dir to scan folders for new files. this thread then should start a ock so only one scanfolder thread runs at a time
|
||||
//Sleep(1000);
|
||||
if (can_run_thread()) {
|
||||
int queue_size = get_queue_size();
|
||||
for (int i = 0; i < queue_size; i++) {
|
||||
char* queue_entry = new char[300 * 2 + 5];
|
||||
queue_entry[0] = '\0';
|
||||
queue_pop(queue_entry);
|
||||
//execute the function which starts the threads
|
||||
// printf("%s\n", queue_entry);
|
||||
start_thread(queue_entry);
|
||||
delete[] queue_entry;
|
||||
}
|
||||
}
|
||||
//to ensure that the loop takes at least 1 second else it will run too fast nd destroy you CPU :)
|
||||
auto stop = std::chrono::high_resolution_clock::now();
|
||||
auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(stop - start);
|
||||
if (duration.count() < 1000)
|
||||
Sleep(1000 - duration.count());
|
||||
|
||||
// printf("\n\n\n");
|
||||
}
|
||||
|
||||
|
||||
|
||||
//ListFilesRecursive("C:\\", 0);
|
||||
/*char md5Hash[2 * MD5_DIGEST_LENGTH + 1]; // +1 for null-terminator
|
||||
printf("Hash of the executable: ");
|
||||
md5_file("C:\\Users\\janis\\Documents\\Projekte_mit_c\\ma\\ma\\src\\client_backend\\x64\\Debug\\client_backend.exe", md5Hash);
|
||||
printf("%s", md5Hash);
|
||||
char a_[2000];
|
||||
printf("\nerror:%d\n",connect_to_srv("https://self-signed.badssl.com/", a_, 2000,1)); //error 60: self signed => option f<>r self-signed ignorieren aktivieren (bool ignore_invalid=true)
|
||||
printf("%s", a_); //error 6: not reachable
|
||||
download_file_from_srv("https://jakach.duckdns.org/php/login/v3/login.php", "c:\\programdata\\jakach\\out12.txt");
|
||||
/*
|
||||
const int numThreads = 12;
|
||||
std::thread threads[numThreads];
|
||||
|
||||
for (int i = 0; i < numThreads; ++i) {
|
||||
threads[i] = std::thread(ListFilesRecursive, "C:\\Users\\janis\\Documents\\ma_av_tests",i);
|
||||
}
|
||||
|
||||
// Join threads to wait for them to finish
|
||||
for (int i = 0; i < numThreads; ++i) {
|
||||
threads[i].join();
|
||||
}
|
||||
|
||||
std::cout << "All threads have finished." << std::endl;
|
||||
*/
|
||||
|
||||
//printf("code:%d",scan_hash("C:\\Users\\janis\\Documents\\ma_av_tests\\OutputFile.txt", "1fddc13c02a79442c911a44b02ee0f58"));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1,101 +0,0 @@
|
||||
#pragma warning(disable:4996)
|
||||
#include <iostream>
|
||||
#include <thread>
|
||||
#include <curl/curl.h>
|
||||
#include <openssl/md5.h>
|
||||
//#include <yara.h>
|
||||
#include "app_ctrl.h"
|
||||
#include "md5hash.h"
|
||||
#include "connect.h"
|
||||
#include "scan.h"
|
||||
#include "queue_ctrl.h"
|
||||
#include "well_known.h"
|
||||
#include "local_com.h"
|
||||
#include "local_schedule.h"
|
||||
#include "log.h"
|
||||
#include "thread_ctrl.h"
|
||||
#include "settings.h"
|
||||
#include "check_dir.h"
|
||||
int main() {
|
||||
printf("welcome to the jakach security tool main thread\n");
|
||||
load_settings();
|
||||
//start a second thread which will scan for new files
|
||||
std::thread folder_scannner_thread(folder_scanner);
|
||||
//
|
||||
//
|
||||
//main thread:
|
||||
/* watches for notifications on bus
|
||||
* start threads (scans etc); only one at a time may run
|
||||
* updates settings etc
|
||||
* start scheduled tasks
|
||||
|
||||
|
||||
*/
|
||||
|
||||
while (!app_stop()) {
|
||||
//run all the tasks described above
|
||||
//check for tasks in com
|
||||
//check for scheduled tasks
|
||||
//execute tasks
|
||||
//call_srv("8.8.8.8","","");
|
||||
auto start = std::chrono::high_resolution_clock::now();
|
||||
// printf("check_from_com:%d\n",check_for_com_tasks(MAIN_COM, MAIN_COM_PATH));
|
||||
// printf("check_from_task:%d\n", check_for_sched_tasks(SCHED,SCHED_PATH));
|
||||
//unlock_task("tsk1"); else it will only be executed once. but this function has to be called at the end of the task. else it will nvr be executed again. this would be bad :(
|
||||
//start a thread that executes check_scan_dir to scan folders for new files. this thread then should start a ock so only one scanfolder thread runs at a time
|
||||
//Sleep(1000);
|
||||
if (can_run_thread()) {
|
||||
int queue_size = get_queue_size();
|
||||
for (int i = 0; i < queue_size; i++) {
|
||||
char* queue_entry = new char[300 * 2 + 5];
|
||||
queue_entry[0] = '\0';
|
||||
queue_pop(queue_entry);
|
||||
//execute the function which starts the threads
|
||||
// printf("%s\n", queue_entry);
|
||||
start_thread(queue_entry);
|
||||
delete[] queue_entry;
|
||||
}
|
||||
}
|
||||
//to ensure that the loop takes at least 1 second else it will run too fast nd destroy you CPU :)
|
||||
auto stop = std::chrono::high_resolution_clock::now();
|
||||
auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(stop - start);
|
||||
if (duration.count() < 1000)
|
||||
Sleep(1000 - duration.count());
|
||||
|
||||
// printf("\n\n\n");
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//ListFilesRecursive("C:\\", 0);
|
||||
/*char md5Hash[2 * MD5_DIGEST_LENGTH + 1]; // +1 for null-terminator
|
||||
printf("Hash of the executable: ");
|
||||
md5_file("C:\\Users\\janis\\Documents\\Projekte_mit_c\\ma\\ma\\src\\client_backend\\x64\\Debug\\client_backend.exe", md5Hash);
|
||||
printf("%s", md5Hash);
|
||||
char a_[2000];
|
||||
printf("\nerror:%d\n",connect_to_srv("https://self-signed.badssl.com/", a_, 2000,1)); //error 60: self signed => option f<>r self-signed ignorieren aktivieren (bool ignore_invalid=true)
|
||||
printf("%s", a_); //error 6: not reachable
|
||||
download_file_from_srv("https://jakach.duckdns.org/php/login/v3/login.php", "c:\\programdata\\jakach\\out12.txt");
|
||||
/*
|
||||
const int numThreads = 12;
|
||||
std::thread threads[numThreads];
|
||||
|
||||
for (int i = 0; i < numThreads; ++i) {
|
||||
threads[i] = std::thread(ListFilesRecursive, "C:\\Users\\janis\\Documents\\ma_av_tests",i);
|
||||
}
|
||||
|
||||
// Join threads to wait for them to finish
|
||||
for (int i = 0; i < numThreads; ++i) {
|
||||
threads[i].join();
|
||||
}
|
||||
|
||||
std::cout << "All threads have finished." << std::endl;
|
||||
*/
|
||||
|
||||
//printf("code:%d",scan_hash("C:\\Users\\janis\\Documents\\ma_av_tests\\OutputFile.txt", "1fddc13c02a79442c911a44b02ee0f58"));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1,116 +0,0 @@
|
||||
#pragma warning(disable:4996)
|
||||
#include <iostream>
|
||||
#include <thread>
|
||||
#include <curl/curl.h>
|
||||
#include <openssl/md5.h>
|
||||
//#include <yara.h>
|
||||
#include "app_ctrl.h"
|
||||
#include "md5hash.h"
|
||||
#include "connect.h"
|
||||
#include "scan.h"
|
||||
#include "queue_ctrl.h"
|
||||
#include "well_known.h"
|
||||
#include "local_com.h"
|
||||
#include "local_schedule.h"
|
||||
#include "log.h"
|
||||
#include "thread_ctrl.h"
|
||||
#include "settings.h"
|
||||
#include "check_dir.h"
|
||||
#include "virus_ctrl.h"
|
||||
#include "update.h"
|
||||
#include "check_process.h"
|
||||
int main() {
|
||||
//log(LOGLEVEL::INFO, "[main()]:Starting main thread.");
|
||||
//return 0;
|
||||
|
||||
log(LOGLEVEL::INFO_NOSEND, "[main()]:Starting main thread.");
|
||||
int err = 0;
|
||||
printf("welcome to the jakach security tool main thread\n");
|
||||
if (load_settings() == 0) {//load the settings from the settings file
|
||||
if (update_settings("settings")!=0) { //update the settings from the server
|
||||
log(LOGLEVEL::ERR_NOSEND, "[main()]:Could not update settings (settings) from server.");
|
||||
}
|
||||
if (update_settings("rtp_included")!=0) { //update the settings from the server
|
||||
log(LOGLEVEL::ERR_NOSEND, "[main()]:Could not update settings (rtp_included) from server.");
|
||||
}
|
||||
if (update_settings("rtp_excluded")!=0) { //update the settings from the server
|
||||
log(LOGLEVEL::ERR_NOSEND, "[main()]:Could not update settings (rtp_excluded) from server.");
|
||||
}
|
||||
if (update_settings("sched")!=0) { //update the settings from the server
|
||||
log(LOGLEVEL::ERR_NOSEND, "[main()]:Could not update settings (scheduled_tasks) from server.");
|
||||
}
|
||||
load_settings(); //load the updated settings from the settings file
|
||||
}
|
||||
else {
|
||||
log(LOGLEVEL::ERR_NOSEND, "[main()]:Could not load settings from file.");
|
||||
log(LOGLEVEL::PANIC_NOSEND, "[main()]:Panic, no settings file loaded, terminating process!");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// Initialize hash databases
|
||||
err = initialize(DB_DIR);
|
||||
if (err != 0) {
|
||||
switch (err) {
|
||||
case 1:
|
||||
log(LOGLEVEL::ERR, "[main()]:Error opening database file in: ", DB_DIR);
|
||||
break;
|
||||
case 2:
|
||||
log(LOGLEVEL::ERR, "[main()]:Error creating database file mapping in: ", DB_DIR);
|
||||
break;
|
||||
case 3:
|
||||
log(LOGLEVEL::ERR, "[main()]:Error mapping database file in: ", DB_DIR);
|
||||
break;
|
||||
default:
|
||||
log(LOGLEVEL::ERR, "[main()]:Unknown error while loading database file in: ", DB_DIR);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Start a second thread for real-time protection
|
||||
if (get_setting("rtp_folder_scan:status") == 1) {
|
||||
log(LOGLEVEL::INFO, "[main()]:Starting real time file protection.");
|
||||
std::thread folder_scanner_thread(folder_scanner);
|
||||
folder_scanner_thread.detach();
|
||||
}
|
||||
if (get_setting("rtp_process_scan:status") == 1) {
|
||||
log(LOGLEVEL::INFO, "[main()]:Starting real time process protection.");
|
||||
std::thread process_scanner_thread(process_scanner);
|
||||
process_scanner_thread.detach();
|
||||
}
|
||||
|
||||
// Main thread loop
|
||||
while (!app_stop()) {
|
||||
auto start = std::chrono::high_resolution_clock::now();
|
||||
|
||||
// Check for tasks from user interface
|
||||
if (check_for_com_tasks(MAIN_COM, MAIN_COM_PATH) != 0) {
|
||||
// Log message commented out as this error is expected when the file doesn't exist
|
||||
// log(LOGLEVEL::ERR, "[main()]:Error opening communication file in: ", MAIN_COM_PATH);
|
||||
}
|
||||
|
||||
// Check for scheduled tasks
|
||||
if (check_for_sched_tasks(SCHED, SCHED_PATH) != 0) {
|
||||
log(LOGLEVEL::ERR, "[main()]:Error opening schedule file in: ", SCHED_PATH);
|
||||
}
|
||||
|
||||
// Execute tasks from the queue
|
||||
if (can_run_thread()) {
|
||||
int queue_size = get_queue_size();
|
||||
for (int i = 0; i < queue_size; i++) {
|
||||
char* queue_entry = new char[300 * 2 + 5];
|
||||
queue_entry[0] = '\0';
|
||||
queue_pop(queue_entry);
|
||||
start_thread(queue_entry);
|
||||
delete[] queue_entry;
|
||||
}
|
||||
}
|
||||
|
||||
// Sleep to ensure loop takes at least 1 second
|
||||
auto stop = std::chrono::high_resolution_clock::now();
|
||||
auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(stop - start);
|
||||
if (duration.count() < 1000)
|
||||
Sleep(1000 - duration.count());
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,242 +0,0 @@
|
||||
#pragma warning(disable:4996)
|
||||
#ifndef CONNECT_CPP
|
||||
#define CONNECT_CPP
|
||||
|
||||
#include "connect.h"
|
||||
#include "well_known.h"
|
||||
#include "security.h"
|
||||
#include <curl/curl.h>
|
||||
#include <string>
|
||||
#include <mutex>
|
||||
std::mutex connect_mutex;
|
||||
|
||||
//this function is thread safe
|
||||
int fast_send(const std::string& url, bool ignore_insecure) {
|
||||
std::lock_guard<std::mutex> lock(connect_mutex);
|
||||
thread_local const std::string url_ = url;
|
||||
thread_local const bool ignore_insecure_ = ignore_insecure;
|
||||
thread_local CURL* curl;
|
||||
thread_local CURLcode res;
|
||||
curl = curl_easy_init();
|
||||
if (curl) {
|
||||
curl_easy_setopt(curl, CURLOPT_URL, url_.c_str());
|
||||
if (ignore_insecure_)
|
||||
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
|
||||
curl_easy_setopt(curl, CURLOPT_TIMEOUT, 1L);
|
||||
res = curl_easy_perform(curl);
|
||||
curl_easy_cleanup(curl);
|
||||
if (res == CURLE_OK) {
|
||||
return 0;
|
||||
}
|
||||
else {
|
||||
return res;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static size_t write_callback_connect(void* contents, size_t size, size_t nmemb, void* userp) {
|
||||
((std::string*)userp)->append((char*)contents, size * nmemb);
|
||||
return size * nmemb;
|
||||
}
|
||||
//make this multi thread safe
|
||||
int connect_to_srv(const std::string& url, char* out, int max_len, bool ignore_insecure) {
|
||||
CURL* curl;
|
||||
CURLcode res;
|
||||
std::string readBuffer;
|
||||
|
||||
curl = curl_easy_init();
|
||||
if (curl) {
|
||||
curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
|
||||
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_callback_connect);
|
||||
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &readBuffer);
|
||||
if (ignore_insecure)
|
||||
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
|
||||
res = curl_easy_perform(curl);
|
||||
curl_easy_cleanup(curl);
|
||||
if (max_len > (int)readBuffer.length()) {
|
||||
strcpy(out, readBuffer.c_str());
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
return 1;
|
||||
}
|
||||
return 2;
|
||||
}
|
||||
|
||||
size_t write_callback_download(void* contents, size_t size, size_t nmemb, void* userp) {
|
||||
size_t totalSize = size * nmemb;
|
||||
FILE* file = (FILE*)userp;
|
||||
if (file) {
|
||||
fwrite(contents, 1, totalSize, file);
|
||||
}
|
||||
return totalSize;
|
||||
}
|
||||
|
||||
int download_file_from_srv(const std::string& url, const std::string& output_file_path, bool ignore_insecure, bool do_not_check_cyberhex_cert) {
|
||||
char* temp_path = new char[output_file_path.size() + 6];
|
||||
strcpy(temp_path, output_file_path.c_str());
|
||||
strcat(temp_path, ".temp");
|
||||
|
||||
CURL* curl;
|
||||
CURLcode res;
|
||||
FILE* output_file;
|
||||
|
||||
curl = curl_easy_init();
|
||||
if (!curl) {
|
||||
delete[] temp_path;
|
||||
return 1;
|
||||
}
|
||||
|
||||
curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
|
||||
|
||||
output_file = fopen(temp_path, "wb");
|
||||
if (!output_file) {
|
||||
curl_easy_cleanup(curl);
|
||||
delete[] temp_path;
|
||||
return 2;
|
||||
}
|
||||
|
||||
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_callback_download);
|
||||
curl_easy_setopt(curl, CURLOPT_WRITEDATA, output_file);
|
||||
if (ignore_insecure)
|
||||
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
|
||||
|
||||
res = curl_easy_perform(curl);
|
||||
if (res != CURLE_OK) {
|
||||
fclose(output_file);
|
||||
delete[] temp_path;
|
||||
return 3;
|
||||
}
|
||||
|
||||
curl_easy_cleanup(curl);
|
||||
fclose(output_file);
|
||||
|
||||
if ((output_file = fopen(temp_path, "r")) == 0) {
|
||||
delete[] temp_path;
|
||||
return 4;
|
||||
}
|
||||
else {
|
||||
char buf[501];
|
||||
fscanf(output_file, "%500s", buf);
|
||||
if (strcmp(buf, "no_auth") == 0) {
|
||||
fclose(output_file);
|
||||
delete[] temp_path;
|
||||
return 5;
|
||||
}
|
||||
else if (check_cert(buf, SECRETS) == 0 or do_not_check_cyberhex_cert==true) {
|
||||
remove(output_file_path.c_str());
|
||||
fclose(output_file);
|
||||
if (rename(temp_path, output_file_path.c_str()) != 0) {
|
||||
delete[] temp_path;
|
||||
return 6;
|
||||
}
|
||||
}
|
||||
else {
|
||||
fclose(output_file);
|
||||
delete[] temp_path;
|
||||
return 7;
|
||||
}
|
||||
}
|
||||
|
||||
delete[] temp_path;
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::string url_encode(const std::string& input) {
|
||||
static const char* const safe_chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_.~";
|
||||
std::string encoded;
|
||||
for (char c : input) {
|
||||
if (std::strchr(safe_chars, c) != nullptr) {
|
||||
encoded += c;
|
||||
}
|
||||
else {
|
||||
char temp[4];
|
||||
sprintf(temp, "%%%02X", (unsigned char)c);
|
||||
encoded += temp;
|
||||
}
|
||||
}
|
||||
return encoded;
|
||||
}
|
||||
|
||||
int upload_to_srv(const std::string& url, const std::string& filepath, bool ignore_insecure) {
|
||||
CURL* curl;
|
||||
CURLcode res;
|
||||
struct curl_httppost* formpost = nullptr;
|
||||
struct curl_httppost* lastptr = nullptr;
|
||||
struct curl_slist* headerlist = nullptr;
|
||||
static const char buf[] = "Expect:";
|
||||
|
||||
curl_global_init(CURL_GLOBAL_ALL);
|
||||
curl_formadd(&formpost, &lastptr, CURLFORM_COPYNAME, "file", CURLFORM_FILE, filepath.c_str(), CURLFORM_END);
|
||||
|
||||
curl = curl_easy_init();
|
||||
if (curl) {
|
||||
curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
|
||||
if (ignore_insecure)
|
||||
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
|
||||
headerlist = curl_slist_append(headerlist, buf);
|
||||
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headerlist);
|
||||
curl_easy_setopt(curl, CURLOPT_HTTPPOST, formpost);
|
||||
res = curl_easy_perform(curl);
|
||||
curl_easy_cleanup(curl);
|
||||
curl_formfree(formpost);
|
||||
curl_slist_free_all(headerlist);
|
||||
if (res == CURLE_OK) {
|
||||
return 0;
|
||||
}
|
||||
else {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 2;
|
||||
}
|
||||
int send_to_pipe(const std::string& message) {
|
||||
HANDLE hPipe;
|
||||
DWORD dwRead;
|
||||
DWORD dwWritten;
|
||||
hPipe = CreateFile(TEXT("\\\\.\\pipe\\cyberhex_pipe"),
|
||||
GENERIC_READ | GENERIC_WRITE,
|
||||
0,
|
||||
NULL,
|
||||
OPEN_EXISTING,
|
||||
0,
|
||||
NULL);
|
||||
if (hPipe != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
WriteFile(hPipe,
|
||||
message.c_str(),
|
||||
strlen(message.c_str()) + 1, // = length of string + terminating '\0' !!!
|
||||
&dwWritten,
|
||||
NULL);
|
||||
CloseHandle(hPipe);
|
||||
return 0;
|
||||
}
|
||||
else {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
std::string read_from_pipe() {
|
||||
HANDLE hPipe;
|
||||
DWORD dwRead;
|
||||
DWORD dwWritten;
|
||||
char buffer[1000];
|
||||
hPipe = CreateFile(TEXT("\\\\.\\pipe\\cyberhex_pipe"),
|
||||
GENERIC_READ | GENERIC_WRITE,
|
||||
0,
|
||||
NULL,
|
||||
OPEN_EXISTING,
|
||||
0,
|
||||
NULL);
|
||||
if (hPipe != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
ReadFile(hPipe, buffer, sizeof(buffer), &dwRead, NULL);
|
||||
CloseHandle(hPipe);
|
||||
buffer[strlen(buffer)+1]= '\0';
|
||||
return std::string(buffer);
|
||||
}
|
||||
else {
|
||||
return "Error";
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -1,36 +0,0 @@
|
||||
#pragma warning(disable:4996)
|
||||
#include "md5hash.h"
|
||||
#include "log.h"
|
||||
int md5_file(const char*path,char*md5Hash) {
|
||||
std::ifstream file(path, std::ios::binary);
|
||||
|
||||
if (!file) {
|
||||
log(LOGLEVEL::ERR, "[md5_file()]: Could not open file for scanning ",path);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Initialize OpenSSL's MD5 context
|
||||
MD5_CTX md5Context;
|
||||
MD5_Init(&md5Context);
|
||||
|
||||
// Read and update the context with the file's content
|
||||
char buffer[1024];
|
||||
while (file.good()) {
|
||||
file.read(buffer, sizeof(buffer));
|
||||
MD5_Update(&md5Context, buffer, file.gcount());
|
||||
}
|
||||
|
||||
// Finalize the MD5 hash and store it in result
|
||||
unsigned char result[MD5_DIGEST_LENGTH];
|
||||
MD5_Final(result, &md5Context);
|
||||
|
||||
// Close the file
|
||||
file.close();
|
||||
|
||||
// Store the MD5 hash in a char array
|
||||
//char md5Hash[2 * MD5_DIGEST_LENGTH + 1]; // +1 for null-terminator
|
||||
|
||||
for (int i = 0; i < MD5_DIGEST_LENGTH; i++) {
|
||||
snprintf(&md5Hash[i * 2], 3, "%02x", result[i]);
|
||||
}
|
||||
}
|
||||
@@ -1,209 +0,0 @@
|
||||
#include "scan.h"
|
||||
#include <windows.h>
|
||||
#include <iostream>
|
||||
#include <openssl/md5.h>
|
||||
#include <windows.h>
|
||||
#include <iostream>
|
||||
#include <thread>
|
||||
#include <chrono>
|
||||
#include <time.h>
|
||||
#include "md5hash.h"
|
||||
#include <string>
|
||||
#include "well_known.h"
|
||||
#include "log.h"
|
||||
#include "virus_ctrl.h"
|
||||
#include "app_ctrl.h"
|
||||
#ifndef SCAN_CPP
|
||||
#define SCAN_CPP
|
||||
std::unordered_map<std::string, HANDLE> fileHandles;
|
||||
std::unordered_map<std::string, HANDLE> mappingHandles;
|
||||
std::unordered_map<std::string, char*> fileData;
|
||||
|
||||
int cnt = 0;
|
||||
int num_threads=0;
|
||||
|
||||
//load all the db files into memory
|
||||
void initialize(const std::string& folderPath) {
|
||||
for (char firstChar = '0'; firstChar <= 'f'; ++firstChar) {
|
||||
for (char secondChar = '0'; secondChar <= 'f'; ++secondChar) {
|
||||
// Ensure that the characters are valid hexadecimal digits
|
||||
if (!std::isxdigit(firstChar) || !std::isxdigit(secondChar) or std::isupper(firstChar) or std::isupper(secondChar)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Create the filename based on the naming convention
|
||||
std::string filename = folderPath +"\\" + firstChar + secondChar + ".jdbf";
|
||||
//printf("Loading %s\n", filename.c_str());
|
||||
|
||||
// Open the file
|
||||
HANDLE hFile = CreateFile(filename.c_str(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
if (hFile == INVALID_HANDLE_VALUE) {
|
||||
log(LOGLEVEL::ERR, "[initialize()]: Error opening database file: ", filename);
|
||||
continue; // Move on to the next file if there's an error
|
||||
}
|
||||
|
||||
// Create the file mapping
|
||||
HANDLE hMapping = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL);
|
||||
if (hMapping == NULL) {
|
||||
log(LOGLEVEL::ERR, "[initialize()]: Error creating database file mapping: ", filename);
|
||||
CloseHandle(hFile);
|
||||
continue; // Move on to the next file if there's an error
|
||||
}
|
||||
|
||||
// Map the file into memory
|
||||
char* fileDataPtr = static_cast<char*>(MapViewOfFile(hMapping, FILE_MAP_READ, 0, 0, 0));
|
||||
if (fileDataPtr == NULL) {
|
||||
log(LOGLEVEL::ERR, "[initialize()]: Error mapping database file: ", filename);
|
||||
CloseHandle(hMapping);
|
||||
CloseHandle(hFile);
|
||||
continue; // Move on to the next file if there's an error
|
||||
}
|
||||
|
||||
// Store the handles in the global maps
|
||||
fileHandles[filename] = hFile;
|
||||
mappingHandles[filename] = hMapping;
|
||||
fileData[filename] = fileDataPtr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Call this function when you are done using the file mappings
|
||||
void cleanup() {
|
||||
for (const auto& entry : fileHandles) {
|
||||
UnmapViewOfFile(fileData[entry.first]);
|
||||
CloseHandle(mappingHandles[entry.first]);
|
||||
CloseHandle(entry.second);
|
||||
}
|
||||
|
||||
// Clear the global maps
|
||||
fileHandles.clear();
|
||||
mappingHandles.clear();
|
||||
fileData.clear();
|
||||
}
|
||||
//the latest and fastest version of searching a hash by now
|
||||
int search_hash(const std::string& dbname_, const std::string& hash_, const std::string& filepath_) {
|
||||
// Check if the file mapping is already open for the given filename
|
||||
thread_local std::string dbname (dbname_);
|
||||
thread_local std::string hash (hash_);
|
||||
thread_local std::string filepath (filepath_);
|
||||
|
||||
thread_local auto fileIter = fileHandles.find(dbname);
|
||||
if (fileIter == fileHandles.end() or dbname_.find("c:.jdbf") != std::string::npos) {
|
||||
log(LOGLEVEL::ERR, "[search_hash()]: File mapping not initialized for ", dbname);
|
||||
return 2;
|
||||
}
|
||||
|
||||
// Use fileData for subsequent searches
|
||||
thread_local DWORD fileSize = GetFileSize(fileHandles[dbname], NULL);
|
||||
thread_local std::string fileContent(fileData[dbname], fileSize);
|
||||
|
||||
// Search for the specific string in the file content
|
||||
thread_local size_t foundPos = fileContent.find(hash);
|
||||
if (foundPos != std::string::npos) {
|
||||
log(LOGLEVEL::VIRUS, "[search_hash()]: Found virus: ", hash, " in file: ", filepath);
|
||||
virus_ctrl_store(filepath.c_str(), hash.c_str(), hash.c_str());
|
||||
//afterwards do the processing with that file
|
||||
virus_ctrl_process(hash.c_str());
|
||||
return 1; // Found
|
||||
}
|
||||
return 0; // Not found
|
||||
}
|
||||
bool file_exists(const std::string& filePath) {
|
||||
DWORD fileAttributes = GetFileAttributes(filePath.c_str());
|
||||
|
||||
if (fileAttributes == INVALID_FILE_ATTRIBUTES) {
|
||||
// The file does not exist or there was an error
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check if it's a regular file and not a directory
|
||||
return (fileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0;
|
||||
}
|
||||
|
||||
//this is the main function to scan folders. it will then start multuiple threads based on the number of cores / settings
|
||||
void scan_folder(const std::string& directory) {
|
||||
std::string search_path = directory + "\\*.*";
|
||||
WIN32_FIND_DATA find_file_data;
|
||||
HANDLE hFind = FindFirstFile(search_path.c_str(), &find_file_data);
|
||||
|
||||
if (hFind == INVALID_HANDLE_VALUE) {
|
||||
log(LOGLEVEL::ERR, "[scan_folder()]: Error opening directory: ", search_path.c_str() , " while scanning files inside folder.");
|
||||
return;
|
||||
}
|
||||
|
||||
do {
|
||||
if (strcmp(find_file_data.cFileName, ".") == 0 || strcmp(find_file_data.cFileName, "..") == 0) {
|
||||
continue; // Skip the current and parent directories
|
||||
}
|
||||
|
||||
|
||||
const std::string full_path = directory + "\\" + find_file_data.cFileName;
|
||||
if (find_file_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
|
||||
// If it's a directory, recurse into it
|
||||
scan_folder(full_path);
|
||||
}
|
||||
else {
|
||||
//action scanfile_t will start the trheads for scanning the hashes
|
||||
//action_scanfile_t(full_path.c_str());
|
||||
|
||||
//do multithreading here
|
||||
while (num_threads >= std::thread::hardware_concurrency()) {
|
||||
Sleep(10);
|
||||
}
|
||||
num_threads++;
|
||||
std::thread scan_thread(scan_file_t, full_path);
|
||||
scan_thread.detach();
|
||||
|
||||
cnt++;
|
||||
if (cnt % 100 == 0) {
|
||||
printf("Processed %d files;\n", cnt);
|
||||
//printf("Number of threads: %d\n", num_threads);
|
||||
}
|
||||
}
|
||||
} while (FindNextFile(hFind, &find_file_data) != 0);
|
||||
|
||||
FindClose(hFind);
|
||||
}
|
||||
|
||||
|
||||
|
||||
//for singlethreaded scans
|
||||
void action_scanfile(const char*filepath) {
|
||||
thread_init();
|
||||
char* db_path = new char[300];
|
||||
|
||||
//log(LOGLEVEL::INFO, "[action_scanfile_t()]: Scanning file: ", filepath);
|
||||
if (strlen(filepath) == 0 or strcmp("", filepath) == 0 or file_exists(filepath) == false) {
|
||||
thread_shutdown();
|
||||
return; //no filepath given or file not accessible
|
||||
}
|
||||
else {
|
||||
char* hash = new char[300];
|
||||
hash[0] = '\0';
|
||||
strcpy_s(hash, 295, md5_file_t(filepath).c_str());
|
||||
sprintf_s(db_path, 295, "%s\\%c%c.jdbf", DB_DIR, hash[0], hash[1]);
|
||||
search_hash(db_path, hash, filepath);
|
||||
delete[] hash;
|
||||
}
|
||||
delete[] db_path;
|
||||
thread_shutdown();
|
||||
}
|
||||
void action_scanfolder(const char*folderpath) {
|
||||
thread_init();
|
||||
cnt = 0;
|
||||
thread_local std::string folderpath_ (folderpath);
|
||||
scan_folder(folderpath_);
|
||||
thread_shutdown();
|
||||
}
|
||||
|
||||
void scan_file_t(const std::string& filepath_) {
|
||||
thread_local const std::string filepath (filepath_);
|
||||
thread_local char* db_path = new char[300];
|
||||
thread_local char* hash = new char[300];
|
||||
strcpy_s(hash,295 ,md5_file_t(filepath).c_str());
|
||||
sprintf_s(db_path, 295, "%s\\%c%c.jdbf", DB_DIR, hash[0], hash[1]);
|
||||
search_hash(db_path, hash, filepath);
|
||||
num_threads--;
|
||||
}
|
||||
#endif
|
||||
@@ -1,312 +0,0 @@
|
||||
#ifndef SCAN_CPP
|
||||
#define SCAN_CPP
|
||||
#include "scan.h"
|
||||
#include <windows.h>
|
||||
#include <iostream>
|
||||
#include <openssl/md5.h>
|
||||
#include <windows.h>
|
||||
#include <iostream>
|
||||
#include <thread>
|
||||
#include <chrono>
|
||||
#include <time.h>
|
||||
#include "md5hash.h"
|
||||
#include <string>
|
||||
#include "well_known.h"
|
||||
#include "log.h"
|
||||
#include "virus_ctrl.h"
|
||||
#include "app_ctrl.h"
|
||||
#include <mutex> // Include the mutex header
|
||||
#include <filesystem>
|
||||
#include "utils.h"
|
||||
|
||||
// Define mutexes for thread synchronization
|
||||
std::mutex fileHandlesMutex;
|
||||
std::mutex mappingHandlesMutex;
|
||||
std::mutex fileDataMutex;
|
||||
std::mutex cntMutex;
|
||||
std::mutex numThreadsMutex;
|
||||
|
||||
std::unordered_map<std::string, HANDLE> fileHandles;
|
||||
std::unordered_map<std::string, HANDLE> mappingHandles;
|
||||
std::unordered_map<std::string, char*> fileData;
|
||||
|
||||
int cnt = 0;
|
||||
int num_threads = 0;
|
||||
|
||||
//load all the db files into memory
|
||||
int initialize(const std::string& folderPath) {
|
||||
for (char firstChar = '0'; firstChar <= 'f'; ++firstChar) {
|
||||
for (char secondChar = '0'; secondChar <= 'f'; ++secondChar) {
|
||||
// Ensure that the characters are valid hexadecimal digits
|
||||
if (!std::isxdigit(firstChar) || !std::isxdigit(secondChar) or std::isupper(firstChar) or std::isupper(secondChar)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Create the filename based on the naming convention
|
||||
std::string filename = folderPath + "\\" + firstChar + secondChar + ".jdbf";
|
||||
//printf("Loading %s\n", filename.c_str());
|
||||
|
||||
// Open the file
|
||||
HANDLE hFile = CreateFile(filename.c_str(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
if (hFile == INVALID_HANDLE_VALUE) {
|
||||
//log(LOGLEVEL::ERR, "[initialize()]: Error opening database file: ", filename);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Create the file mapping
|
||||
HANDLE hMapping = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL);
|
||||
if (hMapping == NULL) {
|
||||
// log(LOGLEVEL::ERR, "[initialize()]: Error creating database file mapping: ", filename);
|
||||
CloseHandle(hFile);
|
||||
return 2;
|
||||
}
|
||||
|
||||
// Map the file into memory
|
||||
char* fileDataPtr = static_cast<char*>(MapViewOfFile(hMapping, FILE_MAP_READ, 0, 0, 0));
|
||||
if (fileDataPtr == NULL) {
|
||||
//log(LOGLEVEL::ERR, "[initialize()]: Error mapping database file: ", filename);
|
||||
CloseHandle(hMapping);
|
||||
CloseHandle(hFile);
|
||||
return 3;
|
||||
}
|
||||
|
||||
// Store the handles in the global maps
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(fileHandlesMutex);
|
||||
fileHandles[filename] = hFile;
|
||||
}
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mappingHandlesMutex);
|
||||
mappingHandles[filename] = hMapping;
|
||||
}
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(fileDataMutex);
|
||||
fileData[filename] = fileDataPtr;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Call this function when you are done using the file mappings
|
||||
void cleanup() {
|
||||
for (const auto& entry : fileHandles) {
|
||||
UnmapViewOfFile(fileData[entry.first]);
|
||||
CloseHandle(mappingHandles[entry.first]);
|
||||
CloseHandle(entry.second);
|
||||
}
|
||||
|
||||
// Clear the global maps
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(fileHandlesMutex);
|
||||
fileHandles.clear();
|
||||
}
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mappingHandlesMutex);
|
||||
mappingHandles.clear();
|
||||
}
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(fileDataMutex);
|
||||
fileData.clear();
|
||||
}
|
||||
}
|
||||
|
||||
//the latest and fastest version of searching a hash by now
|
||||
int search_hash(const std::string& dbname_, const std::string& hash_, const std::string& filepath_) {
|
||||
// Check if the file mapping is already open for the given filename
|
||||
std::string dbname;
|
||||
std::string hash;
|
||||
std::string filepath;
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(fileHandlesMutex);
|
||||
dbname = dbname_;
|
||||
}
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(fileDataMutex);
|
||||
hash = hash_;
|
||||
}
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mappingHandlesMutex);
|
||||
filepath = filepath_;
|
||||
}
|
||||
|
||||
auto fileIter = fileHandles.find(dbname);
|
||||
if (fileIter == fileHandles.end() && dbname_.find("c:.jdbf") == std::string::npos) {
|
||||
log(LOGLEVEL::ERR_NOSEND, "[search_hash()]: File mapping not initialized for ", dbname);
|
||||
return 2;
|
||||
}
|
||||
else if (fileIter == fileHandles.end()) {
|
||||
return 2;
|
||||
}
|
||||
|
||||
// Use fileData for subsequent searches
|
||||
DWORD fileSize;
|
||||
std::string fileContent;
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(fileDataMutex);
|
||||
fileSize = GetFileSize(fileHandles[dbname], NULL);
|
||||
fileContent = std::string(fileData[dbname], fileSize);
|
||||
}
|
||||
|
||||
// Search for the specific string in the file content
|
||||
size_t foundPos = fileContent.find(hash);
|
||||
if (foundPos != std::string::npos) {
|
||||
//log(LOGLEVEL::VIRUS, "[search_hash()]: Found virus: ", hash, " in file: ", filepath);
|
||||
virus_ctrl_store(filepath.c_str(), hash.c_str(), hash.c_str());
|
||||
//afterwards do the processing with that file
|
||||
virus_ctrl_process(hash.c_str());
|
||||
return 1; // Found
|
||||
}
|
||||
return 0; // Not found
|
||||
}
|
||||
|
||||
|
||||
bool file_exists(const std::string& filePath) {
|
||||
DWORD fileAttributes = GetFileAttributes(filePath.c_str());
|
||||
|
||||
if (fileAttributes == INVALID_FILE_ATTRIBUTES) {
|
||||
// The file does not exist or there was an error
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check if it's a regular file and not a directory
|
||||
return (fileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0;
|
||||
}
|
||||
|
||||
//this is the main function to scan folders. it will then start multuiple threads based on the number of cores / settings
|
||||
void scan_folder(const std::string& directory) {
|
||||
std::string search_path = directory + "\\*.*";
|
||||
WIN32_FIND_DATA find_file_data;
|
||||
HANDLE hFind = FindFirstFile(search_path.c_str(), &find_file_data);
|
||||
|
||||
if (hFind == INVALID_HANDLE_VALUE) {
|
||||
log(LOGLEVEL::WARN, "[scan_folder()]: Could not open directory: ", search_path.c_str(), " while scanning files inside directory.");
|
||||
return;
|
||||
}
|
||||
|
||||
do {
|
||||
if (strcmp(find_file_data.cFileName, ".") == 0 || strcmp(find_file_data.cFileName, "..") == 0) {
|
||||
continue; // Skip the current and parent directories
|
||||
}
|
||||
|
||||
|
||||
const std::string full_path = directory + "\\" + find_file_data.cFileName;
|
||||
if (find_file_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
|
||||
// If it's a directory, recurse into it
|
||||
scan_folder(full_path);
|
||||
}
|
||||
else {
|
||||
log(LOGLEVEL::INFO_NOSEND, "[scan_folder()]: Scanning file: ", full_path, "threads: ", num_threads);
|
||||
//action scanfile_t will start the trheads for scanning the hashes
|
||||
//action_scanfile_t(full_path.c_str());
|
||||
|
||||
//do multithreading here
|
||||
int thread_timeout = 0;
|
||||
while (num_threads >= std::thread::hardware_concurrency()) {
|
||||
Sleep(10);
|
||||
thread_timeout++;
|
||||
if (thread_timeout == 100 * 60) {//if there is for more than 30 seconds no thread available, chances are high, that the threads did not temrinate correctly but aren t running anymore. so set the counter to 0 because else it might just stop the scan.
|
||||
num_threads = 0;
|
||||
printf("Number of threads_max: %d\n", num_threads);
|
||||
}
|
||||
}
|
||||
//log(LOGLEVEL::INFO_NOSEND, "[scan_folder()]: Scanning file: ", full_path, "threads: ",num_threads);
|
||||
if (is_valid_path(full_path)==0) {
|
||||
std::uintmax_t fileSize = std::filesystem::file_size(full_path);
|
||||
if (fileSize > 4000000000) {//4gb
|
||||
log(LOGLEVEL::INFO_NOSEND, "[scan_folder()]: File too large to scan: ", full_path);
|
||||
}
|
||||
else {
|
||||
std::thread scan_thread(scan_file_t, full_path);
|
||||
scan_thread.detach();
|
||||
//Sleep(1);
|
||||
}
|
||||
}else
|
||||
log(LOGLEVEL::INFO_NOSEND, "[scan_folder()]: Invalid path: ", full_path);
|
||||
cnt++;
|
||||
if (cnt % 100 == 0) {
|
||||
printf("Processed %d files;\n", cnt);
|
||||
//printf("Number of threads: %d\n", num_threads);
|
||||
}
|
||||
if(num_threads<0)
|
||||
printf("Number of threads_min: %d\n", num_threads);
|
||||
}
|
||||
} while (FindNextFile(hFind, &find_file_data) != 0);
|
||||
|
||||
FindClose(hFind);
|
||||
}
|
||||
|
||||
|
||||
|
||||
//for singlethreaded scans
|
||||
void action_scanfile(const std::string& filepath_) {
|
||||
thread_init();
|
||||
const std::string filepath(filepath_);
|
||||
char* db_path = new char[300];
|
||||
char* hash = new char[300];
|
||||
std::string hash_(md5_file_t(filepath));
|
||||
if (strlen(hash_.c_str()) < 290)
|
||||
strcpy_s(hash, 295, hash_.c_str());
|
||||
else {
|
||||
strcpy_s(hash, 295, "");
|
||||
log(LOGLEVEL::ERR_NOSEND, "[scan_file_t()]: Could not calculate hash for file: ", filepath);
|
||||
}
|
||||
sprintf_s(db_path, 295, "%s\\%c%c.jdbf", DB_DIR, hash[0], hash[1]);
|
||||
if (search_hash(db_path, hash, filepath) != 1) {
|
||||
//notify desktop client by writing to answer_com file
|
||||
//if there is now virus, we notify here. if there is a virus we only notify in the virus_ctrl_process function
|
||||
std::ofstream answer_com(ANSWER_COM_PATH,std::ios::app);
|
||||
if (answer_com.is_open()) {
|
||||
answer_com << "not_found " << "\"" << filepath_ << "\"" << " " << hash << " " << "no_action_taken" << "\n";
|
||||
answer_com.close();
|
||||
}
|
||||
}
|
||||
thread_shutdown();
|
||||
}
|
||||
void action_scanfolder(const std::string& folderpath) {
|
||||
thread_init();
|
||||
cnt = 0;
|
||||
thread_local std::string folderpath_(folderpath);
|
||||
scan_folder(folderpath_);
|
||||
std::ofstream answer_com(ANSWER_COM_PATH, std::ios::app);
|
||||
if (answer_com.is_open()) {
|
||||
answer_com << "end " << "\"" << "nothing" << "\"" << " " << "nothing" << " " << "nothing" << "\n";
|
||||
answer_com.close();
|
||||
}
|
||||
thread_shutdown();
|
||||
}
|
||||
|
||||
void scan_file_t(const std::string& filepath_) {
|
||||
num_threads++;
|
||||
thread_local const std::string filepath(filepath_);
|
||||
thread_local char* db_path = new char[300];
|
||||
thread_local char* hash = new char[300];
|
||||
thread_local std::string hash_(md5_file_t(filepath));
|
||||
if (strlen(hash_.c_str()) < 290)
|
||||
strcpy_s(hash, 295, hash_.c_str());
|
||||
else{
|
||||
strcpy_s(hash, 295, "");
|
||||
log(LOGLEVEL::ERR_NOSEND, "[scan_file_t()]: Could not calculate hash for file: ", filepath);
|
||||
}
|
||||
sprintf_s(db_path, 295, "%s\\%c%c.jdbf", DB_DIR, hash[0], hash[1]);
|
||||
search_hash(db_path, hash, filepath);
|
||||
num_threads--;
|
||||
}
|
||||
void scan_process_t(const std::string& filepath_) {
|
||||
num_threads++;
|
||||
thread_local const std::string filepath(filepath_);
|
||||
thread_local char* db_path = new char[300];
|
||||
thread_local char* hash = new char[300];
|
||||
strcpy_s(hash, 295, md5_file_t(filepath).c_str());
|
||||
sprintf_s(db_path, 295, "%s\\%c%c.jdbf", DB_DIR, hash[0], hash[1]);
|
||||
if (search_hash(db_path, hash, filepath) == 1) {
|
||||
//check if need to kill process
|
||||
if (get_setting("virus_ctrl:virus_process_found:kill") == 1) {
|
||||
//kill the process
|
||||
kill_process(filepath.c_str());
|
||||
log(LOGLEVEL::VIRUS, "[scan_process_t()]: Killing process: ", filepath);
|
||||
}
|
||||
}
|
||||
num_threads--;
|
||||
}
|
||||
#endif
|
||||
@@ -1,311 +0,0 @@
|
||||
#ifndef SCAN_CPP
|
||||
#define SCAN_CPP
|
||||
#include "scan.h"
|
||||
#include <windows.h>
|
||||
#include <iostream>
|
||||
#include <openssl/md5.h>
|
||||
#include <windows.h>
|
||||
#include <iostream>
|
||||
#include <thread>
|
||||
#include <chrono>
|
||||
#include <time.h>
|
||||
#include "md5hash.h"
|
||||
#include <string>
|
||||
#include "well_known.h"
|
||||
#include "log.h"
|
||||
#include "virus_ctrl.h"
|
||||
#include "app_ctrl.h"
|
||||
#include <mutex> // Include the mutex header
|
||||
#include <filesystem>
|
||||
#include "utils.h"
|
||||
|
||||
// Define mutexes for thread synchronization
|
||||
std::mutex fileHandlesMutex;
|
||||
std::mutex mappingHandlesMutex;
|
||||
std::mutex fileDataMutex;
|
||||
std::mutex cntMutex;
|
||||
std::mutex numThreadsMutex;
|
||||
|
||||
std::unordered_map<std::string, HANDLE> fileHandles;
|
||||
std::unordered_map<std::string, HANDLE> mappingHandles;
|
||||
std::unordered_map<std::string, char*> fileData;
|
||||
|
||||
int cnt = 0;
|
||||
int num_threads = 0;
|
||||
|
||||
//load all the db files into memory
|
||||
int initialize(const std::string& folderPath) {
|
||||
for (char firstChar = '0'; firstChar <= 'f'; ++firstChar) {
|
||||
for (char secondChar = '0'; secondChar <= 'f'; ++secondChar) {
|
||||
// Ensure that the characters are valid hexadecimal digits
|
||||
if (!std::isxdigit(firstChar) || !std::isxdigit(secondChar) or std::isupper(firstChar) or std::isupper(secondChar)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Create the filename based on the naming convention
|
||||
std::string filename = folderPath + "\\" + firstChar + secondChar + ".jdbf";
|
||||
//printf("Loading %s\n", filename.c_str());
|
||||
|
||||
// Open the file
|
||||
HANDLE hFile = CreateFile(filename.c_str(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
if (hFile == INVALID_HANDLE_VALUE) {
|
||||
//log(LOGLEVEL::ERR, "[initialize()]: Error opening database file: ", filename);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Create the file mapping
|
||||
HANDLE hMapping = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL);
|
||||
if (hMapping == NULL) {
|
||||
// log(LOGLEVEL::ERR, "[initialize()]: Error creating database file mapping: ", filename);
|
||||
CloseHandle(hFile);
|
||||
return 2;
|
||||
}
|
||||
|
||||
// Map the file into memory
|
||||
char* fileDataPtr = static_cast<char*>(MapViewOfFile(hMapping, FILE_MAP_READ, 0, 0, 0));
|
||||
if (fileDataPtr == NULL) {
|
||||
//log(LOGLEVEL::ERR, "[initialize()]: Error mapping database file: ", filename);
|
||||
CloseHandle(hMapping);
|
||||
CloseHandle(hFile);
|
||||
return 3;
|
||||
}
|
||||
|
||||
// Store the handles in the global maps
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(fileHandlesMutex);
|
||||
fileHandles[filename] = hFile;
|
||||
}
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mappingHandlesMutex);
|
||||
mappingHandles[filename] = hMapping;
|
||||
}
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(fileDataMutex);
|
||||
fileData[filename] = fileDataPtr;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Call this function when you are done using the file mappings
|
||||
void cleanup() {
|
||||
for (const auto& entry : fileHandles) {
|
||||
UnmapViewOfFile(fileData[entry.first]);
|
||||
CloseHandle(mappingHandles[entry.first]);
|
||||
CloseHandle(entry.second);
|
||||
}
|
||||
|
||||
// Clear the global maps
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(fileHandlesMutex);
|
||||
fileHandles.clear();
|
||||
}
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mappingHandlesMutex);
|
||||
mappingHandles.clear();
|
||||
}
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(fileDataMutex);
|
||||
fileData.clear();
|
||||
}
|
||||
}
|
||||
|
||||
//the latest and fastest version of searching a hash by now
|
||||
int search_hash(const std::string& dbname_, const std::string& hash_, const std::string& filepath_) {
|
||||
// Check if the file mapping is already open for the given filename
|
||||
std::string dbname;
|
||||
std::string hash;
|
||||
std::string filepath;
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(fileHandlesMutex);
|
||||
dbname = dbname_;
|
||||
}
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(fileDataMutex);
|
||||
hash = hash_;
|
||||
}
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mappingHandlesMutex);
|
||||
filepath = filepath_;
|
||||
}
|
||||
|
||||
auto fileIter = fileHandles.find(dbname);
|
||||
if (fileIter == fileHandles.end() && dbname_.find("c:.jdbf") == std::string::npos) {
|
||||
log(LOGLEVEL::ERR_NOSEND, "[search_hash()]: File mapping not initialized for ", dbname);
|
||||
return 2;
|
||||
}
|
||||
else if (fileIter == fileHandles.end()) {
|
||||
return 2;
|
||||
}
|
||||
|
||||
// Use fileData for subsequent searches
|
||||
DWORD fileSize;
|
||||
std::string fileContent;
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(fileDataMutex);
|
||||
fileSize = GetFileSize(fileHandles[dbname], NULL);
|
||||
fileContent = std::string(fileData[dbname], fileSize);
|
||||
}
|
||||
|
||||
// Search for the specific string in the file content
|
||||
size_t foundPos = fileContent.find(hash);
|
||||
if (foundPos != std::string::npos) {
|
||||
//log(LOGLEVEL::VIRUS, "[search_hash()]: Found virus: ", hash, " in file: ", filepath);
|
||||
virus_ctrl_store(filepath.c_str(), hash.c_str(), hash.c_str());
|
||||
//afterwards do the processing with that file
|
||||
virus_ctrl_process(hash.c_str());
|
||||
return 1; // Found
|
||||
}
|
||||
return 0; // Not found
|
||||
}
|
||||
|
||||
|
||||
bool file_exists(const std::string& filePath) {
|
||||
DWORD fileAttributes = GetFileAttributes(filePath.c_str());
|
||||
|
||||
if (fileAttributes == INVALID_FILE_ATTRIBUTES) {
|
||||
// The file does not exist or there was an error
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check if it's a regular file and not a directory
|
||||
return (fileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0;
|
||||
}
|
||||
|
||||
//this is the main function to scan folders. it will then start multuiple threads based on the number of cores / settings
|
||||
void scan_folder(const std::string& directory) {
|
||||
std::string search_path = directory + "\\*.*";
|
||||
WIN32_FIND_DATA find_file_data;
|
||||
HANDLE hFind = FindFirstFile(search_path.c_str(), &find_file_data);
|
||||
|
||||
if (hFind == INVALID_HANDLE_VALUE) {
|
||||
log(LOGLEVEL::WARN, "[scan_folder()]: Could not open directory: ", search_path.c_str(), " while scanning files inside directory.");
|
||||
return;
|
||||
}
|
||||
|
||||
do {
|
||||
if (strcmp(find_file_data.cFileName, ".") == 0 || strcmp(find_file_data.cFileName, "..") == 0) {
|
||||
continue; // Skip the current and parent directories
|
||||
}
|
||||
|
||||
|
||||
const std::string full_path = directory + "\\" + find_file_data.cFileName;
|
||||
if (find_file_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
|
||||
// If it's a directory, recurse into it
|
||||
scan_folder(full_path);
|
||||
}
|
||||
else {
|
||||
//action scanfile_t will start the trheads for scanning the hashes
|
||||
//action_scanfile_t(full_path.c_str());
|
||||
|
||||
//do multithreading here
|
||||
int thread_timeout = 0;
|
||||
while (num_threads >= std::thread::hardware_concurrency()) {
|
||||
Sleep(10);
|
||||
thread_timeout++;
|
||||
if (thread_timeout == 100 * 60) {//if there is for more than 30 seconds no thread available, chances are high, that the threads did not temrinate correctly but aren t running anymore. so set the counter to 0 because else it might just stop the scan.
|
||||
num_threads = 0;
|
||||
printf("Number of threads_max: %d\n", num_threads);
|
||||
}
|
||||
}
|
||||
|
||||
if (is_valid_path(full_path)) { //filter out invalid paths and paths with weird characters
|
||||
std::uintmax_t fileSize = std::filesystem::file_size(full_path);
|
||||
if (fileSize > 4000000000) {//4gb
|
||||
log(LOGLEVEL::INFO_NOSEND, "[scan_folder()]: File too large to scan: ", full_path);
|
||||
}
|
||||
else {
|
||||
std::thread scan_thread(scan_file_t, full_path);
|
||||
scan_thread.detach();
|
||||
Sleep(10);
|
||||
}
|
||||
}else
|
||||
log(LOGLEVEL::INFO_NOSEND, "[scan_folder()]: Invalid path: ", full_path);
|
||||
cnt++;
|
||||
if (cnt % 100 == 0) {
|
||||
printf("Processed %d files;\n", cnt);
|
||||
//printf("Number of threads: %d\n", num_threads);
|
||||
}
|
||||
if(num_threads<0)
|
||||
printf("Number of threads_min: %d\n", num_threads);
|
||||
}
|
||||
} while (FindNextFile(hFind, &find_file_data) != 0);
|
||||
|
||||
FindClose(hFind);
|
||||
}
|
||||
|
||||
|
||||
|
||||
//for singlethreaded scans
|
||||
void action_scanfile(const std::string& filepath_) {
|
||||
thread_init();
|
||||
const std::string filepath(filepath_);
|
||||
char* db_path = new char[300];
|
||||
char* hash = new char[300];
|
||||
std::string hash_(md5_file_t(filepath));
|
||||
if (strlen(hash_.c_str()) < 290)
|
||||
strcpy_s(hash, 295, hash_.c_str());
|
||||
else {
|
||||
strcpy_s(hash, 295, "");
|
||||
log(LOGLEVEL::ERR_NOSEND, "[scan_file_t()]: Could not calculate hash for file: ", filepath);
|
||||
}
|
||||
sprintf_s(db_path, 295, "%s\\%c%c.jdbf", DB_DIR, hash[0], hash[1]);
|
||||
if (search_hash(db_path, hash, filepath) != 1) {
|
||||
//notify desktop client by writing to answer_com file
|
||||
//if there is now virus, we notify here. if there is a virus we only notify in the virus_ctrl_process function
|
||||
std::ofstream answer_com(ANSWER_COM_PATH,std::ios::app);
|
||||
if (answer_com.is_open()) {
|
||||
answer_com << "not_found " << "\"" << filepath_ << "\"" << " " << hash << " " << "no_action_taken" << "\n";
|
||||
answer_com.close();
|
||||
}
|
||||
}
|
||||
thread_shutdown();
|
||||
}
|
||||
void action_scanfolder(const std::string& folderpath) {
|
||||
thread_init();
|
||||
cnt = 0;
|
||||
thread_local std::string folderpath_(folderpath);
|
||||
scan_folder(folderpath_);
|
||||
std::ofstream answer_com(ANSWER_COM_PATH, std::ios::app);
|
||||
if (answer_com.is_open()) {
|
||||
answer_com << "end " << "\"" << "nothing" << "\"" << " " << "nothing" << " " << "nothing" << "\n";
|
||||
answer_com.close();
|
||||
}
|
||||
thread_shutdown();
|
||||
}
|
||||
|
||||
void scan_file_t(const std::string& filepath_) {
|
||||
num_threads++;
|
||||
thread_local const std::string filepath(filepath_);
|
||||
thread_local char* db_path = new char[300];
|
||||
thread_local char* hash = new char[300];
|
||||
thread_local std::string hash_(md5_file_t(filepath));
|
||||
if (strlen(hash_.c_str()) < 290)
|
||||
strcpy_s(hash, 295, hash_.c_str());
|
||||
else{
|
||||
strcpy_s(hash, 295, "");
|
||||
log(LOGLEVEL::ERR_NOSEND, "[scan_file_t()]: Could not calculate hash for file: ", filepath);
|
||||
}
|
||||
sprintf_s(db_path, 295, "%s\\%c%c.jdbf", DB_DIR, hash[0], hash[1]);
|
||||
search_hash(db_path, hash, filepath);
|
||||
num_threads--;
|
||||
}
|
||||
void scan_process_t(const std::string& filepath_) {
|
||||
num_threads++;
|
||||
thread_local const std::string filepath(filepath_);
|
||||
thread_local char* db_path = new char[300];
|
||||
thread_local char* hash = new char[300];
|
||||
strcpy_s(hash, 295, md5_file_t(filepath).c_str());
|
||||
sprintf_s(db_path, 295, "%s\\%c%c.jdbf", DB_DIR, hash[0], hash[1]);
|
||||
if (search_hash(db_path, hash, filepath) == 1) {
|
||||
//check if need to kill process
|
||||
if (get_setting("virus_ctrl:virus_process_found:kill") == 1) {
|
||||
//kill the process
|
||||
kill_process(filepath.c_str());
|
||||
log(LOGLEVEL::VIRUS, "[scan_process_t()]: Killing process: ", filepath);
|
||||
}
|
||||
}
|
||||
num_threads--;
|
||||
}
|
||||
#endif
|
||||
@@ -1,388 +0,0 @@
|
||||
#ifndef SCAN_CPP
|
||||
#define SCAN_CPP
|
||||
#include "scan.h"
|
||||
#include <windows.h>
|
||||
#include <iostream>
|
||||
#include <openssl/md5.h>
|
||||
#include <windows.h>
|
||||
#include <iostream>
|
||||
#include <thread>
|
||||
#include <chrono>
|
||||
#include <stack>
|
||||
#include <time.h>
|
||||
#include "md5hash.h"
|
||||
#include <string>
|
||||
#include "well_known.h"
|
||||
#include "log.h"
|
||||
#include "virus_ctrl.h"
|
||||
#include "app_ctrl.h"
|
||||
#include <mutex> // Include the mutex header
|
||||
#include <filesystem>
|
||||
#include "utils.h"
|
||||
|
||||
// Define mutexes for thread synchronization
|
||||
std::mutex fileHandlesMutex;
|
||||
std::mutex mappingHandlesMutex;
|
||||
std::mutex fileDataMutex;
|
||||
std::mutex cntMutex;
|
||||
std::mutex numThreadsMutex;
|
||||
|
||||
std::unordered_map<std::string, HANDLE> fileHandles;
|
||||
std::unordered_map<std::string, HANDLE> mappingHandles;
|
||||
std::unordered_map<std::string, char*> fileData;
|
||||
|
||||
int cnt = 0;
|
||||
int num_threads = 0;
|
||||
int all_files = 0;
|
||||
|
||||
int get_num_threads() {
|
||||
std::lock_guard<std::mutex> lock(numThreadsMutex);
|
||||
return num_threads;
|
||||
}
|
||||
int set_num_threads(int num) {
|
||||
std::lock_guard<std::mutex> lock(numThreadsMutex);
|
||||
num_threads = num;
|
||||
return 0;
|
||||
}
|
||||
//load all the db files into memory
|
||||
int initialize(const std::string& folderPath) {
|
||||
for (char firstChar = '0'; firstChar <= 'f'; ++firstChar) {
|
||||
for (char secondChar = '0'; secondChar <= 'f'; ++secondChar) {
|
||||
// Ensure that the characters are valid hexadecimal digits
|
||||
if (!std::isxdigit(firstChar) || !std::isxdigit(secondChar) or std::isupper(firstChar) or std::isupper(secondChar)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Create the filename based on the naming convention
|
||||
std::string filename = folderPath + "\\" + firstChar + secondChar + ".jdbf";
|
||||
//printf("Loading %s\n", filename.c_str());
|
||||
|
||||
// Open the file
|
||||
HANDLE hFile = CreateFile(filename.c_str(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
if (hFile == INVALID_HANDLE_VALUE) {
|
||||
//log(LOGLEVEL::ERR, "[initialize()]: Error opening database file: ", filename);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Create the file mapping
|
||||
HANDLE hMapping = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL);
|
||||
if (hMapping == NULL) {
|
||||
// log(LOGLEVEL::ERR, "[initialize()]: Error creating database file mapping: ", filename);
|
||||
CloseHandle(hFile);
|
||||
return 2;
|
||||
}
|
||||
|
||||
// Map the file into memory
|
||||
char* fileDataPtr = static_cast<char*>(MapViewOfFile(hMapping, FILE_MAP_READ, 0, 0, 0));
|
||||
if (fileDataPtr == NULL) {
|
||||
//log(LOGLEVEL::ERR, "[initialize()]: Error mapping database file: ", filename);
|
||||
CloseHandle(hMapping);
|
||||
CloseHandle(hFile);
|
||||
return 3;
|
||||
}
|
||||
|
||||
// Store the handles in the global maps
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(fileHandlesMutex);
|
||||
fileHandles[filename] = hFile;
|
||||
}
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mappingHandlesMutex);
|
||||
mappingHandles[filename] = hMapping;
|
||||
}
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(fileDataMutex);
|
||||
fileData[filename] = fileDataPtr;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Call this function when you are done using the file mappings
|
||||
void cleanup() {
|
||||
for (const auto& entry : fileHandles) {
|
||||
UnmapViewOfFile(fileData[entry.first]);
|
||||
CloseHandle(mappingHandles[entry.first]);
|
||||
CloseHandle(entry.second);
|
||||
}
|
||||
|
||||
// Clear the global maps
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(fileHandlesMutex);
|
||||
fileHandles.clear();
|
||||
}
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mappingHandlesMutex);
|
||||
mappingHandles.clear();
|
||||
}
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(fileDataMutex);
|
||||
fileData.clear();
|
||||
}
|
||||
}
|
||||
|
||||
//the latest and fastest version of searching a hash by now
|
||||
int search_hash(const std::string& dbname_, const std::string& hash_, const std::string& filepath_) {
|
||||
// Check if the file mapping is already open for the given filename
|
||||
std::string dbname;
|
||||
std::string hash;
|
||||
std::string filepath;
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(fileHandlesMutex);
|
||||
dbname = dbname_;
|
||||
}
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(fileDataMutex);
|
||||
hash = hash_;
|
||||
}
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mappingHandlesMutex);
|
||||
filepath = filepath_;
|
||||
}
|
||||
|
||||
auto fileIter = fileHandles.find(dbname);
|
||||
if (fileIter == fileHandles.end() && dbname_.find("c:.jdbf") == std::string::npos) {
|
||||
log(LOGLEVEL::ERR_NOSEND, "[search_hash()]: File mapping not initialized for ", dbname);
|
||||
return 2;
|
||||
}
|
||||
else if (fileIter == fileHandles.end()) {
|
||||
return 2;
|
||||
}
|
||||
|
||||
// Use fileData for subsequent searches
|
||||
DWORD fileSize;
|
||||
std::string fileContent;
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(fileDataMutex);
|
||||
fileSize = GetFileSize(fileHandles[dbname], NULL);
|
||||
fileContent = std::string(fileData[dbname], fileSize);
|
||||
}
|
||||
|
||||
// Search for the specific string in the file content
|
||||
size_t foundPos = fileContent.find(hash);
|
||||
if (foundPos != std::string::npos) {
|
||||
//log(LOGLEVEL::VIRUS, "[search_hash()]: Found virus: ", hash, " in file: ", filepath);
|
||||
virus_ctrl_store(filepath.c_str(), hash.c_str(), hash.c_str());
|
||||
//afterwards do the processing with that file
|
||||
virus_ctrl_process(hash.c_str());
|
||||
return 1; // Found
|
||||
}
|
||||
return 0; // Not found
|
||||
}
|
||||
|
||||
//function to get num of files in idr and its subdirs etc (iterative)
|
||||
int get_num_files(const std::string& directory) {
|
||||
std::string search_path = directory + "\\*.*";
|
||||
WIN32_FIND_DATA find_file_data;
|
||||
HANDLE hFind = FindFirstFile(search_path.c_str(), &find_file_data);
|
||||
int num_files = 0;
|
||||
|
||||
if (hFind == INVALID_HANDLE_VALUE) {
|
||||
//std::cerr << "[get_num_files()]: Could not open directory: " << search_path << " while scanning files inside directory." << std::endl;
|
||||
log(LOGLEVEL::ERR_NOSEND, "[get_num_files()]: Could not open directory: ", search_path, " while scanning files inside directory.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Stack to store directories to be traversed iteratively
|
||||
std::stack<std::string> directories;
|
||||
directories.push(directory);
|
||||
|
||||
while (!directories.empty()) {
|
||||
std::string current_dir = directories.top();
|
||||
directories.pop();
|
||||
|
||||
search_path = current_dir + "\\*.*";
|
||||
hFind = FindFirstFile(search_path.c_str(), &find_file_data);
|
||||
|
||||
if (hFind != INVALID_HANDLE_VALUE) {
|
||||
do {
|
||||
if (strcmp(find_file_data.cFileName, ".") == 0 || strcmp(find_file_data.cFileName, "..") == 0) {
|
||||
continue; // Skip the current and parent directories
|
||||
}
|
||||
|
||||
const std::string full_path = current_dir + "\\" + find_file_data.cFileName;
|
||||
if (find_file_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
|
||||
// If it's a directory, add it to the stack
|
||||
directories.push(full_path);
|
||||
}
|
||||
else {
|
||||
num_files++;
|
||||
}
|
||||
} while (FindNextFile(hFind, &find_file_data) != 0);
|
||||
FindClose(hFind);
|
||||
}
|
||||
else {
|
||||
log(LOGLEVEL::ERR_NOSEND, "[get_num_files()]: Could not open directory: ", current_dir, " while scanning files inside directory.");
|
||||
//std::cerr << "[get_num_files()]: Could not open directory: " << current_dir << " while scanning files inside directory." << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
return num_files;
|
||||
}
|
||||
|
||||
//this is the main function to scan folders. it will then start multuiple threads based on the number of cores / settings
|
||||
std::stack<std::string> directories; // Stack to store directories to be scanned
|
||||
|
||||
void scan_folder(const std::string& directory) {
|
||||
directories.push(directory);
|
||||
|
||||
while (!directories.empty()) {
|
||||
std::string current_dir = directories.top();
|
||||
directories.pop();
|
||||
|
||||
std::string search_path = current_dir + "\\*.*";
|
||||
WIN32_FIND_DATA find_file_data;
|
||||
HANDLE hFind = FindFirstFile(search_path.c_str(), &find_file_data);
|
||||
|
||||
if (hFind != INVALID_HANDLE_VALUE) {
|
||||
do {
|
||||
if (strcmp(find_file_data.cFileName, ".") == 0 || strcmp(find_file_data.cFileName, "..") == 0) {
|
||||
continue; // Skip the current and parent directories
|
||||
}
|
||||
|
||||
const std::string full_path = current_dir + "\\" + find_file_data.cFileName;
|
||||
if (find_file_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
|
||||
// If it's a directory, add it to the stack
|
||||
directories.push(full_path);
|
||||
}
|
||||
else {
|
||||
// Do multithreading here
|
||||
int thread_timeout = 0;
|
||||
//log(LOGLEVEL::INFO_NOSEND, "[scan_folder()]: Scanning file: ", full_path);
|
||||
while (get_num_threads() >= std::thread::hardware_concurrency()) {
|
||||
Sleep(10);
|
||||
thread_timeout++;
|
||||
//printf("Thread timeout: %d\n", thread_timeout);
|
||||
if (thread_timeout == 100 * 20) {
|
||||
// If there is no available thread for more than 30 seconds, reset the thread counter
|
||||
set_num_threads(0);
|
||||
}
|
||||
}
|
||||
//log(LOGLEVEL::INFO_NOSEND, "[scan_folder()]: Scanning file: ", full_path);
|
||||
if (is_valid_path(full_path)) { // Filter out invalid paths and paths with weird characters
|
||||
std::uintmax_t fileSize = std::filesystem::file_size(full_path);
|
||||
if (fileSize > 4000000000) { // 4GB
|
||||
log(LOGLEVEL::INFO_NOSEND, "[scan_folder()]: File too large to scan: ", full_path);
|
||||
}
|
||||
else {
|
||||
std::thread scan_thread(scan_file_t, full_path);
|
||||
scan_thread.detach();
|
||||
}
|
||||
}
|
||||
else {
|
||||
log(LOGLEVEL::INFO_NOSEND, "[scan_folder()]: Invalid path: ", full_path);
|
||||
}
|
||||
cnt++;
|
||||
if (cnt % 100 == 0) {
|
||||
printf("Processed %d files;\n", cnt);
|
||||
//printf("Number of threads: %d\n", num_threads);
|
||||
}
|
||||
if (cnt % 1000 == 0) {
|
||||
int actual_threads = get_num_threads();
|
||||
if(get_num_threads()>actual_threads)
|
||||
set_num_threads(actual_threads);//correct value of threads minus the main and the rtp thread
|
||||
printf("Number of threads: %d\n", get_num_threads());
|
||||
//send progress to com file
|
||||
std::ofstream answer_com(ANSWER_COM_PATH, std::ios::app);
|
||||
if (answer_com.is_open()) {
|
||||
answer_com << "progress " << (cnt * 100 / (all_files + 1)) << "\n";
|
||||
answer_com.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
} while (FindNextFile(hFind, &find_file_data) != 0);
|
||||
FindClose(hFind);
|
||||
}
|
||||
else {
|
||||
log(LOGLEVEL::ERR_NOSEND, "[scan_folder()]: Could not open directory: ", current_dir, " while scanning files inside directory.");
|
||||
//std::cerr << "[scan_folder()]: Could not open directory: " << current_dir << " while scanning files inside directory." << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
//for singlethreaded scans
|
||||
void action_scanfile(const std::string& filepath_) {
|
||||
thread_init();
|
||||
const std::string filepath(filepath_);
|
||||
char* db_path = new char[300];
|
||||
char* hash = new char[300];
|
||||
if (is_valid_path(filepath_)) { //filter out invalid paths and paths with weird characters
|
||||
std::string hash_(md5_file_t(filepath));
|
||||
if (strlen(hash_.c_str()) < 290)
|
||||
strcpy_s(hash, 295, hash_.c_str());
|
||||
else {
|
||||
strcpy_s(hash, 295, "");
|
||||
log(LOGLEVEL::ERR_NOSEND, "[scan_file_t()]: Could not calculate hash for file: ", filepath);
|
||||
}
|
||||
sprintf_s(db_path, 295, "%s\\%c%c.jdbf", DB_DIR, hash[0], hash[1]);
|
||||
if (search_hash(db_path, hash, filepath) != 1) {
|
||||
//notify desktop client by writing to answer_com file
|
||||
//if there is now virus, we notify here. if there is a virus we only notify in the virus_ctrl_process function
|
||||
std::ofstream answer_com(ANSWER_COM_PATH, std::ios::app);
|
||||
if (answer_com.is_open()) {
|
||||
answer_com << "not_found " << "\"" << filepath_ << "\"" << " " << hash << " " << "no_action_taken" << "\n";
|
||||
answer_com.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
log(LOGLEVEL::INFO_NOSEND, "[action_scanfile()]: Invalid path: ", filepath_);
|
||||
thread_shutdown();
|
||||
}
|
||||
void action_scanfolder(const std::string& folderpath) {
|
||||
thread_init();
|
||||
thread_local std::string folderpath_(folderpath);
|
||||
cnt = 0;
|
||||
all_files = get_num_files(folderpath_);
|
||||
//tell the desktop client that the scan has started
|
||||
std::ofstream answer_com1(ANSWER_COM_PATH, std::ios::app);
|
||||
if (answer_com1.is_open()) {
|
||||
answer_com1 << "start " << all_files << "\n";
|
||||
answer_com1.close();
|
||||
}
|
||||
scan_folder(folderpath_);
|
||||
std::ofstream answer_com(ANSWER_COM_PATH, std::ios::app);
|
||||
if (answer_com.is_open()) {
|
||||
answer_com << "end " << "\"" << "nothing" << "\"" << " " << "nothing" << " " << "nothing" << "\n";
|
||||
answer_com.close();
|
||||
}
|
||||
thread_shutdown();
|
||||
}
|
||||
|
||||
void scan_file_t(const std::string& filepath_) {
|
||||
set_num_threads(get_num_threads() + 1);
|
||||
thread_local const std::string filepath(filepath_);
|
||||
thread_local char* db_path = new char[300];
|
||||
thread_local char* hash = new char[300];
|
||||
thread_local std::string hash_(md5_file_t(filepath));
|
||||
if (strlen(hash_.c_str()) < 290)
|
||||
strcpy_s(hash, 295, hash_.c_str());
|
||||
else{
|
||||
strcpy_s(hash, 295, "");
|
||||
log(LOGLEVEL::ERR_NOSEND, "[scan_file_t()]: Could not calculate hash for file: ", filepath);
|
||||
}
|
||||
sprintf_s(db_path, 295, "%s\\%c%c.jdbf", DB_DIR, hash[0], hash[1]);
|
||||
search_hash(db_path, hash, filepath);
|
||||
set_num_threads(get_num_threads() - 1);
|
||||
}
|
||||
void scan_process_t(const std::string& filepath_) {
|
||||
set_num_threads(get_num_threads() + 1);
|
||||
thread_local const std::string filepath(filepath_);
|
||||
thread_local char* db_path = new char[300];
|
||||
thread_local char* hash = new char[300];
|
||||
strcpy_s(hash, 295, md5_file_t(filepath).c_str());
|
||||
sprintf_s(db_path, 295, "%s\\%c%c.jdbf", DB_DIR, hash[0], hash[1]);
|
||||
if (search_hash(db_path, hash, filepath) == 1) {
|
||||
//check if need to kill process
|
||||
if (get_setting("virus_ctrl:virus_process_found:kill") == 1) {
|
||||
//kill the process
|
||||
kill_process(filepath.c_str());
|
||||
log(LOGLEVEL::VIRUS, "[scan_process_t()]: Killing process: ", filepath);
|
||||
}
|
||||
}
|
||||
set_num_threads(get_num_threads() - 1);
|
||||
}
|
||||
#endif
|
||||
@@ -1,366 +0,0 @@
|
||||
#ifndef SCAN_CPP
|
||||
#define SCAN_CPP
|
||||
#include "scan.h"
|
||||
#include <windows.h>
|
||||
#include <iostream>
|
||||
#include <openssl/md5.h>
|
||||
#include <windows.h>
|
||||
#include <iostream>
|
||||
#include <thread>
|
||||
#include <chrono>
|
||||
#include <stack>
|
||||
#include <time.h>
|
||||
#include "md5hash.h"
|
||||
#include <string>
|
||||
#include "well_known.h"
|
||||
#include "log.h"
|
||||
#include "virus_ctrl.h"
|
||||
#include "app_ctrl.h"
|
||||
#include <mutex> // Include the mutex header
|
||||
#include <filesystem>
|
||||
#include "utils.h"
|
||||
|
||||
// Define mutexes for thread synchronization
|
||||
std::mutex fileHandlesMutex;
|
||||
std::mutex mappingHandlesMutex;
|
||||
std::mutex fileDataMutex;
|
||||
std::mutex cntMutex;
|
||||
std::mutex numThreadsMutex;
|
||||
|
||||
std::unordered_map<std::string, HANDLE> fileHandles;
|
||||
std::unordered_map<std::string, HANDLE> mappingHandles;
|
||||
std::unordered_map<std::string, char*> fileData;
|
||||
|
||||
int cnt = 0;
|
||||
int num_threads = 0;
|
||||
int all_files = 0;
|
||||
|
||||
int get_num_threads() {
|
||||
std::lock_guard<std::mutex> lock(numThreadsMutex);
|
||||
return num_threads;
|
||||
}
|
||||
int set_num_threads(int num) {
|
||||
std::lock_guard<std::mutex> lock(numThreadsMutex);
|
||||
num_threads = num;
|
||||
return 0;
|
||||
}
|
||||
//load all the db files into memory
|
||||
int initialize(const std::string& folderPath) {
|
||||
for (char firstChar = '0'; firstChar <= 'f'; ++firstChar) {
|
||||
for (char secondChar = '0'; secondChar <= 'f'; ++secondChar) {
|
||||
// Ensure that the characters are valid hexadecimal digits
|
||||
if (!std::isxdigit(firstChar) || !std::isxdigit(secondChar) or std::isupper(firstChar) or std::isupper(secondChar)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Create the filename based on the naming convention
|
||||
std::string filename = folderPath + "\\" + firstChar + secondChar + ".jdbf";
|
||||
//printf("Loading %s\n", filename.c_str());
|
||||
|
||||
// Open the file
|
||||
HANDLE hFile = CreateFile(filename.c_str(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
if (hFile == INVALID_HANDLE_VALUE) {
|
||||
//log(LOGLEVEL::ERR, "[initialize()]: Error opening database file: ", filename);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Create the file mapping
|
||||
HANDLE hMapping = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL);
|
||||
if (hMapping == NULL) {
|
||||
// log(LOGLEVEL::ERR, "[initialize()]: Error creating database file mapping: ", filename);
|
||||
CloseHandle(hFile);
|
||||
return 2;
|
||||
}
|
||||
|
||||
// Map the file into memory
|
||||
char* fileDataPtr = static_cast<char*>(MapViewOfFile(hMapping, FILE_MAP_READ, 0, 0, 0));
|
||||
if (fileDataPtr == NULL) {
|
||||
//log(LOGLEVEL::ERR, "[initialize()]: Error mapping database file: ", filename);
|
||||
CloseHandle(hMapping);
|
||||
CloseHandle(hFile);
|
||||
return 3;
|
||||
}
|
||||
|
||||
// Store the handles in the global maps
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(fileHandlesMutex);
|
||||
fileHandles[filename] = hFile;
|
||||
}
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mappingHandlesMutex);
|
||||
mappingHandles[filename] = hMapping;
|
||||
}
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(fileDataMutex);
|
||||
fileData[filename] = fileDataPtr;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Call this function when you are done using the file mappings
|
||||
void cleanup() {
|
||||
for (const auto& entry : fileHandles) {
|
||||
UnmapViewOfFile(fileData[entry.first]);
|
||||
CloseHandle(mappingHandles[entry.first]);
|
||||
CloseHandle(entry.second);
|
||||
}
|
||||
|
||||
// Clear the global maps
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(fileHandlesMutex);
|
||||
fileHandles.clear();
|
||||
}
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mappingHandlesMutex);
|
||||
mappingHandles.clear();
|
||||
}
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(fileDataMutex);
|
||||
fileData.clear();
|
||||
}
|
||||
}
|
||||
|
||||
//the latest and fastest version of searching a hash by now
|
||||
int search_hash(const std::string& dbname_, const std::string& hash_, const std::string& filepath_) {
|
||||
// Check if the file mapping is already open for the given filename
|
||||
std::string dbname;
|
||||
std::string hash;
|
||||
std::string filepath;
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(fileHandlesMutex);
|
||||
dbname = dbname_;
|
||||
}
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(fileDataMutex);
|
||||
hash = hash_;
|
||||
}
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mappingHandlesMutex);
|
||||
filepath = filepath_;
|
||||
}
|
||||
|
||||
auto fileIter = fileHandles.find(dbname);
|
||||
if (fileIter == fileHandles.end() && dbname_.find("c:.jdbf") == std::string::npos) {
|
||||
log(LOGLEVEL::ERR_NOSEND, "[search_hash()]: File mapping not initialized for ", dbname);
|
||||
return 2;
|
||||
}
|
||||
else if (fileIter == fileHandles.end()) {
|
||||
return 2;
|
||||
}
|
||||
|
||||
// Use fileData for subsequent searches
|
||||
DWORD fileSize;
|
||||
std::string fileContent;
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(fileDataMutex);
|
||||
fileSize = GetFileSize(fileHandles[dbname], NULL);
|
||||
fileContent = std::string(fileData[dbname], fileSize);
|
||||
}
|
||||
|
||||
// Search for the specific string in the file content
|
||||
size_t foundPos = fileContent.find(hash);
|
||||
if (foundPos != std::string::npos) {
|
||||
//log(LOGLEVEL::VIRUS, "[search_hash()]: Found virus: ", hash, " in file: ", filepath);
|
||||
virus_ctrl_store(filepath.c_str(), hash.c_str(), hash.c_str());
|
||||
//afterwards do the processing with that file
|
||||
virus_ctrl_process(hash.c_str());
|
||||
return 1; // Found
|
||||
}
|
||||
return 0; // Not found
|
||||
}
|
||||
|
||||
//function to get num of files in idr and its subdirs etc (iterative)
|
||||
int get_num_files(const std::string& directory) {
|
||||
std::string search_path = directory + "\\*.*";
|
||||
WIN32_FIND_DATA find_file_data;
|
||||
HANDLE hFind = FindFirstFile(search_path.c_str(), &find_file_data);
|
||||
int num_files = 0;
|
||||
|
||||
if (hFind == INVALID_HANDLE_VALUE) {
|
||||
std::cerr << "[get_num_files()]: Could not open directory: " << search_path << " while scanning files inside directory." << std::endl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Stack to store directories to be traversed iteratively
|
||||
std::stack<std::string> directories;
|
||||
directories.push(directory);
|
||||
|
||||
while (!directories.empty()) {
|
||||
std::string current_dir = directories.top();
|
||||
directories.pop();
|
||||
|
||||
search_path = current_dir + "\\*.*";
|
||||
hFind = FindFirstFile(search_path.c_str(), &find_file_data);
|
||||
|
||||
if (hFind != INVALID_HANDLE_VALUE) {
|
||||
do {
|
||||
if (strcmp(find_file_data.cFileName, ".") == 0 || strcmp(find_file_data.cFileName, "..") == 0) {
|
||||
continue; // Skip the current and parent directories
|
||||
}
|
||||
|
||||
const std::string full_path = current_dir + "\\" + find_file_data.cFileName;
|
||||
if (find_file_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
|
||||
// If it's a directory, add it to the stack
|
||||
directories.push(full_path);
|
||||
}
|
||||
else {
|
||||
num_files++;
|
||||
}
|
||||
} while (FindNextFile(hFind, &find_file_data) != 0);
|
||||
FindClose(hFind);
|
||||
}
|
||||
else {
|
||||
std::cerr << "[get_num_files()]: Could not open directory: " << current_dir << " while scanning files inside directory." << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
return num_files;
|
||||
}
|
||||
|
||||
//this is the main function to scan folders. it will then start multuiple threads based on the number of cores / settings
|
||||
std::stack<std::string> directories; // Stack to store directories to be scanned
|
||||
|
||||
void scan_folder(const std::string& directory) {
|
||||
directories.push(directory);
|
||||
|
||||
while (!directories.empty()) {
|
||||
std::string current_dir = directories.top();
|
||||
directories.pop();
|
||||
|
||||
std::string search_path = current_dir + "\\*.*";
|
||||
WIN32_FIND_DATA find_file_data;
|
||||
HANDLE hFind = FindFirstFile(search_path.c_str(), &find_file_data);
|
||||
|
||||
if (hFind != INVALID_HANDLE_VALUE) {
|
||||
do {
|
||||
if (strcmp(find_file_data.cFileName, ".") == 0 || strcmp(find_file_data.cFileName, "..") == 0) {
|
||||
continue; // Skip the current and parent directories
|
||||
}
|
||||
|
||||
const std::string full_path = current_dir + "\\" + find_file_data.cFileName;
|
||||
if (find_file_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
|
||||
// If it's a directory, add it to the stack
|
||||
directories.push(full_path);
|
||||
}
|
||||
else {
|
||||
// Do multithreading here
|
||||
int thread_timeout = 0;
|
||||
while (get_num_threads() >= std::thread::hardware_concurrency()) {
|
||||
Sleep(10);
|
||||
thread_timeout++;
|
||||
if (thread_timeout == 100 * 60) {
|
||||
// If there is no available thread for more than 30 seconds, reset the thread counter
|
||||
set_num_threads(0);
|
||||
}
|
||||
}
|
||||
|
||||
if (is_valid_path(full_path)) { // Filter out invalid paths and paths with weird characters
|
||||
std::uintmax_t fileSize = std::filesystem::file_size(full_path);
|
||||
if (fileSize > 4000000000) { // 4GB
|
||||
log(LOGLEVEL::INFO_NOSEND, "[scan_folder()]: File too large to scan: ", full_path);
|
||||
}
|
||||
else {
|
||||
std::thread scan_thread(scan_file_t, full_path);
|
||||
scan_thread.detach();
|
||||
}
|
||||
}
|
||||
else {
|
||||
log(LOGLEVEL::INFO_NOSEND, "[scan_folder()]: Invalid path: ", full_path);
|
||||
}
|
||||
}
|
||||
} while (FindNextFile(hFind, &find_file_data) != 0);
|
||||
FindClose(hFind);
|
||||
}
|
||||
else {
|
||||
std::cerr << "[scan_folder()]: Could not open directory: " << current_dir << " while scanning files inside directory." << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
//for singlethreaded scans
|
||||
void action_scanfile(const std::string& filepath_) {
|
||||
thread_init();
|
||||
const std::string filepath(filepath_);
|
||||
char* db_path = new char[300];
|
||||
char* hash = new char[300];
|
||||
if (is_valid_path(filepath_)) { //filter out invalid paths and paths with weird characters
|
||||
std::string hash_(md5_file_t(filepath));
|
||||
if (strlen(hash_.c_str()) < 290)
|
||||
strcpy_s(hash, 295, hash_.c_str());
|
||||
else {
|
||||
strcpy_s(hash, 295, "");
|
||||
log(LOGLEVEL::ERR_NOSEND, "[scan_file_t()]: Could not calculate hash for file: ", filepath);
|
||||
}
|
||||
sprintf_s(db_path, 295, "%s\\%c%c.jdbf", DB_DIR, hash[0], hash[1]);
|
||||
if (search_hash(db_path, hash, filepath) != 1) {
|
||||
//notify desktop client by writing to answer_com file
|
||||
//if there is now virus, we notify here. if there is a virus we only notify in the virus_ctrl_process function
|
||||
std::ofstream answer_com(ANSWER_COM_PATH, std::ios::app);
|
||||
if (answer_com.is_open()) {
|
||||
answer_com << "not_found " << "\"" << filepath_ << "\"" << " " << hash << " " << "no_action_taken" << "\n";
|
||||
answer_com.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
log(LOGLEVEL::INFO_NOSEND, "[action_scanfile()]: Invalid path: ", filepath_);
|
||||
thread_shutdown();
|
||||
}
|
||||
void action_scanfolder(const std::string& folderpath) {
|
||||
thread_init();
|
||||
thread_local std::string folderpath_(folderpath);
|
||||
cnt = 0;
|
||||
all_files = get_num_files(folderpath_);
|
||||
//tell the desktop client that the scan has started
|
||||
std::ofstream answer_com1(ANSWER_COM_PATH, std::ios::app);
|
||||
if (answer_com1.is_open()) {
|
||||
answer_com1 << "start " << all_files << "\n";
|
||||
answer_com1.close();
|
||||
}
|
||||
scan_folder(folderpath_);
|
||||
std::ofstream answer_com(ANSWER_COM_PATH, std::ios::app);
|
||||
if (answer_com.is_open()) {
|
||||
answer_com << "end " << "\"" << "nothing" << "\"" << " " << "nothing" << " " << "nothing" << "\n";
|
||||
answer_com.close();
|
||||
}
|
||||
thread_shutdown();
|
||||
}
|
||||
|
||||
void scan_file_t(const std::string& filepath_) {
|
||||
set_num_threads(get_num_threads() + 1);
|
||||
thread_local const std::string filepath(filepath_);
|
||||
thread_local char* db_path = new char[300];
|
||||
thread_local char* hash = new char[300];
|
||||
thread_local std::string hash_(md5_file_t(filepath));
|
||||
if (strlen(hash_.c_str()) < 290)
|
||||
strcpy_s(hash, 295, hash_.c_str());
|
||||
else{
|
||||
strcpy_s(hash, 295, "");
|
||||
log(LOGLEVEL::ERR_NOSEND, "[scan_file_t()]: Could not calculate hash for file: ", filepath);
|
||||
}
|
||||
sprintf_s(db_path, 295, "%s\\%c%c.jdbf", DB_DIR, hash[0], hash[1]);
|
||||
search_hash(db_path, hash, filepath);
|
||||
set_num_threads(get_num_threads() - 1);
|
||||
}
|
||||
void scan_process_t(const std::string& filepath_) {
|
||||
set_num_threads(get_num_threads() + 1);
|
||||
thread_local const std::string filepath(filepath_);
|
||||
thread_local char* db_path = new char[300];
|
||||
thread_local char* hash = new char[300];
|
||||
strcpy_s(hash, 295, md5_file_t(filepath).c_str());
|
||||
sprintf_s(db_path, 295, "%s\\%c%c.jdbf", DB_DIR, hash[0], hash[1]);
|
||||
if (search_hash(db_path, hash, filepath) == 1) {
|
||||
//check if need to kill process
|
||||
if (get_setting("virus_ctrl:virus_process_found:kill") == 1) {
|
||||
//kill the process
|
||||
kill_process(filepath.c_str());
|
||||
log(LOGLEVEL::VIRUS, "[scan_process_t()]: Killing process: ", filepath);
|
||||
}
|
||||
}
|
||||
set_num_threads(get_num_threads() - 1);
|
||||
}
|
||||
#endif
|
||||
@@ -1,367 +0,0 @@
|
||||
#ifndef SCAN_CPP
|
||||
#define SCAN_CPP
|
||||
#include "scan.h"
|
||||
#include <windows.h>
|
||||
#include <iostream>
|
||||
#include <openssl/md5.h>
|
||||
#include <windows.h>
|
||||
#include <iostream>
|
||||
#include <thread>
|
||||
#include <chrono>
|
||||
#include <stack>
|
||||
#include <time.h>
|
||||
#include "md5hash.h"
|
||||
#include <string>
|
||||
#include "well_known.h"
|
||||
#include "log.h"
|
||||
#include "virus_ctrl.h"
|
||||
#include "app_ctrl.h"
|
||||
#include <mutex> // Include the mutex header
|
||||
#include <filesystem>
|
||||
#include "utils.h"
|
||||
|
||||
// Define mutexes for thread synchronization
|
||||
std::mutex fileHandlesMutex;
|
||||
std::mutex mappingHandlesMutex;
|
||||
std::mutex fileDataMutex;
|
||||
std::mutex cntMutex;
|
||||
std::mutex numThreadsMutex;
|
||||
|
||||
std::unordered_map<std::string, HANDLE> fileHandles;
|
||||
std::unordered_map<std::string, HANDLE> mappingHandles;
|
||||
std::unordered_map<std::string, char*> fileData;
|
||||
|
||||
int cnt = 0;
|
||||
int num_threads = 0;
|
||||
int all_files = 0;
|
||||
|
||||
int get_num_threads() {
|
||||
std::lock_guard<std::mutex> lock(numThreadsMutex);
|
||||
return num_threads;
|
||||
}
|
||||
int set_num_threads(int num) {
|
||||
std::lock_guard<std::mutex> lock(numThreadsMutex);
|
||||
num_threads = num;
|
||||
return 0;
|
||||
}
|
||||
//load all the db files into memory
|
||||
int initialize(const std::string& folderPath) {
|
||||
for (char firstChar = '0'; firstChar <= 'f'; ++firstChar) {
|
||||
for (char secondChar = '0'; secondChar <= 'f'; ++secondChar) {
|
||||
// Ensure that the characters are valid hexadecimal digits
|
||||
if (!std::isxdigit(firstChar) || !std::isxdigit(secondChar) or std::isupper(firstChar) or std::isupper(secondChar)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Create the filename based on the naming convention
|
||||
std::string filename = folderPath + "\\" + firstChar + secondChar + ".jdbf";
|
||||
//printf("Loading %s\n", filename.c_str());
|
||||
|
||||
// Open the file
|
||||
HANDLE hFile = CreateFile(filename.c_str(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
if (hFile == INVALID_HANDLE_VALUE) {
|
||||
//log(LOGLEVEL::ERR, "[initialize()]: Error opening database file: ", filename);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Create the file mapping
|
||||
HANDLE hMapping = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL);
|
||||
if (hMapping == NULL) {
|
||||
// log(LOGLEVEL::ERR, "[initialize()]: Error creating database file mapping: ", filename);
|
||||
CloseHandle(hFile);
|
||||
return 2;
|
||||
}
|
||||
|
||||
// Map the file into memory
|
||||
char* fileDataPtr = static_cast<char*>(MapViewOfFile(hMapping, FILE_MAP_READ, 0, 0, 0));
|
||||
if (fileDataPtr == NULL) {
|
||||
//log(LOGLEVEL::ERR, "[initialize()]: Error mapping database file: ", filename);
|
||||
CloseHandle(hMapping);
|
||||
CloseHandle(hFile);
|
||||
return 3;
|
||||
}
|
||||
|
||||
// Store the handles in the global maps
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(fileHandlesMutex);
|
||||
fileHandles[filename] = hFile;
|
||||
}
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mappingHandlesMutex);
|
||||
mappingHandles[filename] = hMapping;
|
||||
}
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(fileDataMutex);
|
||||
fileData[filename] = fileDataPtr;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Call this function when you are done using the file mappings
|
||||
void cleanup() {
|
||||
for (const auto& entry : fileHandles) {
|
||||
UnmapViewOfFile(fileData[entry.first]);
|
||||
CloseHandle(mappingHandles[entry.first]);
|
||||
CloseHandle(entry.second);
|
||||
}
|
||||
|
||||
// Clear the global maps
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(fileHandlesMutex);
|
||||
fileHandles.clear();
|
||||
}
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mappingHandlesMutex);
|
||||
mappingHandles.clear();
|
||||
}
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(fileDataMutex);
|
||||
fileData.clear();
|
||||
}
|
||||
}
|
||||
|
||||
//the latest and fastest version of searching a hash by now
|
||||
int search_hash(const std::string& dbname_, const std::string& hash_, const std::string& filepath_) {
|
||||
// Check if the file mapping is already open for the given filename
|
||||
std::string dbname;
|
||||
std::string hash;
|
||||
std::string filepath;
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(fileHandlesMutex);
|
||||
dbname = dbname_;
|
||||
}
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(fileDataMutex);
|
||||
hash = hash_;
|
||||
}
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mappingHandlesMutex);
|
||||
filepath = filepath_;
|
||||
}
|
||||
|
||||
auto fileIter = fileHandles.find(dbname);
|
||||
if (fileIter == fileHandles.end() && dbname_.find("c:.jdbf") == std::string::npos) {
|
||||
log(LOGLEVEL::ERR_NOSEND, "[search_hash()]: File mapping not initialized for ", dbname);
|
||||
return 2;
|
||||
}
|
||||
else if (fileIter == fileHandles.end()) {
|
||||
return 2;
|
||||
}
|
||||
|
||||
// Use fileData for subsequent searches
|
||||
DWORD fileSize;
|
||||
std::string fileContent;
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(fileDataMutex);
|
||||
fileSize = GetFileSize(fileHandles[dbname], NULL);
|
||||
fileContent = std::string(fileData[dbname], fileSize);
|
||||
}
|
||||
|
||||
// Search for the specific string in the file content
|
||||
size_t foundPos = fileContent.find(hash);
|
||||
if (foundPos != std::string::npos) {
|
||||
//log(LOGLEVEL::VIRUS, "[search_hash()]: Found virus: ", hash, " in file: ", filepath);
|
||||
virus_ctrl_store(filepath.c_str(), hash.c_str(), hash.c_str());
|
||||
//afterwards do the processing with that file
|
||||
virus_ctrl_process(hash.c_str());
|
||||
return 1; // Found
|
||||
}
|
||||
return 0; // Not found
|
||||
}
|
||||
|
||||
//function to get num of files in idr and its subdirs etc (iterative)
|
||||
int get_num_files(const std::string& directory) {
|
||||
std::string search_path = directory + "\\*.*";
|
||||
WIN32_FIND_DATA find_file_data;
|
||||
HANDLE hFind = FindFirstFile(search_path.c_str(), &find_file_data);
|
||||
int num_files = 0;
|
||||
|
||||
if (hFind == INVALID_HANDLE_VALUE) {
|
||||
//std::cerr << "[get_num_files()]: Could not open directory: " << search_path << " while scanning files inside directory." << std::endl;
|
||||
log(LOGLEVEL::ERR_NOSEND, "[get_num_files()]: Could not open directory: ", search_path, " while scanning files inside directory.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Stack to store directories to be traversed iteratively
|
||||
std::stack<std::string> directories;
|
||||
directories.push(directory);
|
||||
|
||||
while (!directories.empty()) {
|
||||
std::string current_dir = directories.top();
|
||||
directories.pop();
|
||||
|
||||
search_path = current_dir + "\\*.*";
|
||||
hFind = FindFirstFile(search_path.c_str(), &find_file_data);
|
||||
|
||||
if (hFind != INVALID_HANDLE_VALUE) {
|
||||
do {
|
||||
if (strcmp(find_file_data.cFileName, ".") == 0 || strcmp(find_file_data.cFileName, "..") == 0) {
|
||||
continue; // Skip the current and parent directories
|
||||
}
|
||||
|
||||
const std::string full_path = current_dir + "\\" + find_file_data.cFileName;
|
||||
if (find_file_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
|
||||
// If it's a directory, add it to the stack
|
||||
directories.push(full_path);
|
||||
}
|
||||
else {
|
||||
num_files++;
|
||||
}
|
||||
} while (FindNextFile(hFind, &find_file_data) != 0);
|
||||
FindClose(hFind);
|
||||
}
|
||||
else {
|
||||
std::cerr << "[get_num_files()]: Could not open directory: " << current_dir << " while scanning files inside directory." << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
return num_files;
|
||||
}
|
||||
|
||||
//this is the main function to scan folders. it will then start multuiple threads based on the number of cores / settings
|
||||
std::stack<std::string> directories; // Stack to store directories to be scanned
|
||||
|
||||
void scan_folder(const std::string& directory) {
|
||||
directories.push(directory);
|
||||
|
||||
while (!directories.empty()) {
|
||||
std::string current_dir = directories.top();
|
||||
directories.pop();
|
||||
|
||||
std::string search_path = current_dir + "\\*.*";
|
||||
WIN32_FIND_DATA find_file_data;
|
||||
HANDLE hFind = FindFirstFile(search_path.c_str(), &find_file_data);
|
||||
|
||||
if (hFind != INVALID_HANDLE_VALUE) {
|
||||
do {
|
||||
if (strcmp(find_file_data.cFileName, ".") == 0 || strcmp(find_file_data.cFileName, "..") == 0) {
|
||||
continue; // Skip the current and parent directories
|
||||
}
|
||||
|
||||
const std::string full_path = current_dir + "\\" + find_file_data.cFileName;
|
||||
if (find_file_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
|
||||
// If it's a directory, add it to the stack
|
||||
directories.push(full_path);
|
||||
}
|
||||
else {
|
||||
// Do multithreading here
|
||||
int thread_timeout = 0;
|
||||
while (get_num_threads() >= std::thread::hardware_concurrency()) {
|
||||
Sleep(10);
|
||||
thread_timeout++;
|
||||
if (thread_timeout == 100 * 60) {
|
||||
// If there is no available thread for more than 30 seconds, reset the thread counter
|
||||
set_num_threads(0);
|
||||
}
|
||||
}
|
||||
|
||||
if (is_valid_path(full_path)) { // Filter out invalid paths and paths with weird characters
|
||||
std::uintmax_t fileSize = std::filesystem::file_size(full_path);
|
||||
if (fileSize > 4000000000) { // 4GB
|
||||
log(LOGLEVEL::INFO_NOSEND, "[scan_folder()]: File too large to scan: ", full_path);
|
||||
}
|
||||
else {
|
||||
std::thread scan_thread(scan_file_t, full_path);
|
||||
scan_thread.detach();
|
||||
}
|
||||
}
|
||||
else {
|
||||
log(LOGLEVEL::INFO_NOSEND, "[scan_folder()]: Invalid path: ", full_path);
|
||||
}
|
||||
}
|
||||
} while (FindNextFile(hFind, &find_file_data) != 0);
|
||||
FindClose(hFind);
|
||||
}
|
||||
else {
|
||||
std::cerr << "[scan_folder()]: Could not open directory: " << current_dir << " while scanning files inside directory." << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
//for singlethreaded scans
|
||||
void action_scanfile(const std::string& filepath_) {
|
||||
thread_init();
|
||||
const std::string filepath(filepath_);
|
||||
char* db_path = new char[300];
|
||||
char* hash = new char[300];
|
||||
if (is_valid_path(filepath_)) { //filter out invalid paths and paths with weird characters
|
||||
std::string hash_(md5_file_t(filepath));
|
||||
if (strlen(hash_.c_str()) < 290)
|
||||
strcpy_s(hash, 295, hash_.c_str());
|
||||
else {
|
||||
strcpy_s(hash, 295, "");
|
||||
log(LOGLEVEL::ERR_NOSEND, "[scan_file_t()]: Could not calculate hash for file: ", filepath);
|
||||
}
|
||||
sprintf_s(db_path, 295, "%s\\%c%c.jdbf", DB_DIR, hash[0], hash[1]);
|
||||
if (search_hash(db_path, hash, filepath) != 1) {
|
||||
//notify desktop client by writing to answer_com file
|
||||
//if there is now virus, we notify here. if there is a virus we only notify in the virus_ctrl_process function
|
||||
std::ofstream answer_com(ANSWER_COM_PATH, std::ios::app);
|
||||
if (answer_com.is_open()) {
|
||||
answer_com << "not_found " << "\"" << filepath_ << "\"" << " " << hash << " " << "no_action_taken" << "\n";
|
||||
answer_com.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
log(LOGLEVEL::INFO_NOSEND, "[action_scanfile()]: Invalid path: ", filepath_);
|
||||
thread_shutdown();
|
||||
}
|
||||
void action_scanfolder(const std::string& folderpath) {
|
||||
thread_init();
|
||||
thread_local std::string folderpath_(folderpath);
|
||||
cnt = 0;
|
||||
all_files = get_num_files(folderpath_);
|
||||
//tell the desktop client that the scan has started
|
||||
std::ofstream answer_com1(ANSWER_COM_PATH, std::ios::app);
|
||||
if (answer_com1.is_open()) {
|
||||
answer_com1 << "start " << all_files << "\n";
|
||||
answer_com1.close();
|
||||
}
|
||||
scan_folder(folderpath_);
|
||||
std::ofstream answer_com(ANSWER_COM_PATH, std::ios::app);
|
||||
if (answer_com.is_open()) {
|
||||
answer_com << "end " << "\"" << "nothing" << "\"" << " " << "nothing" << " " << "nothing" << "\n";
|
||||
answer_com.close();
|
||||
}
|
||||
thread_shutdown();
|
||||
}
|
||||
|
||||
void scan_file_t(const std::string& filepath_) {
|
||||
set_num_threads(get_num_threads() + 1);
|
||||
thread_local const std::string filepath(filepath_);
|
||||
thread_local char* db_path = new char[300];
|
||||
thread_local char* hash = new char[300];
|
||||
thread_local std::string hash_(md5_file_t(filepath));
|
||||
if (strlen(hash_.c_str()) < 290)
|
||||
strcpy_s(hash, 295, hash_.c_str());
|
||||
else{
|
||||
strcpy_s(hash, 295, "");
|
||||
log(LOGLEVEL::ERR_NOSEND, "[scan_file_t()]: Could not calculate hash for file: ", filepath);
|
||||
}
|
||||
sprintf_s(db_path, 295, "%s\\%c%c.jdbf", DB_DIR, hash[0], hash[1]);
|
||||
search_hash(db_path, hash, filepath);
|
||||
set_num_threads(get_num_threads() - 1);
|
||||
}
|
||||
void scan_process_t(const std::string& filepath_) {
|
||||
set_num_threads(get_num_threads() + 1);
|
||||
thread_local const std::string filepath(filepath_);
|
||||
thread_local char* db_path = new char[300];
|
||||
thread_local char* hash = new char[300];
|
||||
strcpy_s(hash, 295, md5_file_t(filepath).c_str());
|
||||
sprintf_s(db_path, 295, "%s\\%c%c.jdbf", DB_DIR, hash[0], hash[1]);
|
||||
if (search_hash(db_path, hash, filepath) == 1) {
|
||||
//check if need to kill process
|
||||
if (get_setting("virus_ctrl:virus_process_found:kill") == 1) {
|
||||
//kill the process
|
||||
kill_process(filepath.c_str());
|
||||
log(LOGLEVEL::VIRUS, "[scan_process_t()]: Killing process: ", filepath);
|
||||
}
|
||||
}
|
||||
set_num_threads(get_num_threads() - 1);
|
||||
}
|
||||
#endif
|
||||
@@ -1,368 +0,0 @@
|
||||
#ifndef SCAN_CPP
|
||||
#define SCAN_CPP
|
||||
#include "scan.h"
|
||||
#include <windows.h>
|
||||
#include <iostream>
|
||||
#include <openssl/md5.h>
|
||||
#include <windows.h>
|
||||
#include <iostream>
|
||||
#include <thread>
|
||||
#include <chrono>
|
||||
#include <stack>
|
||||
#include <time.h>
|
||||
#include "md5hash.h"
|
||||
#include <string>
|
||||
#include "well_known.h"
|
||||
#include "log.h"
|
||||
#include "virus_ctrl.h"
|
||||
#include "app_ctrl.h"
|
||||
#include <mutex> // Include the mutex header
|
||||
#include <filesystem>
|
||||
#include "utils.h"
|
||||
|
||||
// Define mutexes for thread synchronization
|
||||
std::mutex fileHandlesMutex;
|
||||
std::mutex mappingHandlesMutex;
|
||||
std::mutex fileDataMutex;
|
||||
std::mutex cntMutex;
|
||||
std::mutex numThreadsMutex;
|
||||
|
||||
std::unordered_map<std::string, HANDLE> fileHandles;
|
||||
std::unordered_map<std::string, HANDLE> mappingHandles;
|
||||
std::unordered_map<std::string, char*> fileData;
|
||||
|
||||
int cnt = 0;
|
||||
int num_threads = 0;
|
||||
int all_files = 0;
|
||||
|
||||
int get_num_threads() {
|
||||
std::lock_guard<std::mutex> lock(numThreadsMutex);
|
||||
return num_threads;
|
||||
}
|
||||
int set_num_threads(int num) {
|
||||
std::lock_guard<std::mutex> lock(numThreadsMutex);
|
||||
num_threads = num;
|
||||
return 0;
|
||||
}
|
||||
//load all the db files into memory
|
||||
int initialize(const std::string& folderPath) {
|
||||
for (char firstChar = '0'; firstChar <= 'f'; ++firstChar) {
|
||||
for (char secondChar = '0'; secondChar <= 'f'; ++secondChar) {
|
||||
// Ensure that the characters are valid hexadecimal digits
|
||||
if (!std::isxdigit(firstChar) || !std::isxdigit(secondChar) or std::isupper(firstChar) or std::isupper(secondChar)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Create the filename based on the naming convention
|
||||
std::string filename = folderPath + "\\" + firstChar + secondChar + ".jdbf";
|
||||
//printf("Loading %s\n", filename.c_str());
|
||||
|
||||
// Open the file
|
||||
HANDLE hFile = CreateFile(filename.c_str(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
if (hFile == INVALID_HANDLE_VALUE) {
|
||||
//log(LOGLEVEL::ERR, "[initialize()]: Error opening database file: ", filename);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Create the file mapping
|
||||
HANDLE hMapping = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL);
|
||||
if (hMapping == NULL) {
|
||||
// log(LOGLEVEL::ERR, "[initialize()]: Error creating database file mapping: ", filename);
|
||||
CloseHandle(hFile);
|
||||
return 2;
|
||||
}
|
||||
|
||||
// Map the file into memory
|
||||
char* fileDataPtr = static_cast<char*>(MapViewOfFile(hMapping, FILE_MAP_READ, 0, 0, 0));
|
||||
if (fileDataPtr == NULL) {
|
||||
//log(LOGLEVEL::ERR, "[initialize()]: Error mapping database file: ", filename);
|
||||
CloseHandle(hMapping);
|
||||
CloseHandle(hFile);
|
||||
return 3;
|
||||
}
|
||||
|
||||
// Store the handles in the global maps
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(fileHandlesMutex);
|
||||
fileHandles[filename] = hFile;
|
||||
}
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mappingHandlesMutex);
|
||||
mappingHandles[filename] = hMapping;
|
||||
}
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(fileDataMutex);
|
||||
fileData[filename] = fileDataPtr;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Call this function when you are done using the file mappings
|
||||
void cleanup() {
|
||||
for (const auto& entry : fileHandles) {
|
||||
UnmapViewOfFile(fileData[entry.first]);
|
||||
CloseHandle(mappingHandles[entry.first]);
|
||||
CloseHandle(entry.second);
|
||||
}
|
||||
|
||||
// Clear the global maps
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(fileHandlesMutex);
|
||||
fileHandles.clear();
|
||||
}
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mappingHandlesMutex);
|
||||
mappingHandles.clear();
|
||||
}
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(fileDataMutex);
|
||||
fileData.clear();
|
||||
}
|
||||
}
|
||||
|
||||
//the latest and fastest version of searching a hash by now
|
||||
int search_hash(const std::string& dbname_, const std::string& hash_, const std::string& filepath_) {
|
||||
// Check if the file mapping is already open for the given filename
|
||||
std::string dbname;
|
||||
std::string hash;
|
||||
std::string filepath;
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(fileHandlesMutex);
|
||||
dbname = dbname_;
|
||||
}
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(fileDataMutex);
|
||||
hash = hash_;
|
||||
}
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mappingHandlesMutex);
|
||||
filepath = filepath_;
|
||||
}
|
||||
|
||||
auto fileIter = fileHandles.find(dbname);
|
||||
if (fileIter == fileHandles.end() && dbname_.find("c:.jdbf") == std::string::npos) {
|
||||
log(LOGLEVEL::ERR_NOSEND, "[search_hash()]: File mapping not initialized for ", dbname);
|
||||
return 2;
|
||||
}
|
||||
else if (fileIter == fileHandles.end()) {
|
||||
return 2;
|
||||
}
|
||||
|
||||
// Use fileData for subsequent searches
|
||||
DWORD fileSize;
|
||||
std::string fileContent;
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(fileDataMutex);
|
||||
fileSize = GetFileSize(fileHandles[dbname], NULL);
|
||||
fileContent = std::string(fileData[dbname], fileSize);
|
||||
}
|
||||
|
||||
// Search for the specific string in the file content
|
||||
size_t foundPos = fileContent.find(hash);
|
||||
if (foundPos != std::string::npos) {
|
||||
//log(LOGLEVEL::VIRUS, "[search_hash()]: Found virus: ", hash, " in file: ", filepath);
|
||||
virus_ctrl_store(filepath.c_str(), hash.c_str(), hash.c_str());
|
||||
//afterwards do the processing with that file
|
||||
virus_ctrl_process(hash.c_str());
|
||||
return 1; // Found
|
||||
}
|
||||
return 0; // Not found
|
||||
}
|
||||
|
||||
//function to get num of files in idr and its subdirs etc (iterative)
|
||||
int get_num_files(const std::string& directory) {
|
||||
std::string search_path = directory + "\\*.*";
|
||||
WIN32_FIND_DATA find_file_data;
|
||||
HANDLE hFind = FindFirstFile(search_path.c_str(), &find_file_data);
|
||||
int num_files = 0;
|
||||
|
||||
if (hFind == INVALID_HANDLE_VALUE) {
|
||||
//std::cerr << "[get_num_files()]: Could not open directory: " << search_path << " while scanning files inside directory." << std::endl;
|
||||
log(LOGLEVEL::ERR_NOSEND, "[get_num_files()]: Could not open directory: ", search_path, " while scanning files inside directory.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Stack to store directories to be traversed iteratively
|
||||
std::stack<std::string> directories;
|
||||
directories.push(directory);
|
||||
|
||||
while (!directories.empty()) {
|
||||
std::string current_dir = directories.top();
|
||||
directories.pop();
|
||||
|
||||
search_path = current_dir + "\\*.*";
|
||||
hFind = FindFirstFile(search_path.c_str(), &find_file_data);
|
||||
|
||||
if (hFind != INVALID_HANDLE_VALUE) {
|
||||
do {
|
||||
if (strcmp(find_file_data.cFileName, ".") == 0 || strcmp(find_file_data.cFileName, "..") == 0) {
|
||||
continue; // Skip the current and parent directories
|
||||
}
|
||||
|
||||
const std::string full_path = current_dir + "\\" + find_file_data.cFileName;
|
||||
if (find_file_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
|
||||
// If it's a directory, add it to the stack
|
||||
directories.push(full_path);
|
||||
}
|
||||
else {
|
||||
num_files++;
|
||||
}
|
||||
} while (FindNextFile(hFind, &find_file_data) != 0);
|
||||
FindClose(hFind);
|
||||
}
|
||||
else {
|
||||
log(LOGLEVEL::ERR_NOSEND, "[get_num_files()]: Could not open directory: ", current_dir, " while scanning files inside directory.");
|
||||
//std::cerr << "[get_num_files()]: Could not open directory: " << current_dir << " while scanning files inside directory." << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
return num_files;
|
||||
}
|
||||
|
||||
//this is the main function to scan folders. it will then start multuiple threads based on the number of cores / settings
|
||||
std::stack<std::string> directories; // Stack to store directories to be scanned
|
||||
|
||||
void scan_folder(const std::string& directory) {
|
||||
directories.push(directory);
|
||||
|
||||
while (!directories.empty()) {
|
||||
std::string current_dir = directories.top();
|
||||
directories.pop();
|
||||
|
||||
std::string search_path = current_dir + "\\*.*";
|
||||
WIN32_FIND_DATA find_file_data;
|
||||
HANDLE hFind = FindFirstFile(search_path.c_str(), &find_file_data);
|
||||
|
||||
if (hFind != INVALID_HANDLE_VALUE) {
|
||||
do {
|
||||
if (strcmp(find_file_data.cFileName, ".") == 0 || strcmp(find_file_data.cFileName, "..") == 0) {
|
||||
continue; // Skip the current and parent directories
|
||||
}
|
||||
|
||||
const std::string full_path = current_dir + "\\" + find_file_data.cFileName;
|
||||
if (find_file_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
|
||||
// If it's a directory, add it to the stack
|
||||
directories.push(full_path);
|
||||
}
|
||||
else {
|
||||
// Do multithreading here
|
||||
int thread_timeout = 0;
|
||||
while (get_num_threads() >= std::thread::hardware_concurrency()) {
|
||||
Sleep(10);
|
||||
thread_timeout++;
|
||||
if (thread_timeout == 100 * 60) {
|
||||
// If there is no available thread for more than 30 seconds, reset the thread counter
|
||||
set_num_threads(0);
|
||||
}
|
||||
}
|
||||
|
||||
if (is_valid_path(full_path)) { // Filter out invalid paths and paths with weird characters
|
||||
std::uintmax_t fileSize = std::filesystem::file_size(full_path);
|
||||
if (fileSize > 4000000000) { // 4GB
|
||||
log(LOGLEVEL::INFO_NOSEND, "[scan_folder()]: File too large to scan: ", full_path);
|
||||
}
|
||||
else {
|
||||
std::thread scan_thread(scan_file_t, full_path);
|
||||
scan_thread.detach();
|
||||
}
|
||||
}
|
||||
else {
|
||||
log(LOGLEVEL::INFO_NOSEND, "[scan_folder()]: Invalid path: ", full_path);
|
||||
}
|
||||
}
|
||||
} while (FindNextFile(hFind, &find_file_data) != 0);
|
||||
FindClose(hFind);
|
||||
}
|
||||
else {
|
||||
std::cerr << "[scan_folder()]: Could not open directory: " << current_dir << " while scanning files inside directory." << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
//for singlethreaded scans
|
||||
void action_scanfile(const std::string& filepath_) {
|
||||
thread_init();
|
||||
const std::string filepath(filepath_);
|
||||
char* db_path = new char[300];
|
||||
char* hash = new char[300];
|
||||
if (is_valid_path(filepath_)) { //filter out invalid paths and paths with weird characters
|
||||
std::string hash_(md5_file_t(filepath));
|
||||
if (strlen(hash_.c_str()) < 290)
|
||||
strcpy_s(hash, 295, hash_.c_str());
|
||||
else {
|
||||
strcpy_s(hash, 295, "");
|
||||
log(LOGLEVEL::ERR_NOSEND, "[scan_file_t()]: Could not calculate hash for file: ", filepath);
|
||||
}
|
||||
sprintf_s(db_path, 295, "%s\\%c%c.jdbf", DB_DIR, hash[0], hash[1]);
|
||||
if (search_hash(db_path, hash, filepath) != 1) {
|
||||
//notify desktop client by writing to answer_com file
|
||||
//if there is now virus, we notify here. if there is a virus we only notify in the virus_ctrl_process function
|
||||
std::ofstream answer_com(ANSWER_COM_PATH, std::ios::app);
|
||||
if (answer_com.is_open()) {
|
||||
answer_com << "not_found " << "\"" << filepath_ << "\"" << " " << hash << " " << "no_action_taken" << "\n";
|
||||
answer_com.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
log(LOGLEVEL::INFO_NOSEND, "[action_scanfile()]: Invalid path: ", filepath_);
|
||||
thread_shutdown();
|
||||
}
|
||||
void action_scanfolder(const std::string& folderpath) {
|
||||
thread_init();
|
||||
thread_local std::string folderpath_(folderpath);
|
||||
cnt = 0;
|
||||
all_files = get_num_files(folderpath_);
|
||||
//tell the desktop client that the scan has started
|
||||
std::ofstream answer_com1(ANSWER_COM_PATH, std::ios::app);
|
||||
if (answer_com1.is_open()) {
|
||||
answer_com1 << "start " << all_files << "\n";
|
||||
answer_com1.close();
|
||||
}
|
||||
scan_folder(folderpath_);
|
||||
std::ofstream answer_com(ANSWER_COM_PATH, std::ios::app);
|
||||
if (answer_com.is_open()) {
|
||||
answer_com << "end " << "\"" << "nothing" << "\"" << " " << "nothing" << " " << "nothing" << "\n";
|
||||
answer_com.close();
|
||||
}
|
||||
thread_shutdown();
|
||||
}
|
||||
|
||||
void scan_file_t(const std::string& filepath_) {
|
||||
set_num_threads(get_num_threads() + 1);
|
||||
thread_local const std::string filepath(filepath_);
|
||||
thread_local char* db_path = new char[300];
|
||||
thread_local char* hash = new char[300];
|
||||
thread_local std::string hash_(md5_file_t(filepath));
|
||||
if (strlen(hash_.c_str()) < 290)
|
||||
strcpy_s(hash, 295, hash_.c_str());
|
||||
else{
|
||||
strcpy_s(hash, 295, "");
|
||||
log(LOGLEVEL::ERR_NOSEND, "[scan_file_t()]: Could not calculate hash for file: ", filepath);
|
||||
}
|
||||
sprintf_s(db_path, 295, "%s\\%c%c.jdbf", DB_DIR, hash[0], hash[1]);
|
||||
search_hash(db_path, hash, filepath);
|
||||
set_num_threads(get_num_threads() - 1);
|
||||
}
|
||||
void scan_process_t(const std::string& filepath_) {
|
||||
set_num_threads(get_num_threads() + 1);
|
||||
thread_local const std::string filepath(filepath_);
|
||||
thread_local char* db_path = new char[300];
|
||||
thread_local char* hash = new char[300];
|
||||
strcpy_s(hash, 295, md5_file_t(filepath).c_str());
|
||||
sprintf_s(db_path, 295, "%s\\%c%c.jdbf", DB_DIR, hash[0], hash[1]);
|
||||
if (search_hash(db_path, hash, filepath) == 1) {
|
||||
//check if need to kill process
|
||||
if (get_setting("virus_ctrl:virus_process_found:kill") == 1) {
|
||||
//kill the process
|
||||
kill_process(filepath.c_str());
|
||||
log(LOGLEVEL::VIRUS, "[scan_process_t()]: Killing process: ", filepath);
|
||||
}
|
||||
}
|
||||
set_num_threads(get_num_threads() - 1);
|
||||
}
|
||||
#endif
|
||||
@@ -1,369 +0,0 @@
|
||||
#ifndef SCAN_CPP
|
||||
#define SCAN_CPP
|
||||
#include "scan.h"
|
||||
#include <windows.h>
|
||||
#include <iostream>
|
||||
#include <openssl/md5.h>
|
||||
#include <windows.h>
|
||||
#include <iostream>
|
||||
#include <thread>
|
||||
#include <chrono>
|
||||
#include <stack>
|
||||
#include <time.h>
|
||||
#include "md5hash.h"
|
||||
#include <string>
|
||||
#include "well_known.h"
|
||||
#include "log.h"
|
||||
#include "virus_ctrl.h"
|
||||
#include "app_ctrl.h"
|
||||
#include <mutex> // Include the mutex header
|
||||
#include <filesystem>
|
||||
#include "utils.h"
|
||||
|
||||
// Define mutexes for thread synchronization
|
||||
std::mutex fileHandlesMutex;
|
||||
std::mutex mappingHandlesMutex;
|
||||
std::mutex fileDataMutex;
|
||||
std::mutex cntMutex;
|
||||
std::mutex numThreadsMutex;
|
||||
|
||||
std::unordered_map<std::string, HANDLE> fileHandles;
|
||||
std::unordered_map<std::string, HANDLE> mappingHandles;
|
||||
std::unordered_map<std::string, char*> fileData;
|
||||
|
||||
int cnt = 0;
|
||||
int num_threads = 0;
|
||||
int all_files = 0;
|
||||
|
||||
int get_num_threads() {
|
||||
std::lock_guard<std::mutex> lock(numThreadsMutex);
|
||||
return num_threads;
|
||||
}
|
||||
int set_num_threads(int num) {
|
||||
std::lock_guard<std::mutex> lock(numThreadsMutex);
|
||||
num_threads = num;
|
||||
return 0;
|
||||
}
|
||||
//load all the db files into memory
|
||||
int initialize(const std::string& folderPath) {
|
||||
for (char firstChar = '0'; firstChar <= 'f'; ++firstChar) {
|
||||
for (char secondChar = '0'; secondChar <= 'f'; ++secondChar) {
|
||||
// Ensure that the characters are valid hexadecimal digits
|
||||
if (!std::isxdigit(firstChar) || !std::isxdigit(secondChar) or std::isupper(firstChar) or std::isupper(secondChar)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Create the filename based on the naming convention
|
||||
std::string filename = folderPath + "\\" + firstChar + secondChar + ".jdbf";
|
||||
//printf("Loading %s\n", filename.c_str());
|
||||
|
||||
// Open the file
|
||||
HANDLE hFile = CreateFile(filename.c_str(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
if (hFile == INVALID_HANDLE_VALUE) {
|
||||
//log(LOGLEVEL::ERR, "[initialize()]: Error opening database file: ", filename);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Create the file mapping
|
||||
HANDLE hMapping = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL);
|
||||
if (hMapping == NULL) {
|
||||
// log(LOGLEVEL::ERR, "[initialize()]: Error creating database file mapping: ", filename);
|
||||
CloseHandle(hFile);
|
||||
return 2;
|
||||
}
|
||||
|
||||
// Map the file into memory
|
||||
char* fileDataPtr = static_cast<char*>(MapViewOfFile(hMapping, FILE_MAP_READ, 0, 0, 0));
|
||||
if (fileDataPtr == NULL) {
|
||||
//log(LOGLEVEL::ERR, "[initialize()]: Error mapping database file: ", filename);
|
||||
CloseHandle(hMapping);
|
||||
CloseHandle(hFile);
|
||||
return 3;
|
||||
}
|
||||
|
||||
// Store the handles in the global maps
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(fileHandlesMutex);
|
||||
fileHandles[filename] = hFile;
|
||||
}
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mappingHandlesMutex);
|
||||
mappingHandles[filename] = hMapping;
|
||||
}
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(fileDataMutex);
|
||||
fileData[filename] = fileDataPtr;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Call this function when you are done using the file mappings
|
||||
void cleanup() {
|
||||
for (const auto& entry : fileHandles) {
|
||||
UnmapViewOfFile(fileData[entry.first]);
|
||||
CloseHandle(mappingHandles[entry.first]);
|
||||
CloseHandle(entry.second);
|
||||
}
|
||||
|
||||
// Clear the global maps
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(fileHandlesMutex);
|
||||
fileHandles.clear();
|
||||
}
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mappingHandlesMutex);
|
||||
mappingHandles.clear();
|
||||
}
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(fileDataMutex);
|
||||
fileData.clear();
|
||||
}
|
||||
}
|
||||
|
||||
//the latest and fastest version of searching a hash by now
|
||||
int search_hash(const std::string& dbname_, const std::string& hash_, const std::string& filepath_) {
|
||||
// Check if the file mapping is already open for the given filename
|
||||
std::string dbname;
|
||||
std::string hash;
|
||||
std::string filepath;
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(fileHandlesMutex);
|
||||
dbname = dbname_;
|
||||
}
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(fileDataMutex);
|
||||
hash = hash_;
|
||||
}
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mappingHandlesMutex);
|
||||
filepath = filepath_;
|
||||
}
|
||||
|
||||
auto fileIter = fileHandles.find(dbname);
|
||||
if (fileIter == fileHandles.end() && dbname_.find("c:.jdbf") == std::string::npos) {
|
||||
log(LOGLEVEL::ERR_NOSEND, "[search_hash()]: File mapping not initialized for ", dbname);
|
||||
return 2;
|
||||
}
|
||||
else if (fileIter == fileHandles.end()) {
|
||||
return 2;
|
||||
}
|
||||
|
||||
// Use fileData for subsequent searches
|
||||
DWORD fileSize;
|
||||
std::string fileContent;
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(fileDataMutex);
|
||||
fileSize = GetFileSize(fileHandles[dbname], NULL);
|
||||
fileContent = std::string(fileData[dbname], fileSize);
|
||||
}
|
||||
|
||||
// Search for the specific string in the file content
|
||||
size_t foundPos = fileContent.find(hash);
|
||||
if (foundPos != std::string::npos) {
|
||||
//log(LOGLEVEL::VIRUS, "[search_hash()]: Found virus: ", hash, " in file: ", filepath);
|
||||
virus_ctrl_store(filepath.c_str(), hash.c_str(), hash.c_str());
|
||||
//afterwards do the processing with that file
|
||||
virus_ctrl_process(hash.c_str());
|
||||
return 1; // Found
|
||||
}
|
||||
return 0; // Not found
|
||||
}
|
||||
|
||||
//function to get num of files in idr and its subdirs etc (iterative)
|
||||
int get_num_files(const std::string& directory) {
|
||||
std::string search_path = directory + "\\*.*";
|
||||
WIN32_FIND_DATA find_file_data;
|
||||
HANDLE hFind = FindFirstFile(search_path.c_str(), &find_file_data);
|
||||
int num_files = 0;
|
||||
|
||||
if (hFind == INVALID_HANDLE_VALUE) {
|
||||
//std::cerr << "[get_num_files()]: Could not open directory: " << search_path << " while scanning files inside directory." << std::endl;
|
||||
log(LOGLEVEL::ERR_NOSEND, "[get_num_files()]: Could not open directory: ", search_path, " while scanning files inside directory.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Stack to store directories to be traversed iteratively
|
||||
std::stack<std::string> directories;
|
||||
directories.push(directory);
|
||||
|
||||
while (!directories.empty()) {
|
||||
std::string current_dir = directories.top();
|
||||
directories.pop();
|
||||
|
||||
search_path = current_dir + "\\*.*";
|
||||
hFind = FindFirstFile(search_path.c_str(), &find_file_data);
|
||||
|
||||
if (hFind != INVALID_HANDLE_VALUE) {
|
||||
do {
|
||||
if (strcmp(find_file_data.cFileName, ".") == 0 || strcmp(find_file_data.cFileName, "..") == 0) {
|
||||
continue; // Skip the current and parent directories
|
||||
}
|
||||
|
||||
const std::string full_path = current_dir + "\\" + find_file_data.cFileName;
|
||||
if (find_file_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
|
||||
// If it's a directory, add it to the stack
|
||||
directories.push(full_path);
|
||||
}
|
||||
else {
|
||||
num_files++;
|
||||
}
|
||||
} while (FindNextFile(hFind, &find_file_data) != 0);
|
||||
FindClose(hFind);
|
||||
}
|
||||
else {
|
||||
log(LOGLEVEL::ERR_NOSEND, "[get_num_files()]: Could not open directory: ", current_dir, " while scanning files inside directory.");
|
||||
//std::cerr << "[get_num_files()]: Could not open directory: " << current_dir << " while scanning files inside directory." << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
return num_files;
|
||||
}
|
||||
|
||||
//this is the main function to scan folders. it will then start multuiple threads based on the number of cores / settings
|
||||
std::stack<std::string> directories; // Stack to store directories to be scanned
|
||||
|
||||
void scan_folder(const std::string& directory) {
|
||||
directories.push(directory);
|
||||
|
||||
while (!directories.empty()) {
|
||||
std::string current_dir = directories.top();
|
||||
directories.pop();
|
||||
|
||||
std::string search_path = current_dir + "\\*.*";
|
||||
WIN32_FIND_DATA find_file_data;
|
||||
HANDLE hFind = FindFirstFile(search_path.c_str(), &find_file_data);
|
||||
|
||||
if (hFind != INVALID_HANDLE_VALUE) {
|
||||
do {
|
||||
if (strcmp(find_file_data.cFileName, ".") == 0 || strcmp(find_file_data.cFileName, "..") == 0) {
|
||||
continue; // Skip the current and parent directories
|
||||
}
|
||||
|
||||
const std::string full_path = current_dir + "\\" + find_file_data.cFileName;
|
||||
if (find_file_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
|
||||
// If it's a directory, add it to the stack
|
||||
directories.push(full_path);
|
||||
}
|
||||
else {
|
||||
// Do multithreading here
|
||||
int thread_timeout = 0;
|
||||
while (get_num_threads() >= std::thread::hardware_concurrency()) {
|
||||
Sleep(10);
|
||||
thread_timeout++;
|
||||
if (thread_timeout == 100 * 60) {
|
||||
// If there is no available thread for more than 30 seconds, reset the thread counter
|
||||
set_num_threads(0);
|
||||
}
|
||||
}
|
||||
|
||||
if (is_valid_path(full_path)) { // Filter out invalid paths and paths with weird characters
|
||||
std::uintmax_t fileSize = std::filesystem::file_size(full_path);
|
||||
if (fileSize > 4000000000) { // 4GB
|
||||
log(LOGLEVEL::INFO_NOSEND, "[scan_folder()]: File too large to scan: ", full_path);
|
||||
}
|
||||
else {
|
||||
std::thread scan_thread(scan_file_t, full_path);
|
||||
scan_thread.detach();
|
||||
}
|
||||
}
|
||||
else {
|
||||
log(LOGLEVEL::INFO_NOSEND, "[scan_folder()]: Invalid path: ", full_path);
|
||||
}
|
||||
}
|
||||
} while (FindNextFile(hFind, &find_file_data) != 0);
|
||||
FindClose(hFind);
|
||||
}
|
||||
else {
|
||||
log(LOGLEVEL::ERR_NOSEND, "[scan_folder()]: Could not open directory: ", current_dir, " while scanning files inside directory.");
|
||||
//std::cerr << "[scan_folder()]: Could not open directory: " << current_dir << " while scanning files inside directory." << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
//for singlethreaded scans
|
||||
void action_scanfile(const std::string& filepath_) {
|
||||
thread_init();
|
||||
const std::string filepath(filepath_);
|
||||
char* db_path = new char[300];
|
||||
char* hash = new char[300];
|
||||
if (is_valid_path(filepath_)) { //filter out invalid paths and paths with weird characters
|
||||
std::string hash_(md5_file_t(filepath));
|
||||
if (strlen(hash_.c_str()) < 290)
|
||||
strcpy_s(hash, 295, hash_.c_str());
|
||||
else {
|
||||
strcpy_s(hash, 295, "");
|
||||
log(LOGLEVEL::ERR_NOSEND, "[scan_file_t()]: Could not calculate hash for file: ", filepath);
|
||||
}
|
||||
sprintf_s(db_path, 295, "%s\\%c%c.jdbf", DB_DIR, hash[0], hash[1]);
|
||||
if (search_hash(db_path, hash, filepath) != 1) {
|
||||
//notify desktop client by writing to answer_com file
|
||||
//if there is now virus, we notify here. if there is a virus we only notify in the virus_ctrl_process function
|
||||
std::ofstream answer_com(ANSWER_COM_PATH, std::ios::app);
|
||||
if (answer_com.is_open()) {
|
||||
answer_com << "not_found " << "\"" << filepath_ << "\"" << " " << hash << " " << "no_action_taken" << "\n";
|
||||
answer_com.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
log(LOGLEVEL::INFO_NOSEND, "[action_scanfile()]: Invalid path: ", filepath_);
|
||||
thread_shutdown();
|
||||
}
|
||||
void action_scanfolder(const std::string& folderpath) {
|
||||
thread_init();
|
||||
thread_local std::string folderpath_(folderpath);
|
||||
cnt = 0;
|
||||
all_files = get_num_files(folderpath_);
|
||||
//tell the desktop client that the scan has started
|
||||
std::ofstream answer_com1(ANSWER_COM_PATH, std::ios::app);
|
||||
if (answer_com1.is_open()) {
|
||||
answer_com1 << "start " << all_files << "\n";
|
||||
answer_com1.close();
|
||||
}
|
||||
scan_folder(folderpath_);
|
||||
std::ofstream answer_com(ANSWER_COM_PATH, std::ios::app);
|
||||
if (answer_com.is_open()) {
|
||||
answer_com << "end " << "\"" << "nothing" << "\"" << " " << "nothing" << " " << "nothing" << "\n";
|
||||
answer_com.close();
|
||||
}
|
||||
thread_shutdown();
|
||||
}
|
||||
|
||||
void scan_file_t(const std::string& filepath_) {
|
||||
set_num_threads(get_num_threads() + 1);
|
||||
thread_local const std::string filepath(filepath_);
|
||||
thread_local char* db_path = new char[300];
|
||||
thread_local char* hash = new char[300];
|
||||
thread_local std::string hash_(md5_file_t(filepath));
|
||||
if (strlen(hash_.c_str()) < 290)
|
||||
strcpy_s(hash, 295, hash_.c_str());
|
||||
else{
|
||||
strcpy_s(hash, 295, "");
|
||||
log(LOGLEVEL::ERR_NOSEND, "[scan_file_t()]: Could not calculate hash for file: ", filepath);
|
||||
}
|
||||
sprintf_s(db_path, 295, "%s\\%c%c.jdbf", DB_DIR, hash[0], hash[1]);
|
||||
search_hash(db_path, hash, filepath);
|
||||
set_num_threads(get_num_threads() - 1);
|
||||
}
|
||||
void scan_process_t(const std::string& filepath_) {
|
||||
set_num_threads(get_num_threads() + 1);
|
||||
thread_local const std::string filepath(filepath_);
|
||||
thread_local char* db_path = new char[300];
|
||||
thread_local char* hash = new char[300];
|
||||
strcpy_s(hash, 295, md5_file_t(filepath).c_str());
|
||||
sprintf_s(db_path, 295, "%s\\%c%c.jdbf", DB_DIR, hash[0], hash[1]);
|
||||
if (search_hash(db_path, hash, filepath) == 1) {
|
||||
//check if need to kill process
|
||||
if (get_setting("virus_ctrl:virus_process_found:kill") == 1) {
|
||||
//kill the process
|
||||
kill_process(filepath.c_str());
|
||||
log(LOGLEVEL::VIRUS, "[scan_process_t()]: Killing process: ", filepath);
|
||||
}
|
||||
}
|
||||
set_num_threads(get_num_threads() - 1);
|
||||
}
|
||||
#endif
|
||||
@@ -1,382 +0,0 @@
|
||||
#ifndef SCAN_CPP
|
||||
#define SCAN_CPP
|
||||
#include "scan.h"
|
||||
#include <windows.h>
|
||||
#include <iostream>
|
||||
#include <openssl/md5.h>
|
||||
#include <windows.h>
|
||||
#include <iostream>
|
||||
#include <thread>
|
||||
#include <chrono>
|
||||
#include <stack>
|
||||
#include <time.h>
|
||||
#include "md5hash.h"
|
||||
#include <string>
|
||||
#include "well_known.h"
|
||||
#include "log.h"
|
||||
#include "virus_ctrl.h"
|
||||
#include "app_ctrl.h"
|
||||
#include <mutex> // Include the mutex header
|
||||
#include <filesystem>
|
||||
#include "utils.h"
|
||||
|
||||
// Define mutexes for thread synchronization
|
||||
std::mutex fileHandlesMutex;
|
||||
std::mutex mappingHandlesMutex;
|
||||
std::mutex fileDataMutex;
|
||||
std::mutex cntMutex;
|
||||
std::mutex numThreadsMutex;
|
||||
|
||||
std::unordered_map<std::string, HANDLE> fileHandles;
|
||||
std::unordered_map<std::string, HANDLE> mappingHandles;
|
||||
std::unordered_map<std::string, char*> fileData;
|
||||
|
||||
int cnt = 0;
|
||||
int num_threads = 0;
|
||||
int all_files = 0;
|
||||
|
||||
int get_num_threads() {
|
||||
std::lock_guard<std::mutex> lock(numThreadsMutex);
|
||||
return num_threads;
|
||||
}
|
||||
int set_num_threads(int num) {
|
||||
std::lock_guard<std::mutex> lock(numThreadsMutex);
|
||||
num_threads = num;
|
||||
return 0;
|
||||
}
|
||||
//load all the db files into memory
|
||||
int initialize(const std::string& folderPath) {
|
||||
for (char firstChar = '0'; firstChar <= 'f'; ++firstChar) {
|
||||
for (char secondChar = '0'; secondChar <= 'f'; ++secondChar) {
|
||||
// Ensure that the characters are valid hexadecimal digits
|
||||
if (!std::isxdigit(firstChar) || !std::isxdigit(secondChar) or std::isupper(firstChar) or std::isupper(secondChar)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Create the filename based on the naming convention
|
||||
std::string filename = folderPath + "\\" + firstChar + secondChar + ".jdbf";
|
||||
//printf("Loading %s\n", filename.c_str());
|
||||
|
||||
// Open the file
|
||||
HANDLE hFile = CreateFile(filename.c_str(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
if (hFile == INVALID_HANDLE_VALUE) {
|
||||
//log(LOGLEVEL::ERR, "[initialize()]: Error opening database file: ", filename);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Create the file mapping
|
||||
HANDLE hMapping = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL);
|
||||
if (hMapping == NULL) {
|
||||
// log(LOGLEVEL::ERR, "[initialize()]: Error creating database file mapping: ", filename);
|
||||
CloseHandle(hFile);
|
||||
return 2;
|
||||
}
|
||||
|
||||
// Map the file into memory
|
||||
char* fileDataPtr = static_cast<char*>(MapViewOfFile(hMapping, FILE_MAP_READ, 0, 0, 0));
|
||||
if (fileDataPtr == NULL) {
|
||||
//log(LOGLEVEL::ERR, "[initialize()]: Error mapping database file: ", filename);
|
||||
CloseHandle(hMapping);
|
||||
CloseHandle(hFile);
|
||||
return 3;
|
||||
}
|
||||
|
||||
// Store the handles in the global maps
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(fileHandlesMutex);
|
||||
fileHandles[filename] = hFile;
|
||||
}
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mappingHandlesMutex);
|
||||
mappingHandles[filename] = hMapping;
|
||||
}
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(fileDataMutex);
|
||||
fileData[filename] = fileDataPtr;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Call this function when you are done using the file mappings
|
||||
void cleanup() {
|
||||
for (const auto& entry : fileHandles) {
|
||||
UnmapViewOfFile(fileData[entry.first]);
|
||||
CloseHandle(mappingHandles[entry.first]);
|
||||
CloseHandle(entry.second);
|
||||
}
|
||||
|
||||
// Clear the global maps
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(fileHandlesMutex);
|
||||
fileHandles.clear();
|
||||
}
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mappingHandlesMutex);
|
||||
mappingHandles.clear();
|
||||
}
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(fileDataMutex);
|
||||
fileData.clear();
|
||||
}
|
||||
}
|
||||
|
||||
//the latest and fastest version of searching a hash by now
|
||||
int search_hash(const std::string& dbname_, const std::string& hash_, const std::string& filepath_) {
|
||||
// Check if the file mapping is already open for the given filename
|
||||
std::string dbname;
|
||||
std::string hash;
|
||||
std::string filepath;
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(fileHandlesMutex);
|
||||
dbname = dbname_;
|
||||
}
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(fileDataMutex);
|
||||
hash = hash_;
|
||||
}
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mappingHandlesMutex);
|
||||
filepath = filepath_;
|
||||
}
|
||||
|
||||
auto fileIter = fileHandles.find(dbname);
|
||||
if (fileIter == fileHandles.end() && dbname_.find("c:.jdbf") == std::string::npos) {
|
||||
log(LOGLEVEL::ERR_NOSEND, "[search_hash()]: File mapping not initialized for ", dbname);
|
||||
return 2;
|
||||
}
|
||||
else if (fileIter == fileHandles.end()) {
|
||||
return 2;
|
||||
}
|
||||
|
||||
// Use fileData for subsequent searches
|
||||
DWORD fileSize;
|
||||
std::string fileContent;
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(fileDataMutex);
|
||||
fileSize = GetFileSize(fileHandles[dbname], NULL);
|
||||
fileContent = std::string(fileData[dbname], fileSize);
|
||||
}
|
||||
|
||||
// Search for the specific string in the file content
|
||||
size_t foundPos = fileContent.find(hash);
|
||||
if (foundPos != std::string::npos) {
|
||||
//log(LOGLEVEL::VIRUS, "[search_hash()]: Found virus: ", hash, " in file: ", filepath);
|
||||
virus_ctrl_store(filepath.c_str(), hash.c_str(), hash.c_str());
|
||||
//afterwards do the processing with that file
|
||||
virus_ctrl_process(hash.c_str());
|
||||
return 1; // Found
|
||||
}
|
||||
return 0; // Not found
|
||||
}
|
||||
|
||||
//function to get num of files in idr and its subdirs etc (iterative)
|
||||
int get_num_files(const std::string& directory) {
|
||||
std::string search_path = directory + "\\*.*";
|
||||
WIN32_FIND_DATA find_file_data;
|
||||
HANDLE hFind = FindFirstFile(search_path.c_str(), &find_file_data);
|
||||
int num_files = 0;
|
||||
|
||||
if (hFind == INVALID_HANDLE_VALUE) {
|
||||
//std::cerr << "[get_num_files()]: Could not open directory: " << search_path << " while scanning files inside directory." << std::endl;
|
||||
log(LOGLEVEL::ERR_NOSEND, "[get_num_files()]: Could not open directory: ", search_path, " while scanning files inside directory.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Stack to store directories to be traversed iteratively
|
||||
std::stack<std::string> directories;
|
||||
directories.push(directory);
|
||||
|
||||
while (!directories.empty()) {
|
||||
std::string current_dir = directories.top();
|
||||
directories.pop();
|
||||
|
||||
search_path = current_dir + "\\*.*";
|
||||
hFind = FindFirstFile(search_path.c_str(), &find_file_data);
|
||||
|
||||
if (hFind != INVALID_HANDLE_VALUE) {
|
||||
do {
|
||||
if (strcmp(find_file_data.cFileName, ".") == 0 || strcmp(find_file_data.cFileName, "..") == 0) {
|
||||
continue; // Skip the current and parent directories
|
||||
}
|
||||
|
||||
const std::string full_path = current_dir + "\\" + find_file_data.cFileName;
|
||||
if (find_file_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
|
||||
// If it's a directory, add it to the stack
|
||||
directories.push(full_path);
|
||||
}
|
||||
else {
|
||||
num_files++;
|
||||
}
|
||||
} while (FindNextFile(hFind, &find_file_data) != 0);
|
||||
FindClose(hFind);
|
||||
}
|
||||
else {
|
||||
log(LOGLEVEL::ERR_NOSEND, "[get_num_files()]: Could not open directory: ", current_dir, " while scanning files inside directory.");
|
||||
//std::cerr << "[get_num_files()]: Could not open directory: " << current_dir << " while scanning files inside directory." << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
return num_files;
|
||||
}
|
||||
|
||||
//this is the main function to scan folders. it will then start multuiple threads based on the number of cores / settings
|
||||
std::stack<std::string> directories; // Stack to store directories to be scanned
|
||||
|
||||
void scan_folder(const std::string& directory) {
|
||||
directories.push(directory);
|
||||
|
||||
while (!directories.empty()) {
|
||||
std::string current_dir = directories.top();
|
||||
directories.pop();
|
||||
|
||||
std::string search_path = current_dir + "\\*.*";
|
||||
WIN32_FIND_DATA find_file_data;
|
||||
HANDLE hFind = FindFirstFile(search_path.c_str(), &find_file_data);
|
||||
|
||||
if (hFind != INVALID_HANDLE_VALUE) {
|
||||
do {
|
||||
if (strcmp(find_file_data.cFileName, ".") == 0 || strcmp(find_file_data.cFileName, "..") == 0) {
|
||||
continue; // Skip the current and parent directories
|
||||
}
|
||||
|
||||
const std::string full_path = current_dir + "\\" + find_file_data.cFileName;
|
||||
if (find_file_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
|
||||
// If it's a directory, add it to the stack
|
||||
directories.push(full_path);
|
||||
}
|
||||
else {
|
||||
// Do multithreading here
|
||||
int thread_timeout = 0;
|
||||
while (get_num_threads() >= std::thread::hardware_concurrency()) {
|
||||
Sleep(10);
|
||||
thread_timeout++;
|
||||
if (thread_timeout == 100 * 60) {
|
||||
// If there is no available thread for more than 30 seconds, reset the thread counter
|
||||
set_num_threads(0);
|
||||
}
|
||||
}
|
||||
log(LOGLEVEL::INFO_NOSEND, "[scan_folder()]: Scanning file: ", full_path);
|
||||
if (is_valid_path(full_path)) { // Filter out invalid paths and paths with weird characters
|
||||
std::uintmax_t fileSize = std::filesystem::file_size(full_path);
|
||||
if (fileSize > 4000000000) { // 4GB
|
||||
log(LOGLEVEL::INFO_NOSEND, "[scan_folder()]: File too large to scan: ", full_path);
|
||||
}
|
||||
else {
|
||||
std::thread scan_thread(scan_file_t, full_path);
|
||||
scan_thread.detach();
|
||||
}
|
||||
}
|
||||
else {
|
||||
log(LOGLEVEL::INFO_NOSEND, "[scan_folder()]: Invalid path: ", full_path);
|
||||
}
|
||||
cnt++;
|
||||
if (cnt % 100 == 0) {
|
||||
printf("Processed %d files;\n", cnt);
|
||||
//printf("Number of threads: %d\n", num_threads);
|
||||
}
|
||||
if (cnt % 1000 == 0) {
|
||||
//send progress to com file
|
||||
std::ofstream answer_com(ANSWER_COM_PATH, std::ios::app);
|
||||
if (answer_com.is_open()) {
|
||||
answer_com << "progress " << (cnt * 100 / (all_files + 1)) << "\n";
|
||||
answer_com.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
} while (FindNextFile(hFind, &find_file_data) != 0);
|
||||
FindClose(hFind);
|
||||
}
|
||||
else {
|
||||
log(LOGLEVEL::ERR_NOSEND, "[scan_folder()]: Could not open directory: ", current_dir, " while scanning files inside directory.");
|
||||
//std::cerr << "[scan_folder()]: Could not open directory: " << current_dir << " while scanning files inside directory." << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
//for singlethreaded scans
|
||||
void action_scanfile(const std::string& filepath_) {
|
||||
thread_init();
|
||||
const std::string filepath(filepath_);
|
||||
char* db_path = new char[300];
|
||||
char* hash = new char[300];
|
||||
if (is_valid_path(filepath_)) { //filter out invalid paths and paths with weird characters
|
||||
std::string hash_(md5_file_t(filepath));
|
||||
if (strlen(hash_.c_str()) < 290)
|
||||
strcpy_s(hash, 295, hash_.c_str());
|
||||
else {
|
||||
strcpy_s(hash, 295, "");
|
||||
log(LOGLEVEL::ERR_NOSEND, "[scan_file_t()]: Could not calculate hash for file: ", filepath);
|
||||
}
|
||||
sprintf_s(db_path, 295, "%s\\%c%c.jdbf", DB_DIR, hash[0], hash[1]);
|
||||
if (search_hash(db_path, hash, filepath) != 1) {
|
||||
//notify desktop client by writing to answer_com file
|
||||
//if there is now virus, we notify here. if there is a virus we only notify in the virus_ctrl_process function
|
||||
std::ofstream answer_com(ANSWER_COM_PATH, std::ios::app);
|
||||
if (answer_com.is_open()) {
|
||||
answer_com << "not_found " << "\"" << filepath_ << "\"" << " " << hash << " " << "no_action_taken" << "\n";
|
||||
answer_com.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
log(LOGLEVEL::INFO_NOSEND, "[action_scanfile()]: Invalid path: ", filepath_);
|
||||
thread_shutdown();
|
||||
}
|
||||
void action_scanfolder(const std::string& folderpath) {
|
||||
thread_init();
|
||||
thread_local std::string folderpath_(folderpath);
|
||||
cnt = 0;
|
||||
all_files = get_num_files(folderpath_);
|
||||
//tell the desktop client that the scan has started
|
||||
std::ofstream answer_com1(ANSWER_COM_PATH, std::ios::app);
|
||||
if (answer_com1.is_open()) {
|
||||
answer_com1 << "start " << all_files << "\n";
|
||||
answer_com1.close();
|
||||
}
|
||||
scan_folder(folderpath_);
|
||||
std::ofstream answer_com(ANSWER_COM_PATH, std::ios::app);
|
||||
if (answer_com.is_open()) {
|
||||
answer_com << "end " << "\"" << "nothing" << "\"" << " " << "nothing" << " " << "nothing" << "\n";
|
||||
answer_com.close();
|
||||
}
|
||||
thread_shutdown();
|
||||
}
|
||||
|
||||
void scan_file_t(const std::string& filepath_) {
|
||||
set_num_threads(get_num_threads() + 1);
|
||||
thread_local const std::string filepath(filepath_);
|
||||
thread_local char* db_path = new char[300];
|
||||
thread_local char* hash = new char[300];
|
||||
thread_local std::string hash_(md5_file_t(filepath));
|
||||
if (strlen(hash_.c_str()) < 290)
|
||||
strcpy_s(hash, 295, hash_.c_str());
|
||||
else{
|
||||
strcpy_s(hash, 295, "");
|
||||
log(LOGLEVEL::ERR_NOSEND, "[scan_file_t()]: Could not calculate hash for file: ", filepath);
|
||||
}
|
||||
sprintf_s(db_path, 295, "%s\\%c%c.jdbf", DB_DIR, hash[0], hash[1]);
|
||||
search_hash(db_path, hash, filepath);
|
||||
set_num_threads(get_num_threads() - 1);
|
||||
}
|
||||
void scan_process_t(const std::string& filepath_) {
|
||||
set_num_threads(get_num_threads() + 1);
|
||||
thread_local const std::string filepath(filepath_);
|
||||
thread_local char* db_path = new char[300];
|
||||
thread_local char* hash = new char[300];
|
||||
strcpy_s(hash, 295, md5_file_t(filepath).c_str());
|
||||
sprintf_s(db_path, 295, "%s\\%c%c.jdbf", DB_DIR, hash[0], hash[1]);
|
||||
if (search_hash(db_path, hash, filepath) == 1) {
|
||||
//check if need to kill process
|
||||
if (get_setting("virus_ctrl:virus_process_found:kill") == 1) {
|
||||
//kill the process
|
||||
kill_process(filepath.c_str());
|
||||
log(LOGLEVEL::VIRUS, "[scan_process_t()]: Killing process: ", filepath);
|
||||
}
|
||||
}
|
||||
set_num_threads(get_num_threads() - 1);
|
||||
}
|
||||
#endif
|
||||
@@ -1,384 +0,0 @@
|
||||
#ifndef SCAN_CPP
|
||||
#define SCAN_CPP
|
||||
#include "scan.h"
|
||||
#include <windows.h>
|
||||
#include <iostream>
|
||||
#include <openssl/md5.h>
|
||||
#include <windows.h>
|
||||
#include <iostream>
|
||||
#include <thread>
|
||||
#include <chrono>
|
||||
#include <stack>
|
||||
#include <time.h>
|
||||
#include "md5hash.h"
|
||||
#include <string>
|
||||
#include "well_known.h"
|
||||
#include "log.h"
|
||||
#include "virus_ctrl.h"
|
||||
#include "app_ctrl.h"
|
||||
#include <mutex> // Include the mutex header
|
||||
#include <filesystem>
|
||||
#include "utils.h"
|
||||
|
||||
// Define mutexes for thread synchronization
|
||||
std::mutex fileHandlesMutex;
|
||||
std::mutex mappingHandlesMutex;
|
||||
std::mutex fileDataMutex;
|
||||
std::mutex cntMutex;
|
||||
std::mutex numThreadsMutex;
|
||||
|
||||
std::unordered_map<std::string, HANDLE> fileHandles;
|
||||
std::unordered_map<std::string, HANDLE> mappingHandles;
|
||||
std::unordered_map<std::string, char*> fileData;
|
||||
|
||||
int cnt = 0;
|
||||
int num_threads = 0;
|
||||
int all_files = 0;
|
||||
|
||||
int get_num_threads() {
|
||||
std::lock_guard<std::mutex> lock(numThreadsMutex);
|
||||
return num_threads;
|
||||
}
|
||||
int set_num_threads(int num) {
|
||||
std::lock_guard<std::mutex> lock(numThreadsMutex);
|
||||
num_threads = num;
|
||||
return 0;
|
||||
}
|
||||
//load all the db files into memory
|
||||
int initialize(const std::string& folderPath) {
|
||||
for (char firstChar = '0'; firstChar <= 'f'; ++firstChar) {
|
||||
for (char secondChar = '0'; secondChar <= 'f'; ++secondChar) {
|
||||
// Ensure that the characters are valid hexadecimal digits
|
||||
if (!std::isxdigit(firstChar) || !std::isxdigit(secondChar) or std::isupper(firstChar) or std::isupper(secondChar)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Create the filename based on the naming convention
|
||||
std::string filename = folderPath + "\\" + firstChar + secondChar + ".jdbf";
|
||||
//printf("Loading %s\n", filename.c_str());
|
||||
|
||||
// Open the file
|
||||
HANDLE hFile = CreateFile(filename.c_str(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
if (hFile == INVALID_HANDLE_VALUE) {
|
||||
//log(LOGLEVEL::ERR, "[initialize()]: Error opening database file: ", filename);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Create the file mapping
|
||||
HANDLE hMapping = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL);
|
||||
if (hMapping == NULL) {
|
||||
// log(LOGLEVEL::ERR, "[initialize()]: Error creating database file mapping: ", filename);
|
||||
CloseHandle(hFile);
|
||||
return 2;
|
||||
}
|
||||
|
||||
// Map the file into memory
|
||||
char* fileDataPtr = static_cast<char*>(MapViewOfFile(hMapping, FILE_MAP_READ, 0, 0, 0));
|
||||
if (fileDataPtr == NULL) {
|
||||
//log(LOGLEVEL::ERR, "[initialize()]: Error mapping database file: ", filename);
|
||||
CloseHandle(hMapping);
|
||||
CloseHandle(hFile);
|
||||
return 3;
|
||||
}
|
||||
|
||||
// Store the handles in the global maps
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(fileHandlesMutex);
|
||||
fileHandles[filename] = hFile;
|
||||
}
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mappingHandlesMutex);
|
||||
mappingHandles[filename] = hMapping;
|
||||
}
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(fileDataMutex);
|
||||
fileData[filename] = fileDataPtr;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Call this function when you are done using the file mappings
|
||||
void cleanup() {
|
||||
for (const auto& entry : fileHandles) {
|
||||
UnmapViewOfFile(fileData[entry.first]);
|
||||
CloseHandle(mappingHandles[entry.first]);
|
||||
CloseHandle(entry.second);
|
||||
}
|
||||
|
||||
// Clear the global maps
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(fileHandlesMutex);
|
||||
fileHandles.clear();
|
||||
}
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mappingHandlesMutex);
|
||||
mappingHandles.clear();
|
||||
}
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(fileDataMutex);
|
||||
fileData.clear();
|
||||
}
|
||||
}
|
||||
|
||||
//the latest and fastest version of searching a hash by now
|
||||
int search_hash(const std::string& dbname_, const std::string& hash_, const std::string& filepath_) {
|
||||
// Check if the file mapping is already open for the given filename
|
||||
std::string dbname;
|
||||
std::string hash;
|
||||
std::string filepath;
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(fileHandlesMutex);
|
||||
dbname = dbname_;
|
||||
}
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(fileDataMutex);
|
||||
hash = hash_;
|
||||
}
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mappingHandlesMutex);
|
||||
filepath = filepath_;
|
||||
}
|
||||
|
||||
auto fileIter = fileHandles.find(dbname);
|
||||
if (fileIter == fileHandles.end() && dbname_.find("c:.jdbf") == std::string::npos) {
|
||||
log(LOGLEVEL::ERR_NOSEND, "[search_hash()]: File mapping not initialized for ", dbname);
|
||||
return 2;
|
||||
}
|
||||
else if (fileIter == fileHandles.end()) {
|
||||
return 2;
|
||||
}
|
||||
|
||||
// Use fileData for subsequent searches
|
||||
DWORD fileSize;
|
||||
std::string fileContent;
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(fileDataMutex);
|
||||
fileSize = GetFileSize(fileHandles[dbname], NULL);
|
||||
fileContent = std::string(fileData[dbname], fileSize);
|
||||
}
|
||||
|
||||
// Search for the specific string in the file content
|
||||
size_t foundPos = fileContent.find(hash);
|
||||
if (foundPos != std::string::npos) {
|
||||
//log(LOGLEVEL::VIRUS, "[search_hash()]: Found virus: ", hash, " in file: ", filepath);
|
||||
virus_ctrl_store(filepath.c_str(), hash.c_str(), hash.c_str());
|
||||
//afterwards do the processing with that file
|
||||
virus_ctrl_process(hash.c_str());
|
||||
return 1; // Found
|
||||
}
|
||||
return 0; // Not found
|
||||
}
|
||||
|
||||
//function to get num of files in idr and its subdirs etc (iterative)
|
||||
int get_num_files(const std::string& directory) {
|
||||
std::string search_path = directory + "\\*.*";
|
||||
WIN32_FIND_DATA find_file_data;
|
||||
HANDLE hFind = FindFirstFile(search_path.c_str(), &find_file_data);
|
||||
int num_files = 0;
|
||||
|
||||
if (hFind == INVALID_HANDLE_VALUE) {
|
||||
//std::cerr << "[get_num_files()]: Could not open directory: " << search_path << " while scanning files inside directory." << std::endl;
|
||||
log(LOGLEVEL::ERR_NOSEND, "[get_num_files()]: Could not open directory: ", search_path, " while scanning files inside directory.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Stack to store directories to be traversed iteratively
|
||||
std::stack<std::string> directories;
|
||||
directories.push(directory);
|
||||
|
||||
while (!directories.empty()) {
|
||||
std::string current_dir = directories.top();
|
||||
directories.pop();
|
||||
|
||||
search_path = current_dir + "\\*.*";
|
||||
hFind = FindFirstFile(search_path.c_str(), &find_file_data);
|
||||
|
||||
if (hFind != INVALID_HANDLE_VALUE) {
|
||||
do {
|
||||
if (strcmp(find_file_data.cFileName, ".") == 0 || strcmp(find_file_data.cFileName, "..") == 0) {
|
||||
continue; // Skip the current and parent directories
|
||||
}
|
||||
|
||||
const std::string full_path = current_dir + "\\" + find_file_data.cFileName;
|
||||
if (find_file_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
|
||||
// If it's a directory, add it to the stack
|
||||
directories.push(full_path);
|
||||
}
|
||||
else {
|
||||
num_files++;
|
||||
}
|
||||
} while (FindNextFile(hFind, &find_file_data) != 0);
|
||||
FindClose(hFind);
|
||||
}
|
||||
else {
|
||||
log(LOGLEVEL::ERR_NOSEND, "[get_num_files()]: Could not open directory: ", current_dir, " while scanning files inside directory.");
|
||||
//std::cerr << "[get_num_files()]: Could not open directory: " << current_dir << " while scanning files inside directory." << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
return num_files;
|
||||
}
|
||||
|
||||
//this is the main function to scan folders. it will then start multuiple threads based on the number of cores / settings
|
||||
std::stack<std::string> directories; // Stack to store directories to be scanned
|
||||
|
||||
void scan_folder(const std::string& directory) {
|
||||
directories.push(directory);
|
||||
|
||||
while (!directories.empty()) {
|
||||
std::string current_dir = directories.top();
|
||||
directories.pop();
|
||||
|
||||
std::string search_path = current_dir + "\\*.*";
|
||||
WIN32_FIND_DATA find_file_data;
|
||||
HANDLE hFind = FindFirstFile(search_path.c_str(), &find_file_data);
|
||||
|
||||
if (hFind != INVALID_HANDLE_VALUE) {
|
||||
do {
|
||||
if (strcmp(find_file_data.cFileName, ".") == 0 || strcmp(find_file_data.cFileName, "..") == 0) {
|
||||
continue; // Skip the current and parent directories
|
||||
}
|
||||
|
||||
const std::string full_path = current_dir + "\\" + find_file_data.cFileName;
|
||||
if (find_file_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
|
||||
// If it's a directory, add it to the stack
|
||||
directories.push(full_path);
|
||||
}
|
||||
else {
|
||||
// Do multithreading here
|
||||
int thread_timeout = 0;
|
||||
while (get_num_threads() >= std::thread::hardware_concurrency()) {
|
||||
Sleep(10);
|
||||
thread_timeout++;
|
||||
if (thread_timeout == 100 * 60) {
|
||||
// If there is no available thread for more than 30 seconds, reset the thread counter
|
||||
set_num_threads(0);
|
||||
}
|
||||
}
|
||||
//log(LOGLEVEL::INFO_NOSEND, "[scan_folder()]: Scanning file: ", full_path);
|
||||
if (is_valid_path(full_path)) { // Filter out invalid paths and paths with weird characters
|
||||
std::uintmax_t fileSize = std::filesystem::file_size(full_path);
|
||||
if (fileSize > 4000000000) { // 4GB
|
||||
log(LOGLEVEL::INFO_NOSEND, "[scan_folder()]: File too large to scan: ", full_path);
|
||||
}
|
||||
else {
|
||||
std::thread scan_thread(scan_file_t, full_path);
|
||||
scan_thread.detach();
|
||||
}
|
||||
}
|
||||
else {
|
||||
log(LOGLEVEL::INFO_NOSEND, "[scan_folder()]: Invalid path: ", full_path);
|
||||
}
|
||||
cnt++;
|
||||
if (cnt % 100 == 0) {
|
||||
printf("Processed %d files;\n", cnt);
|
||||
//printf("Number of threads: %d\n", num_threads);
|
||||
}
|
||||
if (cnt % 1000 == 0) {
|
||||
set_num_threads(get_num_running_threads()-1-1);//correct value of threads minus the main and the rtp thread
|
||||
printf("Number of threads: %d\n", num_threads);
|
||||
//send progress to com file
|
||||
std::ofstream answer_com(ANSWER_COM_PATH, std::ios::app);
|
||||
if (answer_com.is_open()) {
|
||||
answer_com << "progress " << (cnt * 100 / (all_files + 1)) << "\n";
|
||||
answer_com.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
} while (FindNextFile(hFind, &find_file_data) != 0);
|
||||
FindClose(hFind);
|
||||
}
|
||||
else {
|
||||
log(LOGLEVEL::ERR_NOSEND, "[scan_folder()]: Could not open directory: ", current_dir, " while scanning files inside directory.");
|
||||
//std::cerr << "[scan_folder()]: Could not open directory: " << current_dir << " while scanning files inside directory." << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
//for singlethreaded scans
|
||||
void action_scanfile(const std::string& filepath_) {
|
||||
thread_init();
|
||||
const std::string filepath(filepath_);
|
||||
char* db_path = new char[300];
|
||||
char* hash = new char[300];
|
||||
if (is_valid_path(filepath_)) { //filter out invalid paths and paths with weird characters
|
||||
std::string hash_(md5_file_t(filepath));
|
||||
if (strlen(hash_.c_str()) < 290)
|
||||
strcpy_s(hash, 295, hash_.c_str());
|
||||
else {
|
||||
strcpy_s(hash, 295, "");
|
||||
log(LOGLEVEL::ERR_NOSEND, "[scan_file_t()]: Could not calculate hash for file: ", filepath);
|
||||
}
|
||||
sprintf_s(db_path, 295, "%s\\%c%c.jdbf", DB_DIR, hash[0], hash[1]);
|
||||
if (search_hash(db_path, hash, filepath) != 1) {
|
||||
//notify desktop client by writing to answer_com file
|
||||
//if there is now virus, we notify here. if there is a virus we only notify in the virus_ctrl_process function
|
||||
std::ofstream answer_com(ANSWER_COM_PATH, std::ios::app);
|
||||
if (answer_com.is_open()) {
|
||||
answer_com << "not_found " << "\"" << filepath_ << "\"" << " " << hash << " " << "no_action_taken" << "\n";
|
||||
answer_com.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
log(LOGLEVEL::INFO_NOSEND, "[action_scanfile()]: Invalid path: ", filepath_);
|
||||
thread_shutdown();
|
||||
}
|
||||
void action_scanfolder(const std::string& folderpath) {
|
||||
thread_init();
|
||||
thread_local std::string folderpath_(folderpath);
|
||||
cnt = 0;
|
||||
all_files = get_num_files(folderpath_);
|
||||
//tell the desktop client that the scan has started
|
||||
std::ofstream answer_com1(ANSWER_COM_PATH, std::ios::app);
|
||||
if (answer_com1.is_open()) {
|
||||
answer_com1 << "start " << all_files << "\n";
|
||||
answer_com1.close();
|
||||
}
|
||||
scan_folder(folderpath_);
|
||||
std::ofstream answer_com(ANSWER_COM_PATH, std::ios::app);
|
||||
if (answer_com.is_open()) {
|
||||
answer_com << "end " << "\"" << "nothing" << "\"" << " " << "nothing" << " " << "nothing" << "\n";
|
||||
answer_com.close();
|
||||
}
|
||||
thread_shutdown();
|
||||
}
|
||||
|
||||
void scan_file_t(const std::string& filepath_) {
|
||||
set_num_threads(get_num_threads() + 1);
|
||||
thread_local const std::string filepath(filepath_);
|
||||
thread_local char* db_path = new char[300];
|
||||
thread_local char* hash = new char[300];
|
||||
thread_local std::string hash_(md5_file_t(filepath));
|
||||
if (strlen(hash_.c_str()) < 290)
|
||||
strcpy_s(hash, 295, hash_.c_str());
|
||||
else{
|
||||
strcpy_s(hash, 295, "");
|
||||
log(LOGLEVEL::ERR_NOSEND, "[scan_file_t()]: Could not calculate hash for file: ", filepath);
|
||||
}
|
||||
sprintf_s(db_path, 295, "%s\\%c%c.jdbf", DB_DIR, hash[0], hash[1]);
|
||||
search_hash(db_path, hash, filepath);
|
||||
set_num_threads(get_num_threads() - 1);
|
||||
}
|
||||
void scan_process_t(const std::string& filepath_) {
|
||||
set_num_threads(get_num_threads() + 1);
|
||||
thread_local const std::string filepath(filepath_);
|
||||
thread_local char* db_path = new char[300];
|
||||
thread_local char* hash = new char[300];
|
||||
strcpy_s(hash, 295, md5_file_t(filepath).c_str());
|
||||
sprintf_s(db_path, 295, "%s\\%c%c.jdbf", DB_DIR, hash[0], hash[1]);
|
||||
if (search_hash(db_path, hash, filepath) == 1) {
|
||||
//check if need to kill process
|
||||
if (get_setting("virus_ctrl:virus_process_found:kill") == 1) {
|
||||
//kill the process
|
||||
kill_process(filepath.c_str());
|
||||
log(LOGLEVEL::VIRUS, "[scan_process_t()]: Killing process: ", filepath);
|
||||
}
|
||||
}
|
||||
set_num_threads(get_num_threads() - 1);
|
||||
}
|
||||
#endif
|
||||
@@ -1,132 +0,0 @@
|
||||
#include "scan.h"
|
||||
#include <windows.h>
|
||||
#include <iostream>
|
||||
#include <openssl/md5.h>
|
||||
#include <windows.h>
|
||||
#include <iostream>
|
||||
#include "md5hash.h"
|
||||
#include <string>
|
||||
#include "well_known.h"
|
||||
#include "log.h"
|
||||
#include "virus_ctrl.h"
|
||||
#ifndef SCAN_CPP
|
||||
#define SCAN_CPP
|
||||
int cnt = 0;
|
||||
bool file_exists(const std::string& filePath) {
|
||||
DWORD fileAttributes = GetFileAttributes(filePath.c_str());
|
||||
|
||||
if (fileAttributes == INVALID_FILE_ATTRIBUTES) {
|
||||
// The file does not exist or there was an error
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check if it's a regular file and not a directory
|
||||
return (fileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0;
|
||||
}
|
||||
void scan_files_recursive(const std::string& directory, int thread_id) {
|
||||
std::string search_path = directory + "\\*.*";
|
||||
WIN32_FIND_DATA find_file_data;
|
||||
HANDLE hFind = FindFirstFile(search_path.c_str(), &find_file_data);
|
||||
|
||||
if (hFind == INVALID_HANDLE_VALUE) {
|
||||
log(LOGLEVEL::ERR, "[ListFilesRecursive()]: Error opening directory: ", directory, " while scanning files inside folder.");
|
||||
return;
|
||||
}
|
||||
|
||||
do {
|
||||
if (strcmp(find_file_data.cFileName, ".") == 0 || strcmp(find_file_data.cFileName, "..") == 0) {
|
||||
continue; // Skip the current and parent directories
|
||||
}
|
||||
|
||||
|
||||
std::string full_path = directory + "\\" + find_file_data.cFileName;
|
||||
if (find_file_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
|
||||
// If it's a directory, recurse into it
|
||||
scan_files_recursive(full_path,thread_id);
|
||||
}
|
||||
else {
|
||||
// If it's a file, print its name
|
||||
/*char md5Hash[2 * MD5_DIGEST_LENGTH + 1];
|
||||
|
||||
md5_file(full_path.c_str(), md5Hash);
|
||||
printf("%s\n", md5Hash);
|
||||
printf("%d\n", scan_hash("C:\\Users\\janis\\Documents\\ma_av_tests\\OutputFile.txt", "96be95b122c2b9b8bb5765c312ca4f73"));
|
||||
if (scan_hash("C:\\Users\\janis\\Documents\\ma_av_tests\\OutputFile.txt", md5Hash) == 1) {
|
||||
printf("virus found");
|
||||
|
||||
}*/
|
||||
cnt++;
|
||||
if (cnt % 1000 == 0) {
|
||||
printf("Processed %d files; sent from thread %d\n", cnt,thread_id);
|
||||
}
|
||||
}
|
||||
} while (FindNextFile(hFind, &find_file_data) != 0);
|
||||
|
||||
FindClose(hFind);
|
||||
}
|
||||
int scan_hash(const std::string& filename, const std::string& hash) {//!!!! does not work with e.g. utf-16 or something like that. either ascii or utf8!!
|
||||
HANDLE hFile = CreateFile(filename.c_str(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
if (hFile == INVALID_HANDLE_VALUE) {
|
||||
log(LOGLEVEL::ERR, "[scan_hash()]: Error opening database file: ", filename, " while searching for hash.", hash);
|
||||
return 2;
|
||||
}
|
||||
|
||||
HANDLE hMapping = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL);
|
||||
if (hMapping == NULL) {
|
||||
log(LOGLEVEL::ERR, "[scan_hash()]: Error creating database file mapping: ", filename, " while searching for hash.");
|
||||
CloseHandle(hFile);
|
||||
return 2;
|
||||
}
|
||||
|
||||
char* fileData = static_cast<char*>(MapViewOfFile(hMapping, FILE_MAP_READ, 0, 0, 0));
|
||||
if (fileData == NULL) {
|
||||
log(LOGLEVEL::ERR, "[scan_hash()]: Error mapping database file: ", filename, " while searching for hash.");
|
||||
CloseHandle(hMapping);
|
||||
CloseHandle(hFile);
|
||||
return 2;
|
||||
}
|
||||
|
||||
DWORD fileSize = GetFileSize(hFile, NULL);
|
||||
std::string fileContent(fileData, fileSize);
|
||||
|
||||
// Search for the specific string in the file content
|
||||
size_t foundPos = fileContent.find(hash);
|
||||
if (foundPos != std::string::npos) {
|
||||
UnmapViewOfFile(fileData);
|
||||
CloseHandle(hMapping);
|
||||
CloseHandle(hFile);
|
||||
return 1;//found
|
||||
}
|
||||
|
||||
// Unmap the memory and close the handles
|
||||
UnmapViewOfFile(fileData);
|
||||
CloseHandle(hMapping);
|
||||
CloseHandle(hFile);
|
||||
return 0;
|
||||
}
|
||||
int scan_hash(const char* hash) {
|
||||
char* path = new char[600];
|
||||
path[0] = '\0';
|
||||
sprintf_s(path, 595, "%s\\%c%c.jdbf", DB_DIR, hash[0],hash[1]);
|
||||
return scan_hash(path,hash);
|
||||
}
|
||||
|
||||
void action_scanfile(const char*filepath) {
|
||||
if (strlen(filepath) == 0 or strcmp("", filepath) == 0 or file_exists(filepath) == false) {
|
||||
//log(LOGLEVEL::ERR, "[action_scanfile()]: Error opening file: ", filepath, " while scanning file for viruses.");
|
||||
return; //no filepath given or file not accessible
|
||||
}
|
||||
else {
|
||||
char* hash = new char[300];
|
||||
md5_file(filepath, hash);
|
||||
if (scan_hash(hash) == 1) { //virus found
|
||||
log(LOGLEVEL::VIRUS, "[action_scanfile()]: Virus found in file: ", filepath);
|
||||
//add it to a database which stores filepaths of infected files
|
||||
virus_ctrl_store(filepath, hash, "sf");
|
||||
//afterwards do the processing with that file
|
||||
virus_ctrl_process("sf");
|
||||
}
|
||||
delete[] hash;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -1,147 +0,0 @@
|
||||
#include "scan.h"
|
||||
#include <windows.h>
|
||||
#include <iostream>
|
||||
#include <openssl/md5.h>
|
||||
#include <windows.h>
|
||||
#include <iostream>
|
||||
#include "md5hash.h"
|
||||
#include <string>
|
||||
#include "well_known.h"
|
||||
#include "log.h"
|
||||
#include "virus_ctrl.h"
|
||||
#ifndef SCAN_CPP
|
||||
#define SCAN_CPP
|
||||
int cnt = 0;
|
||||
bool file_exists(const std::string& filePath) {
|
||||
DWORD fileAttributes = GetFileAttributes(filePath.c_str());
|
||||
|
||||
if (fileAttributes == INVALID_FILE_ATTRIBUTES) {
|
||||
// The file does not exist or there was an error
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check if it's a regular file and not a directory
|
||||
return (fileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0;
|
||||
}
|
||||
|
||||
//this is the main function to scan folders. it will then start multuiple threads based on the number of cores / settings
|
||||
void scan_files_recursive(const std::string& directory) {
|
||||
std::string search_path = directory + "\\*.*";
|
||||
WIN32_FIND_DATA find_file_data;
|
||||
HANDLE hFind = FindFirstFile(search_path.c_str(), &find_file_data);
|
||||
|
||||
if (hFind == INVALID_HANDLE_VALUE) {
|
||||
log(LOGLEVEL::ERR, "[ListFilesRecursive()]: Error opening directory: ", directory, " while scanning files inside folder.");
|
||||
return;
|
||||
}
|
||||
|
||||
do {
|
||||
if (strcmp(find_file_data.cFileName, ".") == 0 || strcmp(find_file_data.cFileName, "..") == 0) {
|
||||
continue; // Skip the current and parent directories
|
||||
}
|
||||
|
||||
|
||||
std::string full_path = directory + "\\" + find_file_data.cFileName;
|
||||
if (find_file_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
|
||||
// If it's a directory, recurse into it
|
||||
scan_files_recursive(full_path);
|
||||
}
|
||||
else {
|
||||
//we can use a modified version of action_scanfile for this
|
||||
//action_scanfile_t(full_path.c_str());
|
||||
|
||||
cnt++;
|
||||
if (cnt % 1000 == 0) {
|
||||
printf("Processed %d files;\n", cnt);
|
||||
}
|
||||
}
|
||||
} while (FindNextFile(hFind, &find_file_data) != 0);
|
||||
|
||||
FindClose(hFind);
|
||||
}
|
||||
int scan_hash(thread_local const std::string& filename, thread_local const std::string& hash) {//!!!! does not work with e.g. utf-16 or something like that. either ascii or utf8!!
|
||||
thread_local HANDLE hFile = CreateFile(filename.c_str(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
if (hFile == INVALID_HANDLE_VALUE) {
|
||||
log(LOGLEVEL::ERR, "[scan_hash()]: Error opening database file: ", filename, " while searching for hash.", hash);
|
||||
return 2;
|
||||
}
|
||||
|
||||
thread_local HANDLE hMapping = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL);
|
||||
if (hMapping == NULL) {
|
||||
log(LOGLEVEL::ERR, "[scan_hash()]: Error creating database file mapping: ", filename, " while searching for hash.");
|
||||
CloseHandle(hFile);
|
||||
return 2;
|
||||
}
|
||||
|
||||
char* fileData = static_cast<char*>(MapViewOfFile(hMapping, FILE_MAP_READ, 0, 0, 0));
|
||||
if (fileData == NULL) {
|
||||
log(LOGLEVEL::ERR, "[scan_hash()]: Error mapping database file: ", filename, " while searching for hash.");
|
||||
CloseHandle(hMapping);
|
||||
CloseHandle(hFile);
|
||||
return 2;
|
||||
}
|
||||
|
||||
DWORD fileSize = GetFileSize(hFile, NULL);
|
||||
std::string fileContent(fileData, fileSize);
|
||||
|
||||
// Search for the specific string in the file content
|
||||
size_t foundPos = fileContent.find(hash);
|
||||
if (foundPos != std::string::npos) {
|
||||
UnmapViewOfFile(fileData);
|
||||
CloseHandle(hMapping);
|
||||
CloseHandle(hFile);
|
||||
return 1;//found
|
||||
}
|
||||
|
||||
// Unmap the memory and close the handles
|
||||
UnmapViewOfFile(fileData);
|
||||
CloseHandle(hMapping);
|
||||
CloseHandle(hFile);
|
||||
return 0;
|
||||
}
|
||||
int scan_hash(thread_local const char* hash) {
|
||||
thread_local char* path = new char[600];
|
||||
path[0] = '\0';
|
||||
sprintf_s(path, 595, "%s\\%c%c.jdbf", DB_DIR, hash[0],hash[1]);
|
||||
return scan_hash(path,hash);
|
||||
}
|
||||
|
||||
|
||||
//for singlethreaded scans
|
||||
void action_scanfile(const char*filepath) {
|
||||
if (strlen(filepath) == 0 or strcmp("", filepath) == 0 or file_exists(filepath) == false) {
|
||||
//log(LOGLEVEL::ERR, "[action_scanfile()]: Error opening file: ", filepath, " while scanning file for viruses.");
|
||||
return; //no filepath given or file not accessible
|
||||
}
|
||||
else {
|
||||
char* hash = new char[300];
|
||||
md5_file(filepath, hash);
|
||||
if (scan_hash(hash) == 1) { //virus found
|
||||
log(LOGLEVEL::VIRUS, "[action_scanfile()]: Virus found in file: ", filepath);
|
||||
//add it to a database which stores filepaths of infected files
|
||||
virus_ctrl_store(filepath, hash, "sf");
|
||||
//afterwards do the processing with that file
|
||||
virus_ctrl_process("sf");
|
||||
}
|
||||
delete[] hash;
|
||||
}
|
||||
}
|
||||
//for multithreaded scans
|
||||
void action_scanfile_t(thread_local const char* filepath) {
|
||||
if (strlen(filepath) == 0 or strcmp("", filepath) == 0 or file_exists(filepath) == false) {
|
||||
return; //no filepath given or file not accessible
|
||||
}
|
||||
else {
|
||||
thread_local char* hash = new char[300];
|
||||
md5_file(filepath, hash);
|
||||
if (scan_hash(hash) == 1) { //virus found
|
||||
log(LOGLEVEL::VIRUS, "[action_scanfile()]: Virus found in file: ", filepath);
|
||||
//add it to a database which stores filepaths of infected files
|
||||
virus_ctrl_store(filepath, hash, "sft");
|
||||
//we do the processing at the end of the scan in order to not slow down the scan !!i have to remember to do this!!
|
||||
//virus_ctrl_process("sft");
|
||||
}
|
||||
delete[] hash;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -1,323 +0,0 @@
|
||||
#ifndef SCAN_CPP
|
||||
#define SCAN_CPP
|
||||
#include "scan.h"
|
||||
#include <windows.h>
|
||||
#include <iostream>
|
||||
#include <openssl/md5.h>
|
||||
#include <windows.h>
|
||||
#include <iostream>
|
||||
#include <thread>
|
||||
#include <chrono>
|
||||
#include <time.h>
|
||||
#include "md5hash.h"
|
||||
#include <string>
|
||||
#include "well_known.h"
|
||||
#include "log.h"
|
||||
#include "virus_ctrl.h"
|
||||
#include "app_ctrl.h"
|
||||
#include <mutex> // Include the mutex header
|
||||
#include <filesystem>
|
||||
#include "utils.h"
|
||||
|
||||
// Define mutexes for thread synchronization
|
||||
std::mutex fileHandlesMutex;
|
||||
std::mutex mappingHandlesMutex;
|
||||
std::mutex fileDataMutex;
|
||||
std::mutex cntMutex;
|
||||
std::mutex numThreadsMutex;
|
||||
|
||||
std::unordered_map<std::string, HANDLE> fileHandles;
|
||||
std::unordered_map<std::string, HANDLE> mappingHandles;
|
||||
std::unordered_map<std::string, char*> fileData;
|
||||
|
||||
int cnt = 0;
|
||||
int num_threads = 0;
|
||||
|
||||
//load all the db files into memory
|
||||
int initialize(const std::string& folderPath) {
|
||||
for (char firstChar = '0'; firstChar <= 'f'; ++firstChar) {
|
||||
for (char secondChar = '0'; secondChar <= 'f'; ++secondChar) {
|
||||
// Ensure that the characters are valid hexadecimal digits
|
||||
if (!std::isxdigit(firstChar) || !std::isxdigit(secondChar) or std::isupper(firstChar) or std::isupper(secondChar)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Create the filename based on the naming convention
|
||||
std::string filename = folderPath + "\\" + firstChar + secondChar + ".jdbf";
|
||||
//printf("Loading %s\n", filename.c_str());
|
||||
|
||||
// Open the file
|
||||
HANDLE hFile = CreateFile(filename.c_str(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
if (hFile == INVALID_HANDLE_VALUE) {
|
||||
//log(LOGLEVEL::ERR, "[initialize()]: Error opening database file: ", filename);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Create the file mapping
|
||||
HANDLE hMapping = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL);
|
||||
if (hMapping == NULL) {
|
||||
// log(LOGLEVEL::ERR, "[initialize()]: Error creating database file mapping: ", filename);
|
||||
CloseHandle(hFile);
|
||||
return 2;
|
||||
}
|
||||
|
||||
// Map the file into memory
|
||||
char* fileDataPtr = static_cast<char*>(MapViewOfFile(hMapping, FILE_MAP_READ, 0, 0, 0));
|
||||
if (fileDataPtr == NULL) {
|
||||
//log(LOGLEVEL::ERR, "[initialize()]: Error mapping database file: ", filename);
|
||||
CloseHandle(hMapping);
|
||||
CloseHandle(hFile);
|
||||
return 3;
|
||||
}
|
||||
|
||||
// Store the handles in the global maps
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(fileHandlesMutex);
|
||||
fileHandles[filename] = hFile;
|
||||
}
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mappingHandlesMutex);
|
||||
mappingHandles[filename] = hMapping;
|
||||
}
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(fileDataMutex);
|
||||
fileData[filename] = fileDataPtr;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Call this function when you are done using the file mappings
|
||||
void cleanup() {
|
||||
for (const auto& entry : fileHandles) {
|
||||
UnmapViewOfFile(fileData[entry.first]);
|
||||
CloseHandle(mappingHandles[entry.first]);
|
||||
CloseHandle(entry.second);
|
||||
}
|
||||
|
||||
// Clear the global maps
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(fileHandlesMutex);
|
||||
fileHandles.clear();
|
||||
}
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mappingHandlesMutex);
|
||||
mappingHandles.clear();
|
||||
}
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(fileDataMutex);
|
||||
fileData.clear();
|
||||
}
|
||||
}
|
||||
|
||||
//the latest and fastest version of searching a hash by now
|
||||
int search_hash(const std::string& dbname_, const std::string& hash_, const std::string& filepath_) {
|
||||
// Check if the file mapping is already open for the given filename
|
||||
std::string dbname;
|
||||
std::string hash;
|
||||
std::string filepath;
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(fileHandlesMutex);
|
||||
dbname = dbname_;
|
||||
}
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(fileDataMutex);
|
||||
hash = hash_;
|
||||
}
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mappingHandlesMutex);
|
||||
filepath = filepath_;
|
||||
}
|
||||
|
||||
auto fileIter = fileHandles.find(dbname);
|
||||
if (fileIter == fileHandles.end() && dbname_.find("c:.jdbf") == std::string::npos) {
|
||||
log(LOGLEVEL::ERR_NOSEND, "[search_hash()]: File mapping not initialized for ", dbname);
|
||||
return 2;
|
||||
}
|
||||
else if (fileIter == fileHandles.end()) {
|
||||
return 2;
|
||||
}
|
||||
|
||||
// Use fileData for subsequent searches
|
||||
DWORD fileSize;
|
||||
std::string fileContent;
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(fileDataMutex);
|
||||
fileSize = GetFileSize(fileHandles[dbname], NULL);
|
||||
fileContent = std::string(fileData[dbname], fileSize);
|
||||
}
|
||||
|
||||
// Search for the specific string in the file content
|
||||
size_t foundPos = fileContent.find(hash);
|
||||
if (foundPos != std::string::npos) {
|
||||
//log(LOGLEVEL::VIRUS, "[search_hash()]: Found virus: ", hash, " in file: ", filepath);
|
||||
virus_ctrl_store(filepath.c_str(), hash.c_str(), hash.c_str());
|
||||
//afterwards do the processing with that file
|
||||
virus_ctrl_process(hash.c_str());
|
||||
return 1; // Found
|
||||
}
|
||||
return 0; // Not found
|
||||
}
|
||||
|
||||
|
||||
bool file_exists(const std::string& filePath) {
|
||||
DWORD fileAttributes = GetFileAttributes(filePath.c_str());
|
||||
|
||||
if (fileAttributes == INVALID_FILE_ATTRIBUTES) {
|
||||
// The file does not exist or there was an error
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check if it's a regular file and not a directory
|
||||
return (fileAttributes & FILE_ATTRIBUTE_DIRECTORY) == 0;
|
||||
}
|
||||
|
||||
//this is the main function to scan folders. it will then start multuiple threads based on the number of cores / settings
|
||||
void scan_folder(const std::string& directory) {
|
||||
std::string search_path = directory + "\\*.*";
|
||||
WIN32_FIND_DATA find_file_data;
|
||||
HANDLE hFind = FindFirstFile(search_path.c_str(), &find_file_data);
|
||||
|
||||
if (hFind == INVALID_HANDLE_VALUE) {
|
||||
log(LOGLEVEL::WARN, "[scan_folder()]: Could not open directory: ", search_path.c_str(), " while scanning files inside directory.");
|
||||
return;
|
||||
}
|
||||
|
||||
do {
|
||||
if (strcmp(find_file_data.cFileName, ".") == 0 || strcmp(find_file_data.cFileName, "..") == 0) {
|
||||
continue; // Skip the current and parent directories
|
||||
}
|
||||
|
||||
|
||||
const std::string full_path = directory + "\\" + find_file_data.cFileName;
|
||||
if (find_file_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
|
||||
// If it's a directory, recurse into it
|
||||
scan_folder(full_path);
|
||||
}
|
||||
else {
|
||||
//action scanfile_t will start the trheads for scanning the hashes
|
||||
//action_scanfile_t(full_path.c_str());
|
||||
|
||||
//do multithreading here
|
||||
int thread_timeout = 0;
|
||||
while (num_threads >= std::thread::hardware_concurrency()) {
|
||||
Sleep(10);
|
||||
thread_timeout++;
|
||||
if (thread_timeout == 100 * 60) {//if there is for more than 30 seconds no thread available, chances are high, that the threads did not temrinate correctly but aren t running anymore. so set the counter to 0 because else it might just stop the scan.
|
||||
num_threads = 0;
|
||||
printf("Number of threads_max: %d\n", num_threads);
|
||||
}
|
||||
}
|
||||
|
||||
if (is_valid_path(full_path)) { //filter out invalid paths and paths with weird characters
|
||||
std::uintmax_t fileSize = std::filesystem::file_size(full_path);
|
||||
if (fileSize > 4000000000) {//4gb
|
||||
log(LOGLEVEL::INFO_NOSEND, "[scan_folder()]: File too large to scan: ", full_path);
|
||||
}
|
||||
else {
|
||||
std::thread scan_thread(scan_file_t, full_path);
|
||||
scan_thread.detach();
|
||||
}
|
||||
}else
|
||||
log(LOGLEVEL::INFO_NOSEND, "[scan_folder()]: Invalid path: ", full_path);
|
||||
cnt++;
|
||||
if (cnt % 100 == 0) {
|
||||
printf("Processed %d files;\n", cnt);
|
||||
//printf("Number of threads: %d\n", num_threads);
|
||||
}
|
||||
if (cnt % 1000 == 0) {
|
||||
//send progress to com file
|
||||
printf("Processed %d files; Sending to frontend\n", cnt);
|
||||
std::ofstream answer_com(ANSWER_COM_PATH, std::ios::app);
|
||||
if (answer_com.is_open()) {
|
||||
answer_com << "progress " << 50 << "\n";
|
||||
answer_com.close();
|
||||
}
|
||||
}
|
||||
if(num_threads<0)
|
||||
printf("Number of threads_min: %d\n", num_threads);
|
||||
}
|
||||
} while (FindNextFile(hFind, &find_file_data) != 0);
|
||||
|
||||
FindClose(hFind);
|
||||
}
|
||||
|
||||
|
||||
|
||||
//for singlethreaded scans
|
||||
void action_scanfile(const std::string& filepath_) {
|
||||
thread_init();
|
||||
const std::string filepath(filepath_);
|
||||
char* db_path = new char[300];
|
||||
char* hash = new char[300];
|
||||
if (is_valid_path(filepath_)) { //filter out invalid paths and paths with weird characters
|
||||
std::string hash_(md5_file_t(filepath));
|
||||
if (strlen(hash_.c_str()) < 290)
|
||||
strcpy_s(hash, 295, hash_.c_str());
|
||||
else {
|
||||
strcpy_s(hash, 295, "");
|
||||
log(LOGLEVEL::ERR_NOSEND, "[scan_file_t()]: Could not calculate hash for file: ", filepath);
|
||||
}
|
||||
sprintf_s(db_path, 295, "%s\\%c%c.jdbf", DB_DIR, hash[0], hash[1]);
|
||||
if (search_hash(db_path, hash, filepath) != 1) {
|
||||
//notify desktop client by writing to answer_com file
|
||||
//if there is now virus, we notify here. if there is a virus we only notify in the virus_ctrl_process function
|
||||
std::ofstream answer_com(ANSWER_COM_PATH, std::ios::app);
|
||||
if (answer_com.is_open()) {
|
||||
answer_com << "not_found " << "\"" << filepath_ << "\"" << " " << hash << " " << "no_action_taken" << "\n";
|
||||
answer_com.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
log(LOGLEVEL::INFO_NOSEND, "[action_scanfile()]: Invalid path: ", filepath_);
|
||||
thread_shutdown();
|
||||
}
|
||||
void action_scanfolder(const std::string& folderpath) {
|
||||
thread_init();
|
||||
cnt = 0;
|
||||
thread_local std::string folderpath_(folderpath);
|
||||
scan_folder(folderpath_);
|
||||
std::ofstream answer_com(ANSWER_COM_PATH, std::ios::app);
|
||||
if (answer_com.is_open()) {
|
||||
answer_com << "end " << "\"" << "nothing" << "\"" << " " << "nothing" << " " << "nothing" << "\n";
|
||||
answer_com.close();
|
||||
}
|
||||
thread_shutdown();
|
||||
}
|
||||
|
||||
void scan_file_t(const std::string& filepath_) {
|
||||
num_threads++;
|
||||
thread_local const std::string filepath(filepath_);
|
||||
thread_local char* db_path = new char[300];
|
||||
thread_local char* hash = new char[300];
|
||||
thread_local std::string hash_(md5_file_t(filepath));
|
||||
if (strlen(hash_.c_str()) < 290)
|
||||
strcpy_s(hash, 295, hash_.c_str());
|
||||
else{
|
||||
strcpy_s(hash, 295, "");
|
||||
log(LOGLEVEL::ERR_NOSEND, "[scan_file_t()]: Could not calculate hash for file: ", filepath);
|
||||
}
|
||||
sprintf_s(db_path, 295, "%s\\%c%c.jdbf", DB_DIR, hash[0], hash[1]);
|
||||
search_hash(db_path, hash, filepath);
|
||||
num_threads--;
|
||||
}
|
||||
void scan_process_t(const std::string& filepath_) {
|
||||
num_threads++;
|
||||
thread_local const std::string filepath(filepath_);
|
||||
thread_local char* db_path = new char[300];
|
||||
thread_local char* hash = new char[300];
|
||||
strcpy_s(hash, 295, md5_file_t(filepath).c_str());
|
||||
sprintf_s(db_path, 295, "%s\\%c%c.jdbf", DB_DIR, hash[0], hash[1]);
|
||||
if (search_hash(db_path, hash, filepath) == 1) {
|
||||
//check if need to kill process
|
||||
if (get_setting("virus_ctrl:virus_process_found:kill") == 1) {
|
||||
//kill the process
|
||||
kill_process(filepath.c_str());
|
||||
log(LOGLEVEL::VIRUS, "[scan_process_t()]: Killing process: ", filepath);
|
||||
}
|
||||
}
|
||||
num_threads--;
|
||||
}
|
||||
#endif
|
||||
@@ -1,344 +0,0 @@
|
||||
#ifndef SCAN_CPP
|
||||
#define SCAN_CPP
|
||||
#include "scan.h"
|
||||
#include <windows.h>
|
||||
#include <iostream>
|
||||
#include <openssl/md5.h>
|
||||
#include <windows.h>
|
||||
#include <iostream>
|
||||
#include <thread>
|
||||
#include <chrono>
|
||||
#include <time.h>
|
||||
#include "md5hash.h"
|
||||
#include <string>
|
||||
#include "well_known.h"
|
||||
#include "log.h"
|
||||
#include "virus_ctrl.h"
|
||||
#include "app_ctrl.h"
|
||||
#include <mutex> // Include the mutex header
|
||||
#include <filesystem>
|
||||
#include "utils.h"
|
||||
|
||||
// Define mutexes for thread synchronization
|
||||
std::mutex fileHandlesMutex;
|
||||
std::mutex mappingHandlesMutex;
|
||||
std::mutex fileDataMutex;
|
||||
std::mutex cntMutex;
|
||||
std::mutex numThreadsMutex;
|
||||
|
||||
std::unordered_map<std::string, HANDLE> fileHandles;
|
||||
std::unordered_map<std::string, HANDLE> mappingHandles;
|
||||
std::unordered_map<std::string, char*> fileData;
|
||||
|
||||
int cnt = 0;
|
||||
int num_threads = 0;
|
||||
int all_files = 0;
|
||||
|
||||
//load all the db files into memory
|
||||
int initialize(const std::string& folderPath) {
|
||||
for (char firstChar = '0'; firstChar <= 'f'; ++firstChar) {
|
||||
for (char secondChar = '0'; secondChar <= 'f'; ++secondChar) {
|
||||
// Ensure that the characters are valid hexadecimal digits
|
||||
if (!std::isxdigit(firstChar) || !std::isxdigit(secondChar) or std::isupper(firstChar) or std::isupper(secondChar)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Create the filename based on the naming convention
|
||||
std::string filename = folderPath + "\\" + firstChar + secondChar + ".jdbf";
|
||||
//printf("Loading %s\n", filename.c_str());
|
||||
|
||||
// Open the file
|
||||
HANDLE hFile = CreateFile(filename.c_str(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
if (hFile == INVALID_HANDLE_VALUE) {
|
||||
//log(LOGLEVEL::ERR, "[initialize()]: Error opening database file: ", filename);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Create the file mapping
|
||||
HANDLE hMapping = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL);
|
||||
if (hMapping == NULL) {
|
||||
// log(LOGLEVEL::ERR, "[initialize()]: Error creating database file mapping: ", filename);
|
||||
CloseHandle(hFile);
|
||||
return 2;
|
||||
}
|
||||
|
||||
// Map the file into memory
|
||||
char* fileDataPtr = static_cast<char*>(MapViewOfFile(hMapping, FILE_MAP_READ, 0, 0, 0));
|
||||
if (fileDataPtr == NULL) {
|
||||
//log(LOGLEVEL::ERR, "[initialize()]: Error mapping database file: ", filename);
|
||||
CloseHandle(hMapping);
|
||||
CloseHandle(hFile);
|
||||
return 3;
|
||||
}
|
||||
|
||||
// Store the handles in the global maps
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(fileHandlesMutex);
|
||||
fileHandles[filename] = hFile;
|
||||
}
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mappingHandlesMutex);
|
||||
mappingHandles[filename] = hMapping;
|
||||
}
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(fileDataMutex);
|
||||
fileData[filename] = fileDataPtr;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Call this function when you are done using the file mappings
|
||||
void cleanup() {
|
||||
for (const auto& entry : fileHandles) {
|
||||
UnmapViewOfFile(fileData[entry.first]);
|
||||
CloseHandle(mappingHandles[entry.first]);
|
||||
CloseHandle(entry.second);
|
||||
}
|
||||
|
||||
// Clear the global maps
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(fileHandlesMutex);
|
||||
fileHandles.clear();
|
||||
}
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mappingHandlesMutex);
|
||||
mappingHandles.clear();
|
||||
}
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(fileDataMutex);
|
||||
fileData.clear();
|
||||
}
|
||||
}
|
||||
|
||||
//the latest and fastest version of searching a hash by now
|
||||
int search_hash(const std::string& dbname_, const std::string& hash_, const std::string& filepath_) {
|
||||
// Check if the file mapping is already open for the given filename
|
||||
std::string dbname;
|
||||
std::string hash;
|
||||
std::string filepath;
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(fileHandlesMutex);
|
||||
dbname = dbname_;
|
||||
}
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(fileDataMutex);
|
||||
hash = hash_;
|
||||
}
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mappingHandlesMutex);
|
||||
filepath = filepath_;
|
||||
}
|
||||
|
||||
auto fileIter = fileHandles.find(dbname);
|
||||
if (fileIter == fileHandles.end() && dbname_.find("c:.jdbf") == std::string::npos) {
|
||||
log(LOGLEVEL::ERR_NOSEND, "[search_hash()]: File mapping not initialized for ", dbname);
|
||||
return 2;
|
||||
}
|
||||
else if (fileIter == fileHandles.end()) {
|
||||
return 2;
|
||||
}
|
||||
|
||||
// Use fileData for subsequent searches
|
||||
DWORD fileSize;
|
||||
std::string fileContent;
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(fileDataMutex);
|
||||
fileSize = GetFileSize(fileHandles[dbname], NULL);
|
||||
fileContent = std::string(fileData[dbname], fileSize);
|
||||
}
|
||||
|
||||
// Search for the specific string in the file content
|
||||
size_t foundPos = fileContent.find(hash);
|
||||
if (foundPos != std::string::npos) {
|
||||
//log(LOGLEVEL::VIRUS, "[search_hash()]: Found virus: ", hash, " in file: ", filepath);
|
||||
virus_ctrl_store(filepath.c_str(), hash.c_str(), hash.c_str());
|
||||
//afterwards do the processing with that file
|
||||
virus_ctrl_process(hash.c_str());
|
||||
return 1; // Found
|
||||
}
|
||||
return 0; // Not found
|
||||
}
|
||||
|
||||
//function to get num of files in idr and its subdirs etc
|
||||
int get_num_files(const std::string& directory) {
|
||||
std::string search_path = directory + "\\*.*";
|
||||
WIN32_FIND_DATA find_file_data;
|
||||
HANDLE hFind = FindFirstFile(search_path.c_str(), &find_file_data);
|
||||
int num_files = 0;
|
||||
if (hFind == INVALID_HANDLE_VALUE) {
|
||||
log(LOGLEVEL::ERR_NOSEND, "[get_num_files()]: Could not open directory: ", search_path.c_str(), " while scanning files inside directory.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
do {
|
||||
if (strcmp(find_file_data.cFileName, ".") == 0 || strcmp(find_file_data.cFileName, "..") == 0) {
|
||||
continue; // Skip the current and parent directories
|
||||
}
|
||||
|
||||
const std::string full_path = directory + "\\" + find_file_data.cFileName;
|
||||
if (find_file_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
|
||||
// If it's a directory, recurse into it
|
||||
num_files += get_num_files(full_path);
|
||||
}
|
||||
else {
|
||||
num_files++;
|
||||
}
|
||||
} while (FindNextFile(hFind, &find_file_data) != 0);
|
||||
FindClose(hFind);
|
||||
return num_files;
|
||||
}
|
||||
|
||||
//this is the main function to scan folders. it will then start multuiple threads based on the number of cores / settings
|
||||
void scan_folder(const std::string& directory) {
|
||||
std::string search_path = directory + "\\*.*";
|
||||
WIN32_FIND_DATA find_file_data;
|
||||
HANDLE hFind = FindFirstFile(search_path.c_str(), &find_file_data);
|
||||
|
||||
if (hFind == INVALID_HANDLE_VALUE) {
|
||||
log(LOGLEVEL::WARN, "[scan_folder()]: Could not open directory: ", search_path.c_str(), " while scanning files inside directory.");
|
||||
return;
|
||||
}
|
||||
|
||||
do {
|
||||
if (strcmp(find_file_data.cFileName, ".") == 0 || strcmp(find_file_data.cFileName, "..") == 0) {
|
||||
continue; // Skip the current and parent directories
|
||||
}
|
||||
|
||||
|
||||
const std::string full_path = directory + "\\" + find_file_data.cFileName;
|
||||
if (find_file_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
|
||||
// If it's a directory, recurse into it
|
||||
scan_folder(full_path);
|
||||
}
|
||||
else {
|
||||
//action scanfile_t will start the trheads for scanning the hashes
|
||||
//action_scanfile_t(full_path.c_str());
|
||||
if (cnt > 47400) {
|
||||
//say which file we are scanning now
|
||||
log(LOGLEVEL::INFO_NOSEND, "[scan_folder()]: Scanning file: ", full_path);
|
||||
}
|
||||
//do multithreading here
|
||||
int thread_timeout = 0;
|
||||
while (num_threads >= std::thread::hardware_concurrency()) {
|
||||
Sleep(10);
|
||||
thread_timeout++;
|
||||
if (thread_timeout == 100 * 60) {//if there is for more than 30 seconds no thread available, chances are high, that the threads did not temrinate correctly but aren t running anymore. so set the counter to 0 because else it might just stop the scan.
|
||||
num_threads = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (is_valid_path(full_path)) { //filter out invalid paths and paths with weird characters
|
||||
std::uintmax_t fileSize = std::filesystem::file_size(full_path);
|
||||
if (fileSize > 4000000000) {//4gb
|
||||
log(LOGLEVEL::INFO_NOSEND, "[scan_folder()]: File too large to scan: ", full_path);
|
||||
}
|
||||
else {
|
||||
std::thread scan_thread(scan_file_t, full_path);
|
||||
scan_thread.detach();
|
||||
}
|
||||
}else
|
||||
log(LOGLEVEL::INFO_NOSEND, "[scan_folder()]: Invalid path: ", full_path);
|
||||
cnt++;
|
||||
if (cnt % 100 == 0) {
|
||||
printf("Processed %d files;\n", cnt);
|
||||
//printf("Number of threads: %d\n", num_threads);
|
||||
}
|
||||
if (cnt % 1000 == 0) {
|
||||
//send progress to com file
|
||||
std::ofstream answer_com(ANSWER_COM_PATH, std::ios::app);
|
||||
if (answer_com.is_open()) {
|
||||
answer_com << "progress " << (cnt*100/(all_files+1)) << "\n";
|
||||
answer_com.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
} while (FindNextFile(hFind, &find_file_data) != 0);
|
||||
|
||||
FindClose(hFind);
|
||||
}
|
||||
|
||||
|
||||
|
||||
//for singlethreaded scans
|
||||
void action_scanfile(const std::string& filepath_) {
|
||||
thread_init();
|
||||
const std::string filepath(filepath_);
|
||||
char* db_path = new char[300];
|
||||
char* hash = new char[300];
|
||||
if (is_valid_path(filepath_)) { //filter out invalid paths and paths with weird characters
|
||||
std::string hash_(md5_file_t(filepath));
|
||||
if (strlen(hash_.c_str()) < 290)
|
||||
strcpy_s(hash, 295, hash_.c_str());
|
||||
else {
|
||||
strcpy_s(hash, 295, "");
|
||||
log(LOGLEVEL::ERR_NOSEND, "[scan_file_t()]: Could not calculate hash for file: ", filepath);
|
||||
}
|
||||
sprintf_s(db_path, 295, "%s\\%c%c.jdbf", DB_DIR, hash[0], hash[1]);
|
||||
if (search_hash(db_path, hash, filepath) != 1) {
|
||||
//notify desktop client by writing to answer_com file
|
||||
//if there is now virus, we notify here. if there is a virus we only notify in the virus_ctrl_process function
|
||||
std::ofstream answer_com(ANSWER_COM_PATH, std::ios::app);
|
||||
if (answer_com.is_open()) {
|
||||
answer_com << "not_found " << "\"" << filepath_ << "\"" << " " << hash << " " << "no_action_taken" << "\n";
|
||||
answer_com.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
log(LOGLEVEL::INFO_NOSEND, "[action_scanfile()]: Invalid path: ", filepath_);
|
||||
thread_shutdown();
|
||||
}
|
||||
void action_scanfolder(const std::string& folderpath) {
|
||||
thread_init();
|
||||
thread_local std::string folderpath_(folderpath);
|
||||
cnt = 0;
|
||||
all_files = get_num_files(folderpath_);
|
||||
//tell the desktop client that the scan has started
|
||||
std::ofstream answer_com1(ANSWER_COM_PATH, std::ios::app);
|
||||
if (answer_com1.is_open()) {
|
||||
answer_com1 << "start " << all_files << "\n";
|
||||
answer_com1.close();
|
||||
}
|
||||
scan_folder(folderpath_);
|
||||
std::ofstream answer_com(ANSWER_COM_PATH, std::ios::app);
|
||||
if (answer_com.is_open()) {
|
||||
answer_com << "end " << "\"" << "nothing" << "\"" << " " << "nothing" << " " << "nothing" << "\n";
|
||||
answer_com.close();
|
||||
}
|
||||
thread_shutdown();
|
||||
}
|
||||
|
||||
void scan_file_t(const std::string& filepath_) {
|
||||
num_threads++;
|
||||
thread_local const std::string filepath(filepath_);
|
||||
thread_local char* db_path = new char[300];
|
||||
thread_local char* hash = new char[300];
|
||||
thread_local std::string hash_(md5_file_t(filepath));
|
||||
if (strlen(hash_.c_str()) < 290)
|
||||
strcpy_s(hash, 295, hash_.c_str());
|
||||
else{
|
||||
strcpy_s(hash, 295, "");
|
||||
log(LOGLEVEL::ERR_NOSEND, "[scan_file_t()]: Could not calculate hash for file: ", filepath);
|
||||
}
|
||||
sprintf_s(db_path, 295, "%s\\%c%c.jdbf", DB_DIR, hash[0], hash[1]);
|
||||
search_hash(db_path, hash, filepath);
|
||||
num_threads--;
|
||||
}
|
||||
void scan_process_t(const std::string& filepath_) {
|
||||
thread_local const std::string filepath(filepath_);
|
||||
thread_local char* db_path = new char[300];
|
||||
thread_local char* hash = new char[300];
|
||||
strcpy_s(hash, 295, md5_file_t(filepath).c_str());
|
||||
sprintf_s(db_path, 295, "%s\\%c%c.jdbf", DB_DIR, hash[0], hash[1]);
|
||||
if (search_hash(db_path, hash, filepath) == 1) {
|
||||
//check if need to kill process
|
||||
if (get_setting("virus_ctrl:virus_process_found:kill") == 1) {
|
||||
//kill the process
|
||||
kill_process(filepath.c_str());
|
||||
log(LOGLEVEL::VIRUS, "[scan_process_t()]: Killing process: ", filepath);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -1,78 +0,0 @@
|
||||
#ifndef THREAD_CTRL_CPP
|
||||
#define THREAD_CTRL_CPP
|
||||
#include "thread_ctrl.h"
|
||||
#include "log.h"
|
||||
#include "well_known.h"
|
||||
#include "scan.h"
|
||||
#include "app_ctrl.h"
|
||||
#include "update.h"
|
||||
void split(char* input,const char delimiter, char* out1, char* out2) {
|
||||
//split a string at the delimiter. the delimiter only occurs once. so the first part is out1 and the second part is out2
|
||||
int i = 0;
|
||||
int j = 0;
|
||||
int k = 0;
|
||||
while (input[i] != '\0') {
|
||||
if (input[i] == delimiter) {
|
||||
out1[j] = '\0';
|
||||
i++;
|
||||
while (input[i] != '\0') {
|
||||
out2[k] = input[i];
|
||||
i++;
|
||||
k++;
|
||||
}
|
||||
out2[k] = '\0';
|
||||
return;
|
||||
}
|
||||
else {
|
||||
out1[j] = input[i];
|
||||
i++;
|
||||
j++;
|
||||
}
|
||||
}
|
||||
}
|
||||
int start_thread(const char* command) {
|
||||
if (can_run_thread()) {
|
||||
char* out2 = new char[100]; //for the command
|
||||
char* out1 = new char[300]; //for the arguments
|
||||
split((char*)command,';', (char*)out1, (char*)out2);
|
||||
//log(LOGLEVEL::INFO, "[start_thread()]: starting command: ", out1, " with arguments: ",out2);
|
||||
//printf("out1: %s\n", out1);
|
||||
//printf("out2: %s\n", out2);
|
||||
//determine what should be executed
|
||||
if (strcmp(out1, "scanfile") == 0) {
|
||||
log(LOGLEVEL::INFO, "[start_thread()]: starting scanfile with arguments: ", out2);
|
||||
//start a new thread with the scanfile function
|
||||
std::thread t1(action_scanfile, out2);
|
||||
t1.detach();
|
||||
}
|
||||
else if (strcmp(out1, "scanfolder") == 0) {
|
||||
//start a new thread with the scanfolder function
|
||||
log(LOGLEVEL::INFO, "[start_thread()]: starting scanfolder with arguments: ", out2);
|
||||
std::thread t1(action_scanfolder, out2);
|
||||
log(LOGLEVEL::INFO, "[start_thread()]: started scanfolder with arguments: ", out2);
|
||||
t1.detach();
|
||||
}
|
||||
else if (strcmp(out1, "update_settings") == 0) {
|
||||
//start a new thread with the scanfolder function
|
||||
log(LOGLEVEL::INFO, "[start_thread()]: starting update_settings with arguments: ", out2);
|
||||
std::thread t1(action_update_settings);
|
||||
t1.detach();
|
||||
}
|
||||
else if (strcmp(out1, "update_db") == 0) {
|
||||
//start a new thread with the scanfolder function
|
||||
log(LOGLEVEL::INFO, "[start_thread()]: starting update_db with arguments: ", out2);
|
||||
std::thread t1(action_update_settings);
|
||||
t1.detach();
|
||||
}
|
||||
|
||||
while (can_run_thread()) {
|
||||
//delay a bit, in order to wait until the thread is started
|
||||
Sleep(10);
|
||||
}
|
||||
delete[] out1;
|
||||
delete[] out2;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,102 +0,0 @@
|
||||
#include "utils.h"
|
||||
#include <windows.h>
|
||||
#include <string.h>
|
||||
#include <iostream>
|
||||
#include "log.h"
|
||||
#include <tlhelp32.h>
|
||||
#include <regex>
|
||||
|
||||
void split(const std::string& input, char delimiter, std::string& out1, std::string& out2) {
|
||||
// Split a string at the delimiter. The delimiter only occurs once.
|
||||
// The first part is stored in out1 and the second part in out2.
|
||||
size_t pos = input.find(delimiter);
|
||||
if (pos != std::string::npos) {
|
||||
out1 = input.substr(0, pos);
|
||||
out2 = input.substr(pos + 1);
|
||||
}
|
||||
}
|
||||
bool is_valid_path(const std::string& filename) {
|
||||
// Define a regular expression pattern for allowed characters
|
||||
// This pattern allows letters (upper and lower case), numbers, underscores, and hyphens
|
||||
std::regex pattern("[^<>:\"/\\\\|?*]+");
|
||||
// Check if the filename matches the pattern
|
||||
return std::regex_match(filename, pattern);
|
||||
}
|
||||
|
||||
|
||||
void startup(LPCTSTR lpApplicationName)
|
||||
{
|
||||
// additional information
|
||||
STARTUPINFO si;
|
||||
PROCESS_INFORMATION pi;
|
||||
|
||||
// set the size of the structures
|
||||
ZeroMemory(&si, sizeof(si));
|
||||
si.cb = sizeof(si);
|
||||
ZeroMemory(&pi, sizeof(pi));
|
||||
|
||||
// start the program up
|
||||
CreateProcess(lpApplicationName, // the path
|
||||
NULL, // Command line
|
||||
NULL, // Process handle not inheritable
|
||||
NULL, // Thread handle not inheritable
|
||||
FALSE, // Set handle inheritance to FALSE
|
||||
0, // No creation flags
|
||||
NULL, // Use parent's environment block
|
||||
NULL, // Use parent's starting directory
|
||||
&si, // Pointer to STARTUPINFO structure
|
||||
&pi // Pointer to PROCESS_INFORMATION structure
|
||||
);
|
||||
// Close process and thread handles.
|
||||
CloseHandle(pi.hProcess);
|
||||
CloseHandle(pi.hThread);
|
||||
}
|
||||
|
||||
|
||||
std::string get_filename(const std::string& path) {
|
||||
auto pos = path.find_last_of("\\");
|
||||
if (pos == std::string::npos) {
|
||||
// No directory separator found, return the original path
|
||||
return path;
|
||||
}
|
||||
else {
|
||||
// Return the substring after the last directory separator
|
||||
return path.substr(pos + 1);
|
||||
}
|
||||
}
|
||||
|
||||
int strcasecmp(const std::string& s1, const std::string& s2) {
|
||||
auto it1 = s1.begin();
|
||||
auto it2 = s2.begin();
|
||||
while (it1 != s1.end() && it2 != s2.end()) {
|
||||
int diff = std::tolower(*it1) - std::tolower(*it2);
|
||||
if (diff != 0)
|
||||
return diff;
|
||||
++it1;
|
||||
++it2;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void kill_process(const std::string& path) {
|
||||
HANDLE hSnapShot = CreateToolhelp32Snapshot(TH32CS_SNAPALL, NULL);
|
||||
PROCESSENTRY32 pEntry;
|
||||
pEntry.dwSize = sizeof(pEntry);
|
||||
BOOL hRes = Process32First(hSnapShot, &pEntry);
|
||||
while (hRes)
|
||||
{
|
||||
if (strcasecmp(pEntry.szExeFile, get_filename(path).c_str()) == 0)
|
||||
{
|
||||
HANDLE hProcess = OpenProcess(PROCESS_TERMINATE, 0, static_cast<DWORD>(pEntry.th32ProcessID));
|
||||
if (hProcess != NULL)
|
||||
{
|
||||
TerminateProcess(hProcess, 9);
|
||||
CloseHandle(hProcess);
|
||||
}
|
||||
else
|
||||
log(LOGLEVEL::ERR, "[kill_process()]: Error while killing process: ", path);
|
||||
}
|
||||
hRes = Process32Next(hSnapShot, &pEntry);
|
||||
}
|
||||
CloseHandle(hSnapShot);
|
||||
}
|
||||
@@ -1,105 +0,0 @@
|
||||
#include "utils.h"
|
||||
#include <windows.h>
|
||||
#include <string.h>
|
||||
#include <iostream>
|
||||
#include "log.h"
|
||||
#include <tlhelp32.h>
|
||||
#include <regex>
|
||||
#include <filesystem>
|
||||
#include <regex>
|
||||
|
||||
void split(const std::string& input, char delimiter, std::string& out1, std::string& out2) {
|
||||
// Split a string at the delimiter. The delimiter only occurs once.
|
||||
// The first part is stored in out1 and the second part in out2.
|
||||
size_t pos = input.find(delimiter);
|
||||
if (pos != std::string::npos) {
|
||||
out1 = input.substr(0, pos);
|
||||
out2 = input.substr(pos + 1);
|
||||
}
|
||||
}
|
||||
bool is_valid_path(const std::string& filename) {
|
||||
for (char c : filename) {
|
||||
if (c == '<' || c == '>' || c == '"' || c == '|' || c == '?' || c == '*') {
|
||||
return 0; // Special character found
|
||||
}
|
||||
}
|
||||
return 1; // No special character found
|
||||
}
|
||||
|
||||
|
||||
void startup(LPCTSTR lpApplicationName)
|
||||
{
|
||||
// additional information
|
||||
STARTUPINFO si;
|
||||
PROCESS_INFORMATION pi;
|
||||
|
||||
// set the size of the structures
|
||||
ZeroMemory(&si, sizeof(si));
|
||||
si.cb = sizeof(si);
|
||||
ZeroMemory(&pi, sizeof(pi));
|
||||
|
||||
// start the program up
|
||||
CreateProcess(lpApplicationName, // the path
|
||||
NULL, // Command line
|
||||
NULL, // Process handle not inheritable
|
||||
NULL, // Thread handle not inheritable
|
||||
FALSE, // Set handle inheritance to FALSE
|
||||
0, // No creation flags
|
||||
NULL, // Use parent's environment block
|
||||
NULL, // Use parent's starting directory
|
||||
&si, // Pointer to STARTUPINFO structure
|
||||
&pi // Pointer to PROCESS_INFORMATION structure
|
||||
);
|
||||
// Close process and thread handles.
|
||||
CloseHandle(pi.hProcess);
|
||||
CloseHandle(pi.hThread);
|
||||
}
|
||||
|
||||
|
||||
std::string get_filename(const std::string& path) {
|
||||
auto pos = path.find_last_of("\\");
|
||||
if (pos == std::string::npos) {
|
||||
// No directory separator found, return the original path
|
||||
return path;
|
||||
}
|
||||
else {
|
||||
// Return the substring after the last directory separator
|
||||
return path.substr(pos + 1);
|
||||
}
|
||||
}
|
||||
|
||||
int strcasecmp(const std::string& s1, const std::string& s2) {
|
||||
auto it1 = s1.begin();
|
||||
auto it2 = s2.begin();
|
||||
while (it1 != s1.end() && it2 != s2.end()) {
|
||||
int diff = std::tolower(*it1) - std::tolower(*it2);
|
||||
if (diff != 0)
|
||||
return diff;
|
||||
++it1;
|
||||
++it2;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void kill_process(const std::string& path) {
|
||||
HANDLE hSnapShot = CreateToolhelp32Snapshot(TH32CS_SNAPALL, NULL);
|
||||
PROCESSENTRY32 pEntry;
|
||||
pEntry.dwSize = sizeof(pEntry);
|
||||
BOOL hRes = Process32First(hSnapShot, &pEntry);
|
||||
while (hRes)
|
||||
{
|
||||
if (strcasecmp(pEntry.szExeFile, get_filename(path).c_str()) == 0)
|
||||
{
|
||||
HANDLE hProcess = OpenProcess(PROCESS_TERMINATE, 0, static_cast<DWORD>(pEntry.th32ProcessID));
|
||||
if (hProcess != NULL)
|
||||
{
|
||||
TerminateProcess(hProcess, 9);
|
||||
CloseHandle(hProcess);
|
||||
}
|
||||
else
|
||||
log(LOGLEVEL::ERR, "[kill_process()]: Error while killing process: ", path);
|
||||
}
|
||||
hRes = Process32Next(hSnapShot, &pEntry);
|
||||
}
|
||||
CloseHandle(hSnapShot);
|
||||
}
|
||||
@@ -1,105 +0,0 @@
|
||||
#include "utils.h"
|
||||
#include <windows.h>
|
||||
#include <string.h>
|
||||
#include <iostream>
|
||||
#include "log.h"
|
||||
#include <tlhelp32.h>
|
||||
#include <regex>
|
||||
#include <filesystem>
|
||||
#include <regex>
|
||||
|
||||
void split(const std::string& input, char delimiter, std::string& out1, std::string& out2) {
|
||||
// Split a string at the delimiter. The delimiter only occurs once.
|
||||
// The first part is stored in out1 and the second part in out2.
|
||||
size_t pos = input.find(delimiter);
|
||||
if (pos != std::string::npos) {
|
||||
out1 = input.substr(0, pos);
|
||||
out2 = input.substr(pos + 1);
|
||||
}
|
||||
}
|
||||
bool is_valid_path(const std::string& filename) {
|
||||
for (char c : filename) {
|
||||
if (c == '<' || c == '>' || c == '"' || c == '|' || c == '?' || c == '*' || c > 126 || c < 32 ) {
|
||||
return 0; // Special character found
|
||||
}
|
||||
}
|
||||
return 1; // No special character found
|
||||
}
|
||||
|
||||
|
||||
void startup(LPCTSTR lpApplicationName)
|
||||
{
|
||||
// additional information
|
||||
STARTUPINFO si;
|
||||
PROCESS_INFORMATION pi;
|
||||
|
||||
// set the size of the structures
|
||||
ZeroMemory(&si, sizeof(si));
|
||||
si.cb = sizeof(si);
|
||||
ZeroMemory(&pi, sizeof(pi));
|
||||
|
||||
// start the program up
|
||||
CreateProcess(lpApplicationName, // the path
|
||||
NULL, // Command line
|
||||
NULL, // Process handle not inheritable
|
||||
NULL, // Thread handle not inheritable
|
||||
FALSE, // Set handle inheritance to FALSE
|
||||
0, // No creation flags
|
||||
NULL, // Use parent's environment block
|
||||
NULL, // Use parent's starting directory
|
||||
&si, // Pointer to STARTUPINFO structure
|
||||
&pi // Pointer to PROCESS_INFORMATION structure
|
||||
);
|
||||
// Close process and thread handles.
|
||||
CloseHandle(pi.hProcess);
|
||||
CloseHandle(pi.hThread);
|
||||
}
|
||||
|
||||
|
||||
std::string get_filename(const std::string& path) {
|
||||
auto pos = path.find_last_of("\\");
|
||||
if (pos == std::string::npos) {
|
||||
// No directory separator found, return the original path
|
||||
return path;
|
||||
}
|
||||
else {
|
||||
// Return the substring after the last directory separator
|
||||
return path.substr(pos + 1);
|
||||
}
|
||||
}
|
||||
|
||||
int strcasecmp(const std::string& s1, const std::string& s2) {
|
||||
auto it1 = s1.begin();
|
||||
auto it2 = s2.begin();
|
||||
while (it1 != s1.end() && it2 != s2.end()) {
|
||||
int diff = std::tolower(*it1) - std::tolower(*it2);
|
||||
if (diff != 0)
|
||||
return diff;
|
||||
++it1;
|
||||
++it2;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void kill_process(const std::string& path) {
|
||||
HANDLE hSnapShot = CreateToolhelp32Snapshot(TH32CS_SNAPALL, NULL);
|
||||
PROCESSENTRY32 pEntry;
|
||||
pEntry.dwSize = sizeof(pEntry);
|
||||
BOOL hRes = Process32First(hSnapShot, &pEntry);
|
||||
while (hRes)
|
||||
{
|
||||
if (strcasecmp(pEntry.szExeFile, get_filename(path).c_str()) == 0)
|
||||
{
|
||||
HANDLE hProcess = OpenProcess(PROCESS_TERMINATE, 0, static_cast<DWORD>(pEntry.th32ProcessID));
|
||||
if (hProcess != NULL)
|
||||
{
|
||||
TerminateProcess(hProcess, 9);
|
||||
CloseHandle(hProcess);
|
||||
}
|
||||
else
|
||||
log(LOGLEVEL::ERR, "[kill_process()]: Error while killing process: ", path);
|
||||
}
|
||||
hRes = Process32Next(hSnapShot, &pEntry);
|
||||
}
|
||||
CloseHandle(hSnapShot);
|
||||
}
|
||||
@@ -1,368 +0,0 @@
|
||||
#include <Windows.h>
|
||||
#include <shlobj.h>
|
||||
#include <thread>
|
||||
#include <chrono>
|
||||
#include <fstream>
|
||||
#include <codecvt>
|
||||
#include <locale>
|
||||
#include "../client_backend/well_known.h"
|
||||
|
||||
#define IDM_SCAN_FILE 101
|
||||
#define IDM_SCAN_FOLDER 102
|
||||
|
||||
|
||||
std::wstring string_to_widestring(const std::string& str) {
|
||||
std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> converter;
|
||||
return converter.from_bytes(str);
|
||||
}
|
||||
void send_command(const std::string& command) {
|
||||
std::ofstream outputFile(MAIN_COM_PATH);
|
||||
if (outputFile.is_open()) {
|
||||
outputFile << command;
|
||||
outputFile.close();
|
||||
}
|
||||
}
|
||||
|
||||
// Function to update the content of the text field with the provided text
|
||||
void update_textfield(HWND hWndTextField, const std::string& text) {
|
||||
// Get the current text length
|
||||
int textLength = GetWindowTextLength(hWndTextField);
|
||||
|
||||
// Set the selection to the end of the text field
|
||||
SendMessage(hWndTextField, EM_SETSEL, textLength, textLength);
|
||||
|
||||
// Append the new text
|
||||
SendMessage(hWndTextField, EM_REPLACESEL, FALSE, (LPARAM)string_to_widestring(text).c_str());
|
||||
}
|
||||
|
||||
void scan_file(HWND hWndTextField, const std::string& filePath) {
|
||||
// Remove the answer file
|
||||
std::remove(ANSWER_COM_PATH);
|
||||
// Display the scanned file path in the window
|
||||
update_textfield(hWndTextField, "Scanning file: " + filePath + "\r\n");
|
||||
bool answered = false;
|
||||
// Write command into com file
|
||||
//printf("%d\n",send_to_pipe("scanfile \"" + filePath + "\""));
|
||||
std::ofstream outputFile(MAIN_COM_PATH);
|
||||
if (outputFile.is_open()) {
|
||||
outputFile << "scanfile \"" << filePath << "\"";
|
||||
outputFile.close();
|
||||
}
|
||||
else {
|
||||
update_textfield(hWndTextField, "Error: Unable to talk to daemon!\n");
|
||||
return;
|
||||
}
|
||||
while (!answered) {
|
||||
// Wait for answer in file
|
||||
std::ifstream inputFile(ANSWER_COM_PATH);
|
||||
// The structure of the answer file is as follows:
|
||||
// found/not_found
|
||||
// filepath
|
||||
// hash
|
||||
// action_taken/no_action_taken
|
||||
if (inputFile.is_open()) {
|
||||
std::string status, scannedFilePath, hash, action;
|
||||
if (inputFile >> status) {
|
||||
inputFile.ignore(1); // Ignore space
|
||||
inputFile.ignore(1); // Ignore starting double quote
|
||||
if (status == "found" || status == "not_found") {
|
||||
std::getline(inputFile, scannedFilePath, '\"'); // Read until closing double quote
|
||||
inputFile.ignore(1); // Ignore space between filepath and hash
|
||||
inputFile.ignore(1); // Ignore starting double quote
|
||||
std::getline(inputFile, hash, ' '); // Read until space
|
||||
std::getline(inputFile, action); // Read until end of line
|
||||
|
||||
answered = true;
|
||||
|
||||
if (status == "found") {
|
||||
update_textfield(hWndTextField, "Virus found in file: " + scannedFilePath + "\r\n");
|
||||
update_textfield(hWndTextField, "File: " + scannedFilePath + " is infected\r\n");
|
||||
update_textfield(hWndTextField, "Hash: " + hash + "\r\n");
|
||||
update_textfield(hWndTextField, "Action taken: " + action + "\r\n");
|
||||
|
||||
}
|
||||
else {
|
||||
update_textfield(hWndTextField, "No virus found in file: " + scannedFilePath + "\r\n");
|
||||
}
|
||||
update_textfield(hWndTextField, "------------------------------------------\r\n");
|
||||
}
|
||||
}
|
||||
else {
|
||||
answered = true;
|
||||
update_textfield(hWndTextField, "Error: Unable to talk to daemon!\n");
|
||||
update_textfield(hWndTextField, "------------------------------------------\n");
|
||||
}
|
||||
inputFile.close();
|
||||
std::remove(ANSWER_COM_PATH);
|
||||
}
|
||||
// Wait for 1 second before checking again
|
||||
std::this_thread::sleep_for(std::chrono::seconds(1));
|
||||
}
|
||||
// Remove the answer file
|
||||
std::remove(ANSWER_COM_PATH);
|
||||
}
|
||||
|
||||
// Function to simulate folder scanning
|
||||
void scan_folder(HWND hProgressBar,HWND hWndTextField, const std::string& folderPath) {
|
||||
int num_of_found = 0;
|
||||
// Remove the answer file
|
||||
std::remove(ANSWER_COM_PATH);
|
||||
// Display the scanned folder path in the window
|
||||
update_textfield(hWndTextField, "Scanning folder: " + folderPath + "\r\n");
|
||||
bool answered = false;
|
||||
// Write command into com file
|
||||
std::ofstream outputFile(MAIN_COM_PATH);
|
||||
if (outputFile.is_open()) {
|
||||
outputFile << "scanfolder \"" << folderPath << "\"";
|
||||
outputFile.close();
|
||||
}
|
||||
else {
|
||||
update_textfield(hWndTextField, "Error: Unable to talk to daemon!\n");
|
||||
return;
|
||||
}
|
||||
while (!answered) {
|
||||
// Wait for answer in file
|
||||
std::ifstream inputFile(ANSWER_COM_PATH);
|
||||
// The structure of the answer file is as follows:
|
||||
// found/not_found
|
||||
// filepath
|
||||
// hash
|
||||
// action_taken/no_action_taken
|
||||
if (inputFile.is_open()) {
|
||||
std::string status, scannedFilePath, hash, action;
|
||||
while (!inputFile.eof()) {
|
||||
if (inputFile >> status) {
|
||||
if (status == "found" || status == "not_found") {
|
||||
inputFile.ignore(1); // Ignore space
|
||||
inputFile.ignore(1); // Ignore starting double quote
|
||||
std::getline(inputFile, scannedFilePath, '\"'); // Read until closing double quote
|
||||
inputFile.ignore(1); // Ignore space between filepath and hash
|
||||
inputFile.ignore(1); // Ignore starting double quote
|
||||
std::getline(inputFile, hash, ' '); // Read until space
|
||||
std::getline(inputFile, action); // Read until end of line
|
||||
|
||||
//answered = true;
|
||||
|
||||
if (status == "found") {
|
||||
update_textfield(hWndTextField, "Virus found in file: " + scannedFilePath + "\r\n");
|
||||
update_textfield(hWndTextField, "File: " + scannedFilePath + " is infected\r\n");
|
||||
update_textfield(hWndTextField, "Hash: " + hash + "\r\n");
|
||||
update_textfield(hWndTextField, "Action taken: " + action + "\r\n");
|
||||
num_of_found++;
|
||||
}
|
||||
else {
|
||||
update_textfield(hWndTextField, "No virus found in file: " + scannedFilePath + "\r\n");
|
||||
}
|
||||
update_textfield(hWndTextField, "------------------------------------------\r\n");
|
||||
}
|
||||
else if (status == "progress") {
|
||||
std::string progress;
|
||||
inputFile.ignore(1); // Ignore space
|
||||
inputFile >> progress;
|
||||
MessageBox(NULL, string_to_widestring(progress).c_str(), L"Progress", MB_OK);
|
||||
SendMessage(hProgressBar, PBM_SETPOS, atoi(progress.c_str()), 0);
|
||||
}
|
||||
else if (status == "end")
|
||||
answered = true;
|
||||
}
|
||||
}
|
||||
inputFile.close();
|
||||
Sleep(1000);//only see for new entrys ~ once a second
|
||||
std::ofstream(ANSWER_COM_PATH);//clear the file
|
||||
}
|
||||
// Wait for 1 second before checking again
|
||||
std::this_thread::sleep_for(std::chrono::seconds(1));
|
||||
}
|
||||
update_textfield(hWndTextField, "Folder scan completed\r\n");
|
||||
update_textfield(hWndTextField, "Number of infected files: " + std::to_string(num_of_found) + "\r\n");
|
||||
// Remove the answer file
|
||||
std::remove(ANSWER_COM_PATH);
|
||||
}
|
||||
|
||||
|
||||
|
||||
std::string getFolderPath(HWND hWnd) {
|
||||
std::wstring selectedFolderPath;
|
||||
|
||||
// Initialize COM
|
||||
CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE);
|
||||
|
||||
// Display the folder picker dialog
|
||||
BROWSEINFO browseInfo = { 0 };
|
||||
TCHAR selectedPath[MAX_PATH];
|
||||
browseInfo.hwndOwner = hWnd; // Set the owner window
|
||||
browseInfo.pidlRoot = NULL; // Start from the desktop
|
||||
browseInfo.pszDisplayName = selectedPath;
|
||||
browseInfo.lpszTitle = TEXT("Select a folder");
|
||||
browseInfo.ulFlags = BIF_RETURNONLYFSDIRS | BIF_NEWDIALOGSTYLE;
|
||||
|
||||
LPITEMIDLIST pidlSelected = SHBrowseForFolder(&browseInfo);
|
||||
if (pidlSelected != NULL) {
|
||||
SHGetPathFromIDList(pidlSelected, selectedPath);
|
||||
|
||||
// Convert TCHAR array to std::string
|
||||
std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> converter;
|
||||
selectedFolderPath = selectedPath;
|
||||
|
||||
// Free the PIDL
|
||||
IMalloc* pMalloc;
|
||||
if (SUCCEEDED(SHGetMalloc(&pMalloc))) {
|
||||
pMalloc->Free(pidlSelected);
|
||||
pMalloc->Release();
|
||||
}
|
||||
}
|
||||
|
||||
// Uninitialize COM
|
||||
CoUninitialize();
|
||||
|
||||
return std::string(selectedFolderPath.begin(), selectedFolderPath.end());
|
||||
}
|
||||
|
||||
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
|
||||
static HWND hWndTextField;
|
||||
static HWND hProgressBar;
|
||||
static HBRUSH hBackgroundBrush = CreateSolidBrush(RGB(255, 255, 255)); // White color
|
||||
RECT rect;
|
||||
GetClientRect(hWnd, &rect);
|
||||
int width = rect.right - rect.left;
|
||||
int height = rect.bottom - rect.top;
|
||||
switch (message) {
|
||||
case WM_CREATE:
|
||||
{
|
||||
|
||||
// Create the "Scan File" button
|
||||
CreateWindowEx(NULL, L"BUTTON", L"Scan File",
|
||||
WS_TABSTOP | WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON,
|
||||
20, 10, 100, 30, hWnd, (HMENU)IDM_SCAN_FILE, GetModuleHandle(NULL), NULL);
|
||||
|
||||
// Create the "Scan Folder" button
|
||||
CreateWindowEx(NULL, L"BUTTON", L"Scan Folder",
|
||||
WS_TABSTOP | WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON,
|
||||
20, 50, 100, 30, hWnd, (HMENU)IDM_SCAN_FOLDER, GetModuleHandle(NULL), NULL);
|
||||
|
||||
// Create a multi-line edit control for displaying text
|
||||
hWndTextField = CreateWindowEx(WS_EX_CLIENTEDGE, L"EDIT", NULL,
|
||||
WS_CHILD | WS_VISIBLE | WS_VSCROLL | ES_MULTILINE | ES_AUTOVSCROLL | ES_READONLY,
|
||||
140, 10, width-140-20, height-10-50, hWnd, NULL, NULL, NULL);
|
||||
update_textfield(hWndTextField, "Welcome to Cyberhex endpoint protection!\r\n");
|
||||
|
||||
hProgressBar = CreateWindowEx(0, PROGRESS_CLASS, NULL,
|
||||
WS_CHILD | WS_VISIBLE | PBS_SMOOTH,
|
||||
140, height-40, 200, 20, hWnd, NULL, NULL, NULL);
|
||||
SendMessage(hProgressBar, PBM_SETRANGE, 0, MAKELPARAM(0, 100));
|
||||
SendMessage(hProgressBar, PBM_SETSTEP, 1, 0);
|
||||
}
|
||||
break;
|
||||
case WM_SIZE:
|
||||
{
|
||||
// Resize the text field to fit the window
|
||||
MoveWindow(hWndTextField, 140, 10, width - 140 - 20, height - 10 - 50, TRUE);
|
||||
MoveWindow(hProgressBar, 140, height - 40, 200, 20, TRUE);
|
||||
break;
|
||||
}
|
||||
case WM_COMMAND:
|
||||
{
|
||||
int wmId = LOWORD(wParam);
|
||||
// Parse the menu selections:
|
||||
switch (wmId) {
|
||||
case IDM_SCAN_FILE:
|
||||
{
|
||||
// Open file dialog to select a file
|
||||
// Call scan_file function in a separate thread
|
||||
OPENFILENAME ofn;
|
||||
WCHAR szFile[MAX_PATH] = L""; // Use WCHAR for Unicode compatibility
|
||||
|
||||
ZeroMemory(&ofn, sizeof(ofn));
|
||||
ofn.lStructSize = sizeof(ofn);
|
||||
ofn.hwndOwner = hWnd;
|
||||
ofn.lpstrFile = szFile;
|
||||
ofn.lpstrFile[0] = L'\0'; // Use wide character constant L'\0'
|
||||
ofn.nMaxFile = sizeof(szFile);
|
||||
ofn.lpstrFilter = L"All Files\0*.*\0"; // Use wide character string literal L""
|
||||
ofn.nFilterIndex = 1;
|
||||
ofn.lpstrFileTitle = NULL;
|
||||
ofn.lpstrInitialDir = NULL;
|
||||
ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST;
|
||||
|
||||
if (GetOpenFileName(&ofn) == TRUE) {
|
||||
std::wstring selectedFile = ofn.lpstrFile; // Use std::wstring for wide characters
|
||||
std::string narrowSelectedFile(selectedFile.begin(), selectedFile.end());
|
||||
std::thread(scan_file, hWndTextField, narrowSelectedFile).detach();
|
||||
}
|
||||
}
|
||||
break;
|
||||
case IDM_SCAN_FOLDER:
|
||||
{
|
||||
// Open folder picker dialog
|
||||
// Call scan_folder function in a separate thread
|
||||
std::string selectedFolder = getFolderPath(hWnd);
|
||||
std::thread(scan_folder,hProgressBar, hWndTextField, selectedFolder).detach();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return DefWindowProc(hWnd, message, wParam, lParam);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case WM_PAINT:
|
||||
{
|
||||
PAINTSTRUCT ps;
|
||||
HDC hdc = BeginPaint(hWnd, &ps);
|
||||
RECT rect;
|
||||
GetClientRect(hWnd, &rect);
|
||||
FillRect(hdc, &rect, hBackgroundBrush); // Fill the entire client area with white color
|
||||
EndPaint(hWnd, &ps);
|
||||
}
|
||||
break;
|
||||
case WM_DESTROY:
|
||||
PostQuitMessage(0);
|
||||
break;
|
||||
default:
|
||||
return DefWindowProc(hWnd, message, wParam, lParam);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
|
||||
const wchar_t CLASS_NAME[] = L"Cyberhex endpoint protection frontend";
|
||||
|
||||
WNDCLASS wc = { };
|
||||
|
||||
wc.lpfnWndProc = WndProc;
|
||||
wc.hInstance = hInstance;
|
||||
wc.lpszClassName = CLASS_NAME;
|
||||
|
||||
RegisterClass(&wc);
|
||||
|
||||
HWND hWnd = CreateWindowEx(
|
||||
0,
|
||||
CLASS_NAME,
|
||||
L"Cyberhex endpoint protection",
|
||||
WS_OVERLAPPEDWINDOW,
|
||||
CW_USEDEFAULT,
|
||||
CW_USEDEFAULT,
|
||||
640,
|
||||
480,
|
||||
NULL,
|
||||
NULL,
|
||||
hInstance,
|
||||
NULL
|
||||
);
|
||||
|
||||
|
||||
if (hWnd == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
ShowWindow(hWnd, nCmdShow);
|
||||
UpdateWindow(hWnd);
|
||||
|
||||
MSG msg = { };
|
||||
while (GetMessage(&msg, NULL, 0, 0)) {
|
||||
TranslateMessage(&msg);
|
||||
DispatchMessage(&msg);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,367 +0,0 @@
|
||||
#include <Windows.h>
|
||||
#include <shlobj.h>
|
||||
#include <thread>
|
||||
#include <chrono>
|
||||
#include <fstream>
|
||||
#include <codecvt>
|
||||
#include <locale>
|
||||
#include "../client_backend/well_known.h"
|
||||
|
||||
#define IDM_SCAN_FILE 101
|
||||
#define IDM_SCAN_FOLDER 102
|
||||
|
||||
|
||||
std::wstring string_to_widestring(const std::string& str) {
|
||||
std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> converter;
|
||||
return converter.from_bytes(str);
|
||||
}
|
||||
void send_command(const std::string& command) {
|
||||
std::ofstream outputFile(MAIN_COM_PATH);
|
||||
if (outputFile.is_open()) {
|
||||
outputFile << command;
|
||||
outputFile.close();
|
||||
}
|
||||
}
|
||||
|
||||
// Function to update the content of the text field with the provided text
|
||||
void update_textfield(HWND hWndTextField, const std::string& text) {
|
||||
// Get the current text length
|
||||
int textLength = GetWindowTextLength(hWndTextField);
|
||||
|
||||
// Set the selection to the end of the text field
|
||||
SendMessage(hWndTextField, EM_SETSEL, textLength, textLength);
|
||||
|
||||
// Append the new text
|
||||
SendMessage(hWndTextField, EM_REPLACESEL, FALSE, (LPARAM)string_to_widestring(text).c_str());
|
||||
}
|
||||
|
||||
void scan_file(HWND hWndTextField, const std::string& filePath) {
|
||||
// Remove the answer file
|
||||
std::remove(ANSWER_COM_PATH);
|
||||
// Display the scanned file path in the window
|
||||
update_textfield(hWndTextField, "Scanning file: " + filePath + "\r\n");
|
||||
bool answered = false;
|
||||
// Write command into com file
|
||||
//printf("%d\n",send_to_pipe("scanfile \"" + filePath + "\""));
|
||||
std::ofstream outputFile(MAIN_COM_PATH);
|
||||
if (outputFile.is_open()) {
|
||||
outputFile << "scanfile \"" << filePath << "\"";
|
||||
outputFile.close();
|
||||
}
|
||||
else {
|
||||
update_textfield(hWndTextField, "Error: Unable to talk to daemon!\n");
|
||||
return;
|
||||
}
|
||||
while (!answered) {
|
||||
// Wait for answer in file
|
||||
std::ifstream inputFile(ANSWER_COM_PATH);
|
||||
// The structure of the answer file is as follows:
|
||||
// found/not_found
|
||||
// filepath
|
||||
// hash
|
||||
// action_taken/no_action_taken
|
||||
if (inputFile.is_open()) {
|
||||
std::string status, scannedFilePath, hash, action;
|
||||
if (inputFile >> status) {
|
||||
inputFile.ignore(1); // Ignore space
|
||||
inputFile.ignore(1); // Ignore starting double quote
|
||||
if (status == "found" || status == "not_found") {
|
||||
std::getline(inputFile, scannedFilePath, '\"'); // Read until closing double quote
|
||||
inputFile.ignore(1); // Ignore space between filepath and hash
|
||||
inputFile.ignore(1); // Ignore starting double quote
|
||||
std::getline(inputFile, hash, ' '); // Read until space
|
||||
std::getline(inputFile, action); // Read until end of line
|
||||
|
||||
answered = true;
|
||||
|
||||
if (status == "found") {
|
||||
update_textfield(hWndTextField, "Virus found in file: " + scannedFilePath + "\r\n");
|
||||
update_textfield(hWndTextField, "File: " + scannedFilePath + " is infected\r\n");
|
||||
update_textfield(hWndTextField, "Hash: " + hash + "\r\n");
|
||||
update_textfield(hWndTextField, "Action taken: " + action + "\r\n");
|
||||
|
||||
}
|
||||
else {
|
||||
update_textfield(hWndTextField, "No virus found in file: " + scannedFilePath + "\r\n");
|
||||
}
|
||||
update_textfield(hWndTextField, "------------------------------------------\r\n");
|
||||
}
|
||||
}
|
||||
else {
|
||||
answered = true;
|
||||
update_textfield(hWndTextField, "Error: Unable to talk to daemon!\n");
|
||||
update_textfield(hWndTextField, "------------------------------------------\n");
|
||||
}
|
||||
inputFile.close();
|
||||
std::remove(ANSWER_COM_PATH);
|
||||
}
|
||||
// Wait for 1 second before checking again
|
||||
std::this_thread::sleep_for(std::chrono::seconds(1));
|
||||
}
|
||||
// Remove the answer file
|
||||
std::remove(ANSWER_COM_PATH);
|
||||
}
|
||||
|
||||
// Function to simulate folder scanning
|
||||
void scan_folder(HWND hProgressBar,HWND hWndTextField, const std::string& folderPath) {
|
||||
int num_of_found = 0;
|
||||
// Remove the answer file
|
||||
std::remove(ANSWER_COM_PATH);
|
||||
// Display the scanned folder path in the window
|
||||
update_textfield(hWndTextField, "Scanning folder: " + folderPath + "\r\n");
|
||||
bool answered = false;
|
||||
// Write command into com file
|
||||
std::ofstream outputFile(MAIN_COM_PATH);
|
||||
if (outputFile.is_open()) {
|
||||
outputFile << "scanfolder \"" << folderPath << "\"";
|
||||
outputFile.close();
|
||||
}
|
||||
else {
|
||||
update_textfield(hWndTextField, "Error: Unable to talk to daemon!\n");
|
||||
return;
|
||||
}
|
||||
while (!answered) {
|
||||
// Wait for answer in file
|
||||
std::ifstream inputFile(ANSWER_COM_PATH);
|
||||
// The structure of the answer file is as follows:
|
||||
// found/not_found
|
||||
// filepath
|
||||
// hash
|
||||
// action_taken/no_action_taken
|
||||
if (inputFile.is_open()) {
|
||||
std::string status, scannedFilePath, hash, action;
|
||||
while (!inputFile.eof()) {
|
||||
if (inputFile >> status) {
|
||||
if (status == "found" || status == "not_found") {
|
||||
inputFile.ignore(1); // Ignore space
|
||||
inputFile.ignore(1); // Ignore starting double quote
|
||||
std::getline(inputFile, scannedFilePath, '\"'); // Read until closing double quote
|
||||
inputFile.ignore(1); // Ignore space between filepath and hash
|
||||
inputFile.ignore(1); // Ignore starting double quote
|
||||
std::getline(inputFile, hash, ' '); // Read until space
|
||||
std::getline(inputFile, action); // Read until end of line
|
||||
|
||||
//answered = true;
|
||||
|
||||
if (status == "found") {
|
||||
update_textfield(hWndTextField, "Virus found in file: " + scannedFilePath + "\r\n");
|
||||
update_textfield(hWndTextField, "File: " + scannedFilePath + " is infected\r\n");
|
||||
update_textfield(hWndTextField, "Hash: " + hash + "\r\n");
|
||||
update_textfield(hWndTextField, "Action taken: " + action + "\r\n");
|
||||
num_of_found++;
|
||||
}
|
||||
else {
|
||||
update_textfield(hWndTextField, "No virus found in file: " + scannedFilePath + "\r\n");
|
||||
}
|
||||
update_textfield(hWndTextField, "------------------------------------------\r\n");
|
||||
}
|
||||
else if (status == "progress") {
|
||||
std::string progress;
|
||||
inputFile.ignore(1); // Ignore space
|
||||
inputFile >> progress;
|
||||
SendMessage(hProgressBar, PBM_SETPOS, atoi(progress.c_str()), 0);
|
||||
}
|
||||
else if (status == "end")
|
||||
answered = true;
|
||||
}
|
||||
}
|
||||
inputFile.close();
|
||||
Sleep(1000);//only see for new entrys ~ once a second
|
||||
std::ofstream(ANSWER_COM_PATH);//clear the file
|
||||
}
|
||||
// Wait for 1 second before checking again
|
||||
std::this_thread::sleep_for(std::chrono::seconds(1));
|
||||
}
|
||||
update_textfield(hWndTextField, "Folder scan completed\r\n");
|
||||
update_textfield(hWndTextField, "Number of infected files: " + std::to_string(num_of_found) + "\r\n");
|
||||
// Remove the answer file
|
||||
std::remove(ANSWER_COM_PATH);
|
||||
}
|
||||
|
||||
|
||||
|
||||
std::string getFolderPath(HWND hWnd) {
|
||||
std::wstring selectedFolderPath;
|
||||
|
||||
// Initialize COM
|
||||
CoInitializeEx(NULL, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE);
|
||||
|
||||
// Display the folder picker dialog
|
||||
BROWSEINFO browseInfo = { 0 };
|
||||
TCHAR selectedPath[MAX_PATH];
|
||||
browseInfo.hwndOwner = hWnd; // Set the owner window
|
||||
browseInfo.pidlRoot = NULL; // Start from the desktop
|
||||
browseInfo.pszDisplayName = selectedPath;
|
||||
browseInfo.lpszTitle = TEXT("Select a folder");
|
||||
browseInfo.ulFlags = BIF_RETURNONLYFSDIRS | BIF_NEWDIALOGSTYLE;
|
||||
|
||||
LPITEMIDLIST pidlSelected = SHBrowseForFolder(&browseInfo);
|
||||
if (pidlSelected != NULL) {
|
||||
SHGetPathFromIDList(pidlSelected, selectedPath);
|
||||
|
||||
// Convert TCHAR array to std::string
|
||||
std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> converter;
|
||||
selectedFolderPath = selectedPath;
|
||||
|
||||
// Free the PIDL
|
||||
IMalloc* pMalloc;
|
||||
if (SUCCEEDED(SHGetMalloc(&pMalloc))) {
|
||||
pMalloc->Free(pidlSelected);
|
||||
pMalloc->Release();
|
||||
}
|
||||
}
|
||||
|
||||
// Uninitialize COM
|
||||
CoUninitialize();
|
||||
|
||||
return std::string(selectedFolderPath.begin(), selectedFolderPath.end());
|
||||
}
|
||||
|
||||
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
|
||||
static HWND hWndTextField;
|
||||
static HWND hProgressBar;
|
||||
static HBRUSH hBackgroundBrush = CreateSolidBrush(RGB(255, 255, 255)); // White color
|
||||
RECT rect;
|
||||
GetClientRect(hWnd, &rect);
|
||||
int width = rect.right - rect.left;
|
||||
int height = rect.bottom - rect.top;
|
||||
switch (message) {
|
||||
case WM_CREATE:
|
||||
{
|
||||
|
||||
// Create the "Scan File" button
|
||||
CreateWindowEx(NULL, L"BUTTON", L"Scan File",
|
||||
WS_TABSTOP | WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON,
|
||||
20, 10, 100, 30, hWnd, (HMENU)IDM_SCAN_FILE, GetModuleHandle(NULL), NULL);
|
||||
|
||||
// Create the "Scan Folder" button
|
||||
CreateWindowEx(NULL, L"BUTTON", L"Scan Folder",
|
||||
WS_TABSTOP | WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON,
|
||||
20, 50, 100, 30, hWnd, (HMENU)IDM_SCAN_FOLDER, GetModuleHandle(NULL), NULL);
|
||||
|
||||
// Create a multi-line edit control for displaying text
|
||||
hWndTextField = CreateWindowEx(WS_EX_CLIENTEDGE, L"EDIT", NULL,
|
||||
WS_CHILD | WS_VISIBLE | WS_VSCROLL | ES_MULTILINE | ES_AUTOVSCROLL | ES_READONLY,
|
||||
140, 10, width-140-20, height-10-50, hWnd, NULL, NULL, NULL);
|
||||
update_textfield(hWndTextField, "Welcome to Cyberhex endpoint protection!\r\n");
|
||||
|
||||
hProgressBar = CreateWindowEx(0, PROGRESS_CLASS, NULL,
|
||||
WS_CHILD | WS_VISIBLE | PBS_SMOOTH,
|
||||
140, height-40, 200, 20, hWnd, NULL, NULL, NULL);
|
||||
SendMessage(hProgressBar, PBM_SETRANGE, 0, MAKELPARAM(0, 100));
|
||||
SendMessage(hProgressBar, PBM_SETSTEP, 1, 0);
|
||||
}
|
||||
break;
|
||||
case WM_SIZE:
|
||||
{
|
||||
// Resize the text field to fit the window
|
||||
MoveWindow(hWndTextField, 140, 10, width - 140 - 20, height - 10 - 50, TRUE);
|
||||
MoveWindow(hProgressBar, 140, height - 40, 200, 20, TRUE);
|
||||
break;
|
||||
}
|
||||
case WM_COMMAND:
|
||||
{
|
||||
int wmId = LOWORD(wParam);
|
||||
// Parse the menu selections:
|
||||
switch (wmId) {
|
||||
case IDM_SCAN_FILE:
|
||||
{
|
||||
// Open file dialog to select a file
|
||||
// Call scan_file function in a separate thread
|
||||
OPENFILENAME ofn;
|
||||
WCHAR szFile[MAX_PATH] = L""; // Use WCHAR for Unicode compatibility
|
||||
|
||||
ZeroMemory(&ofn, sizeof(ofn));
|
||||
ofn.lStructSize = sizeof(ofn);
|
||||
ofn.hwndOwner = hWnd;
|
||||
ofn.lpstrFile = szFile;
|
||||
ofn.lpstrFile[0] = L'\0'; // Use wide character constant L'\0'
|
||||
ofn.nMaxFile = sizeof(szFile);
|
||||
ofn.lpstrFilter = L"All Files\0*.*\0"; // Use wide character string literal L""
|
||||
ofn.nFilterIndex = 1;
|
||||
ofn.lpstrFileTitle = NULL;
|
||||
ofn.lpstrInitialDir = NULL;
|
||||
ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST;
|
||||
|
||||
if (GetOpenFileName(&ofn) == TRUE) {
|
||||
std::wstring selectedFile = ofn.lpstrFile; // Use std::wstring for wide characters
|
||||
std::string narrowSelectedFile(selectedFile.begin(), selectedFile.end());
|
||||
std::thread(scan_file, hWndTextField, narrowSelectedFile).detach();
|
||||
}
|
||||
}
|
||||
break;
|
||||
case IDM_SCAN_FOLDER:
|
||||
{
|
||||
// Open folder picker dialog
|
||||
// Call scan_folder function in a separate thread
|
||||
std::string selectedFolder = getFolderPath(hWnd);
|
||||
std::thread(scan_folder,hProgressBar, hWndTextField, selectedFolder).detach();
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return DefWindowProc(hWnd, message, wParam, lParam);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case WM_PAINT:
|
||||
{
|
||||
PAINTSTRUCT ps;
|
||||
HDC hdc = BeginPaint(hWnd, &ps);
|
||||
RECT rect;
|
||||
GetClientRect(hWnd, &rect);
|
||||
FillRect(hdc, &rect, hBackgroundBrush); // Fill the entire client area with white color
|
||||
EndPaint(hWnd, &ps);
|
||||
}
|
||||
break;
|
||||
case WM_DESTROY:
|
||||
PostQuitMessage(0);
|
||||
break;
|
||||
default:
|
||||
return DefWindowProc(hWnd, message, wParam, lParam);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
|
||||
const wchar_t CLASS_NAME[] = L"Cyberhex endpoint protection frontend";
|
||||
|
||||
WNDCLASS wc = { };
|
||||
|
||||
wc.lpfnWndProc = WndProc;
|
||||
wc.hInstance = hInstance;
|
||||
wc.lpszClassName = CLASS_NAME;
|
||||
|
||||
RegisterClass(&wc);
|
||||
|
||||
HWND hWnd = CreateWindowEx(
|
||||
0,
|
||||
CLASS_NAME,
|
||||
L"Cyberhex endpoint protection",
|
||||
WS_OVERLAPPEDWINDOW,
|
||||
CW_USEDEFAULT,
|
||||
CW_USEDEFAULT,
|
||||
640,
|
||||
480,
|
||||
NULL,
|
||||
NULL,
|
||||
hInstance,
|
||||
NULL
|
||||
);
|
||||
|
||||
|
||||
if (hWnd == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
ShowWindow(hWnd, nCmdShow);
|
||||
UpdateWindow(hWnd);
|
||||
|
||||
MSG msg = { };
|
||||
while (GetMessage(&msg, NULL, 0, 0)) {
|
||||
TranslateMessage(&msg);
|
||||
DispatchMessage(&msg);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user