diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..58200d4 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +__pycache__/ diff --git a/README.md b/README.md index d5659e7..530d85b 100644 --- a/README.md +++ b/README.md @@ -63,3 +63,6 @@ It is also important that attaching a debugger will create a new debugger instan ## Demo ![demo](idacode/images/preview.gif) + +## Contributors +* [mrexodia](https://github.com/mrexodia) \ No newline at end of file diff --git a/ida/idacode.py b/ida/idacode.py index 5603417..5fd4ed3 100644 --- a/ida/idacode.py +++ b/ida/idacode.py @@ -1,47 +1,9 @@ -import socket, sys, os, threading, inspect, asyncio -import tornado, debugpy -import idaapi -import idacode_utils.dbg as dbg -import idacode_utils.hooks as hooks -import idacode_utils.settings as settings -from idacode_utils.socket_handler import SocketHandler +import sys +if sys.version_info < (3, 3): + print("[IDACode] Python 2.7 is not (yet) supported, vote at https://github.com/ioncodes/idacode/issues/3") + sys.exit() -def setup_patches(): - hooks.install() - sys.executable = settings.PYTHON - -def create_socket_handler(): - asyncio.set_event_loop(asyncio.new_event_loop()) - app = tornado.web.Application([ - (r"/ws", SocketHandler), - ]) - server = tornado.httpserver.HTTPServer(app) - print(f"IDACode listening on {settings.HOST}:{settings.PORT}") - server.listen(address=settings.HOST, port=settings.PORT) - -def start_server(): - setup_patches() - create_socket_handler() - tornado.ioloop.IOLoop.current().start() - -class IDACode(idaapi.plugin_t): - def __init__(self): - self.flags = idaapi.PLUGIN_UNL - self.comment = "IDACode" - self.help = "IDACode" - self.wanted_name = "Start IDACode" - self.wanted_hotkey = "" - - def init(self): - return idaapi.PLUGIN_OK - - def run(self, args): - thread = threading.Thread(target=start_server) - thread.daemon = True - thread.start() - - def term(self): - pass +import idacode_utils.plugin as plugin def PLUGIN_ENTRY(): - return IDACode() \ No newline at end of file + return plugin.IDACode() \ No newline at end of file diff --git a/ida/idacode_utils/dbg.py b/ida/idacode_utils/dbg.py index 15c1b33..448c1cc 100644 --- a/ida/idacode_utils/dbg.py +++ b/ida/idacode_utils/dbg.py @@ -14,5 +14,5 @@ def bp(*args): break if condition: if message: - print(message) + print(f"[IDACode] {message}") api.breakpoint() \ No newline at end of file diff --git a/ida/idacode_utils/plugin.py b/ida/idacode_utils/plugin.py new file mode 100644 index 0000000..7f10c82 --- /dev/null +++ b/ida/idacode_utils/plugin.py @@ -0,0 +1,73 @@ +import socket, sys, os, threading, inspect, asyncio, subprocess +try: + import tornado, debugpy +except ImportError: + print("[IDACode] Dependencies missing, run: python3 -m pip install --user debugpy tornado") + sys.exit() +import idaapi +import idacode_utils.dbg as dbg +import idacode_utils.hooks as hooks +import idacode_utils.settings as settings +from idacode_utils.socket_handler import SocketHandler + +VERSION = "0.1.2" +initialized = False + +def setup_patches(): + hooks.install() + sys.executable = settings.PYTHON + +def create_socket_handler(): + asyncio.set_event_loop(asyncio.new_event_loop()) + app = tornado.web.Application([ + (r"/ws", SocketHandler), + ]) + server = tornado.httpserver.HTTPServer(app) + print(f"[IDACode] listening on {settings.HOST}:{settings.PORT}") + server.listen(address=settings.HOST, port=settings.PORT) + +def start_server(): + setup_patches() + create_socket_handler() + tornado.ioloop.IOLoop.current().start() + +def get_python_versions(): + settings_version = subprocess.check_output([settings.PYTHON, "-c", "import sys; print(sys.version + sys.platform)"]) + settings_version = settings_version.decode("utf-8", "ignore").strip() + ida_version = f"{sys.version}{sys.platform}" + return (settings_version, ida_version) + +class IDACode(idaapi.plugin_t): + def __init__(self): + self.flags = idaapi.PLUGIN_UNL + self.comment = "IDACode" + self.help = "IDACode" + self.wanted_name = "IDACode" + self.wanted_hotkey = "" + + def init(self): + global initialized + if not initialized: + initialized = True + if os.path.isfile(settings.PYTHON): + settings_version, ida_version = get_python_versions() + if settings_version != ida_version: + print("[IDACode] settings.PYTHON version mismatch, aborting load:") + print(f"[IDACode] IDA interpreter: {ida_version}") + print(f"[IDACode] settings.PYTHON: {settings_version}") + return idaapi.PLUGIN_SKIP + else: + print(f"[IDACode] settings.PYTHON ({settings.PYTHON}) does not exist, aborting load") + print("[IDACode] To fix this issue, modify idacode_utils/settings.py to point to the python executable") + return idaapi.PLUGIN_SKIP + print(f"[IDACode] Plugin version {VERSION}") + print("[IDACode] Plugin loaded, use Edit -> Plugins -> IDACode to start the server") + return idaapi.PLUGIN_OK + + def run(self, args): + thread = threading.Thread(target=start_server) + thread.daemon = True + thread.start() + + def term(self): + pass \ No newline at end of file diff --git a/ida/idacode_utils/socket_handler.py b/ida/idacode_utils/socket_handler.py index 7407817..e90cd9f 100644 --- a/ida/idacode_utils/socket_handler.py +++ b/ida/idacode_utils/socket_handler.py @@ -16,13 +16,13 @@ def start_debug_server(): if settings.LOGGING: tmp_path = tempfile.gettempdir() debugpy.log_to(tmp_path) - print(f"Logging to {tmp_path} with pattern debugpy.*.log") + print(f"[IDACode] Logging to {tmp_path} with pattern debugpy.*.log") debugpy.listen((settings.HOST, settings.DEBUG_PORT)) - print(f"IDACode debug server listening on {settings.HOST}:{settings.DEBUG_PORT}") + print(f"[IDACode] IDACode debug server listening on {settings.HOST}:{settings.DEBUG_PORT}") class SocketHandler(tornado.websocket.WebSocketHandler): def open(self): - print("IDACode client connected") + print("[IDACode] client connected") def on_message(self, message): message = json.loads(message.decode("utf8")) @@ -30,7 +30,7 @@ def on_message(self, message): if message["event"] == "set_workspace": path = message["path"] hooks.set_script_folder(path) - print(f"Set workspace folder to {path}") + print(f"[IDACode] Set workspace folder to {path}") elif message["event"] == "attach_debugger": start_debug_server() self.write_message({ @@ -39,13 +39,13 @@ def on_message(self, message): elif message["event"] == "execute_script": script = message["path"] env = create_env() - print(f"Executing {script}") + print(f"[IDACode] Executing {script}") idaapi.execute_sync( lambda: idaapi.IDAPython_ExecScript(script, env), idaapi.MFF_WRITE ) else: - print(f"Invalid event {message['event']}") + print(f"[IDACode] Invalid event {message['event']}") def on_close(self): - print("IDACode client disconnected") \ No newline at end of file + print("[IDACode] client disconnected") \ No newline at end of file diff --git a/idacode/CHANGELOG.md b/idacode/CHANGELOG.md index dbe5bcb..dbe2389 100644 --- a/idacode/CHANGELOG.md +++ b/idacode/CHANGELOG.md @@ -8,4 +8,9 @@ ## 0.1.1 -- Added logging support \ No newline at end of file +- Added logging support + +### 0.1.2 + +- Enhanced UX +- Added configuration checks \ No newline at end of file diff --git a/idacode/README.md b/idacode/README.md index b0e4434..59783af 100644 --- a/idacode/README.md +++ b/idacode/README.md @@ -45,4 +45,9 @@ IDACode doesn't support host to VM communication unless the VM uses a shared vol ### 0.1.1 -- Added logging support \ No newline at end of file +- Added logging support + +### 0.1.2 + +- Enhanced UX +- Added configuration checks \ No newline at end of file diff --git a/idacode/package.json b/idacode/package.json index 58538a8..f0ead47 100644 --- a/idacode/package.json +++ b/idacode/package.json @@ -3,7 +3,7 @@ "displayName": "IDACode", "description": "Run and debug your IDA scripts from VS Code", "icon": "images/icon.png", - "version": "0.1.1", + "version": "0.1.2", "publisher": "Layle", "license": "SEE LICENSE IN LICENSE.md", "preview": true, @@ -38,19 +38,19 @@ "commands": [ { "command": "idacode.connectToIDA", - "title": "Connect to IDA" + "title": "IDACode: Connect to IDA" }, { "command": "idacode.attachToIDA", - "title": "Attach a debugger to IDA" + "title": "IDACode: Attach a debugger to IDA" }, { "command": "idacode.connectAndAttachToIDA", - "title": "Connect and attach a debugger to IDA" + "title": "IDACode: Connect and attach a debugger to IDA" }, { "command": "idacode.executeScript", - "title": "Execute script in IDA" + "title": "IDACode: Execute script in IDA" } ], "configuration": { diff --git a/images/commands.png b/images/commands.png index e9cfa28..8d08c20 100644 Binary files a/images/commands.png and b/images/commands.png differ