forked from Mysterie/uncompyle2
-
Notifications
You must be signed in to change notification settings - Fork 0
/
uncompyle2.py
executable file
·187 lines (168 loc) · 5.94 KB
/
uncompyle2.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
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
#!/usr/bin/env python2.7
# Mode: -*- python -*-
#
# Copyright (c) 2000-2002 by hartmut Goebel <h.goebel@crazy-compilers.com>
#
'''
Usage: uncompyle [OPTIONS]... [ FILE | DIR]...
Examples:
uncompyle foo.pyc bar.pyc # uncompyle foo.pyc, bar.pyc to stdout
uncompyle -o . foo.pyc bar.pyc # uncompyle to ./foo.dis and ./bar.dis
uncompyle -o /tmp /usr/lib/python1.5 # uncompyle whole library
Options:
-o <path> output decompiled files to this path:
if multiple input files are decompiled, the common prefix
is stripped from these names and the remainder appended to
<path>
uncompyle -o /tmp bla/fasel.pyc bla/foo.pyc
-> /tmp/fasel.dis, /tmp/foo.dis
uncompyle -o /tmp bla/fasel.pyc bar/foo.pyc
-> /tmp/bla/fasel.dis, /tmp/bar/foo.dis
uncompyle -o /tmp /usr/lib/python1.5
-> /tmp/smtplib.dis ... /tmp/lib-tk/FixTk.dis
-c <file> attempts a disassembly after compiling <file>
-d do not print timestamps
-p <integer> use <integer> number of processes
-r recurse directories looking for .pyc and .pyo files
--verify compare generated source with input byte-code
(requires -o)
--help show this message
Debugging Options:
--showasm -a include byte-code (disables --verify)
--showast -t include AST (abstract syntax tree) (disables --verify)
Extensions of generated files:
'.dis' successfully decompiled (and verified if --verify)
'.dis_unverified' successfully decompile but --verify failed
'.nodis' uncompyle failed (contact author for enhancement)
'''
Usage_short = \
"decomyple [--help] [--verify] [--showasm] [--showast] [-o <path>] FILE|DIR..."
import sys, os, getopt
import os.path
from uncompyle2 import main, verify
import time
if sys.version[:3] != '2.7':
print >>sys.stderr, 'Error: uncompyle2 requires Python 2.7.'
sys.exit(-1)
showasm = showast = do_verify = numproc = recurse_dirs = 0
outfile = '-'
out_base = None
codes = []
timestamp = True
timestampfmt = "# %Y.%m.%d %H:%M:%S %Z"
try:
opts, files = getopt.getopt(sys.argv[1:], 'hatdro:c:p:',
['help', 'verify', 'showast', 'showasm'])
except getopt.GetoptError, e:
print >>sys.stderr, '%s: %s' % (os.path.basename(sys.argv[0]), e)
sys.exit(-1)
for opt, val in opts:
if opt in ('-h', '--help'):
print __doc__
sys.exit(0)
elif opt == '--verify':
do_verify = 1
elif opt in ('--showasm', '-a'):
showasm = 1
do_verify = 0
elif opt in ('--showast', '-t'):
showast = 1
do_verify = 0
elif opt == '-o':
outfile = val
elif opt == '-d':
timestamp = False
elif opt == '-c':
codes.append(val)
elif opt == '-p':
numproc = int(val)
elif opt == '-r':
recurse_dirs = 1
else:
print opt
print Usage_short
sys.exit(1)
# expand directory if specified
if recurse_dirs:
expanded_files = []
for f in files:
if os.path.isdir(f):
for root, _, dir_files in os.walk(f):
for df in dir_files:
if df.endswith('.pyc') or df.endswith('.pyo'):
expanded_files.append(os.path.join(root, df))
files = expanded_files
# argl, commonprefix works on strings, not on path parts,
# thus we must handle the case with files in 'some/classes'
# and 'some/cmds'
src_base = os.path.commonprefix(files)
if src_base[-1:] != os.sep:
src_base = os.path.dirname(src_base)
if src_base:
sb_len = len( os.path.join(src_base, '') )
files = map(lambda f: f[sb_len:], files)
del sb_len
if outfile == '-':
outfile = None # use stdout
elif outfile and os.path.isdir(outfile):
out_base = outfile; outfile = None
elif outfile and len(files) > 1:
out_base = outfile; outfile = None
if timestamp:
print time.strftime(timestampfmt)
if numproc <= 1:
try:
result = main(src_base, out_base, files, codes, outfile, showasm, showast, do_verify)
print '# decompiled %i files: %i okay, %i failed, %i verify failed' % result
except (KeyboardInterrupt):
pass
except verify.VerifyCmpError:
raise
else:
from multiprocessing import Process, Queue
from Queue import Empty
fqueue = Queue(len(files)+numproc)
for f in files:
fqueue.put(f)
for i in range(numproc):
fqueue.put(None)
rqueue = Queue(numproc)
def process_func():
try:
(tot_files, okay_files, failed_files, verify_failed_files) = (0,0,0,0)
while 1:
f = fqueue.get()
if f == None:
break
(t, o, f, v) = \
main(src_base, out_base, [f], codes, outfile, showasm, showast, do_verify)
tot_files += t
okay_files += o
failed_files += f
verify_failed_files += v
except (Empty, KeyboardInterrupt):
pass
rqueue.put((tot_files, okay_files, failed_files, verify_failed_files))
rqueue.close()
try:
procs = [Process(target=process_func) for i in range(numproc)]
for p in procs:
p.start()
for p in procs:
p.join()
try:
(tot_files, okay_files, failed_files, verify_failed_files) = (0,0,0,0)
while 1:
(t, o, f, v) = rqueue.get(False)
tot_files += t
okay_files += o
failed_files += f
verify_failed_files += v
except Empty:
pass
print '# decompiled %i files: %i okay, %i failed, %i verify failed' % \
(tot_files, okay_files, failed_files, verify_failed_files)
except (KeyboardInterrupt, OSError):
pass
if timestamp:
print time.strftime(timestampfmt)