In developing a RESTful API for IDA >= 7.5 [https://github.com/sfinktah/idarest75], I have observed that a standard threaded webserver does not release it's socket when IDA terminates, unless it is run as a plugin. This behaviour may extend to all threading, I have not tested.
If the code below is simply loaded as a script (or pasted into the CLI) it will actually cause IDA to invisibly hang when IDA is exited, i.e. IDA appears to close but can actually found to be still running in Task Explorer -> Details.
Is there perhaps an IDA-specific atexit
analog, as the builtin Python version certainly does not help.
Whilst the finished project is capable of running either as a plugin or a stand-alone script, the lack of any way to unload a python plugin requires keeping a reference to the class instance in order to call .term()
, which is contra-indicated if one actually expects destruction to occur correctly.
Sample code (paste, exit IDA, observe running tasks).
def ida_issue():
from http.server import BaseHTTPRequestHandler, HTTPServer
from socketserver import ThreadingMixIn
import threading
class Handler(BaseHTTPRequestHandler):
def do_GET(self):
self.send_response(200)
self.end_headers()
class ThreadedHTTPServer(ThreadingMixIn, HTTPServer):
allow_reuse_address = True
class Worker(threading.Thread):
def __init__(self, host, port):
threading.Thread.__init__(self)
self.httpd = ThreadedHTTPServer((host, port), Handler)
self.host = host
self.port = port
def run(self):
self.httpd.serve_forever()
def stop(self):
self.httpd.shutdown()
self.httpd.server_close()
class Master:
def __init__(self):
self.worker = Worker('127.0.0.1', 28612)
self.worker.start()
def main():
master = Master()
return master
return main()
server = ida_issue()
How to re/unload [co-operative] IDAPython plugins.
class idarest_plugin_t(IdaRestConfiguration, ida_idaapi.plugin_t):
flags = ida_idaapi.PLUGIN_UNL
def run(self, *args):
pass
def reload_idarest():
l = ida_loader.load_plugin(sys.modules['__plugins__idarest_plugin'].__file__)
ida_load.run_plugin(l, 0)
# pip install exectools (or ida_idaapi.require would probably suffice)
unload('idarest_plugin')
# reload plugin (or not)
l = ida_loader.load_plugin(sys.modules['__plugins__idarest_plugin'].__file__)