def write_file(self, report_path): """ Temporary function :param report_path: :todo: fixme :return: """ report_filename: str = "thekadeshi.report." + datetime.strftime( datetime.now(), "%Y.%m.%d.%H.%M") + ".html" report_file: str = os.path.join(report_path, report_filename) report_template = self.load_template() rendered_template = report_template.replace( b'{Result_Json}', bytes(json.dumps(self.report_list), 'utf-8')) rendered_template = rendered_template.replace( b'{Application_Version}', bytes(__version__, 'utf-8')) rendered_template = rendered_template.replace( b'{Result_Total_Files_Size}', bytes(str(self.total_files_size), 'utf-8')) rendered_template = rendered_template.replace( b'{Result_Total_Files_Count}', bytes(str(self.total_files_count), 'utf-8')) rendered_template = rendered_template.replace( b'{Result_Scan_Date}', bytes(datetime.strftime(datetime.now(), "%Y-%m-%d %H:%M"), 'utf-8')) fs = f_system.FileSystem() fs.put_file_content(report_file, bytes(rendered_template))
def test_get_file_content(self): """ Проверка чтения содержимого файла """ if os.path.exists(self.wordpress_folder): file_system = fs.FileSystem() function_result = file_system.get_file_content( os.path.join(self.wordpress_folder, "index.php")) self.assertNotEqual(len(function_result), 0, "Файл не открылся") # Проверка на FileNotFoundError function_result = file_system.get_file_content( os.path.join(self.wordpress_folder, "index2.php")) self.assertEqual(function_result, None, "Открылся, а не должен был")
def export(): """ Exports signatures :return: """ database = dbase.Database() raw_signatures = { 'r': database.get_raw_regexp_signatures(), 'h': database.get_hash_signatures() } json_data = json.dumps(raw_signatures) file_system = f_system.FileSystem() file_system.put_file_content('signatures.json', bytes(json_data, 'utf-8')) print('Export complete')
def load_template(): """ Функция загрузки шаблона отчета :return: """ if getattr(sys, 'frozen', False): current_folder = os.path.dirname(sys.executable) template_path = 'report.html' else: current_folder = os.path.dirname(__file__) template_path = '../files/report.html' fs = f_system.FileSystem() total_path = os.path.join(current_folder, template_path) data = fs.get_file_content(total_path) return data
def scan_files(self): """ Функция сканирования файлов :return: Ничего """ def check_signature_correctness(file_size: int): """ Check signature size correctness :type signature: object :param signature: Signature element :param file_size: File size in bytes :return: :rtype bool """ signature_correctness_flag: bool = True if signature['min_size'] is not None and signature[ 'max_size'] is not None: if signature['min_size'] > file_size > signature['max_size']: signature_correctness_flag = False else: if signature['min_size'] is not None: if file_size < signature['min_size']: signature_correctness_flag = False if signature['max_size'] is not None: if file_size > signature['max_size']: signature_correctness_flag = False return signature_correctness_flag # Таймер timer_start: float = time.time() # Сколько просканировано в байтах, необходимо для вычисления скорости total_scanned: int = 0 # Расчетная скорость сканирования scan_speed: float = 0 # Счетчик проверенных файлов scanner_counter: int = 0 signatures_statistic = {} file_system = f_system.FileSystem() local_hash_signatures = self.signatures_database['h'] local_regex_signatures = self.signatures_database['r'] # Берем файл из списка local_files_list = self.files_list for file_item in local_files_list: anamnesis_element: list = [] current_progress = (total_scanned + file_item['size'] ) * 100 / self.total_files_size is_file_clean: bool = True is_file_error: bool = False # Флаг, нужно ли продолжать сканирование need_to_scan: bool = True content = file_system.get_file_content(file_item['path']) # Если нет ошибок чтения, то сканируем content_length: int = len(content) if content_length == 0: break # Хеш сумма файла file_hash: str = hashlib.sha256(content).hexdigest() # local_signatures = self.signatures_database['h'] for signature in local_hash_signatures: if file_hash == signature['expression']: is_file_clean = False anamnesis_element = { 'id': signature['id'], 'type': 'h', 'path': file_item['path'], 'size': file_item['size'], 'title': signature['title'], 'action': signature['action'] } if signature['action'] == 'delete': need_to_scan = False # Прерываем цикл break if need_to_scan: # Если сканирование по хэш ничего не выявило, то ищем по сигнатурам try: string_content = content.decode('utf-8') except UnicodeDecodeError: string_content = content.decode('latin-1') for signature in local_regex_signatures: is_signature_correct = check_signature_correctness( file_item['size']) if is_signature_correct: signature_time_start = time.time() # print("now shall scan:", signature['id']) matches = re.search(signature['expression'], string_content) signature_time_end = time.time() if self.debug_mode: signatures_time_delta = signature_time_end - signature_time_start if not signature['id'] in signatures_statistic: signatures_statistic[signature['id']] = 0 old_value = signatures_statistic[signature['id']] signatures_statistic[signature['id']] = old_value + \ signatures_time_delta if matches is not None: is_file_clean = False start_position: int = matches.span()[0] end_position: int = matches.span()[1] anamnesis_element = { 'id': signature['id'], 'type': 'r', 'path': file_item['path'], 'size': file_item['size'], 'title': signature['title'], 'action': signature['action'], 'cure': { 'start': start_position, 'end': end_position, 'length': end_position - start_position } } # Прерываем цикл break total_scanned = total_scanned + file_item['size'] current_time = time.time() time_delta = current_time - timer_start if time_delta != 0: scan_speed = total_scanned / time_delta / 1024 scanner_counter = scanner_counter + 1 file_message: str = ''.join(cls.C_GREEN + "Clean" + cls.C_DEFAULT) if self.no_color: file_message = "Clean" if is_file_error: file_message = "Error" else: if not is_file_clean: file_message = cls.C_RED + "Infected" + \ cls.C_DEFAULT + ": " + \ cls.C_L_YELLOW + anamnesis_element['title'] + \ cls.C_DEFAULT if self.no_color: file_message = "Infected: " + anamnesis_element['title'] short_file_path: str = file_item['path'][len(self.site_folder)::] print('[{0:.2f}% | {1:.1f}kB/s] {2!s} ({3!s})'.format( current_progress, scan_speed, short_file_path, file_message, sep=" ", end="", flush=True)) # print(len(anamnesis_element)) anamnesis_length = len(anamnesis_element) if anamnesis_length > 0: self.anamnesis_list.append(anamnesis_element) if self.debug_mode: a1_sorted_keys = sorted(signatures_statistic, key=signatures_statistic.get, reverse=False) for array_element in a1_sorted_keys: print(array_element, signatures_statistic[array_element])
def cure(self): """ Healing function :return: Void """ rpt = report.Report() fs = f_system.FileSystem() for element in self.anamnesis_list: cure_result = { 'signature_id': element['id'], 'path': element['path'], 'size': element['size'], 'action': element['action'], 'title': element['title'], 'type': element['type'], 'result': '', 'result_message': '', 'position': '', 'cure': { 'start': 0, 'end': 0, 'length': 0, 'sample': '' } } # Удаление зараженного файла if self.no_cure: cure_result['result'] = 'disabled' else: if element['action'] == 'delete': try: os.remove(element['path']) cure_result['result'] = 'ok' except PermissionError as e: cure_result['result'] = 'false' cure_result['result_message'] = e if 'cure' in element and 'length' in element['cure']: cure_result['cure']['length'] = element['cure'][ 'length'] # Лечение зараженного файла elif element['action'] == 'cure': file_content = fs.get_file_content(element['path']) cure_result['result'] = 'cure' slice_start: int = element['cure']['start'] slice_end: int = element['cure']['end'] first_part: bytes = file_content[:slice_start] second_part: bytes = file_content[slice_end:] # Sample code start position sample_start: int = 0 if slice_start > 30: sample_start = slice_start - 30 cure_result['cure']['start'] = slice_start cure_result['cure']['end'] = slice_end cure_result['cure']['length'] = slice_end - slice_start sample_slice = file_content[sample_start:slice_start + 120] cure_result['cure']['sample'] = str( base64.b64encode(sample_slice), 'ascii') result = fs.put_file_content(element['path'], first_part + second_part) cure_result['result'] = 'false' if result: cure_result['result'] = 'ok' else: # element['action'] == 'quarantine': try: os.rename(element['path'], element['path'] + '.suspected') except PermissionError as e: cure_result['result'] = 'false' cure_result['result_message'] = e rpt.append(cure_result) self.write_statistic(cure_result) # dbase.Database.write_statistic(cure_result) rpt.total_files_size = self.total_files_size rpt.total_files_count = len(self.files_list) if not self.no_report: rpt.write_file(self.site_folder) rpt.output()