def test_default_bytecode_transforms(): cl = ClassLoader(bytecode_transforms=[simple_swap]) cf = ClassFile.create('TestClass') cl.update(cf) test_method = cf.methods.create('test', '(V)V;', code=True) test_method.code.max_stack = 2 test_method.code.max_locals = 0 test_method.code.assemble( assemble([('iconst_0', ), ('pop', ), ('return', )])) # Load from the ClassLoader to bind to it. cf = cl.load('TestClass') # Ensure the defaults apply. ins_iter = test_method.code.disassemble() ins = next(ins_iter) assert ins.mnemonic == 'bipush' assert len(ins.operands) == 1 assert ins.operands[0].value == 0 # Ensure we can override the default. ins_iter = test_method.code.disassemble(transforms=[]) ins = next(ins_iter) assert ins.mnemonic == 'iconst_0' assert len(ins.operands) == 0
def test_default_bytecode_transforms(): cl = ClassLoader(bytecode_transforms=[simple_swap]) cf = ClassFile.create('TestClass') cl.update(cf) test_method = cf.methods.create('test', '(V)V;', code=True) test_method.code.max_stack = 2 test_method.code.max_locals = 0 test_method.code.assemble(assemble([ ('iconst_0',), ('pop',), ('return',) ])) # Load from the ClassLoader to bind to it. cf = cl.load('TestClass') # Ensure the defaults apply. ins_iter = test_method.code.disassemble() ins = next(ins_iter) assert ins.mnemonic == 'bipush' assert len(ins.operands) == 1 assert ins.operands[0].value == 0 # Ensure we can override the default. ins_iter = test_method.code.disassemble(transforms=[]) ins = next(ins_iter) assert ins.mnemonic == 'iconst_0' assert len(ins.operands) == 0
def test_load_from_class(): """Ensure we can add ClassFile's directly to the ClassLoader.""" cl = ClassLoader() cf = ClassFile.create('TestClass') cl.update(cf) assert cl.load('TestClass') is cf
def dependencies(source): """Output a list of all classes referenced by the given source.""" loader = ClassLoader(source, max_cache=-1) all_dependencies = set() for klass in loader.classes: new_dependencies = loader.dependencies(klass) - all_dependencies all_dependencies.update(new_dependencies) for new_dep in new_dependencies: click.echo(new_dep)
def test_load_from_directory(): """Ensure we can load a ClassFile from a simple directory.""" with tempfile.TemporaryDirectory() as dir: shutil.copy( os.path.join(os.path.dirname(__file__), 'data', 'HelloWorld.class'), dir) cl = ClassLoader() cl.update(dir) assert isinstance(cl.load('HelloWorld'), cl.klass)
def test_load_from_zipfile(): """Ensure we can load a ClassFile from a ZipFile.""" with tempfile.NamedTemporaryFile(suffix='.jar') as tmp: with zipfile.ZipFile(tmp, 'w') as zf: zf.write(os.path.join(os.path.dirname(__file__), 'data', 'HelloWorld.class'), arcname='HelloWorld.class') cl = ClassLoader() cl.update(tmp.name) assert isinstance(cl.load('HelloWorld'), cl.klass)
def grep(source, regex, stop_on_first=False): """Grep the constant pool of all classes in source.""" loader = ClassLoader(source, max_cache=-1) r = re.compile(regex) def _matches(constant): return r.match(constant.value) for klass in loader.classes: it = loader.search_constant_pool(path=klass, type_=UTF8, f=_matches) if next(it, None): print(klass) if stop_on_first: break
def test_load_from_directory(): """Ensure we can load a ClassFile from a simple directory.""" with tempfile.TemporaryDirectory() as dir: shutil.copy( os.path.join( os.path.dirname(__file__), 'data', 'HelloWorld.class' ), dir ) cl = ClassLoader() cl.update(dir) assert isinstance(cl.load('HelloWorld'), cl.klass)
def dump_class_from_jar(path, name): """A command that displays useful information that exists in a class that is inside a JAR Similar to `dump_class` """ loader = ClassLoader(path) utils.dump_class(loader[name], click.echo)
def shell_command(class_path): """Drop into a debugging shell.""" loader = ClassLoader(*class_path) shell.start_shell(local_ns={ 'ClassFile': ClassFile, 'loader': loader, 'constants': importlib.import_module('jawa.constants'), })
def test_load_from_zipfile(): """Ensure we can load a ClassFile from a ZipFile.""" with tempfile.NamedTemporaryFile(suffix='.jar') as tmp: with zipfile.ZipFile(tmp, 'w') as zf: zf.write( os.path.join( os.path.dirname(__file__), 'data', 'HelloWorld.class' ), arcname='HelloWorld.class' ) cl = ClassLoader() cl.update(tmp.name) assert isinstance(cl.load('HelloWorld'), cl.klass)
def main(class_path, classes): loader = ClassLoader(*class_path) for class_ in classes: cf = loader[class_] # The constant pool. print('; {0:->60}'.format(' constant pool')) print('; {0:->60}'.format(' total: {0}'.format(len(cf.constants)))) for constant in cf.constants: print('; {0:04}: {1!r}'.format(constant.index, constant)) # The fields table. print('; {0:->60}'.format(' fields')) print('; {0:->60}'.format(' total: {0}'.format(len(cf.fields)))) for field in cf.fields: print('; {0!r}'.format(field)) # The methods table. print('; {0:->60}'.format(' methods')) print('; {0:->60}'.format(' total: {0}'.format(len(cf.methods)))) for method in cf.methods: # Find all enabled flags and print them out (such as acc_public # and acc_private) flags = method.access_flags.to_dict() flags = [k for k, v in flags.items() if v] print('{0} {1} {2}({3}) {{'.format( ' '.join(flags), method.returns.name, method.name.value, ', '.join(a.name + ('[]' * a.dimensions) for a in method.args)).strip()) r = [] if method.code: for ins in method.code.disassemble(): line = [ f'{ins.pos:04}', f'[0x{ins.opcode:02X}]', f'{ins.mnemonic:>15} <-' ] for operand in ins.operands: if isinstance(operand, dict): line.append(f'JT[{operand!r}]') continue line.append({ OperandTypes.CONSTANT_INDEX: f'C[{operand.value}]', OperandTypes.BRANCH: f'J[{operand.value}]', OperandTypes.LITERAL: f'#[{operand.value}]', OperandTypes.LOCAL_INDEX: f'L[{operand.value}]', OperandTypes.PADDING: 'P' }[operand.op_type]) print(' ' + ' '.join(line)) print('}')
jarlist.append(client_path) # Download a copy of the latest snapshot jar if download_latest: client_path = website.latest_client_jar(verbose) jarlist.append(client_path) # Download a JAR from the given URL if url: url_path = urllib.urlretrieve(url)[0] jarlist.append(url_path) summary = [] for path in jarlist: classloader = ClassLoader(path, max_cache=0, bytecode_transforms=[simple_swap, expand_constants]) names = classloader.path_map.keys() num_classes = sum(1 for name in names if name.endswith(".class")) aggregate = { "source": { "file": path, "classes": num_classes, "other": len(names), "size": os.path.getsize(path) } } available = [] for topping in to_be_run: missing = [dep for dep in topping.DEPENDS if dep not in available]
def loader() -> ClassLoader: return ClassLoader(Path(__file__).parent / 'data', max_cache=-1)