commit 9334a46f24d2d38b8bbbbc289f45a2bd33966772 Author: root Date: Fri Apr 5 16:22:03 2019 +0800 update diff --git a/README.md b/README.md new file mode 100644 index 0000000..404b871 --- /dev/null +++ b/README.md @@ -0,0 +1,32 @@ +### 工具介绍 +绿盟远程安全评估系统漏洞数据导出工具,只支持RSAS6.0以上版本。 + +写这个工具的时候刚开始接触Python,采用的是先读取HTML内容写入到临时文件,再用正则从临时文件匹配。 + +后来发现了xpath这个新大陆,本打算重新写一下,想了想,能用就行了。 + +工具涉及:读取目录下的文件、ZIP文件读取、正则表达式、Excel表格写入、文件读写、PyQt5、TKinter(舍弃) + +### 功能 + +- [x] 自定义漏洞等级 +- [x] 自定义导出数据 +- [x] 自定义Excel模板 +- [x] 支持导出的数据:主机名、IP地址、端口、协议、服务、漏洞名称、风险等级、整改建议、漏洞描述、漏洞CVE编号、扫描起始时间、扫描结束时间、漏洞扫描月份 +- [x] 导出不同端口的同一个漏洞,也就是一个端口对应一个漏洞,保证导出漏洞的完整性。 +- [x] 导出端口和导出网站为单独的功能,导出网站的功能是采用正则去匹配http、www这两个服务。 + +### 须知 +- [x] 当一个漏洞存在两个或者两个以上CVE编号,则只取第一个CVE漏洞编号。 +- [x] 当一个漏洞不存在CVE编号时,则替换为 漏洞暂无CVE编号 。 +- [x] 当一个漏洞整改建议为空时(个别低危漏洞),导出留空。 + +### 下载 +下载链接是Windows版本的,如果需要在其他平台使用,可下载源码自己打包。 +链接: https://pan.baidu.com/s/1JyyNJGiK_ZEc7JUGm4Ap_Q 提取码: 5pxt + +### 使用方法 + +导出的原始报告必须勾选主机报表才行,程序是直接读取zip的,不能解压,把原始报告放到一个文件夹内,路径选择对应的文件夹就可以了。 + +![](https://webing.io/do/images/rsas_1.8.gif) diff --git a/favicon.ico b/favicon.ico new file mode 100644 index 0000000..c963673 Binary files /dev/null and b/favicon.ico differ diff --git a/gui/mainwindow.py b/gui/mainwindow.py new file mode 100644 index 0000000..52f3c4a --- /dev/null +++ b/gui/mainwindow.py @@ -0,0 +1,70 @@ +import os +import re +from PyQt5 import QtGui, QtWidgets +from gui.ui_mainwindow import * +from .threads import WorkThread + +class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow): + + def __init__(self, parent=None): + super(MainWindow, self).__init__(parent) + self.setupUi(self) + self.input_Button.clicked.connect(self.input_Button_click) + self.output_Button.clicked.connect(self.output_Button_click) + self.start_Button.clicked.connect(self.start_Button_click) + + def input_Button_click(self): + self.input_Button_cent = QtWidgets.QFileDialog.getExistingDirectory(None) + self.input_lineEdit.setText(self.input_Button_cent) + + def output_Button_click(self): + self.output_Button_cent = QtWidgets.QFileDialog.getExistingDirectory(None) + self.output_lineEdit.setText(self.output_Button_cent) + + def start_Button_click(self): + if self.input_lineEdit.text(): + self.input_Button_cent = self.input_lineEdit.text() + else: + try: + self.input_Button_cent = self.input_Button_cent + except Exception as e: + QtWidgets.QMessageBox.information(None, "提示!", "要先设置文件夹!", QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No , QtWidgets.QMessageBox.Yes ) + return e + + if self.output_lineEdit.text(): + self.output_Button_cent = self.output_lineEdit.text() + else: + try: + self.output_Button_cent = self.output_Button_cent + except Exception as e: + QtWidgets.QMessageBox.information(None, "提示!", "要先设置文件夹!", QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No , QtWidgets.QMessageBox.Yes ) + return e + + self.dirList = os.listdir(self.input_Button_cent) + self.file_name_box = re.findall('.*?.zip',str(self.dirList)) + try: + self.file_name_box[0] + except Exception as e: + QtWidgets.QMessageBox.information(None, "提示", "找不到原始报告,请查看使用说明!", QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No , QtWidgets.QMessageBox.Yes ) + return e + + self.hight_status = self.hight_checkBox.isChecked() + self.middle_status = self.middle_checkBox.isChecked() + self.low_status = self.low_checkBox.isChecked() + self.port_status = self.port_checkBox.isChecked() + self.web_status = self.web_checkBox.isChecked() + + self.start_Button.setChecked(True) + self.start_Button.setDisabled(True) + self.work = WorkThread(self.input_Button_cent,self.output_Button_cent,self.hight_status,self.middle_status,self.low_status,self.port_status,self.web_status) + self.work.log_return.connect(self.logger) + self.work.start() + + def logger(self, msg): + str_log='{}\n'.format(msg) + self.log_textEdit.moveCursor(QtGui.QTextCursor.End) + self.log_textEdit.insertPlainText(str_log) + QtWidgets.QApplication.processEvents() + if self.work.isRunning() == False: + self.start_Button.setChecked(False) + self.start_Button.setDisabled(False) \ No newline at end of file diff --git a/gui/threads.py b/gui/threads.py new file mode 100644 index 0000000..7c57df1 --- /dev/null +++ b/gui/threads.py @@ -0,0 +1,496 @@ +import os +import re +import sys +import html +import queue +import shutil +import zipfile +import datetime +import openpyxl +from PyQt5 import QtWidgets +from PyQt5.QtCore import QThread, pyqtSignal +from openpyxl.styles import PatternFill, Font, Alignment, Border, Side + +class Vul_re(object): + def __init__(self): + super(Vul_re, self).__init__() + self.vul_list_re = 'ip.*?host.*?IP地址.*?(.*?).*?(\d+-\d+-\d+\s\d+:\d+:\d+).*?.*?(\d+-\d+-\d+\s\d+:\d+:\d+).*?.*?host.*?vul_list(.*?)vul_list.*?ip' + self.vul_ip_re = '(ip.*?ip)' + self.vul_detail_re = 'vul_detail(.*?)vul_detail' + self.vul_details_re = 'vul_details(.*?)vul_details' + + self.danger_re = '(.*?)' + self.title_re = 'title(.*?)title' + self.time_re = 'host.*?(\d+-\d+-\d+).*?host' + self.scan_time_re = 'host.*?(\d+-\d+-\d+\s\d+:\d+:\d+).*?host' + self.other_re = '(.*?).*?(.*?).*?(.*?).*?.*?
    (.*?)
' + self.host_name = 'host.*?主机名.*?(.*?).*?.*?host' + +class File_re(object): + def __init__(self): + super(File_re, self).__init__() + self.file_re = '.*?.zip' + self.uzip_re = '.*?.html' + self.all_title_re = '任务名称.*?(.*?)' + self.vul_list_re = '(.*?
)' + self.vul_detail_re = '(
.*?
)' + self.vul_details_re = '(.*?.*?.*?
.*?.*?)' + self.host_re = '(.*?.*?.*?.*?.*?
IP地址
)' + +class Vul_content(object): + def __init__(self,vul_re): + super(Vul_content, self).__init__() + self.vul_ip_content = re.findall(vul_re.vul_ip_re,htmlcont,re.S|re.M) + self.vul_detail_content = re.findall(vul_re.vul_detail_re,htmlcont,re.S|re.M) + +class Solve_re(object): + def __init__(self): + super(Solve_re, self).__init__() + self.solve_re = '解决办法.*?(.*?)' + self.describe_re = '详细描述.*?(.*?)' + self.cve_re = 'CVE编号.*?(.*?).*?' + +class Other(object): + def __init__(self, vul_re, all_vuln_list): + super(Other, self).__init__() + self.all_other = re.findall(vul_re.other_re,all_vuln_list,re.S|re.M) + +class Danger(object): + def __init__(self, vul_re, other): + super(Danger, self).__init__() + self.danger_coneent = re.findall(vul_re.danger_re,other,re.S|re.M) + +class Solve(object): + def __init__(self, solve, all_vul_details): + super(Solve, self).__init__() + self.solve_plumb = re.findall(solve.solve_re,all_vul_details,re.S|re.M) + self.describe_plumb = re.findall(solve.describe_re,all_vul_details,re.S|re.M) + self.cve_plumb = re.findall(solve.cve_re,all_vul_details,re.S|re.M) + +class Port_File_re(object): + def __init__(self): + super(Port_File_re, self).__init__() + self.file_re = '.*?.zip' + self.uzip_re = '.*?.html' + self.all_title_re = '任务名称.*?(.*?)' + self.host_re = 'IP地址.*?(\d+.\d+.\d+.\d+).*?扫描起始时间.*?(\d+-\d+-\d+).*?.*?.*?端口.*?协议.*?服务.*?状态.*?.*?(.*?)' + self.port_re = ' 0: + for set_vuls in set_vul: + if set_vuls[1] == danger[2]: + vul_name = set_vuls[0] + break + vul_all_list.append([danger[1],all_vul_list[0],danger[2].strip(),vul_name.replace('low','低').replace('middle','中').replace('high','高'),other[0],other[1],other[2],all_vul_list[1],all_vul_list[2],host_name[0]]) + + for all_vul_detail in vul_content.vul_detail_content: + vul_details_content = re.findall(vul_re.vul_details_re,all_vul_detail,re.S|re.M) + for all_vul_details in vul_details_content: + vul_detail = Solve(Solve_re(),all_vul_details) + for solve,describe in zip(vul_detail.solve_plumb,vul_detail.describe_plumb): + cve = vul_detail.cve_plumb + if cve: + pass + else: + cve = ['漏洞暂无CVE编号'] + vul_all_detail[describe[0]] = re.sub('\s{2,}','\n',html.unescape(re.sub('\s{2,}','',solve)).replace('
','\n')),re.sub('\s{2,}','\n',html.unescape(re.sub('\s{2,}','',describe[1])).replace('
','\n')),cve[0] + + + vul_amount = [] + + for wait_list in vul_all_list: + wait_detail = vul_all_detail[wait_list[0]] + vul_amount.append(['',self.company_ini,sheet_name,wait_list[9],wait_list[1],wait_list[4],wait_list[5],wait_list[6],wait_list[2],'漏洞',wait_list[3],wait_detail[0].strip(),wait_detail[1],wait_detail[2],wait_list[7],wait_list[8],vul_time]) + + for amount in vul_amount: + if self.hight_status == True and amount[10] == '高': + ws.row_dimensions[i+1].height = 25 + ws.append([i,amount[int(excel['B'][0]) if 'B' in excel else 0],amount[int(excel['C'][0]) if 'C' in excel else 0],amount[int(excel['D'][0]) if 'D' in excel else 0],amount[int(excel['E'][0]) if 'E' in excel else 0],amount[int(excel['F'][0]) if 'F' in excel else 0],amount[int(excel['G'][0]) if 'G' in excel else 0],amount[int(excel['H'][0]) if 'H' in excel else 0],amount[int(excel['I'][0]) if 'I' in excel else 0],amount[int(excel['J'][0]) if 'J' in excel else 0],amount[int(excel['K'][0]) if 'K' in excel else 0],amount[int(excel['L'][0]) if 'L' in excel else 0],amount[int(excel['M'][0]) if 'M' in excel else 0],amount[int(excel['N'][0]) if 'N' in excel else 0],amount[int(excel['O'][0]) if 'O' in excel else 0],amount[int(excel['P'][0]) if 'P' in excel else 0],amount[int(excel['Q'][0]) if 'Q' in excel else 0],amount[int(excel['R'][0]) if 'R' in excel else 0],amount[int(excel['S'][0]) if 'S' in excel else 0],amount[int(excel['T'][0]) if 'T' in excel else 0],amount[int(excel['U'][0]) if 'U' in excel else 0],amount[int(excel['V'][0]) if 'V' in excel else 0],amount[int(excel['W'][0]) if 'W' in excel else 0],amount[int(excel['X'][0]) if 'X' in excel else 0],amount[int(excel['Y'][0]) if 'Y' in excel else 0],amount[int(excel['Z'][0]) if 'Z' in excel else 0],amount[int(excel['AA'][0]) if 'AA' in excel else 0],amount[int(excel['AB'][0]) if 'AB' in excel else 0],amount[int(excel['AC'][0]) if 'AC' in excel else 0],amount[int(excel['AD'][0]) if 'AD' in excel else 0],amount[int(excel['AE'][0]) if 'AE' in excel else 0],amount[int(excel['AF'][0]) if 'AF' in excel else 0],amount[int(excel['AG'][0]) if 'AG' in excel else 0],amount[int(excel['AH'][0]) if 'AH' in excel else 0],amount[int(excel['AI'][0]) if 'AI' in excel else 0],amount[int(excel['AJ'][0]) if 'AJ' in excel else 0],amount[int(excel['AK'][0]) if 'AK' in excel else 0],amount[int(excel['AL'][0]) if 'AL' in excel else 0],amount[int(excel['AM'][0]) if 'AM' in excel else 0],amount[int(excel['AN'][0]) if 'AN' in excel else 0],amount[int(excel['AO'][0]) if 'AO' in excel else 0],amount[int(excel['AP'][0]) if 'AP' in excel else 0],amount[int(excel['AQ'][0]) if 'AQ' in excel else 0],amount[int(excel['AR'][0]) if 'AR' in excel else 0],amount[int(excel['AS'][0]) if 'AS' in excel else 0],amount[int(excel['AT'][0]) if 'AT' in excel else 0],amount[int(excel['AU'][0]) if 'AU' in excel else 0],amount[int(excel['AV'][0]) if 'AV' in excel else 0],amount[int(excel['AW'][0]) if 'AW' in excel else 0],amount[int(excel['AX'][0]) if 'AX' in excel else 0],amount[int(excel['AY'][0]) if 'AY' in excel else 0],amount[int(excel['AZ'][0]) if 'AZ' in excel else 0]]) + i += 1 + + if self.middle_status == True and amount[10] == '中': + ws.row_dimensions[i+1].height = 25 + ws.append([i,amount[int(excel['B'][0]) if 'B' in excel else 0],amount[int(excel['C'][0]) if 'C' in excel else 0],amount[int(excel['D'][0]) if 'D' in excel else 0],amount[int(excel['E'][0]) if 'E' in excel else 0],amount[int(excel['F'][0]) if 'F' in excel else 0],amount[int(excel['G'][0]) if 'G' in excel else 0],amount[int(excel['H'][0]) if 'H' in excel else 0],amount[int(excel['I'][0]) if 'I' in excel else 0],amount[int(excel['J'][0]) if 'J' in excel else 0],amount[int(excel['K'][0]) if 'K' in excel else 0],amount[int(excel['L'][0]) if 'L' in excel else 0],amount[int(excel['M'][0]) if 'M' in excel else 0],amount[int(excel['N'][0]) if 'N' in excel else 0],amount[int(excel['O'][0]) if 'O' in excel else 0],amount[int(excel['P'][0]) if 'P' in excel else 0],amount[int(excel['Q'][0]) if 'Q' in excel else 0],amount[int(excel['R'][0]) if 'R' in excel else 0],amount[int(excel['S'][0]) if 'S' in excel else 0],amount[int(excel['T'][0]) if 'T' in excel else 0],amount[int(excel['U'][0]) if 'U' in excel else 0],amount[int(excel['V'][0]) if 'V' in excel else 0],amount[int(excel['W'][0]) if 'W' in excel else 0],amount[int(excel['X'][0]) if 'X' in excel else 0],amount[int(excel['Y'][0]) if 'Y' in excel else 0],amount[int(excel['Z'][0]) if 'Z' in excel else 0],amount[int(excel['AA'][0]) if 'AA' in excel else 0],amount[int(excel['AB'][0]) if 'AB' in excel else 0],amount[int(excel['AC'][0]) if 'AC' in excel else 0],amount[int(excel['AD'][0]) if 'AD' in excel else 0],amount[int(excel['AE'][0]) if 'AE' in excel else 0],amount[int(excel['AF'][0]) if 'AF' in excel else 0],amount[int(excel['AG'][0]) if 'AG' in excel else 0],amount[int(excel['AH'][0]) if 'AH' in excel else 0],amount[int(excel['AI'][0]) if 'AI' in excel else 0],amount[int(excel['AJ'][0]) if 'AJ' in excel else 0],amount[int(excel['AK'][0]) if 'AK' in excel else 0],amount[int(excel['AL'][0]) if 'AL' in excel else 0],amount[int(excel['AM'][0]) if 'AM' in excel else 0],amount[int(excel['AN'][0]) if 'AN' in excel else 0],amount[int(excel['AO'][0]) if 'AO' in excel else 0],amount[int(excel['AP'][0]) if 'AP' in excel else 0],amount[int(excel['AQ'][0]) if 'AQ' in excel else 0],amount[int(excel['AR'][0]) if 'AR' in excel else 0],amount[int(excel['AS'][0]) if 'AS' in excel else 0],amount[int(excel['AT'][0]) if 'AT' in excel else 0],amount[int(excel['AU'][0]) if 'AU' in excel else 0],amount[int(excel['AV'][0]) if 'AV' in excel else 0],amount[int(excel['AW'][0]) if 'AW' in excel else 0],amount[int(excel['AX'][0]) if 'AX' in excel else 0],amount[int(excel['AY'][0]) if 'AY' in excel else 0],amount[int(excel['AZ'][0]) if 'AZ' in excel else 0]]) + i += 1 + + if self.low_status == True and amount[10] == '低': + ws.row_dimensions[i+1].height = 25 + ws.append([i,amount[int(excel['B'][0]) if 'B' in excel else 0],amount[int(excel['C'][0]) if 'C' in excel else 0],amount[int(excel['D'][0]) if 'D' in excel else 0],amount[int(excel['E'][0]) if 'E' in excel else 0],amount[int(excel['F'][0]) if 'F' in excel else 0],amount[int(excel['G'][0]) if 'G' in excel else 0],amount[int(excel['H'][0]) if 'H' in excel else 0],amount[int(excel['I'][0]) if 'I' in excel else 0],amount[int(excel['J'][0]) if 'J' in excel else 0],amount[int(excel['K'][0]) if 'K' in excel else 0],amount[int(excel['L'][0]) if 'L' in excel else 0],amount[int(excel['M'][0]) if 'M' in excel else 0],amount[int(excel['N'][0]) if 'N' in excel else 0],amount[int(excel['O'][0]) if 'O' in excel else 0],amount[int(excel['P'][0]) if 'P' in excel else 0],amount[int(excel['Q'][0]) if 'Q' in excel else 0],amount[int(excel['R'][0]) if 'R' in excel else 0],amount[int(excel['S'][0]) if 'S' in excel else 0],amount[int(excel['T'][0]) if 'T' in excel else 0],amount[int(excel['U'][0]) if 'U' in excel else 0],amount[int(excel['V'][0]) if 'V' in excel else 0],amount[int(excel['W'][0]) if 'W' in excel else 0],amount[int(excel['X'][0]) if 'X' in excel else 0],amount[int(excel['Y'][0]) if 'Y' in excel else 0],amount[int(excel['Z'][0]) if 'Z' in excel else 0],amount[int(excel['AA'][0]) if 'AA' in excel else 0],amount[int(excel['AB'][0]) if 'AB' in excel else 0],amount[int(excel['AC'][0]) if 'AC' in excel else 0],amount[int(excel['AD'][0]) if 'AD' in excel else 0],amount[int(excel['AE'][0]) if 'AE' in excel else 0],amount[int(excel['AF'][0]) if 'AF' in excel else 0],amount[int(excel['AG'][0]) if 'AG' in excel else 0],amount[int(excel['AH'][0]) if 'AH' in excel else 0],amount[int(excel['AI'][0]) if 'AI' in excel else 0],amount[int(excel['AJ'][0]) if 'AJ' in excel else 0],amount[int(excel['AK'][0]) if 'AK' in excel else 0],amount[int(excel['AL'][0]) if 'AL' in excel else 0],amount[int(excel['AM'][0]) if 'AM' in excel else 0],amount[int(excel['AN'][0]) if 'AN' in excel else 0],amount[int(excel['AO'][0]) if 'AO' in excel else 0],amount[int(excel['AP'][0]) if 'AP' in excel else 0],amount[int(excel['AQ'][0]) if 'AQ' in excel else 0],amount[int(excel['AR'][0]) if 'AR' in excel else 0],amount[int(excel['AS'][0]) if 'AS' in excel else 0],amount[int(excel['AT'][0]) if 'AT' in excel else 0],amount[int(excel['AU'][0]) if 'AU' in excel else 0],amount[int(excel['AV'][0]) if 'AV' in excel else 0],amount[int(excel['AW'][0]) if 'AW' in excel else 0],amount[int(excel['AX'][0]) if 'AX' in excel else 0],amount[int(excel['AY'][0]) if 'AY' in excel else 0],amount[int(excel['AZ'][0]) if 'AZ' in excel else 0]]) + i += 1 + for row in ws['A2:{}{}'.format(letter[len(excel)-1],i)]: + for cell in row: + cell.font = font + cell.border = border + cell.alignment = alignment + + ws.delete_cols(len_excel,len(letter)) + wb.save(self.folder_end+'/汇总-漏洞跟踪表/高中风险漏洞跟踪表--汇总.xlsx') + del vul_all_list[:] + vul_all_detail.clear() + + self.log_return.emit('漏洞跟踪表导出完成,保存在输出路径 汇总-漏洞跟踪表 目录下。') + shutil.rmtree('temp') + endtime = datetime.datetime.now() + self.log_return.emit('导出花时:{}秒...\n'.format((endtime - starttime).seconds)) + + if self.port_status: + try: + shutil.rmtree(self.folder_end+'/汇总-端口对应关系表') + except Exception as e: + pass + self.log_return.emit('正在导出端口,请稍后!') + starttime = datetime.datetime.now() + os.mkdir(self.folder_end+'/汇总-端口对应关系表') + dirList = os.listdir(self.folder_start) + for name in dirList: + all_file_name = re.findall(Port_File_re().file_re,name) + for file_name in all_file_name: + uzip = zipfile.ZipFile(self.folder_start+'/'+file_name) + i = 1 + wb = openpyxl.Workbook() + wps = wb.active + + wps.column_dimensions['A'].width = 16.5 + wps.column_dimensions['B'].width = 16 + wps.column_dimensions['C'].width = 20 + wps.column_dimensions['D'].width = 30 + wps.column_dimensions['E'].width = 25 + wps.column_dimensions['F'].width = 28 + wps.column_dimensions['G'].width = 42 + wps.column_dimensions['H'].width = 17 + + + wps.title = '端口数据' + wps['A1'] = '设备端口和服务信息表' + wps.merge_cells('A1:H1') + wps['A2'] = '收集时间' + wps.merge_cells('A2:B2') + wps.merge_cells('C2:D2') + wps['E2'] = '所属系统' + wps.merge_cells('F2:H2') + wps['A3'] = '填表人' + wps['C3'] = self.name_ini + wps.merge_cells('A3:B3') + wps.merge_cells('C3:D3') + wps['E3'] = '系统责任人' + wps.merge_cells('F3:H3') + wps['A4'] = 'IP地址' + wps['B4'] = '端口' + wps['C4'] = '协议' + wps['D4'] = '服务' + wps['E4'] = '状态' + wps['F4'] = '访问权限开放范围' + wps['G4'] = '应用说明' + wps['H4'] = '备注' + + # 样式 + font = Font(size=12, name='宋体') + thin = Side(border_style="thin") + border = Border(left=thin, right=thin, top=thin, bottom=thin) + # 对齐 + alignment = Alignment(horizontal="center", vertical="center", wrap_text=True) + #设置第一行的格式 + one_font = Font(size=12, bold=True, name='宋体') + for one_style in wps['A1:H1']: + for one_cell in one_style: + one_cell.font = one_font + one_cell.border = border + one_cell.alignment = alignment + + for excel_style in wps['A2:H4']: + for excel_cell in excel_style: + excel_cell.font = font + excel_cell.border = border + excel_cell.alignment = alignment + + for uzip_content in uzip.namelist(): + all_uzip_content = re.findall(Port_File_re().uzip_re,uzip_content) + for all_uzip in all_uzip_content: + htmlcont_zip = uzip.open(all_uzip).read().decode('utf8') + vul_title = re.findall(Port_File_re().all_title_re,htmlcont_zip,re.S|re.M) + for title_content in vul_title: + pass + + vul_host = re.findall(Port_File_re().host_re,htmlcont_zip,re.S|re.M) + for host_content in vul_host: + for vul_port in re.findall(Port_File_re().port_re,host_content[2],re.S|re.M): + wps.row_dimensions[i+4].height = 15 + wps['C2'] = '%s' % host_content[1] + wps.append([host_content[0],vul_port[0].replace(' ','').strip(),vul_port[1].replace(' ','').strip(),vul_port[2].replace(' ','').strip(),vul_port[3].replace(' ','').strip()]) + for row in wps['A%s:H%s'%(i+4,i+4)]: + for cell in row: + cell.font = font + cell.border = border + cell.alignment = alignment + i += 1 + + wb.save(self.folder_end+'/汇总-端口对应关系表/端口服务对应关系表--%s.xlsx' % title_content) + self.log_return.emit('导出 %s'%title_content) + + endtime = datetime.datetime.now() + self.log_return.emit('所有端口导出完成,保存在输出路径 汇总-端口对应关系表 目录下。') + self.log_return.emit('导出花时:%s秒...\n'%(endtime - starttime).seconds) + + if self.web_status: + try: + shutil.rmtree(self.folder_end+'/汇总-WEB网站') + except Exception as e: + pass + self.log_return.emit('正在WEB网站,请稍后!') + starttime = datetime.datetime.now() + os.mkdir(self.folder_end+'/汇总-WEB网站') + dirList = os.listdir(self.folder_start) + for name in dirList: + all_file_name = re.findall(Port_File_re().file_re,name) + for file_name in all_file_name: + uzip = zipfile.ZipFile(self.folder_start+'/'+file_name) + + x = 1 + web = openpyxl.Workbook() + wes = web.active + wes.title = 'WEB网站' + + wes.column_dimensions['A'].width = 16.5 + wes.column_dimensions['B'].width = 16 + wes.column_dimensions['C'].width = 20 + wes.column_dimensions['D'].width = 30 + wes.column_dimensions['E'].width = 25 + wes.column_dimensions['F'].width = 45 + + wes['A1'] = 'IP地址' + wes['B1'] = '端口' + wes['C1'] = '协议' + wes['D1'] = '服务' + wes['E1'] = '状态' + wes['F1'] = 'WEB网站信息' + + # 样式 + font = Font(size=12, name='宋体') + thin = Side(border_style="thin") + border = Border(left=thin, right=thin, top=thin, bottom=thin) + # 对齐 + alignment = Alignment(horizontal="center", vertical="center", wrap_text=True) + + for uzip_content in uzip.namelist(): + all_uzip_content = re.findall(Port_File_re().uzip_re,uzip_content) + for all_uzip in all_uzip_content: + htmlcont_zip = uzip.open(all_uzip).read().decode('utf8') + vul_title = re.findall(Port_File_re().all_title_re,htmlcont_zip,re.S|re.M) + for title_content in vul_title: + pass + + vul_host = re.findall(Port_File_re().host_re,htmlcont_zip,re.S|re.M) + for host_content in vul_host: + for vul_port in re.findall(Port_File_re().port_re,host_content[2],re.S|re.M): + vul_web = re.findall(Port_File_re().http_re,vul_port[2].replace(' ','').strip(),re.S|re.M) + if vul_web: + wes.row_dimensions[x+1].height = 15 + wes.append([host_content[0],vul_port[0].replace(' ','').strip(),vul_port[1].replace(' ','').strip(),vul_port[2].replace(' ','').strip(),vul_port[3].replace(' ','').strip(),'http://'+ host_content[0] + ':' + vul_port[0].replace(' ','').strip()]) + x += 1 + vul_web = re.findall(Port_File_re().https_re,vul_port[2].replace(' ','').strip(),re.S|re.M) + if vul_web: + wes.row_dimensions[x+1].height = 15 + wes.append([host_content[0],vul_port[0].replace(' ','').strip(),vul_port[1].replace(' ','').strip(),vul_port[2].replace(' ','').strip(),vul_port[3].replace(' ','').strip(),'https://'+ host_content[0] + ':' + vul_port[0].replace(' ','').strip()]) + x += 1 + vul_web = re.findall(Port_File_re().www_re,vul_port[2].replace(' ','').strip(),re.S|re.M) + if vul_web: + wes.row_dimensions[x+1].height = 15 + wes.append([host_content[0],vul_port[0].replace(' ','').strip(),vul_port[1].replace(' ','').strip(),vul_port[2].replace(' ','').strip(),vul_port[3].replace(' ','').strip(),'http://'+ host_content[0] + ':' + vul_port[0].replace(' ','').strip()]) + x += 1 + + for row in wes['A1:F{}'.format(x)]: + for cell in row: + cell.font = font + cell.border = border + cell.alignment = alignment + + web.save(self.folder_end+'/汇总-WEB网站/WEB网站--%s.xlsx' % title_content) + self.log_return.emit('导出 %s'%title_content) + endtime = datetime.datetime.now() + self.log_return.emit('所有WEB网站导出导出完成,保存在输出路径 汇总-WEB网站 目录下。') + self.log_return.emit('导出花时:%s秒...'%(endtime - starttime).seconds) diff --git a/gui/ui_mainwindow.py b/gui/ui_mainwindow.py new file mode 100644 index 0000000..9eda5d0 --- /dev/null +++ b/gui/ui_mainwindow.py @@ -0,0 +1,167 @@ +import images_ico +from PyQt5 import QtCore, QtGui, QtWidgets + +class Ui_MainWindow(object): + def setupUi(self, MainWindow): + setini = """:::::::::导出的人员信息::::::::: +检查单位=宝宝 +检查人员=宝宝 + +:::::::::自定义导出数据 - 可删除、添加、调换位置::::::::: +1:6:检查单位|2:28:系统名称|3:8:主机名|4:16:IP地址|5:8:端口|6:8:协议|7:8:服务|8:45:漏洞名称|9:8:风险分类|10:8:风险等级|11:45:整改建议|12:45:漏洞描述|13:13:漏洞CVE编号|14:11:扫描起始时间|15:11:扫描结束时间|16:11:漏洞发现月份 + +:::::::::自定义标题颜色::::::::: +A-S:ff0000 + +:::::::::自定义漏洞等级 - 可删除,添加::::::::: +中|检测到目标NTP服务支持monlist命令 +中|目标主机rpcinfo -p信息泄露 +中|可通过finger服务猜测用户名列表 +中|可通过finger服务获取用户信息 +中|可通过rusers服务获取用户信息 +高|目标主机showmount -e信息泄露""" + try: + with open('set.ini') as info_ini: + ini = info_ini.readlines()[1:3] + self.name_ini = ini[1].split('=')[1].strip() + self.company_ini = ini[0].split('=')[1].strip() + except Exception as e: + with open('set.ini','a',encoding='gb18030') as set_ini: + set_ini.write(setini) + QtWidgets.QMessageBox.information(MainWindow, "提示!", "请修改同目录下的配置文件,重新打开软件!", QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No , QtWidgets.QMessageBox.Yes ) + exit() + + title = 'RSAS漏洞数据导出工具1.8' + font = QtGui.QFont() + font.setFamily("宋体") + font.setPointSize(10) + MainWindow.setFont(font) + #定义程序的标题 + MainWindow.setWindowTitle(title) + #设定程序的最大分辨率,禁止最大化、拖动窗口 + MainWindow.setFixedSize(560, 310) + #设置图标 + MainWindow.setWindowIcon(QtGui.QIcon(':/favicon.ico')) + #获取显示器的分辨率 + screen = QtWidgets.QDesktopWidget().screenGeometry() + #获取程序的宽和高 + size = MainWindow.geometry() + #实现在屏幕中间显示程序 + MainWindow.move((screen.width() - size.width())/2, (screen.height() - size.height())/2) + + #这是底部的状态栏 + MainWindow.status = MainWindow.statusBar() + MainWindow.status.showMessage("检查单位:%s 检查人员:%s" % (self.company_ini,self.name_ini)) + + #这是一个框架,用来固定按钮用的 + self.formLayoutWidget = QtWidgets.QWidget(MainWindow) + self.formLayoutWidget.setGeometry(QtCore.QRect(10, 10, 451, 54)) + self.formLayoutWidget.setObjectName("formLayoutWidget") + self.formLayout = QtWidgets.QFormLayout(self.formLayoutWidget) + self.formLayout.setContentsMargins(0, 0, 0, 0) + self.formLayout.setObjectName("formLayout") + #文字:原始报告路径 + self.input_label = QtWidgets.QLabel(self.formLayoutWidget) + self.input_label.setObjectName("input_label") + self.formLayout.setWidget(0, QtWidgets.QFormLayout.LabelRole, self.input_label) + #文字:输出报告路径 + self.output_label = QtWidgets.QLabel(self.formLayoutWidget) + self.output_label.setObjectName("output_label") + self.formLayout.setWidget(2, QtWidgets.QFormLayout.LabelRole, self.output_label) + + #原始报告路径后边的文本框 + self.input_lineEdit = QtWidgets.QLineEdit(self.formLayoutWidget) + self.input_lineEdit.setObjectName("input_lineEdit") + self.formLayout.addWidget(self.input_lineEdit) + self.formLayout.setWidget(0, QtWidgets.QFormLayout.FieldRole, self.input_lineEdit) + + #输出报告路径后边的文本框 + self.output_lineEdit = QtWidgets.QLineEdit(self.formLayoutWidget) + self.output_lineEdit.setObjectName("output_lineEdit") + self.formLayout.addWidget(self.output_lineEdit) + self.formLayout.setWidget(2, QtWidgets.QFormLayout.FieldRole, self.output_lineEdit) + + #框架的结束部分 + spacerItem = QtWidgets.QSpacerItem(20, 40, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding) + self.formLayout.setItem(1, QtWidgets.QFormLayout.LabelRole, spacerItem) + #这玩意就是打开路径按钮的框架 + self.start_verticalLayoutWidget = QtWidgets.QWidget(MainWindow) + self.start_verticalLayoutWidget.setGeometry(QtCore.QRect(463, 2, 91, 71)) + self.start_verticalLayoutWidget.setObjectName("start_verticalLayoutWidget") + self.start_verticalLayout = QtWidgets.QVBoxLayout(self.start_verticalLayoutWidget) + self.start_verticalLayout.setContentsMargins(0, 0, 0, 0) + self.start_verticalLayout.setObjectName("start_verticalLayout") + #这是原始报告路径后边的文本框后边的打开路径按钮 + self.input_Button = QtWidgets.QPushButton(self.start_verticalLayoutWidget) + self.input_Button.setObjectName("input_Button") + self.start_verticalLayout.addWidget(self.input_Button) + + #这是输出报告路径后边的文本框后边的打开路径按钮 + self.output_Button = QtWidgets.QPushButton(self.start_verticalLayoutWidget) + self.output_Button.setObjectName("output_Button") + self.start_verticalLayout.addWidget(self.output_Button) + + #这又是一个框架,固定用的 + self.horizontalLayoutWidget = QtWidgets.QWidget(MainWindow) + self.horizontalLayoutWidget.setGeometry(QtCore.QRect(10, 75, 451, 21)) + self.horizontalLayoutWidget.setObjectName("horizontalLayoutWidget") + self.horizontalLayout = QtWidgets.QHBoxLayout(self.horizontalLayoutWidget) + self.horizontalLayout.setContentsMargins(0, 0, 0, 0) + self.horizontalLayout.setObjectName("horizontalLayout") + #文字:选择导出数据 + self.data_label = QtWidgets.QLabel(self.horizontalLayoutWidget) + self.data_label.setObjectName("data_label") + self.horizontalLayout.addWidget(self.data_label) + #复选框:高危 + self.hight_checkBox = QtWidgets.QCheckBox(self.horizontalLayoutWidget) + self.hight_checkBox.setObjectName("hight_checkBox") + self.horizontalLayout.addWidget(self.hight_checkBox) + #复选框:中危 + self.middle_checkBox = QtWidgets.QCheckBox(self.horizontalLayoutWidget) + self.middle_checkBox.setObjectName("middle_checkBox") + self.horizontalLayout.addWidget(self.middle_checkBox) + #复选框:低危 + self.low_checkBox = QtWidgets.QCheckBox(self.horizontalLayoutWidget) + self.low_checkBox.setObjectName("low_checkBox") + self.horizontalLayout.addWidget(self.low_checkBox) + #复选框:端口 + self.port_checkBox = QtWidgets.QCheckBox(self.horizontalLayoutWidget) + self.port_checkBox.setObjectName("port_checkBox") + self.horizontalLayout.addWidget(self.port_checkBox) + #复选框:网站 + self.web_checkBox = QtWidgets.QCheckBox(self.horizontalLayoutWidget) + self.web_checkBox.setObjectName("web_checkBox") + self.horizontalLayout.addWidget(self.web_checkBox) + #这又是一个框架 + self.end_verticalLayoutWidget = QtWidgets.QWidget(MainWindow) + self.end_verticalLayoutWidget.setGeometry(QtCore.QRect(463, 69, 91, 31)) + self.end_verticalLayoutWidget.setObjectName("end_verticalLayoutWidget") + self.end_verticalLayout = QtWidgets.QVBoxLayout(self.end_verticalLayoutWidget) + self.end_verticalLayout.setContentsMargins(0, 0, 0, 0) + self.end_verticalLayout.setObjectName("end_verticalLayout") + #按钮:开始导出 + self.start_Button = QtWidgets.QPushButton(self.end_verticalLayoutWidget) + self.start_Button.setObjectName("start_Button") + #框架结尾 + self.end_verticalLayout.addWidget(self.start_Button) + #详细输出日志的文本框 + self.log_textEdit = QtWidgets.QTextEdit(MainWindow) + self.log_textEdit.setGeometry(QtCore.QRect(5, 120, 550, 171)) + self.log_textEdit.setObjectName("log_textEdit") + + self.retranslateUi(MainWindow) + QtCore.QMetaObject.connectSlotsByName(MainWindow) + + def retranslateUi(self, MainWindow): + _translate = QtCore.QCoreApplication.translate + self.input_label.setText(_translate("MainWindow", "原始报告路径:")) + self.output_label.setText(_translate("MainWindow", "输出报告路径:")) + self.input_Button.setText(_translate("MainWindow", "打开路径")) + self.output_Button.setText(_translate("MainWindow", "打开路径")) + self.data_label.setText(_translate("MainWindow", "选择导出数据:")) + self.hight_checkBox.setText(_translate("MainWindow", "高危")) + self.middle_checkBox.setText(_translate("MainWindow", "中危")) + self.low_checkBox.setText(_translate("MainWindow", "低危")) + self.port_checkBox.setText(_translate("MainWindow", "端口")) + self.web_checkBox.setText(_translate("MainWindow", "网站")) + self.start_Button.setText(_translate("MainWindow", "开始导出")) diff --git a/images_ico.py b/images_ico.py new file mode 100644 index 0000000..be25b44 --- /dev/null +++ b/images_ico.py @@ -0,0 +1,274 @@ +# -*- coding: utf-8 -*- + +# Resource object code +# +# Created by: The Resource Compiler for PyQt5 (Qt v5.11.1) +# +# WARNING! All changes made in this file will be lost! + +from PyQt5 import QtCore + +qt_resource_data = b"\ +\x00\x00\x0e\x0a\ +\x00\ +\x01\x08\x3e\x78\x9c\xed\x9d\x49\x93\x24\x37\x15\xc7\x5f\x53\x86\ +\x36\x6b\x03\x36\xcb\x89\x06\x8c\x61\x58\x8c\xc1\x10\x66\x9b\xe8\ +\xe6\x03\xc0\x00\x76\xb0\x83\x3d\x9c\xd8\x2e\x6c\x26\x86\x60\xa0\ +\x8b\xfd\x0a\x17\x22\x80\x23\x60\xb3\x9b\xd5\x36\x5c\xa8\x0f\x00\ +\xc1\xbe\x0f\xe1\x82\x30\xbb\x81\x86\x08\x7b\x6a\xec\x66\x06\xfd\ +\x4a\xd2\x74\x95\x26\x95\x99\x95\x99\xca\x54\x66\xe9\xef\xf8\x8f\ +\x47\x1d\x3d\x95\x4a\x3d\xe9\x6d\x7a\x52\x89\x6c\xa8\xff\xc6\x63\ +\x51\x7f\x3e\x56\x8e\x5c\xbc\x21\x8f\x14\x91\x23\x8a\xea\x47\xfc\ +\x70\xfe\x73\x8d\x0d\xb9\xe4\x81\x32\x67\x42\xc2\x9a\xe3\x3e\x8a\ +\xc7\x14\x9f\x69\xfe\x9e\xb0\x3e\xb8\x48\xf1\xb8\xe2\x1d\x8a\xb7\ +\x2a\x3e\xb9\xd3\xde\x24\xb4\x09\xd6\xfa\x75\x8a\x7f\x51\x3c\xa7\ +\x78\xb7\xe2\x37\x14\xaf\xea\xb2\x53\x09\xad\x60\x24\x5a\xf6\x7f\ +\x12\x2d\xfb\x45\x7e\x59\xf1\x72\x49\xb6\x60\xa8\x40\xf6\xc7\xe5\ +\x70\xdd\xbb\xbc\x47\xb4\x2d\x78\x56\x47\xfd\x4b\x08\x07\xd6\xf4\ +\xeb\x24\x7b\xdd\x2f\xf2\x5e\xc5\x9b\x14\x9f\x2a\xf3\xc8\x29\x61\ +\x00\xc0\xd7\x7b\x83\x14\xcb\x7e\x71\x0e\xdc\x26\xc9\x27\x1c\x02\ +\x58\xc3\xaf\x57\xfc\xb3\x94\x93\xbd\xe5\x69\xc5\xaf\x88\x8e\x0d\ +\x13\xfa\x09\xd6\xfd\xf5\x52\x7e\xdd\xbb\x3c\xab\xf8\x55\xc5\x27\ +\x49\xf2\x09\xfb\x06\xe4\x85\xec\x7d\xbe\x5e\x59\xce\x14\xbf\x23\ +\x29\x36\xec\x13\xf0\xf3\xd1\xf9\x55\xd7\xbd\xcb\xff\x29\x7e\x5e\ +\xb4\x1e\x48\x3e\x61\xdc\x40\xf6\xf8\x7a\xab\xda\xfb\x22\x1e\x28\ +\x7e\x4f\xf1\x29\xed\xbd\x4a\xc2\x8a\xb0\x31\x5e\xd3\xb2\x5f\xb4\ +\x05\x5f\x54\x7c\x86\x24\x3d\x10\x1b\x6c\x3e\xbf\x29\x9d\x9f\x67\ +\x0b\xc8\x15\x1f\x69\xe5\xad\x12\xca\x80\x75\x8f\xbd\xaf\xeb\xeb\ +\x95\xe5\x5d\x8a\xdf\x16\xad\x07\x12\xba\x05\xeb\xde\x97\xcf\x0f\ +\x4d\xf2\x84\x29\x36\xec\x0e\x8c\xfb\x71\x69\x6f\xdd\xbb\xb4\x79\ +\xc2\xa7\x07\x7e\xcf\x84\x0b\x81\x9f\x5f\x26\x9f\x1f\x9a\xec\x19\ +\xdd\xa8\x78\xa5\x24\x9f\xb0\x2d\xd8\x7c\x7e\x28\x3f\x7f\x55\x12\ +\x1b\xde\x22\xda\x16\x24\x84\x05\x6b\x2c\x64\x8c\x57\x95\xd4\x90\ +\x7c\x5d\x92\x4f\x18\x12\x6d\xc5\x78\x55\xc9\x7e\xc1\x97\x44\xef\ +\x1b\x26\x9f\xb0\x59\xb8\x35\x5b\xb1\x92\x1c\x11\x3e\x61\xd2\x03\ +\xcd\x21\xaf\x66\x2b\x46\xe2\x0f\xb0\x5f\xf0\x34\x49\x3e\x61\x5d\ +\x14\xd5\x6c\xc5\x4a\xf2\x84\xec\x17\x24\x9f\xb0\x3a\xca\xd6\x6c\ +\xc5\x4a\x6a\x48\xa8\x29\x4d\x35\x24\xab\x23\xb6\x18\xaf\x8e\x1e\ +\xa0\x86\x04\x9f\x30\xd9\x82\x72\x88\x35\xc6\xab\x4a\x62\x43\xea\ +\x8a\xaf\x6c\x72\x90\x06\x8a\xba\x35\x5b\xb1\x92\xd8\x90\x3c\x21\ +\x75\xc5\x29\x36\xcc\x46\x53\x35\x5b\xb1\x92\xb8\xe0\xbb\x92\x6a\ +\x48\xb2\x80\xec\x5f\x2d\xc3\xd1\xf9\x3e\x9e\x11\xed\x0f\x3c\xbb\ +\x99\x61\x1b\x0c\xb6\x14\x3f\x23\xda\x5f\xea\x5a\x46\xa1\x89\x7e\ +\x3b\xd6\xcc\xb0\x0d\x06\xf7\x55\xbc\x5a\xf1\x0b\xa2\x73\x68\x5d\ +\xcb\x28\x14\xff\xa9\xf8\x16\xc5\xcd\x66\x86\x6d\x70\x78\x82\xe2\ +\xb7\x44\xeb\xc9\xae\x65\xd5\x34\xff\xae\xf8\x66\xd1\x73\x7d\xdd\ +\x41\x8c\x97\xe5\x07\xf3\x33\x7c\xe4\xcf\xc9\xb0\x6c\xc1\x9d\x8a\ +\x6f\x12\xff\xba\x5f\xa7\xdc\x80\x8d\xf1\xc8\xef\xf8\xc6\x83\x9a\ +\x1a\xf6\xd4\x87\x60\x0b\xfe\x21\x5a\xe7\xdf\xcf\xf3\xae\x8f\x52\ +\xbc\x41\x74\x9e\x70\xe8\xf3\x60\x31\xc6\xfb\x9d\xe2\x4b\xc4\x3f\ +\x07\xb0\x05\xd4\x5b\x13\x37\x75\x2d\xc3\x3a\xb2\x7f\xa3\xf8\x65\ +\xff\x68\xc5\x4f\x8b\xb6\x77\xe4\x88\x9e\x98\x37\x78\x3d\x87\x5b\ +\xb3\x85\x7e\xff\x8d\xe8\xf9\x30\xca\xf8\x7d\xd6\x02\xe7\xae\xc8\ +\xa1\xf7\x51\x0f\xa0\xf3\xdf\x2a\xfe\xf9\xfd\x08\xd1\x31\xcf\x69\ +\xf3\xfb\xfc\xff\x66\x19\xe6\x7e\x41\xde\xb9\x9c\x5f\x28\x5e\xa3\ +\xe8\xbb\x95\xec\x71\xa2\x7d\xc2\x3e\xe9\x01\x7c\x3d\xec\xbd\xcf\ +\xd7\x43\xe7\x23\xfb\x7b\x9d\x7f\xc7\x9a\xa0\x86\x84\x1c\xd1\x50\ +\xf2\x84\x65\xf2\xf9\xbf\x57\x7c\xb9\x64\xeb\x01\xc6\x81\xbd\x74\ +\x62\xc3\x3e\xcc\x81\xa2\x18\x8f\xeb\xf9\xd0\xf9\x3e\x9d\x86\x1e\ +\xb8\xd5\xbc\x73\xdf\xb1\x4a\xcd\xd6\x4f\x45\x9f\xe3\xb8\xd8\xf3\ +\x59\x8c\x07\x67\x71\x4f\xe7\x7c\x46\xd7\x64\xdd\x23\x7b\xdf\xba\ +\xb7\x3a\xff\x9e\x82\xcf\xb1\x35\x24\x57\x48\x7f\x7d\xc2\x2a\x35\ +\x5b\xa7\x44\xe7\xc6\x2e\xca\xf8\x3c\xc6\x81\x7a\x0a\xf6\x51\x62\ +\x8c\x0d\x6d\x8c\x97\xe7\xe7\x7f\x4a\xca\xe7\x36\xd8\x33\x42\x0f\ +\x5c\xee\xf9\xbc\x98\x51\xb5\x66\xcb\xfa\x84\xc7\x25\xdb\x16\x00\ +\x7c\x42\xce\xe0\xc5\x94\x23\xc2\xcf\xc7\xd7\xf3\xc9\xde\xae\xfb\ +\x55\xfd\x58\xde\x11\xff\xb7\x4f\xfb\x05\x4d\xd4\x6c\xfd\x52\x74\ +\x6c\xe8\xf3\x09\x1f\x2f\x7a\x0e\xc4\xe0\x0f\x94\x8d\xf1\x8a\x74\ +\x7e\xde\x9a\x20\x2e\xe8\x43\x2d\x59\x93\x35\x5b\xbf\x15\xbd\x27\ +\x98\xa5\x07\xf8\x19\xf5\x14\xf8\x84\x5d\xea\x81\x22\x5f\x8f\x75\ +\x8f\xec\xeb\xfa\x2c\xb6\x86\xe4\x0a\xcf\x73\x62\x40\x88\x9a\xad\ +\x9f\x88\x9e\x03\xf7\xf7\x3c\x93\xba\x2a\x62\xc3\x2e\x7c\xc2\xa2\ +\x18\x0f\x3f\x3f\x2b\xc6\xab\x4a\xf4\x00\xbe\x0f\x73\xc0\x67\x1b\ +\xbb\x42\xc8\x9a\x2d\x62\xc3\x17\x8b\x3f\x36\xe4\x2c\x3e\xe3\x72\ +\x36\xc0\xb3\xf3\xd6\x3d\x7b\x39\x79\x31\x1e\xbe\x5e\xd3\x79\x2b\ +\xe6\xd2\x2d\x12\xd7\xfd\x03\xa1\xcf\xe5\x20\xd7\x5f\x99\x67\xf8\ +\xd6\x1a\x39\x33\xce\xe4\xb7\x91\x27\x6c\x2a\xc6\xab\x4a\xec\x1d\ +\x79\x71\xee\x29\xed\x3a\x36\x6c\xb3\x66\x8b\x3c\x21\x3e\xa1\x2f\ +\x3f\x70\x99\xe8\xda\x9a\x90\xb1\x21\x31\x5e\x91\xaf\xb7\x4a\x8c\ +\x57\x67\x4d\x7c\x53\xf4\x1e\x49\x57\x68\xfa\x9e\xad\x22\x22\x57\ +\x7c\x42\xec\x4c\x56\x6e\x94\xb5\x80\x1e\x08\x55\x43\x62\xf3\xf9\ +\x4d\xc7\x78\x55\x89\xcf\x83\xef\xd3\xc5\x59\x33\x1b\xe3\x75\x51\ +\xaf\xf7\x33\xd1\xb9\xe2\x07\x78\xfa\x46\xbe\x84\x71\x69\x52\xff\ +\x86\x8e\xf1\xaa\x92\xf8\x17\x5b\x40\x6e\xb4\xad\xfd\x82\x18\xce\ +\xe5\xe0\x13\xbe\x54\xfc\xb1\x21\x71\x01\x7a\xa0\x09\x9f\xb0\xad\ +\x18\xaf\x2a\xd1\x37\xc4\x86\x6d\xd4\x15\xaf\x7a\x97\x72\x28\x22\ +\xd7\x9f\x8b\xf6\x3d\x7c\x72\x21\x3f\x80\x1e\xb8\xbb\xc6\x73\x8a\ +\x6a\xb6\x6c\x8c\xd7\xf6\xba\x77\xc9\xf3\xb9\x8f\x28\xe4\xdd\x74\ +\x6d\xdf\xb3\x55\x86\xc4\x05\xc4\x86\x3e\xf9\x60\x0b\xd0\x8f\x55\ +\x7c\xc2\xa2\x18\xcf\xe6\xf3\x63\xaa\x4d\x20\x06\xba\xcc\xd3\xdf\ +\x3a\x88\xf5\x5c\x0e\x72\x3d\x65\xfa\xe6\xb3\x7f\xec\x17\x70\x97\ +\xf7\x2a\x72\x2a\xaa\xd9\xb2\xbe\x5e\x4c\x7b\x10\xe7\x4c\x7f\xc8\ +\x15\x37\xb9\x5f\xd0\x87\x73\x39\xd8\x82\x6b\xc5\xbf\x5f\x80\x1e\ +\x60\x6d\x94\xd1\x03\xb1\xfa\x7a\x65\xc9\x3b\xb2\x67\xd4\xc4\xf7\ +\x17\xb4\x1d\xe3\xd5\x21\xf5\x84\xaf\x10\xbf\x4f\x48\x5d\x31\x3e\ +\x61\x9e\xdc\x62\x8b\xf1\xaa\x12\x5f\x94\xb3\x66\x75\x6a\x48\x42\ +\xdd\xa5\x1c\x92\xc4\x86\xcc\x57\xdf\x7e\x01\xe3\x41\xde\x24\xcb\ +\x27\xac\x5a\xb3\x15\x2b\xed\x77\xd9\xe0\x13\xae\x1a\x1b\xf6\xf9\ +\x0c\x36\x39\xa2\x17\x49\x76\x0d\x09\xe3\x40\xce\xcc\x8d\x0d\xcb\ +\xd6\x6c\xc5\x5c\x7b\x94\x45\xf2\x03\xd4\x4c\xad\x52\x57\x1c\xfb\ +\x3d\x5b\x45\x44\xae\xa7\xa4\xb8\x86\x84\xfb\xda\xf0\x97\xb0\xf7\ +\x79\x31\x5e\xe8\x7c\x7e\x68\xda\x33\xa7\x57\x7b\xde\x6f\x11\x7d\ +\xb9\x67\xab\x0c\xb1\x05\xe4\x88\x7c\x79\x42\xab\x07\x90\x7d\x53\ +\x35\x5b\xb1\x92\x35\x71\xb3\xe4\xef\x17\x74\x79\x97\x72\xa8\x77\ +\x46\x0f\xbc\x46\xfc\x67\xcd\x88\x95\x7d\xfb\x49\xb1\xc6\x78\x55\ +\x89\xed\xe2\x6e\xba\xac\x7b\x48\xfa\x7a\xcf\x56\x19\x52\x57\xcc\ +\x1c\xf0\xe9\x81\x2c\xc4\x1e\xe3\x55\x25\x3e\x21\x3a\x8f\x39\x60\ +\xd7\x04\xeb\xbe\xeb\x7c\x7e\x68\xda\xb3\x66\x3e\x3d\xbf\x88\xbe\ +\xfa\x7a\x65\xc9\x9c\xa6\x86\xc4\xde\x49\xc5\xda\xe8\xa3\x9f\xbf\ +\x0a\xb1\x05\xb6\xae\x38\x0f\xd8\x82\x4f\x4a\x7f\x62\xbc\xaa\x24\ +\x7f\xf1\x35\xd1\x39\x91\x8f\x29\xee\x47\xd0\xa7\xd0\x24\xc6\x7b\ +\x95\xe4\x03\x7f\x8f\x5c\x71\x8c\xe7\x0b\x9a\xe6\x0f\x45\xdb\x01\ +\x6c\xdd\xdb\x14\xff\x1a\x41\x9f\x42\xb1\xa8\x66\xcb\x02\x5b\x48\ +\x6c\x38\xf4\x7b\x48\x7e\xa0\xf8\x1c\x39\xf4\x01\xb8\x7f\xe7\x83\ +\x32\xcc\x39\x50\x74\x2e\x27\x0b\xd4\xda\x63\x23\x87\xa8\x07\x58\ +\xf7\xcf\xcd\x78\x67\xe6\xc0\x3b\x14\xff\x15\x41\x1f\x9b\x94\x7d\ +\x5e\x3e\x9f\xfd\xa2\x2c\x9d\x40\x3c\xc4\x1c\xe8\xfb\xfd\x03\x2e\ +\x59\xf7\xcf\xf3\x8c\x05\xb8\x54\xf1\xbd\x32\x8c\x38\xb0\xcc\x3e\ +\xde\x27\x44\xef\x71\xf8\x72\x00\xd8\x47\xf2\x84\x77\x45\xf0\x3e\ +\x75\xc9\xba\x2f\x93\x03\x24\x4e\xde\x53\xfc\x77\x04\x7d\xae\xca\ +\xb2\x35\x5b\xd8\xf8\xbc\x1a\x12\xe2\x23\x72\x66\xf8\x84\x6d\x9e\ +\x2f\x68\x9a\xac\xfb\xe7\x7b\xc6\x22\x0b\x97\x88\xb6\x05\x7d\xd4\ +\x03\x65\x6b\xb6\x6c\x8c\x87\x5c\x6f\x17\x9d\xfb\xf4\xed\x17\x50\ +\x6b\xcf\x9e\x7a\x1f\x73\x81\xc8\xbe\xcc\xba\x77\xf1\x10\xc5\x8f\ +\x88\x5e\x4b\x5d\xbf\x43\x59\xd6\xa9\xd9\xe2\xac\x19\x35\x24\xbe\ +\x3c\x21\x7b\x68\x7d\xf3\x09\xd1\xf9\xab\xac\x7b\x17\xf8\x84\xc4\ +\x86\x7d\xf0\x09\x6d\xcd\x56\xd1\x3e\x5e\xde\x1a\xa6\xae\xd8\x57\ +\x43\x62\xef\xa6\xbb\xb1\xe0\x33\x62\xa1\x8d\xf1\xea\x02\x5b\x30\ +\x96\xb8\x73\x84\x4d\xd6\x6c\xb1\x6f\x48\x3e\xdc\x57\x43\xc2\xf9\ +\x4b\x6a\x48\x62\xce\x0f\xb0\xee\x9b\x90\xbd\xc5\x83\x45\xc7\x05\ +\x31\xfa\x84\x21\x6a\xb6\xc8\x15\x53\x43\xe2\x8b\x0d\xd9\x37\xc4\ +\x1f\x88\xd1\x27\x5c\xd5\xd7\x2b\x0b\xc6\xf1\x5d\x12\x97\x4f\x68\ +\xd7\x7d\x88\x9a\x2d\x5b\x57\xec\xfb\x6c\xf2\x84\xd4\x55\xd4\x39\ +\x5f\xd0\x34\xcb\xc6\x78\x55\x41\xbe\xe4\xa3\x12\x87\x1e\x68\xa3\ +\x66\xeb\xc7\x8a\x2f\xcb\x79\x06\x3e\x21\xb6\x20\x06\x9f\x90\x75\ +\xff\x02\x4f\x3f\x9b\x84\xf5\x09\xef\x6c\xf9\xfd\x16\xd9\xd6\xb9\ +\x1c\xf4\xfb\x54\xf4\xbe\x51\xd6\xb9\x1a\x7e\x46\x8e\x88\xbb\xba\ +\xba\xf4\x07\xaa\xc6\x78\x55\xf1\x30\xc5\x0f\x49\x37\x3e\x61\xd1\ +\x5d\xca\x21\xce\xe5\x14\xdd\x43\x42\x5c\x40\x6c\xd8\x45\xae\x18\ +\x9d\x9f\x97\xd3\x0d\x05\xf2\x03\xef\x96\x76\x6d\x41\x97\xe7\x72\ +\xa8\x21\x39\xe6\x79\xf6\xa2\x4f\xd8\xa6\x2d\x60\xdd\x67\xed\xe5\ +\xb4\x05\xf4\xec\x09\x69\x67\xdf\x30\x86\x73\x39\xe4\x8a\xaf\x17\ +\xbf\xee\xb1\x3e\x61\x1b\xfb\x05\x4d\xc7\x78\x55\x81\x4f\x88\x2d\ +\x08\x99\x23\x42\xe7\xc7\x72\x06\x9b\x7a\x42\x5f\x2d\x99\xdd\x2f\ +\xa0\xd6\x36\xa4\x1e\x08\x15\xe3\x55\xc5\xc3\x45\xfb\x84\x7f\x93\ +\xe6\xdf\x35\xb6\x73\x39\xf8\x84\x7f\x10\x7f\x5d\x31\x40\x0f\x70\ +\xf6\x26\x84\x1d\x6a\xdb\xd7\x2b\x8b\x87\x8a\xde\x2f\x40\x5e\x4d\ +\xbd\x6b\xdd\xbb\x94\x43\x92\xd8\xf0\x95\xe2\xdf\x2f\xa0\xbe\x92\ +\x7a\xeb\x26\xf5\x40\xdd\x7c\x7e\x68\x3c\x48\xf1\xed\xd2\x4c\x3d\ +\x61\xd7\xf7\x6c\x95\x21\x39\xa2\x6b\x3c\x7d\x44\x37\x50\x43\x72\ +\x53\x43\x7d\x8c\x75\xdd\xbb\xa0\x86\xe4\x7d\x52\x2f\x36\x2c\xaa\ +\xd9\x6a\xeb\x9e\xad\x22\xda\x7b\x48\x38\x73\xea\xd3\x51\x9c\xbf\ +\xa4\x86\xa4\x8e\x6f\xe2\xab\xd9\x8a\x15\xe8\x81\xf7\x4b\x35\x9f\ +\x30\xd4\x5d\xca\x21\x49\x5c\xc0\x7e\x41\xd6\x1c\x40\x0f\xf0\x1d\ +\x16\xd4\x5b\x57\xd9\x2f\x28\xaa\xd9\x8a\x15\xec\x1b\x62\x0b\x56\ +\x89\x0d\x63\x88\xf1\xaa\xf2\x76\xd1\xfb\x86\x59\xe7\x8e\x01\x3e\ +\x21\xf5\x84\xab\xcc\xdb\xd0\xf9\xfc\xd0\x20\x47\xc4\x7e\x41\x99\ +\x1a\x92\xd8\xef\xd9\x2a\xc3\x1f\x89\xbe\x9b\xce\x57\x4f\xc8\x7e\ +\x01\xe7\xb1\xcb\xe4\x09\x63\x8b\xf1\xaa\x02\x5b\x40\x6c\x98\x97\ +\x27\x6c\xfb\x2e\xe5\x50\xb4\xfb\x05\xbe\xef\xb2\x21\x3f\x40\xae\ +\xf8\xb3\x92\xef\xbb\xf4\xc5\xd7\x2b\x0b\x6c\xc1\x07\x24\xfb\x8c\ +\x61\x1f\xef\xd9\x2a\xa2\xfd\x2e\x9b\xbc\xef\x37\x44\x0f\x64\xd9\ +\xb1\xd8\x63\xbc\xaa\xa0\x86\x84\x5c\xf1\xa2\x1e\x68\xa2\x66\x2b\ +\x56\x72\x0f\x09\xfb\x05\x59\xb6\xc0\xfa\x84\xee\x7d\xc5\x4d\xd5\ +\x6c\xc5\x0a\x5b\x43\x42\x9e\xb0\xcc\x5d\xca\xf6\xbb\x11\xbb\x96\ +\x65\x9d\x39\x70\x5d\xce\x3b\x2e\x7e\xbf\x61\xdf\x62\xbc\xaa\xc0\ +\x1f\x20\x4f\x58\x66\x1f\xaf\x4f\x3a\xdf\x47\xf2\x84\xd4\x15\xfb\ +\x6c\x01\x39\xa2\x8f\xcb\x30\x75\xbe\x0f\xd4\x90\xf8\x7c\x64\xec\ +\x7d\xac\x31\x5e\x15\xe2\x13\xfe\x51\x74\xae\xd8\x77\x0f\xc9\xa5\ +\x25\xc6\x6c\x1d\x30\xe4\xbb\x17\xd0\x03\xaf\x15\x7f\x0d\xc9\xba\ +\xc3\xee\xe3\x0d\x65\xdd\x67\x91\xfd\x02\xea\x09\xd3\x1c\x58\x06\ +\xb6\xe0\xc3\x32\x6c\xd9\x43\x6c\xc1\xaf\x45\xdf\x4b\x96\x70\x08\ +\xf2\x84\xd4\x90\xf4\xe9\xac\x59\x55\xe2\xe7\x5f\xd5\xcc\xb0\x0d\ +\x06\xe4\xc5\xc8\x11\x91\x27\x6c\xb2\x7e\x20\x36\xc6\x52\xb3\x15\ +\x2b\xa8\x2b\x26\x36\x24\x2f\xd4\xb5\xac\x9a\xe6\x50\xf2\xf9\xa1\ +\x81\x6f\xc4\xbe\xe1\x7f\xa4\x7b\x99\x35\x29\xfb\x21\xe5\xf3\x43\ +\x83\x78\x98\xfa\x81\x21\xdc\x49\x98\xd6\x7d\x35\xb0\x5f\x70\x52\ +\xfa\x71\xf6\x3c\xad\xfb\x30\x20\x0f\xfc\x4e\xe9\xa7\x4f\xd8\xd5\ +\xb9\x9c\xa1\x81\x5c\x31\x3e\x61\x97\xe7\x0d\xab\xac\xfb\x75\xd8\ +\xcb\x69\x0b\xec\x19\xf5\xe5\x6e\xba\xbe\xd7\x6c\xc5\x0a\x7c\x42\ +\x5f\x0d\x49\x2c\x4c\xbe\x5e\x58\x70\xd6\x8c\x1a\x92\x18\x63\xc3\ +\xe4\xeb\xb5\x03\xf6\x08\x39\x77\x1c\xe2\xac\x59\x1d\x9d\x9f\xd6\ +\x7d\x7b\xb0\xfb\x05\x31\xe4\x09\x87\x5e\xb3\x15\x2b\x38\x6f\x88\ +\x4f\xd8\x65\x5c\xb0\x2e\x35\x5b\xb1\x02\x9f\x90\x7b\xcb\xbb\xb0\ +\x05\x7d\x3d\x97\x33\x34\xb0\x5f\x80\x3f\xf0\x5f\x69\x77\xdd\x27\ +\x5f\x2f\x1e\x90\x27\xe4\x7e\xc2\x36\xee\x23\x6a\xeb\x9e\xad\x84\ +\xd5\x80\x4f\xb8\x27\x61\xfd\x81\x14\xe3\xc5\x0d\x7b\x6f\x79\x88\ +\xb8\x20\xe5\xf3\xfb\x01\x6a\x48\xa8\x25\x6c\x72\xcf\x28\xc5\x78\ +\xfd\x02\x3e\xe1\x0d\xd2\x4c\x9e\x30\xd5\x6c\xf5\x13\xf8\x84\xdc\ +\x43\x72\x87\xd4\x5b\xf7\x29\xaf\xd7\x5f\xb0\x5f\x50\xf5\xde\xf2\ +\xe4\xeb\x0d\x03\x55\x6a\x48\xd2\xba\x1f\x16\xec\xf7\x1b\x96\x99\ +\x03\x69\xdd\x0f\x13\xd4\x13\x72\xf6\x3c\xef\x8c\x49\x8a\xf1\x86\ +\x0d\xeb\x13\x66\xe5\x09\x53\xcd\xd6\x7a\x80\xb3\x86\xef\x91\xe5\ +\xd8\x30\xe9\xfc\xf5\x02\x35\x24\x63\xd1\xf5\x84\x7c\xd7\xcf\x0b\ +\xbb\xec\x4c\x97\x38\x97\x8d\x83\xdd\xe5\xf6\xcc\x69\xef\x6f\x2f\ +\xb7\xa7\x9b\xcb\xed\x89\xd3\x1e\x6f\x2c\xb7\x65\xb9\x7d\x56\x64\ +\x6f\xe9\xf1\x22\x4b\x0f\x9c\x39\xed\x7d\xe5\xd1\x2d\x3d\xde\x69\ +\x4f\x44\x46\x4b\x8f\x77\xda\xea\xc5\x17\x3b\xc0\xa9\xdc\xc5\x0e\ +\x1c\x38\x6d\x6e\x21\x91\xed\xa5\xc7\x2f\xb5\xa7\xb4\x17\x3a\x30\ +\xa1\xbd\xf0\xc0\xb1\xd3\x76\x86\xfe\xac\xd3\x3e\xd0\xed\xdd\xa5\ +\xc7\x2f\x3c\x70\xdf\x69\x4f\x75\xfb\xfc\x90\x4f\x9c\xf6\x58\xb7\ +\x47\x65\xdb\xce\xe7\x9d\x31\xed\xad\xef\x9b\xc7\xdb\xfe\x98\x37\ +\x9e\x9e\xd0\xed\x1d\xd3\x9e\x1c\xd5\xed\x93\xe6\x03\xc6\x8f\xd1\ +\xed\x99\x19\xf2\xb9\x33\xae\x04\xb0\xbf\x61\xde\x7e\x53\x8f\xd7\ +\x54\x0f\xf9\x81\x8c\xe6\x6d\xf5\xd3\x3d\xfd\xf6\x1b\xf3\x17\xde\ +\x1a\xeb\x37\xde\xd7\xb7\x0b\xcb\xb6\x19\x81\xa9\xae\x08\x94\x1d\ +\x23\x82\xc9\xfc\xaf\xf3\xa3\x23\x23\xf3\x76\xf3\x0e\xcc\x4c\x5b\ +\x7f\x94\xfe\x50\x33\xf8\x74\x60\x34\xd5\x6d\x06\x9f\x0e\xcc\x3b\ +\xb5\xa7\x07\x9f\xdf\xe5\xdf\xf0\xc0\xf9\xb3\xf7\xe7\x8f\x9f\xb7\ +\xa7\xe6\x59\x3b\x66\xc8\xe6\x7d\x3f\xaa\x4f\xae\xd0\x1e\x9b\xbe\ +\xce\xcc\x10\xeb\xa1\x1c\xeb\x77\x12\x23\xfb\xcd\xf1\x48\x0f\xb2\ +\x91\xfd\x68\xaa\xc7\x44\x76\xf5\x58\x6f\x4c\xb7\xb4\x90\xb6\x8d\ +\xec\x67\xdb\x46\x26\x46\x36\x27\x77\x4c\x5b\xff\x33\x39\x7a\x52\ +\xcc\x07\x1b\x59\x19\x99\xd9\xef\xb0\xd9\x32\x9f\x63\xb1\x39\xcd\ +\x6f\xdb\xe7\x88\xf3\x79\x23\xf3\xbc\x1d\x33\x07\x46\x6e\x7f\x6c\ +\x7f\xcd\x1c\xd8\x32\xef\xb3\x6f\xde\x67\xd7\x79\xdf\x3d\xdd\xde\ +\x9c\x98\x0f\xde\x5b\x1e\xaf\x8d\xc3\xf1\xb4\xed\xf9\xef\xed\x1c\ +\x8e\xf7\xbc\x03\x0b\xf2\x98\xff\xde\xcc\xcc\x81\x2d\x47\x9e\xbb\ +\x46\xde\x53\x33\x52\xbb\x17\xce\x87\xf3\xf3\xc5\xb6\xc7\x46\xf6\ +\x76\x3e\x4d\x0e\xe7\xdb\xa6\x99\x8f\xf3\xbe\x1c\x35\xed\x7d\x23\ +\x7b\x3b\x5f\xcf\xcf\x67\xd3\x3e\x30\x83\x66\xe7\xbb\xbb\x1e\xce\ +\xe9\xae\xaa\x0e\x98\xf5\x33\x36\xb2\x9f\x99\x05\x3b\x31\x63\x7d\ +\xc2\xb4\xa7\x46\xf6\x76\x3d\xba\xeb\xf5\x8c\x91\xc9\xd6\x6e\xf6\ +\x7a\xb7\xfa\xa3\xb4\xbe\x70\xdb\xee\xe7\xb9\xfa\xca\xf4\xc7\x3e\ +\xfe\x02\x7d\xe7\xea\x43\x57\x5f\x5e\xa0\x4f\x27\x4e\x7b\x6a\x64\ +\xbd\xd4\x81\xed\xc3\xb6\xab\xcf\x5d\x7d\xef\xda\x03\xd7\x5e\xd0\ +\x81\xa5\xf6\x64\xe1\x6d\x4d\x07\x96\xec\x91\x6b\xaf\x5c\x7b\xe6\ +\xda\xbb\xb3\xae\x61\x76\xdb\xae\x3d\x75\xed\xad\x6b\x8f\x5d\x7b\ +\x3d\xb3\xed\xff\x03\xa4\x68\xdb\xc8\ +" + +qt_resource_name = b"\ +\x00\x0b\ +\x0a\xb8\x56\x7f\ +\x00\x66\ +\x00\x61\x00\x76\x00\x69\x00\x63\x00\x6f\x00\x6e\x00\x2e\x00\x69\x00\x63\x00\x6f\ +" + +qt_resource_struct_v1 = b"\ +\x00\x00\x00\x00\x00\x02\x00\x00\x00\x01\x00\x00\x00\x01\ +\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\ +" + +qt_resource_struct_v2 = b"\ +\x00\x00\x00\x00\x00\x02\x00\x00\x00\x01\x00\x00\x00\x01\ +\x00\x00\x00\x00\x00\x00\x00\x00\ +\x00\x00\x00\x00\x00\x01\x00\x00\x00\x01\x00\x00\x00\x00\ +\x00\x00\x01\x65\xeb\xd5\xeb\xa7\ +" + +qt_version = [int(v) for v in QtCore.qVersion().split('.')] +if qt_version < [5, 8, 0]: + rcc_version = 1 + qt_resource_struct = qt_resource_struct_v1 +else: + rcc_version = 2 + qt_resource_struct = qt_resource_struct_v2 + +def qInitResources(): + QtCore.qRegisterResourceData(rcc_version, qt_resource_struct, qt_resource_name, qt_resource_data) + +def qCleanupResources(): + QtCore.qUnregisterResourceData(rcc_version, qt_resource_struct, qt_resource_name, qt_resource_data) + +qInitResources() diff --git a/main.py b/main.py new file mode 100644 index 0000000..0392d54 --- /dev/null +++ b/main.py @@ -0,0 +1,10 @@ +import sys +from PyQt5.QtWidgets import QApplication +from gui.mainwindow import MainWindow + +if __name__ == '__main__': + + app = QApplication(sys.argv) + main_window = MainWindow() + main_window.show() + sys.exit(app.exec_()) \ No newline at end of file