Created
April 26, 2011 06:00
-
-
Save MostAwesomeDude/941853 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python | |
from collections import defaultdict | |
from hashlib import sha512 | |
from pprint import pprint | |
from StringIO import StringIO | |
import sys | |
from zipfile import ZipFile | |
from nu.bytecode import StreamDisassembler | |
from nu.classfile import ClassFile | |
jar = ZipFile(sys.argv[-1]) | |
counter = defaultdict(list) | |
print "Grepping the JAR..." | |
for name in jar.namelist(): | |
if name.endswith(".class"): | |
handle = jar.open(name) | |
cf = ClassFile(handle) | |
for constant in cf.constants: | |
# UTF8 is tag 1 | |
if constant.tag == 1: | |
# Is it packet-related? | |
if "packet" in constant.value.lower(): | |
counter[name].append(constant.value) | |
pprint(counter) | |
packet_class = max(counter, key=lambda k: len(counter[k])) | |
print "Guessing packet class %s" % packet_class | |
cf = ClassFile(jar.open(packet_class)) | |
static_init = cf.methods.find_one("<clinit>") | |
code = static_init.attributes.find_one("Code").code | |
dis = StreamDisassembler(StringIO(code)) | |
stack = [] | |
classes = {} | |
for instruction in dis.iter_ins(): | |
if instruction.name.startswith("iconst"): | |
stack.append(int(instruction.name[-1])) # hax | |
elif instruction.name.endswith("ipush"): | |
stack.append(instruction.operands[0].value) | |
elif instruction.name == "ldc": | |
# Loading a class. | |
offset = instruction.operands[0].value | |
name = cf.constants[cf.constants[offset - 1].name_index].value | |
second = stack.pop() | |
first = stack.pop() | |
index = stack.pop() | |
classes[index] = "%s.class" % name | |
print "Found packet %d (%s, %s): %s" % ( | |
index, bool(first), bool(second), name) | |
elif instruction.name == "return": | |
# All finished. | |
print "Found all packets; analyzing..." | |
def dis_virtuals(cls, dis): | |
for instruction in dis.iter_ins(): | |
if instruction.name == "invokestatic": | |
offset = instruction.operands[0].value | |
offset = cls.constants[offset - 1].name_and_type_index | |
offset = cls.constants[offset].name_index | |
name = cls.constants[offset].value | |
if name == "a": | |
print "a() (short-length-prefixed UCS2 string)" | |
else: | |
print "%s()???" % name | |
elif instruction.name == "invokevirtual": | |
offset = instruction.operands[0].value | |
offset = cls.constants[offset - 1].name_and_type_index | |
offset = cls.constants[offset].name_index | |
print "%s()" % cls.constants[offset].value | |
def analyze_class(pclass): | |
im = pclass.methods.find_one("a", ("java/io/DataInputStream",)) | |
om = pclass.methods.find_one("a", ("java/io/DataOutputStream",)) | |
if not (im and om): | |
print "Bogus class %s" % pclass.this | |
return | |
print "To read the packet:" | |
dis = StreamDisassembler(StringIO(im.attributes.find_one("Code").code)) | |
dis_virtuals(pclass, dis) | |
print "Hash: %s" % sha512(im.attributes.find_one("Code").code).hexdigest() | |
print "To write the packet:" | |
dis = StreamDisassembler(StringIO(om.attributes.find_one("Code").code)) | |
dis_virtuals(pclass, dis) | |
print "Hash: %s" % sha512(om.attributes.find_one("Code").code).hexdigest() | |
for index, name in classes.iteritems(): | |
print "Packet %d" % index | |
if index: | |
analyze_class(ClassFile(jar.open(name))) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment