Merge branch 'main' of https://github.com/jakani24/ma
This commit is contained in:
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1,244 +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;
|
|
||||||
unsigned 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
|
|
||||||
fileHandles[filename] = hFile;
|
|
||||||
mappingHandles[filename] = hMapping;
|
|
||||||
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
|
|
||||||
fileHandles.clear();
|
|
||||||
mappingHandles.clear();
|
|
||||||
fileData.clear();
|
|
||||||
}
|
|
||||||
std::mutex searchMutex;
|
|
||||||
int search_hash(const std::string& dbname_, const std::string& hash_, const std::string& filepath_) {
|
|
||||||
std::string dbname(dbname_);
|
|
||||||
std::string hash(hash_);
|
|
||||||
std::string 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
DWORD fileSize;
|
|
||||||
std::string fileContent;
|
|
||||||
|
|
||||||
{
|
|
||||||
// Retrieve file size and content
|
|
||||||
fileSize = GetFileSize(fileHandles[dbname], NULL);
|
|
||||||
fileContent = fileData[dbname];
|
|
||||||
} // Release the lock immediately after retrieving the required data
|
|
||||||
|
|
||||||
// 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
|
|
||||||
while (num_threads >= std::thread::hardware_concurrency()) {
|
|
||||||
Sleep(10);
|
|
||||||
}
|
|
||||||
//log(LOGLEVEL::INFO_NOSEND, "[scan_folder()]: Scanning file: ", full_path, "threads: ",num_threads);
|
|
||||||
std::thread scan_thread(scan_file_t, full_path);
|
|
||||||
scan_thread.detach();
|
|
||||||
//Sleep(1);
|
|
||||||
|
|
||||||
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();
|
|
||||||
delete[] db_path;
|
|
||||||
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_) {
|
|
||||||
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,241 +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;
|
|
||||||
unsigned 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
|
|
||||||
fileHandles[filename] = hFile;
|
|
||||||
mappingHandles[filename] = hMapping;
|
|
||||||
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
|
|
||||||
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() and dbname_.find("c:.jdbf") == std::string::npos) {
|
|
||||||
log(LOGLEVEL::ERR, "[search_hash()]: File mapping not initialized for ", dbname);
|
|
||||||
return 2;
|
|
||||||
}
|
|
||||||
else if (fileIter == fileHandles.end()) {
|
|
||||||
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::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
|
|
||||||
while (num_threads >= std::thread::hardware_concurrency()) {
|
|
||||||
Sleep(10);
|
|
||||||
}
|
|
||||||
//log(LOGLEVEL::INFO_NOSEND, "[scan_folder()]: Scanning file: ", full_path, "threads: ",num_threads);
|
|
||||||
std::thread scan_thread(scan_file_t, full_path);
|
|
||||||
scan_thread.detach();
|
|
||||||
//Sleep(1);
|
|
||||||
|
|
||||||
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();
|
|
||||||
delete[] db_path;
|
|
||||||
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_) {
|
|
||||||
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,299 +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
|
|
||||||
|
|
||||||
// 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 cnt = 0;
|
|
||||||
while (num_threads >= std::thread::hardware_concurrency()) {
|
|
||||||
Sleep(10);
|
|
||||||
cnt++;
|
|
||||||
if(cnt==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;
|
|
||||||
}
|
|
||||||
//log(LOGLEVEL::INFO_NOSEND, "[scan_folder()]: Scanning file: ", full_path, "threads: ",num_threads);
|
|
||||||
std::thread scan_thread(scan_file_t, full_path);
|
|
||||||
scan_thread.detach();
|
|
||||||
//Sleep(1);
|
|
||||||
|
|
||||||
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: %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,145 +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"
|
|
||||||
#include "utils.h"
|
|
||||||
#include "deepscan.h"
|
|
||||||
int main(int argc, char* argv[]) {
|
|
||||||
|
|
||||||
//log(LOGLEVEL::INFO, "[main()]:Starting main thread.");
|
|
||||||
//return 0;
|
|
||||||
//runner();
|
|
||||||
//printf("done\n");
|
|
||||||
|
|
||||||
|
|
||||||
log(LOGLEVEL::INFO_NOSEND, "[main()]:Starting main thread.");
|
|
||||||
int err = 0;
|
|
||||||
printf("welcome to the jakach security tool main thread\n");
|
|
||||||
//exit(0);
|
|
||||||
if (load_settings() == 0) {//load the settings from the settings file
|
|
||||||
if (argc != 2) {
|
|
||||||
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!");
|
|
||||||
Sleep(1000); //wait for the log to be written
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
//do self check
|
|
||||||
if ((err = selfcheck()) != 0) {
|
|
||||||
log(LOGLEVEL::PANIC, "[main()]:This installation of cyberhex failed the self check! Application may be tampered with!", err);
|
|
||||||
log(LOGLEVEL::PANIC, "[main()]:Panic, self check failed, terminating process!");
|
|
||||||
Sleep(1000); //wait for the log to be written and swnt to the server
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
//printf("self check passed\n");
|
|
||||||
//update_db2(DB_DIR);
|
|
||||||
//printf("db update finished\n");
|
|
||||||
|
|
||||||
|
|
||||||
//init debug mode if needed
|
|
||||||
if (argc == 2) {
|
|
||||||
if (strcmp(argv[1], "-d") == 0) {
|
|
||||||
debug_mode_init();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//initialize the deep scan database
|
|
||||||
yr_initialize();
|
|
||||||
|
|
||||||
//
|
|
||||||
// Main thread loop
|
|
||||||
while (!app_stop()) {
|
|
||||||
auto start = std::chrono::high_resolution_clock::now();
|
|
||||||
|
|
||||||
// Check for tasks from user interface
|
|
||||||
//printf("checking for tasks from user interface\n");
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
//printf("checking for tasks from sched interface\n");
|
|
||||||
// Check for scheduled tasks
|
|
||||||
if (check_for_sched_tasks(SCHED, SCHED_PATH) != 0) {
|
|
||||||
log(LOGLEVEL::ERR, "[main()]:Error opening schedule file in: ", SCHED_PATH);
|
|
||||||
}
|
|
||||||
//printf("checking for tasks from run interface\n");
|
|
||||||
// Execute tasks from the queue
|
|
||||||
if (can_run_thread()) {
|
|
||||||
int queue_size = get_queue_size();
|
|
||||||
for (int i = 0; i < queue_size; i++) {
|
|
||||||
start_thread(queue_pop());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// 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,148 +0,0 @@
|
|||||||
/*
|
|
||||||
This file is the main file for the client backend. It is responsible for starting the main thread and initializing all the other threads and functions. It also contains the main loop for the main thread which checks for tasks from the user interface, scheduled tasks, and tasks from the queue. It also initializes the hash databases, the yara rules, and the real-time protection threads. The main thread will run until the app_stop() function returns true, which is set by the user interface when the user wants to stop the application.
|
|
||||||
|
|
||||||
Functions:
|
|
||||||
- main(): The main function of the client backend. It initializes the hash databases, yara rules, and real-time protection threads. It then enters a loop where it checks for tasks from the user interface, scheduled tasks, and tasks from the queue. It will run until the app_stop() function returns true.
|
|
||||||
*/
|
|
||||||
|
|
||||||
#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"
|
|
||||||
#include "utils.h"
|
|
||||||
#include "deepscan.h"
|
|
||||||
int main(int argc, char* argv[]) {
|
|
||||||
;
|
|
||||||
log(LOGLEVEL::INFO_NOSEND, "[main()]:Starting main thread.");
|
|
||||||
int err = 0;
|
|
||||||
printf("welcome to the jakach security tool main thread\n");
|
|
||||||
//exit(0);
|
|
||||||
if (load_settings() == 0) {//load the settings from the settings file
|
|
||||||
if (argc != 2) {
|
|
||||||
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 included paths database for the real time proccess scanner from the server
|
|
||||||
log(LOGLEVEL::ERR_NOSEND, "[main()]:Could not update settings (rtp_included) from server.");
|
|
||||||
}
|
|
||||||
if (update_settings("rtp_excluded") != 0) {//update the excluded paths database for the real time proccess scanner from the server
|
|
||||||
log(LOGLEVEL::ERR_NOSEND, "[main()]:Could not update settings (rtp_excluded) from server.");
|
|
||||||
}
|
|
||||||
if (update_settings("sched") != 0) { //update the settings for the scheduler from the server
|
|
||||||
log(LOGLEVEL::ERR_NOSEND, "[main()]:Could not update settings (scheduled_tasks) from server.");
|
|
||||||
}
|
|
||||||
if (update_settings("disallowed_start") != 0) { //update the settings for applicaiton control from the server
|
|
||||||
log(LOGLEVEL::ERR_NOSEND, "[main()]:Could not update settings (disallowed_start) 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!");
|
|
||||||
Sleep(1000); //wait for the log to be written
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
//do self check
|
|
||||||
if ((err = selfcheck()) != 0) {
|
|
||||||
log(LOGLEVEL::PANIC, "[main()]:This installation of cyberhex failed the self check! Application may be tampered with!", err);
|
|
||||||
log(LOGLEVEL::PANIC, "[main()]:Panic, self check failed, terminating process!");
|
|
||||||
Sleep(1000); //wait for the log to be written and swnt to the server
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//init debug mode if needed
|
|
||||||
if (argc == 2) {
|
|
||||||
if (strcmp(argv[1], "--debug") == 0) {
|
|
||||||
debug_mode_init();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Initialize hash databases
|
|
||||||
err = initialize(DB_DIR);
|
|
||||||
log(LOGLEVEL::INFO_NOSEND, "[main()]:Hash databases initialized.");
|
|
||||||
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();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//initialize the deep scan database
|
|
||||||
yr_initialize();
|
|
||||||
init_yara_rules(YARA_DB_DIR);
|
|
||||||
log(LOGLEVEL::INFO_NOSEND, "[main()]:Yara rules initialized.");
|
|
||||||
|
|
||||||
// Main thread loop
|
|
||||||
while (!app_stop()) {
|
|
||||||
auto start = std::chrono::high_resolution_clock::now();
|
|
||||||
|
|
||||||
// Check for tasks from user interface
|
|
||||||
//printf("checking for tasks from user interface\n");
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
//printf("checking for tasks from sched interface\n");
|
|
||||||
// Check for scheduled tasks
|
|
||||||
if (check_for_sched_tasks(SCHED, SCHED_PATH) != 0) {
|
|
||||||
log(LOGLEVEL::ERR, "[main()]:Error opening schedule file in: ", SCHED_PATH);
|
|
||||||
}
|
|
||||||
//printf("checking for tasks from run interface\n");
|
|
||||||
// Execute tasks from the queue
|
|
||||||
if (can_run_thread()) {
|
|
||||||
int queue_size = get_queue_size();
|
|
||||||
for (int i = 0; i < queue_size; i++) {
|
|
||||||
start_thread(queue_pop());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// 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());
|
|
||||||
}
|
|
||||||
yr_finalize();
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
@@ -1,103 +0,0 @@
|
|||||||
#include "utils.h"
|
|
||||||
#include <windows.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <iostream>
|
|
||||||
#include "log.h"
|
|
||||||
#include <tlhelp32.h>
|
|
||||||
#include <regex>
|
|
||||||
#include <filesystem>
|
|
||||||
|
|
||||||
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) {
|
|
||||||
// Regular expression to match Windows path name criteria and illegal characters
|
|
||||||
std::regex pattern(R"(^(?:[a-zA-Z]:)?(?:\\[^<>:"/\\|?*]*)*$)");
|
|
||||||
|
|
||||||
// Check if the path matches the pattern
|
|
||||||
return std::regex_match(path, 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,150 +0,0 @@
|
|||||||
#include "utils.h"
|
|
||||||
#include <windows.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <iostream>
|
|
||||||
#include "log.h"
|
|
||||||
#include <tlhelp32.h>
|
|
||||||
#include <winternl.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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!std::filesystem::exists(filename)) {
|
|
||||||
return 0; // File does not exist
|
|
||||||
}
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
int get_num_running_threads() {
|
|
||||||
DWORD runningThreads = 0;
|
|
||||||
HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);
|
|
||||||
|
|
||||||
if (hSnapshot != INVALID_HANDLE_VALUE) {
|
|
||||||
THREADENTRY32 te;
|
|
||||||
te.dwSize = sizeof(THREADENTRY32);
|
|
||||||
|
|
||||||
if (Thread32First(hSnapshot, &te)) {
|
|
||||||
do {
|
|
||||||
if (te.dwSize >= FIELD_OFFSET(THREADENTRY32, th32OwnerProcessID) +
|
|
||||||
sizeof(te.th32OwnerProcessID)) {
|
|
||||||
if (te.th32OwnerProcessID == GetCurrentProcessId()) {
|
|
||||||
runningThreads++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
te.dwSize = sizeof(THREADENTRY32);
|
|
||||||
} while (Thread32Next(hSnapshot, &te));
|
|
||||||
}
|
|
||||||
|
|
||||||
CloseHandle(hSnapshot);
|
|
||||||
}
|
|
||||||
|
|
||||||
return runningThreads;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
Reference in New Issue
Block a user