diff --git a/.github/workflows/build-ci.yml b/.github/workflows/build-ci.yml index 837ddc1b4..6ab9b2bf3 100644 --- a/.github/workflows/build-ci.yml +++ b/.github/workflows/build-ci.yml @@ -10,21 +10,18 @@ jobs: fail-fast: false matrix: #os: [windows-2019, macos-10.15, ubuntu-18.04, ubuntu-20.04] - os: [windows-latest, ubuntu-18.04, ubuntu-20.04] - python-version: [3.8, 3.9] - exclude: - - os: ubuntu-18.04 - python-version: 3.9 + os: [windows-latest, ubuntu-20.04] + python-version: [3.8, 3.9] include: - os: ubuntu-18.04 python-version: 3.9 container: Docker steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Set up Python - uses: actions/setup-python@v2 + uses: actions/setup-python@v4 with: python-version: ${{ matrix.python-version }} @@ -80,7 +77,7 @@ jobs: cd ../qiling cd ../examples/rootfs/x86_linux/kernel && unzip -P infected m0hamed_rootkit.ko.zip cd ../../../../ - pip3 install -e .[evm,RE,tui] + pip3 install -e .[evm,RE] if [ ${{ matrix.os }} == 'ubuntu-18.04' ] and [ ${{ matrix.python-version }} == '3.9' ]; then docker run -it --rm -v ${GITHUB_WORKSPACE}:/qiling qilingframework/qiling:dev bash -c "cd tests && ./test_onlinux.sh" diff --git a/qltool b/qltool index 5f358dab2..be6a52d3f 100755 --- a/qltool +++ b/qltool @@ -9,7 +9,6 @@ import sys import ast import pickle from pprint import pprint -import qltui from unicorn import __version__ as uc_ver from qiling import __version__ as ql_ver @@ -199,6 +198,7 @@ if __name__ == '__main__': # set "qltui" subcommand qltui_parser = commands.add_parser('qltui', help='show qiling Terminal User Interface', add_help=False) + qltui_enabled = False comm_parser = run_parser if len(sys.argv) > 1 and sys.argv[1] == 'code': @@ -229,7 +229,9 @@ if __name__ == '__main__': handle_examples(parser) if options.subcommand == 'qltui': + import qltui options = qltui.get_data() + qltui_enabled = True # ql file setup if options.subcommand == 'run': @@ -259,17 +261,16 @@ if __name__ == '__main__': # ql run with cov_utils.collect_coverage(ql, options.coverage_format, options.coverage_file): - if options.subcommand == 'qltui': + if qltui_enabled: hook_dictionary = qltui.hook(ql) ql.run(timeout=options.timeout) if options.json: report = report.generate_report(ql) - report["syscalls"] = qltui.transform_syscalls(ql.os.stats.syscalls) - if options.subcommand == 'qltui': + if qltui_enabled: + report["syscalls"] = qltui.transform_syscalls(ql.os.stats.syscalls) qltui.show_report(ql, report, hook_dictionary) else: pprint(report) - exit(ql.os.exit_code) diff --git a/qltui.py b/qltui.py index e15c26b0a..8e841881f 100644 --- a/qltui.py +++ b/qltui.py @@ -4,15 +4,14 @@ import re import six import argparse -from json2html import * -import pdfkit -from pyfx import PyfxApp import json + +from pyfx import PyfxApp from pprint import pprint from datetime import datetime import questionary -from questionary import Validator, ValidationError, prompt +from questionary import Validator, ValidationError try: from termcolor import colored except ImportError: @@ -141,21 +140,6 @@ def log(string, color): six.print_(string) -class PdfConverter(object): - """ - Pdf Converter object - """ - - def __init__(self): - pass - - def to_html(self, json_doc): - return json2html.convert(json=json_doc) - - def to_pdf(self, html_str): - return pdfkit.from_string(html_str, None) - - class IntValidator(Validator): """ Integer validator @@ -338,6 +322,8 @@ def ask_additional_options(): """ Ask additional options for run/code """ + options = {} + verbose = questionary.select( "verbose:", choices=list(verbose_map.keys()), @@ -347,15 +333,18 @@ def ask_additional_options(): env = questionary.path("env:", default="{}", validate=ENVFilePathValidator).ask() env = env_arg(env) - gdb = questionary.text("gdb:").ask() - if not gdb: - gdb = None - - qdb = questionary.confirm("qdb:", + debug = questionary.confirm("debug:", default=False, auto_enter=True).ask() + gdb = None + qdb, rr = False, False + if debug: + gdb = questionary.text("\tgdb:").ask() - rr = questionary.confirm("rr:", - default=False, auto_enter=True).ask() + qdb = questionary.confirm("\tqdb:", + default=False, auto_enter=True).ask() + + rr = questionary.confirm("\trr:", + default=False, auto_enter=True).ask() profile = questionary.text("profile:").ask() if not profile: @@ -385,15 +374,18 @@ def ask_additional_options(): default=False, auto_enter=True).ask() timeout = int(questionary.text("profile:", default="0", validate=IntValidator).ask()) - - coverage_file = questionary.path("coverage-file:", validate=FilePathValidator).ask() - if not coverage_file: - coverage_file = None - - coverage_format = questionary.select( - "coverage-format:", - choices=list(cov_utils.factory.formats), - default="drcov").ask() + + coverage = questionary.confirm("coverage:", + default=False, auto_enter=True).ask() + coverage_file = None + coverage_format = "drcov" + if coverage: + coverage_file = questionary.path("\tcoverage-file:", validate=FilePathValidator).ask() + + coverage_format = questionary.select( + "\tcoverage-format:", + choices=list(cov_utils.factory.formats), + default="drcov").ask() json_ = questionary.confirm("json:", default=False, auto_enter=True).ask() @@ -401,13 +393,14 @@ def ask_additional_options(): libcache = questionary.confirm("libcache:", default=False, auto_enter=True).ask() - return {"verbose": verbose, "env": env, "gdb": gdb, "qdb": qdb, - "rr": rr, "profile": profile, "console": console, + options = {"verbose": verbose, "env": env, "gdb": gdb, "qdb": qdb, "rr": rr, "profile": profile, "console": console, "filter": filter_, "log_file": log_file, "log_plain": log_plain, "root": root, "debug_stop": debug_stop, "multithread": multithread, "timeout": timeout, "coverage_file": coverage_file, "coverage_format": coverage_format, "json": json_, "libcache": libcache} + + return options def get_data(): @@ -437,7 +430,8 @@ def get_data(): else: log("Error", ERROR_COLOR) - options = command_options | additional_options + command_options.update(additional_options) + options = command_options options['subcommand'] = command namespace = argparse.Namespace(**options) @@ -451,7 +445,7 @@ def ask_report(): """ answer = questionary.select( "Select an Option:", - choices=['Report', 'Interactive Report', 'Report to PDF', 'Quit']).ask() + choices=['Report', 'Interactive Report', 'Save to Json', 'Quit']).ask() return answer.lower() @@ -481,12 +475,11 @@ def show_report(ql: Qiling, report, hook_dictionary): pprint(report) elif command == 'interactive report': PyfxApp(data=report).run() - elif command == 'report to pdf': + elif command == 'save to json': time = datetime.now().strftime("%Y_%m_%d_%H-%M-%S") - report_name = f"report_{ql.targetname.replace('.', '_')}_{os_name}_{arch_name}_{time}.pdf" - pdfc = PdfConverter() - with open(report_name, "wb") as pdf_fl: - pdf_fl.write(pdfc.to_pdf(pdfc.to_html(json.dumps(report)))) + report_name = f"report_{ql.targetname.replace('.', '_')}_{os_name}_{arch_name}_{time}.json" + with open(report_name, "w") as json_file: + json_file.write(json.dumps(report)) print(f"The report was saved in your current directory as {report_name}") elif command == 'quit': break diff --git a/setup.py b/setup.py index 349b19e34..eca31524a 100644 --- a/setup.py +++ b/setup.py @@ -19,8 +19,6 @@ "multiprocess>=0.70.12.2", "windows-curses>=2.1.0;platform_system=='Windows'", "pyyaml>=6.0", - "json2html", - "pdfkit", "python-fx", "questionary", "termcolor",