Add a lot of stuff

This commit is contained in:
ecx86
2018-08-02 06:57:30 -04:00
parent d22ae25852
commit d55d5d2e2c
31 changed files with 5417 additions and 13 deletions

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
plugins/IDASkins.dll Normal file

Binary file not shown.

BIN
plugins/IDASkins64.dll Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

128
plugins/force_lvar_width.py Normal file
View File

@@ -0,0 +1,128 @@
""" Forcibly change the width of an lvar.
Useful for making an lvar smaller (which Hex-Rays does not let you do apparently)
Tags (for search engines):
IDA Pro Hex-Rays make stack variable smaller force variable size decrease width delete variable split up break up variable into smaller
"""
import idautils
import idaapi
import idc
import ida_hexrays
import traceback
force_width_actname = "forcelvarwidth:forcewidth"
class force_width_action_handler_t(idaapi.action_handler_t):
def __init__(self, callback_info):
idaapi.action_handler_t.__init__(self)
self.callback_info = callback_info
def activate(self, ctx):
vdui = idaapi.get_widget_vdui(ctx.widget)
self.callback_info.gui_action_callback(vdui)
return 1
def update(self, ctx):
return idaapi.AST_ENABLE_FOR_WIDGET if \
ctx.widget_type == idaapi.BWN_PSEUDOCODE else \
idaapi.AST_DISABLE_FOR_WIDGET
class hexrays_callback_info(object):
def __init__(self):
self.vu = None
return
def load(self):
return
def save(self):
return
def do_force_width(self, cfunc, insn):
if insn.opname != 'if':
return False
cif = insn.details
if not cif.ithen or not cif.ielse:
return False
idaapi.qswap(cif.ithen, cif.ielse)
cond = idaapi.cexpr_t(cif.expr)
notcond = idaapi.lnot(cond)
cif.expr.swap(notcond)
return True
def gui_action_callback(self, vu):
cfunc = vu.cfunc.__deref__()
if not vu.get_current_item(idaapi.USE_KEYBOARD):
print "Force lvar width: you don't have anything selected"
return False
badlv = vu.item.get_lvar()
if not badlv:
print "Force lvar width: you don't have an lvar selected"
return False
new_width = idc.AskLong(badlv.width, "Enter the new width for " + badlv.name)
if new_width == None: # cancelled
print "Force lvar width: operation cancelled"
return False
if new_width <= 0:
print "Force lvar width: not allowed. Non-positive width will crash IDA"
return False
badlv.set_width(new_width)
print 'Set the type in IDA (Y) for it to apply'
idaapi.process_ui_action('hx:SetType')
# vu.refresh_ctext()
print 'Force lvar width: OK.'
return True
def event_callback(self, event, *args):
if event == idaapi.hxe_populating_popup:
widget, phandle, vu = args
res = idaapi.attach_action_to_popup(vu.ct, None, force_width_actname)
return 0
class ForceLvarWidth(idaapi.plugin_t):
flags = idaapi.PLUGIN_PROC | idaapi.PLUGIN_HIDE
wanted_hotkey = "Shift-W"
comment = "Force lvar width plugin for Hex-Rays decompiler"
help = "There is no one to help you now"
wanted_name = "Hex-Rays lvar width forcer"
def init(self):
if idaapi.init_hexrays_plugin():
i = hexrays_callback_info()
idaapi.register_action(
idaapi.action_desc_t(
force_width_actname,
"Force lvar width",
force_width_action_handler_t(i),
"Shift-W"))
idaapi.install_hexrays_callback(i.event_callback)
print 'Hex-Rays lvar width forcer by ecx86 loaded!'
else:
print 'Force lvar width: Hexrays is not available.'
def term(self):
pass
def run(self, arg):
pass
def PLUGIN_ENTRY():
return ForceLvarWidth()

BIN
plugins/labeless_ida_70.dll Normal file

Binary file not shown.

Binary file not shown.

4
plugins/ret-sync.py Normal file
View File

@@ -0,0 +1,4 @@
from ret_sync_ext_ida import SyncPlugin
def PLUGIN_ENTRY():
return SyncPlugin.SyncPlugin()

File diff suppressed because it is too large Load Diff

View File

View File

@@ -0,0 +1,296 @@
#
# Copyright (C) 2016, Alexandre Gazet.
#
# Copyright (C) 2012-2015, Quarkslab.
#
# This file is part of ret-sync.
#
# ret-sync is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# Note that broker.py is executed by IDA Pro so it is not possible to see
# any output using print() or similar
import os
import sys
import time
import re
import shlex
import argparse
import subprocess
import socket
import select
import binascii
import ConfigParser
try:
import json
except:
print "[-] failed to import json\n%s" % repr(sys.exc_info())
sys.exit(0)
RUN_DISPATCHER_MAX_ATTEMPT = 4
HOST = "localhost"
PORT = 9100
# default value is current script's path
DISPATCHER_PATH = os.path.join(os.path.realpath(os.path.dirname(__file__)), "dispatcher.py")
if not os.path.exists(DISPATCHER_PATH):
print "[-] dispatcher path is not properly set, current value: <%s>" % DISPATCHER_PATH
sys.exit(0)
class Client():
def __init__(self, s):
self.sock = s
self.buffer = ''
def feed(self, data):
batch = []
self.buffer = ''.join([self.buffer, data])
if self.buffer.endswith("\n"):
batch = [req for req in self.buffer.strip().split('\n') if req != '']
self.buffer = ''
return batch
class BrokerSrv():
def puts(self, msg):
print msg
sys.stdout.flush()
def announcement(self, msg):
self.puts("[sync]{\"type\":\"broker\",\"subtype\":\"msg\",\"msg\":\"%s\"}\n" % msg)
def notice_idb(self, msg):
self.puts("[sync]{\"type\":\"broker\",\"subtype\":\"notice\",\"port\":\"%d\"}\n" % msg)
def notice_dispatcher(self, type, args=None):
if args:
notice = "[notice]{\"type\":\"%s\",%s}\n" % (type, args)
else:
notice = "[notice]{\"type\":\"%s\"}\n" % (type)
self.notify_socket.sendall(notice)
def bind(self):
self.srv_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.srv_sock.bind(('localhost', 0))
self.srv_port = self.srv_sock.getsockname()[1]
def run_dispatcher(self):
cmdline = "\"%s\" -u \"%s\"" % (os.path.join(PYTHON_PATH, PYTHON_BIN), DISPATCHER_PATH)
tokenizer = shlex.shlex(cmdline)
tokenizer.whitespace_split = True
args = [arg.replace('\"', '') for arg in list(tokenizer)]
try:
proc = subprocess.Popen(args, shell=False, close_fds=True)
pid = proc.pid
except:
pid = None
self.announcement("failed to run dispatcher")
time.sleep(0.2)
return pid
def notify(self):
for attempt in range(RUN_DISPATCHER_MAX_ATTEMPT):
try:
self.notify_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.notify_socket.connect((HOST, PORT))
break
except:
self.notify_socket.close()
if (attempt != 0):
self.announcement("failed to connect to dispatcher (attempt %d)" % (attempt))
if (attempt == (RUN_DISPATCHER_MAX_ATTEMPT - 1)):
self.announcement("failed to connect to dispatcher, too much attempts, exiting...")
sys.exit()
self.announcement("dispatcher not found, trying to run it")
pid = self.run_dispatcher()
if pid:
self.announcement("dispatcher now runs with pid: %d" % (pid))
time.sleep(0.1)
self.notice_dispatcher("new_client", "\"port\":%d,\"idb\":\"%s\"" % (self.srv_port, self.name))
self.announcement('connected to dispatcher')
self.notice_idb(self.srv_port)
def accept(self):
new_socket, addr = self.srv_sock.accept()
self.clients_list.append(Client(new_socket))
self.opened_sockets.append(new_socket)
def close(self, s):
client = [client for client in self.clients_list if (client.sock == s)]
if len(client) == 1:
self.clients_list.remove(client[0])
s.close()
self.opened_sockets.remove(s)
def recvall(self, client):
try:
data = client.sock.recv(4096)
if data == '':
raise
except:
self.announcement("dispatcher connection error, quitting")
sys.exit()
return client.feed(data)
def req_dispatcher(self, s, hash):
subtype = hash['subtype']
if (subtype == 'msg'):
msg = hash['msg']
self.announcement("dispatcher msg: %s" % msg)
def req_cmd(self, s, hash):
cmd = hash['cmd']
self.notice_dispatcher("cmd", "\"cmd\":\"%s\"" % cmd)
def req_kill(self, s, hash):
self.notice_dispatcher("kill")
self.announcement("received kill notice")
for s in ([self.srv_sock] + self.opened_sockets):
s.close()
sys.exit()
def parse_exec(self, s, req):
if not (req[0:8] == '[notice]'):
self.puts(req)
return
req = self.normalize(req, 8)
try:
hash = json.loads(req)
except:
print "[-] broker failed to parse json\n %s" % repr(req)
return
type = hash['type']
if not type in self.req_handlers:
print ("[*] broker unknown request: %s" % type)
return
req_handler = self.req_handlers[type]
req_handler(s, hash)
def normalize(self, req, taglen):
req = req[taglen:]
req = req.replace("\\", "\\\\")
req = req.replace("\n", "")
return req
def handle(self, s):
client = [client for client in self.clients_list if (client.sock == s)]
if len(client) == 1:
batch = self.recvall(client[0])
else:
self.announcement("socket error")
raise Exception("rabbit eating the cable")
for req in batch:
if req != '':
self.parse_exec(s, req)
def loop(self):
self.srv_sock.listen(5)
while True:
rlist, wlist, xlist = select.select([self.srv_sock] + self.opened_sockets, [], [])
if not rlist:
self.announcement("socket error: select")
raise Exception("rabbit eating the cable")
for s in rlist:
if s is self.srv_sock:
self.accept()
else:
self.handle(s)
def __init__(self, name):
self.name = name
self.opened_sockets = []
self.clients_list = []
self.pat = re.compile('dbg disconnected')
self.req_handlers = {
'dispatcher': self.req_dispatcher,
'cmd': self.req_cmd,
'kill': self.req_kill
}
def err_log(msg):
fd = open("%s.err" % __file__, 'w')
fd.write(msg)
fd.close()
if __name__ == "__main__":
try:
PYTHON_PATH = os.environ['PYTHON_PATH']
PYTHON_BIN = os.environ['PYTHON_BIN']
except Exception as e:
err_log("broker failed to retreive PYTHON_PATH or PYTHON_BIN value.")
sys.exit()
parser = argparse.ArgumentParser()
parser.add_argument('--idb', nargs=1, action='store')
args = parser.parse_args()
if not args.idb:
print "[sync] no idb argument"
sys.exit()
for loc in ['IDB_PATH', 'USERPROFILE', 'HOME']:
if loc in os.environ:
confpath = os.path.join(os.path.realpath(os.environ[loc]), '.sync')
if os.path.exists(confpath):
config = ConfigParser.SafeConfigParser({'port': PORT, 'host': HOST})
config.read(confpath)
PORT = config.getint("INTERFACE", 'port')
HOST = config.get("INTERFACE", 'host')
break
server = BrokerSrv(args.idb[0])
try:
server.bind()
except Exception as e:
server.announcement("failed to bind")
err_log(repr(e))
sys.exit()
try:
server.notify()
except Exception as e:
server.announcement("failed to notify dispatcher")
err_log(repr(e))
sys.exit()
try:
server.loop()
except Exception as e:
server.announcement("broker stop")
err_log(repr(e))

View File

@@ -0,0 +1,463 @@
#
# Copyright (C) 2016, Alexandre Gazet.
#
# Copyright (C) 2012-2014, Quarkslab.
#
# This file is part of ret-sync.
#
# ret-sync is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import os
import os.path as altpath
import sys
import socket
import select
import base64
import binascii
import re
import ConfigParser
import traceback
HOST = 'localhost'
PORT = 9100
try:
import json
except:
print "[-] failed to import json\n%s" % repr(sys.exc_info())
sys.exit(0)
class Client():
def __init__(self, s_client, s_srv, name):
self.client_sock = s_client
self.srv_sock = s_srv
self.name = name
self.enabled = False
self.buffer = ''
def close(self):
self.enabled = False
if self.client_sock:
self.client_sock.close()
if self.srv_sock:
self.srv_sock.close()
def feed(self, data):
batch = []
self.buffer = ''.join([self.buffer, data])
if self.buffer.endswith("\n"):
batch = [req for req in self.buffer.strip().split('\n') if req != '']
self.buffer = ''
return batch
class DispatcherSrv():
def __init__(self):
self.idb_clients = []
self.dbg_client = None
self.srv_socks = []
self.opened_socks = []
self.current_dbg = None
self.current_dialect = 'unknown'
self.current_idb = None
self.current_module = None
self.sync_mode_auto = True
self.disconn_pat = re.compile('dbg disconnected')
self.req_handlers = {
'new_client': self.req_new_client,
'new_dbg': self.req_new_dbg,
'dbg_quit': self.req_dbg_quit,
'idb_n': self.req_idb_n,
'idb_list': self.req_idb_list,
'module': self.req_module,
'sync_mode': self.req_sync_mode,
'cmd': self.req_cmd,
'bc': self.req_bc,
'kill': self.req_kill
}
def bind(self, host, port):
self.dbg_srv_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.dbg_srv_sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
self.dbg_srv_sock.bind((host, port))
self.srv_socks.append(self.dbg_srv_sock)
if not (socket.gethostbyname(host) == '127.0.0.1'):
self.localhost_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.localhost_sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
self.localhost_sock.bind(('localhost', port))
self.srv_socks.append(self.localhost_sock)
def accept(self, s):
new_socket, addr = s.accept()
self.opened_socks.append(new_socket)
def listen(self):
for s in self.srv_socks:
s.listen(5)
def close(self, s):
s.close()
self.opened_socks.remove(s)
def loop(self):
self.listen()
self.announcement("dispatcher listening")
while True:
rlist, wlist, xlist = select.select(self.srv_socks + self.opened_socks, [], [])
if not rlist:
self.announcement("socket error: select")
raise Exception("rabbit eating the cable")
for s in rlist:
if s in self.srv_socks:
self.accept(s)
else:
self.handle(s)
def handle(self, s):
client = self.sock_to_client(s)
for req in self.recvall(client):
self.parse_exec(s, req)
# find client object for its srv socket
def sock_to_client(self, s):
if self.current_dbg and (s == self.current_dbg.srv_sock):
client = self.current_dbg
else:
clist = [client for client in self.idb_clients if (client.srv_sock == s)]
if not clist:
client = Client(None, s, None)
self.idb_clients.append(client)
else:
client = clist[0]
return client
# buffered readline like function
def recvall(self, client):
try:
data = client.srv_sock.recv(4096)
if data == '':
raise
except:
if client == self.current_dbg:
self.broadcast("debugger closed the connection")
self.dbg_quit()
else:
self.client_quit(client.srv_sock)
self.broadcast("a client quit, nb client(s) left: %d" % len(self.idb_clients))
return []
return client.feed(data)
# parse and execute requests from clients (idbs or dbg)
def parse_exec(self, s, req):
if not (req[0:8] == '[notice]'):
# this is a normal [sync] request from debugger, forward it
self.forward(req)
# receive 'dbg disconnected', socket can be closed
if re.search(self.disconn_pat, req):
self.close(s)
return
req = self.normalize(req, 8)
try:
hash = json.loads(req)
except:
print "[-] dispatcher failed to parse json\n %s\n" % req
return
type = hash['type']
if not type in self.req_handlers:
print ("[*] dispatcher unknown request: %s" % type)
return
req_handler = self.req_handlers[type]
req_handler(s, hash)
def normalize(self, req, taglen):
req = req[taglen:]
req = req.replace("\\", "\\\\")
req = req.replace("\n", "")
return req
def puts(self, msg, s):
s.sendall(msg)
# dispatcher announcements are forwarded to the idb
def announcement(self, msg, s=None):
if not s:
if not self.current_idb:
return
s = self.current_idb.client_sock
try:
s.sendall("[notice]{\"type\":\"dispatcher\",\"subtype\":\"msg\",\"msg\":\"%s\"}\n" % msg)
except:
return
# send message to all connected idb clients
def broadcast(self, msg):
for idbc in self.idb_clients:
self.announcement(msg, idbc.client_sock)
# send dbg message to currently active idb client
def forward(self, msg, s=None):
if not s:
if not self.current_idb:
return
s = self.current_idb.client_sock
if s:
s.sendall(msg + "\n")
# send dbg message to all idb clients
def forward_all(self, msg, s=None):
for idbc in self.idb_clients:
self.forward(msg, idbc.client_sock)
# disable current idb and enable new idb matched from current module name
def switch_idb(self, new_idb):
msg = "[sync]{\"type\":\"broker\",\"subtype\":\"%s\"}\n"
if (not self.current_idb == new_idb) & (self.current_idb.enabled):
self.current_idb.client_sock.sendall(msg % "disable_idb")
self.current_idb.enabled = False
if new_idb:
new_idb.client_sock.sendall(msg % "enable_idb")
self.current_idb = new_idb
new_idb.enabled = True
# a new idb client connects to the dispatcher via its broker
def req_new_client(self, srv_sock, hash):
port, name = hash['port'], hash['idb']
try:
client_sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client_sock.connect(('localhost', port))
self.opened_socks.append(client_sock)
except:
self.opened_socks.remove(srv_sock)
srv_sock.close()
return
# check if an idb client is already registered with the same name
conflicting = [client for client in self.idb_clients if (client.name == name)]
# promote to idb client
new_client = self.sock_to_client(srv_sock)
new_client.client_sock = client_sock
new_client.name = name
self.broadcast("add new client (listening on port %d), nb client(s): %d" % (port, len(self.idb_clients)))
if conflicting:
self.broadcast("conflicting name: %s !" % new_client.name)
if not self.current_idb:
self.current_idb = new_client
# if new client match current module name, then enable it
if self.current_module == name:
self.switch_idb(new_client)
# inform new client about debugger's dialect
self.dbg_dialect(new_client)
# clean state when a client is quiting
def client_quit(self, s):
self.opened_socks.remove(s)
# remove exiting client from the list of active clients
for idbc in [idbc for idbc in self.idb_clients if (idbc.srv_sock == s)]:
self.idb_clients.remove(idbc)
self.opened_socks.remove(idbc.client_sock)
idbc.close()
# no more clients, let's kill ourself
if not self.idb_clients:
for s in self.srv_socks:
s.close()
sys.exit()
# determine if debugger is Windows specific
def is_windows_dbg(self, dialect):
return (dialect in ['windbg', 'x64_dbg', 'ollydbg2'])
# a new debugger client connects to the dispatcher
def req_new_dbg(self, s, hash):
msg = hash['msg']
if self.current_dbg:
self.dbg_quit()
# promote to dbg client
self.current_dbg = self.sock_to_client(s)
self.current_dbg.client_sock = s
self.idb_clients.remove(self.current_dbg)
self.broadcast("new debugger client: %s" % msg)
# store dbb's dialect
if 'dialect' in hash:
self.current_dialect = hash['dialect']
# case when IDA is on a linux/bsd host and connected to remote windows
# use ntpath instead of posixpath
if sys.platform.startswith('linux') or sys.platform == 'darwin':
if self.is_windows_dbg(self.current_dialect):
global altpath
import ntpath as altpath
self.dbg_dialect()
# inform client about debugger's dialect
def dbg_dialect(self, client=None):
msg = "[sync]{\"type\":\"dialect\",\"dialect\":\"%s\"}\n" % self.current_dialect
if client:
client.client_sock.sendall(msg)
else:
for idbc in self.idb_clients:
idbc.client_sock.sendall(msg)
# debugger client disconnect from the dispatcher
def req_dbg_quit(self, s, hash):
msg = hash['msg']
self.broadcast("debugger quit: %s" % msg)
self.dbg_quit()
# clean state when debugger is quiting
def dbg_quit(self):
self.opened_socks.remove(self.current_dbg.srv_sock)
self.current_dbg.close()
self.current_dbg = None
self.current_module = None
self.switch_idb(None)
self.current_dialect = 'unknown'
# handle kill notice from a client, exit properly if no more client
def req_kill(self, s, hash):
self.client_quit(s)
self.broadcast("received a kill notice from client, %d client(s) left" % len(self.idb_clients))
# send list of currently connected idb clients
def req_idb_list(self, s, hash):
clist = "> currently connected idb(s):\n"
if not self.idb_clients:
clist += " no idb client yet\n"
else:
for i in range(len(self.idb_clients)):
clist += (" [%d] %s\n" % (i, self.idb_clients[i].name))
s.sendall(clist)
# manually set current active idb to idb n from idb list
def req_idb_n(self, s, hash):
idb = hash['idb']
try:
idbn = int(idb)
except:
s.sendall("> n should be a decimal value")
return
try:
idbc = self.idb_clients[idbn]
except:
s.sendall("> %d is invalid (see idblist)" % idbn)
return
self.switch_idb(idbc)
s.sendall("> current idb set to %d" % idbn)
# dbg notice that its current module has changed
def req_module(self, s, hash):
modpath = hash['path']
self.current_module = modname = altpath.basename(modpath)
matching = [idbc for idbc in self.idb_clients if (idbc.name.lower() == modname.lower())]
if not self.sync_mode_auto:
self.broadcast("sync_mode_auto off")
return
if len(matching) == 1:
# matched is set as active
self.switch_idb(matching[0])
else:
if not len(matching):
msg = "mod request has no match for %s"
else:
msg = "ambiguous mod request, too many matches for %s"
self.broadcast(msg % modname)
# no match current idb (if existing) is disabled
if self.current_idb.enabled:
self.switch_idb(None)
# sync mode tells if idb switch is automatic or manual
def req_sync_mode(self, s, hash):
mode = hash['auto']
self.broadcast("sync mode auto set to %s" % mode)
self.sync_mode_auto = (mode == "on")
# bc request should be forwarded to all idbs
def req_bc(self, s, hash):
msg = "[sync]%s" % json.dumps(hash)
self.forward_all(msg)
def req_cmd(self, s, hash):
cmd = hash['cmd']
self.current_dbg.client_sock.sendall("%s\n" % cmd)
def err_log(msg):
fd = open("%s.err" % __file__, 'w')
fd.write(msg)
fd.close()
if __name__ == "__main__":
server = DispatcherSrv()
for loc in ['IDB_PATH', 'USERPROFILE', 'HOME']:
if loc in os.environ:
confpath = os.path.join(os.path.realpath(os.environ[loc]), '.sync')
if os.path.exists(confpath):
config = ConfigParser.SafeConfigParser({'host': HOST, 'port': PORT})
config.read(confpath)
HOST = config.get("INTERFACE", 'host')
PORT = config.getint("INTERFACE", 'port')
server.announcement("configuration file loaded")
break
try:
server.bind(HOST, PORT)
except Exception as e:
err_log("dispatcher failed to bind on %s:%s\n-> %s" % (HOST, PORT, repr(e)))
sys.exit()
try:
server.loop()
except Exception as e:
err_log("dispatcher failed\n-> %s" % repr(e))
server.announcement("dispatcher stop")