Browse Source

Cleanup with help from pylint, etc

master
Ben Kurtovic 12 years ago
parent
commit
8cff89f8c7
1 changed files with 90 additions and 100 deletions
  1. +90
    -100
      func_smash.py

+ 90
- 100
func_smash.py View File

@@ -1,47 +1,15 @@
from code import interact
import imp import imp
import opcode import opcode
import os import os
import random import random
import re import re
import sys import sys
import traceback
import types import types


MARKOV_START = -1 MARKOV_START = -1
MARKOV_END = -2 MARKOV_END = -2


def run():
try:
path, name = os.path.split(sys.argv[1])
name = re.sub("\.pyc?$", "", name)
except IndexError:
raise RuntimeError("Needs a filename as a command-line argument")
f, path, desc = imp.find_module(name, [path])
try:
module = imp.load_module(name, f, path, desc)
finally:
f.close()

corpus = module.corpus
chain = make_chain(corpus)
func = make_function(chain, "func")
print "Using {0}-function corpus.".format(len(corpus))
print "Smashed function disassembly:"
print_function(func)
print
n = 12.0
print "func(%s) =" % n, func(n)
if len(sys.argv) > 2 and sys.argv[2] == "-i": # Allow input after the fact
print
while 1:
try:
input(">>> ")
except EOFError:
break
except Exception:
traceback.print_exc()

def make_chain(funcs): def make_chain(funcs):
chain = {} chain = {}
for func in funcs: for func in funcs:
@@ -50,87 +18,96 @@ def make_chain(funcs):


def make_function(chain, name, argcount=1): def make_function(chain, name, argcount=1):
codes, constants, varnames = _make_codes(chain) codes, constants, varnames = _make_codes(chain)
nlocals = len(varnames)
stacksize = 1024 # High limit?
flags = 0 # Denotes funcs with *args and/or **kwargs; nothing for now
codestring = "".join([chr(code) for code in codes])
names = () names = ()
filename = "<smash>"
firstlineno = 1
codestring = "".join([chr(code) for code in codes])
lnotab = "" lnotab = ""


code = types.CodeType(argcount, nlocals, stacksize, flags, codestring,
constants, names, varnames, filename, name,
firstlineno, lnotab)
code = types.CodeType(argcount, len(varnames), 1024, 0, codestring,
constants, names, varnames, "<smash>", name, 1,
lnotab)
func = types.FunctionType(code, globals(), name) func = types.FunctionType(code, globals(), name)
return func return func


def print_chain(chain): def print_chain(chain):
print "{" print "{"
for key in sorted(chain.keys()):
op = _int_to_opname(key)
targets = {}
for op2 in chain[key]:
target = _int_to_opname(op2[0])
if op2[0] >= opcode.HAVE_ARGUMENT:
target = "{0}({1})".format(target, op2[1])
for code in sorted(chain.keys()):
name = _opcode_to_opname(code)
target_counts = {}
for tcode in chain[code]:
target = _opcode_to_opname(tcode[0])
if tcode[0] >= opcode.HAVE_ARGUMENT:
target = "{0}({1})".format(target, tcode[1])
try: try:
targets[target] += 1
target_counts[target] += 1
except KeyError: except KeyError:
targets[target] = 1
targs = []
for optarget, count in targets.iteritems():
target_counts[target] = 1
targets = []
for target, count in target_counts.iteritems():
if count == 1: if count == 1:
targs.append(optarget)
targets.append(target)
else: else:
targs.append("{0}x {1}".format(count, optarget))
targs.sort()
print op.rjust(20), "=> [{0}]".format(", ".join(targs))
targets.append("{0}x {1}".format(count, target))
targets.sort()
print name.rjust(20), "=> [{0}]".format(", ".join(targets))
print "}" print "}"


def print_function(func): def print_function(func):
co = func.__code__
code = co.co_code
n = len(code)
codeobj = func.__code__
codestring = codeobj.co_code
length = len(codestring)
i = 0 i = 0
while i < n:
op = ord(code[i])
while i < length:
code = ord(codestring[i])
i += 1 i += 1
print opcode.opname[op].rjust(20),
if op >= opcode.HAVE_ARGUMENT:
arg = _get_argument(co, code, i, op)
print opcode.opname[code].rjust(20),
if code >= opcode.HAVE_ARGUMENT:
arg = _get_argument(codeobj, codestring, i, code)
i += 2 i += 2
print " ({0})".format(arg) print " ({0})".format(arg)
else: else:
print print


def run():
try:
path, name = os.path.split(sys.argv[1])
name = re.sub("\.pyc?$", "", name)
except IndexError:
raise RuntimeError("Needs a filename as a command-line argument")
file_obj, path, desc = imp.find_module(name, [path])
try:
module = imp.load_module(name, file_obj, path, desc)
finally:
file_obj.close()

_demo(module.corpus)

def _parse_func(func, chain): def _parse_func(func, chain):
co = func.__code__
code = co.co_code
n = len(code)
codeobj = func.__code__
codestring = codeobj.co_code
length = len(codestring)
i = 0 i = 0
lastop = MARKOV_START
while i < n:
op = ord(code[i])
prevcode = MARKOV_START
while i < length:
code = ord(codestring[i])
i += 1 i += 1
if op >= opcode.HAVE_ARGUMENT:
arg = _get_argument(co, code, i, op)
if code >= opcode.HAVE_ARGUMENT:
arg = _get_argument(codeobj, codestring, i, code)
i += 2 i += 2
else: else:
arg = None arg = None
_chain_append(chain, lastop, (op, arg))
lastop = op
_chain_append(chain, op, (MARKOV_END, None))
def _get_argument(co, code, i, op):
oparg = ord(code[i]) + ord(code[i + 1]) * 256
if op in opcode.hasconst:
return co.co_consts[oparg]
elif op in opcode.haslocal:
return co.co_varnames[oparg]
elif op in opcode.hascompare:
return opcode.cmp_op[oparg]
raise NotImplementedError(op, opcode.opname[op])
_chain_append(chain, prevcode, (code, arg))
prevcode = code
_chain_append(chain, code, (MARKOV_END, None))
def _get_argument(codeobj, codestring, i, code):
arg = ord(codestring[i]) + ord(codestring[i + 1]) * 256
if code in opcode.hasconst:
return codeobj.co_consts[arg]
elif code in opcode.haslocal:
return codeobj.co_varnames[arg]
elif code in opcode.hascompare:
return opcode.cmp_op[arg]
raise NotImplementedError(code, opcode.opname[code])


def _chain_append(chain, first, second): def _chain_append(chain, first, second):
try: try:
@@ -140,37 +117,50 @@ def _chain_append(chain, first, second):


def _make_codes(chain): def _make_codes(chain):
codes = [] codes = []
code = random.choice(chain[MARKOV_START])
instruction = random.choice(chain[MARKOV_START])
constants, varnames = [], [] constants, varnames = [], []
while 1: while 1:
op, arg = code
if op == MARKOV_END:
code, arg = instruction
if code == MARKOV_END:
break break
codes.append(op)
if op >= opcode.HAVE_ARGUMENT:
if op in opcode.hasconst:
codes.append(code)
if code >= opcode.HAVE_ARGUMENT:
if code in opcode.hasconst:
if arg not in constants: if arg not in constants:
constants.append(arg) constants.append(arg)
args = constants args = constants
elif op in opcode.haslocal:
elif code in opcode.haslocal:
if arg not in varnames: if arg not in varnames:
varnames.append(arg) varnames.append(arg)
args = varnames args = varnames
elif op in opcode.hascompare:
elif code in opcode.hascompare:
args = opcode.cmp_op args = opcode.cmp_op
else: else:
raise NotImplementedError(op, opcode.opname[op])
raise NotImplementedError(code, opcode.opname[code])
codes.append(args.index(arg) % 256) codes.append(args.index(arg) % 256)
codes.append(args.index(arg) // 256) codes.append(args.index(arg) // 256)
code = random.choice(chain[op])
instruction = random.choice(chain[code])
return codes, tuple(constants), tuple(varnames) return codes, tuple(constants), tuple(varnames)


def _int_to_opname(op):
if op == MARKOV_START:
def _opcode_to_opname(code):
if code == MARKOV_START:
return "START" return "START"
elif op == MARKOV_END:
elif code == MARKOV_END:
return "END" return "END"
return opcode.opname[op]
return opcode.opname[code]

def _demo(corpus, arg=12.0):
chain = make_chain(corpus)
func = make_function(chain, "func")
print "Using {0}-function corpus.".format(len(corpus))
print "Smashed function disassembly:"
print_function(func)
print
print "func({0}) =".format(arg), func(arg)

if len(sys.argv) > 2 and sys.argv[2] == "-i":
variables = dict(globals().items() + locals().items())
interact(banner="", local=variables)


if __name__ == "__main__": if __name__ == "__main__":
run() run()

Loading…
Cancel
Save