Skip to content

Instantly share code, notes, and snippets.

@MostAwesomeDude
Created April 26, 2011 06:00
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save MostAwesomeDude/941853 to your computer and use it in GitHub Desktop.
Save MostAwesomeDude/941853 to your computer and use it in GitHub Desktop.
#!/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