-
Notifications
You must be signed in to change notification settings - Fork 6
/
monkeyhex.py
144 lines (123 loc) · 3.95 KB
/
monkeyhex.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
from __future__ import print_function
from future.utils import iteritems
from past.builtins import long
DEFAULT_HEX_THRESHOLD = 10**17 # since that hex is more succinct ...
HEX_THRESHOLD = None
ENABLED = True
def conditional_hex(x):
if ENABLED and (HEX_THRESHOLD is None or abs(x) >= HEX_THRESHOLD):
return hex(x)
return repr(x)
def maybe_hex(item, list_depth=0):
if isinstance(item, bool):
return repr(item)
if isinstance(item, (int, long)):
if _monkeyhex_idapy:
return '%X' % item
else:
return conditional_hex(item)
elif isinstance(item, (list,)):
return '[%s]' % joinlist(item, list_depth + 1)
elif isinstance(item, (set,)):
return '{%s}' % joinlist(item, list_depth + 1)
elif isinstance(item, (dict,)):
return '{%s}' % joindict(item, list_depth + 1)
elif isinstance(item, (tuple,)):
return '(%s)' % joinlist(item, list_depth + 1)
else:
return repr(item)
def get_joiner(lst, list_depth):
joiner = ',\n' if len(repr(lst)) > 80 and len(lst) < 400 else ', '
if joiner[1] == '\n':
joiner += ' '*list_depth
return joiner
def joinlist(lst, list_depth):
return get_joiner(lst, list_depth).join(maybe_hex(a, list_depth) for a in lst)
def joindict(dct, list_depth):
return get_joiner(dct, list_depth).join(
'%s: %s' % (maybe_hex(key, list_depth), maybe_hex(val, list_depth))
for key, val in iteritems(dct)
)
def hex_print(item):
if type(item) is bool:
old_display_hook(item)
return
elif item is None:
old_display_hook(item)
return
try:
class hexprinted(type(item)):
def __repr__(self):
return maybe_hex(item)
old_display_hook(hexprinted(item))
except:
old_display_hook(item)
# detect ipython
ipython = False
import inspect
for frame in inspect.stack():
if 'IPython' in frame[1]:
ipython = True
_monkeyhex_idapy = False
# detect idapy - note: requires ida 7.3+
try:
import idaapi
_monkeyhex_idapy = True
except:
pass
# monkeypatch the interpreter
if ipython:
import IPython
from IPython.core.magic import register_line_magic
formatter = IPython.get_ipython().display_formatter.formatters['text/plain']
formatter.for_type(int, lambda n, p, cycle: p.text(conditional_hex(n)))
if long is not int:
formatter.for_type(long, lambda n, p, cycle: p.text(conditional_hex(n)))
try:
@register_line_magic
def hexoff(line):
"""Turn off MonkeyHex"""
global ENABLED
ENABLED = False
@register_line_magic
def hexon(line):
"""Turn on MonkeyHex"""
global ENABLED
ENABLED = True
except NameError:
pass
else:
import sys
old_display_hook = sys.displayhook
sys.displayhook = hex_print
# monkeypatch pprint
import pprint
try:
old_safe_repr = pprint._safe_repr
def safe_hex_repr(obj, *args, **kwargs):
if type(obj) in (int, long):
return conditional_hex(obj), False, False
else:
return old_safe_repr(obj, *args, **kwargs)
pprint._safe_repr = safe_hex_repr
except AttributeError:
old_safe_repr = pprint.PrettyPrinter._safe_repr
def safe_hex_repr(self, obj, *args, **kwargs):
if type(obj) in (int, long):
return conditional_hex(obj), False, False
else:
return old_safe_repr(self, obj, *args, **kwargs)
pprint.PrettyPrinter._safe_repr = safe_hex_repr
# monkeypatch pdb/ipdb "p" command
import pdb
def hex_p(self, arg):
try:
print(maybe_hex(self._getval(arg)), file=self.stdout)
except: # pylint: disable=bare-except
pass
pdb.Pdb.do_p = hex_p
# monkeypatch ipdb/ipdb bang-escape
def simple_displayhook(self, obj): # pylint: disable=unused-argument
if obj is not None:
print(maybe_hex(obj))
pdb.Pdb.displayhook = simple_displayhook