Skip to content

Instantly share code, notes, and snippets.

@SpaceManiac
Created June 5, 2011 17:07
Show Gist options
  • Save SpaceManiac/1009163 to your computer and use it in GitHub Desktop.
Save SpaceManiac/1009163 to your computer and use it in GitHub Desktop.
from solum.jar import JarFile
from solum.classfile.classfile import ClassFile
from solum.bytecode import Disassembler
from cStringIO import StringIO
from glob import glob
from os import path
def find(f, seq):
for item in seq:
if f(item):
return item
return None
def grok(jar, ns=None):
classes = []
fields = []
methods = []
def add(cf):
cf = ClassFile(cf, str_as_buffer=True)
if ns == None or cf.this.find(ns) == 0:
classes.append(cf)
jar.map(add)
for cf in classes:
for c in cf.methods.find():
methods.append([cf, c])
for c in cf.fields.find():
fields.append([cf, c])
return (classes, fields, methods)
def methodSignature(c):
cf = c[0].this.replace("/", ".")
method = c[1]
returns = method.returns
name = method.name
args, sep = "", ""
for arg in method.args:
args += sep + arg
sep = ","
return returns + ":" + cf + "." + name + "(" + args + ")"
def examine(jarfile):
classes, fields, methods = grok(jarfile)
safe = True
for c in methods:
classFile = c[0]
method = c[1]
#print methodSignature(c)
code = method.attributes.find_one(name="Code")
if not code:
continue
dism = Disassembler(StringIO(code.code))
for ins in dism:
n = ins.name
if n in ("invokestatic", "invokespecial", "invokevirtual", "invokeinterface"):
#if n == "invokeinterface":
# print ins.operands[1]
# print classFile.constants[ins.operands[0].value]
# exit()
#else:
call = ins.operands[0][0]
mData = classFile.constants[call]
if not 'name' in mData.keys():
if not 'class' in mData.keys():
print methodSignature(c), n, call, mData
# void:com.sk89q.jnbt.EndTag.<init>() invokespecial 1 {'tag': 8, 'string': {'tag': 1, 'value': ''}, 'string_index': 19}
className = mData['class']['name']['value']
methodName = mData['name_and_type']['name']['value']
else:
fullName = mData['name']['value']
className = path.dirname(fullName)
methodName = path.basename(fullName)
methodClass = find(lambda cf: cf.this == className, bClasses + classes)
if not methodClass:
continue
parent = methodClass.superclass
calledMethod = find(lambda md: md.name == methodName, methodClass.methods.find())
if not calledMethod and n == "invokevirtual":
while not calledMethod:
parent = methodClass.superclass
methodClass = find(lambda cf: cf.this == parent, bClasses + classes)
if not methodClass: break
calledMethod = find(lambda md: md.name == methodName, methodClass.methods.find())
if calledMethod:
sig = methodSignature([methodClass, calledMethod])
if sig.find("craftbukkit") >= 0 or sig.find("net.minecraft") >= 0:
safe = False
elif n.find("invoke") == 0:
pass
return safe
bukkit = JarFile("craftbukkit.jar")
bClasses, bFields, bMethods = grok(bukkit, "org/bukkit")
#print "CraftBukkit stats:", len(bMethods), len(bFields), len(bClasses)
for jar in glob("plugins/*.jar"):
plugin = JarFile(jar)
safe = examine(plugin)
print path.basename(jar) + ": " + str(safe)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment