cemu-idapython/python/init.py

228 lines
6.6 KiB
Python

#!/usr/bin/env python
#------------------------------------------------------------
# IDAPython - Python plugin for Interactive Disassembler Pro
#
# Copyright (c) 2004-2009 Gergely Erdelyi <dyce@d-dome.net>
#
# All rights reserved.
#
# For detailed copyright information see the file COPYING in
# the root of the distribution archive.
#------------------------------------------------------------
# init.py - Essential init routines
#------------------------------------------------------------
import os
import sys
import time
import warnings
import _idaapi
__EA64__ = _idaapi.BADADDR == 0xFFFFFFFFFFFFFFFFL
# FIXME: Should fix the offending constant instead
warnings.filterwarnings('ignore', category=FutureWarning)
def addscriptpath(script):
"""
Add the path part of the scriptfile to the system path to
allow modules to be loaded from the same place.
Each path is added only once.
"""
pathfound = 0
scriptpath = os.path.dirname(script)
for pathitem in sys.path:
if pathitem == scriptpath:
pathfound = 1
break
if pathfound == 0:
sys.path.append(scriptpath)
# Add the script to ScriptBox if it's not there yet
if not script in scriptbox.list:
scriptbox.list.insert(0, script)
def runscript(script):
"""
Run the specified script after adding its directory path to
system path.
This function is used by the low-level plugin code.
"""
addscriptpath(script)
watchdog.reset()
argv = sys.argv
sys.argv = [ script ]
# Adjust the __file__ path in the globals we pass to the script
g = globals()
old__file__ = g['__file__']
g['__file__'] = script
try:
execfile(script, g)
except:
raise
finally:
g['__file__'] = old__file__
def print_banner():
version1 = "Python interpreter version %d.%d.%d %s (serial %d)" % sys.version_info
version2 = "Copyright (c) 1990-2009 Python Software Foundation - http://www.python.org/"
if __EA64__:
version3 = "IDAPython 64-bit"
else:
version3 = "IDAPython"
version3 += " version %d.%d.%d %s (serial %d)" % IDAPYTHON_VERSION
version4 = "Copyright (c) 2004-2009 Gergely Erdelyi - http://d-dome.net/idapython/"
linelen = max(len(version1), len(version2), len(version3), len(version4))
print '-' * linelen
print version1
print version2
print
print version3
print version4
print '-' * linelen
#-----------------------------------------------------------
# Take over the standard text outputs
#-----------------------------------------------------------
class MyStdOut:
"""
Dummy file-like class that receives stout and stderr
"""
def write(self, text):
# Swap out the unprintable characters
text = text.decode('ascii', 'replace').encode('ascii', 'replace')
_idaapi.msg(text.replace("%", "%%"))
def flush(self):
pass
def isatty(self):
return False
# Redirect stderr and stdout to the IDA message window
sys.stdout = sys.stderr = MyStdOut()
# Assign a default sys.argv
sys.argv = [ "" ]
# Have to make sure Python finds our modules
if _idaapi.idainfo_is_64bit(_idaapi.cvar.inf):
pythonDir = "python64"
else:
pythonDir = "python"
sys.path.append(_idaapi.idadir(pythonDir))
print_banner()
#-----------------------------------------------------------
# Import all the required modules
#-----------------------------------------------------------
from idaapi import Choose, get_user_idadir, cvar
from idc import *
from idautils import *
#-----------------------------------------------------------
# Build up the ScriptBox tool
#-----------------------------------------------------------
class ScriptBox(Choose):
def __init__(self, list=None):
if list:
self.list = list
else:
self.list = []
Choose.__init__(self, self.list, "ScriptBox", 1)
self.width = 50
def run(self):
if len(self.list) == 0:
Warning("ScriptBox history is empty.\nRun some script with Alt-9 and try again.")
return None
n = self.choose()
if n > 0:
return self.list[n-1]
else:
return None
def addscript(self, scriptpath):
self.list.append(scriptpath)
scriptbox = ScriptBox()
#-------------------------------------------------------------
# Watchdog to catch runaway scripts after a specified timeout
#
# Usage:
# watchdog.install()
# watchdog.activate(10) # Use 10-second timeout
#
# Note: The watchdog only works for code running inside
# functions, not in global/module namespace.
#-------------------------------------------------------------
class WatchDog():
"""
Python tracer-based watchdog class
"""
def __init__(self, timeout=10):
self.timestamp = 0
self.timeout = timeout
self.installed = False
self.active = False
def install(self):
""" Install the tracer function, required for the watchdog """
if not self.installed:
sys.settrace(self.tracer)
self.installed = True
def activate(self, timeout=None):
""" Activate the watchdog, with optional timeout change """
assert self.installed, "WatchDog must be installed before activating"
if timeout:
self.timeout = timeout
self.reset()
self.active = True
def deactivate(self):
""" Deactivate the watchdog """
self.active = True
def reset(self):
""" Reset the timer, useful for long-running scripts """
self.timestamp = time.clock()
def tracer(self, frame, event, arg):
""" Tracer function that receives the tracing events """
if not self.active:
return None
if event == 'line':
if time.clock() - self.timestamp > self.timeout:
if AskYN(0, "The script has not finished in %d seconds\nWould you like to stop it now?" % self.timeout) == 1:
raise KeyboardInterrupt
else:
self.timestamp = time.clock()
return self.tracer
watchdog = WatchDog(10)
# Load the users personal init file
userrc = get_user_idadir() + os.sep + "idapythonrc.py"
if os.path.exists(userrc):
runscript(userrc)
# Remove the user script from the history
del scriptbox.list[0]
# All done, ready to rock.