| | import os |
| | from typing import Any |
| |
|
| | import frontmatter |
| | import gradio as gr |
| | from gradio_client import Client, handle_file |
| | from tenacity import retry, stop_after_attempt, wait_fixed, before_log, after_log |
| | import logging |
| |
|
| | logging.basicConfig(level=logging.INFO) |
| | logger = logging.getLogger(__name__) |
| |
|
| | SPACE_URL = "https://ejschwartz-ghidrafunctioncppexporter-space.hf.space/" |
| |
|
| | @retry(stop=stop_after_attempt(10), wait=wait_fixed(120), before=before_log(logger, logging.INFO)) |
| | def _connect_client(url: str) -> Client: |
| | return Client(url) |
| |
|
| | client = _connect_client(SPACE_URL) |
| |
|
| |
|
| | def _load_intro_text() -> str: |
| | readme_path = os.path.join(os.path.dirname(__file__), "README.md") |
| | try: |
| | post = frontmatter.load(readme_path) |
| | except (OSError, ValueError): |
| | return "Upload an executable file to get started." |
| |
|
| | return post.content.strip() |
| |
|
| | INTRO_TEXT = _load_intro_text() |
| |
|
| | with gr.Blocks() as demo: |
| | intro = gr.Markdown(INTRO_TEXT) |
| |
|
| | file_widget = gr.File(label="Executable file") |
| |
|
| | with gr.Column(visible=False) as col: |
| | gr.Markdown( |
| | """ |
| | Great, you selected an executable! Now pick the function you would like |
| | to analyze. |
| | """ |
| | ) |
| |
|
| | fun_dropdown = gr.Dropdown( |
| | label="Select a function", choices=["Woohoo!"], interactive=True |
| | ) |
| |
|
| | gr.Markdown( |
| | """ |
| | Below you can find some information. |
| | """ |
| | ) |
| |
|
| | extra_args = gr.Textbox(label="Extra args to export.bash", placeholder="emit_type_definitions false", value="") |
| |
|
| | with gr.Row(visible=True): |
| | disassembly = gr.Code( |
| | label="Disassembly", |
| | lines=20, |
| | max_lines=20, |
| | ) |
| | original_decompile = gr.Code( |
| | language="c", |
| | label="Decompilation", |
| | lines=20, |
| | max_lines=20, |
| | ) |
| |
|
| | examples_dir = os.path.join(os.path.dirname(__file__), "examples") |
| | examples = [f.path for f in os.scandir(examples_dir)] if os.path.isdir(examples_dir) else [] |
| |
|
| | gr.Examples( |
| | examples=examples, |
| | inputs=file_widget, |
| | outputs=[disassembly, original_decompile], |
| | ) |
| |
|
| | @file_widget.change(inputs=file_widget, outputs=[intro, col, fun_dropdown]) |
| | def file_change_fn(file): |
| | if file is None: |
| | return { |
| | intro: INTRO_TEXT, |
| | col: gr.update(visible=False), |
| | fun_dropdown: gr.update(choices=["Woohoo!"], value=None), |
| | } |
| |
|
| | try: |
| | markdown_value, funs = client.predict( |
| | file=handle_file(file), |
| | api_name="/file_change_fn", |
| | ) |
| | except Exception as e: |
| | raise gr.Error(f"Unable to analyze binary with remote app: {e}") |
| |
|
| | return { |
| | intro: markdown_value, |
| | col: gr.update(visible=True), |
| | fun_dropdown: gr.update(**funs), |
| | } |
| |
|
| | @fun_dropdown.change(inputs=[fun_dropdown, extra_args], outputs=[disassembly, original_decompile]) |
| | @extra_args.submit(inputs=[fun_dropdown, extra_args], outputs=[disassembly, original_decompile]) |
| | def function_change_fn(selected_fun, extra_args): |
| |
|
| | if selected_fun is None: |
| | return { |
| | disassembly: "", |
| | original_decompile: "", |
| | } |
| |
|
| | try: |
| | disassembly_str, decompile_str = client.predict( |
| | selected_fun=selected_fun, |
| | extra_args=extra_args, |
| | api_name="/function_change_fn", |
| | ) |
| | except Exception as e: |
| | raise gr.Error(f"Unable to select function {selected_fun} from remote app: {e}") |
| |
|
| | return { |
| | disassembly: disassembly_str, |
| | original_decompile: decompile_str, |
| | } |
| |
|
| |
|
| | demo.queue() |
| | demo.launch(server_name="0.0.0.0", server_port=7860, show_error=True, debug=True) |
| |
|