Skip to content

Instantly share code, notes, and snippets.

@comp500
Created August 21, 2020 23:27
Show Gist options
  • Save comp500/a752b4b5cd13f30e5e4ecbc07dabc511 to your computer and use it in GitHub Desktop.
Save comp500/a752b4b5cd13f30e5e4ecbc07dabc511 to your computer and use it in GitHub Desktop.
Terrible technique for dumping class files using JDI/JDWP
package link.infra.jdwp;
import com.sun.jdi.Field;
import com.sun.jdi.LocalVariable;
import com.sun.jdi.Method;
import com.sun.jdi.ReferenceType;
import com.sun.jdi.*;
import com.sun.jdi.connect.AttachingConnector;
import com.sun.jdi.connect.Connector;
import com.sun.jdi.connect.IllegalConnectorArgumentsException;
import org.apache.bcel.classfile.*;
import org.apache.bcel.generic.Type;
import org.apache.bcel.generic.*;
import java.io.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
public class App {
public static void main(String[] args) throws IOException, IllegalConnectorArgumentsException {
List<AttachingConnector> connectors = Bootstrap.virtualMachineManager().attachingConnectors();
for (AttachingConnector connector : connectors) {
if (connector.name().equals("com.sun.jdi.SocketAttach")) {
Map<String, Connector.Argument> connArgs = connector.defaultArguments();
connArgs.get("port").setValue("5005");
VirtualMachine vm = connector.attach(connArgs);
for (ReferenceType refType : vm.allClasses()) {
if (!(refType instanceof ClassType)) {
continue;
}
ClassType clazz = ((ClassType) refType);
// TODO: test with j9+
if (clazz.classLoader() == null) {
continue;
}
// TODO: workaround for lambdas?
String sourceName;
try {
sourceName = clazz.sourceName();
} catch (AbsentInformationException ignored) { continue; }
String name = clazz.name().replace('.', '/');
byte[] hmmm = clazz.constantPool();
ByteArrayOutputStream baos = new ByteArrayOutputStream(hmmm.length + 2);
DataOutputStream dos = new DataOutputStream(baos);
// TODO: unsigned?
dos.writeShort(clazz.constantPoolCount());
dos.write(hmmm);
ConstantPoolGen poolGen = new ConstantPoolGen(new ConstantPool(new DataInputStream(new ByteArrayInputStream(baos.toByteArray()))));
String superClassName;
ClassType superClass = clazz.superclass();
if (superClass != null) {
superClassName = superClass.name().replace('.', '/');
} else {
superClassName = "java/lang/Object";
}
String[] implementedInterfaces = clazz.interfaces().stream().map(ReferenceType::name).toArray(String[]::new);
ClassGen classGen = new ClassGen(name,
superClassName,
sourceName,
clazz.modifiers(),
implementedInterfaces, poolGen);
classGen.setMinor(clazz.minorVersion());
classGen.setMajor(clazz.majorVersion());
String classGenericSignature = clazz.genericSignature();
if (classGenericSignature != null && classGenericSignature.length() > 0) {
classGen.addAttribute(new Signature(poolGen.lookupUtf8("Signature"), 2, poolGen.lookupUtf8(classGenericSignature), poolGen.getConstantPool()));
}
// TODO: the necessary metadata for bootstrap methods isn't available!! :(
// TODO: inner classes
// TODO: enclosing method?
for (Field field : clazz.fields()) {
FieldGen fieldGen = new FieldGen(field.modifiers(),
Type.getType(Utility.getSignature(field.typeName())),
field.name(),
poolGen);
String genericSignature = field.genericSignature();
if (genericSignature != null && genericSignature.length() > 0) {
fieldGen.addAttribute(new Signature(poolGen.lookupUtf8("Signature"), 2, poolGen.lookupUtf8(genericSignature), poolGen.getConstantPool()));
}
classGen.addField(fieldGen.getField());
}
for (Method method : clazz.methods()) {
String[] argNameList = null;
try {
argNameList = method.arguments().stream().map(LocalVariable::name).toArray(String[]::new);
} catch (AbsentInformationException ignored) {}
String[] argTypeList = Utility.methodSignatureArgumentTypes(method.signature());
if (argNameList == null || argTypeList.length != argNameList.length) {
// TODO: better names
argNameList = argTypeList;
}
MethodGen methodGen = new MethodGen(method.modifiers(),
Type.getReturnType(method.signature()),
Type.getArgumentTypes(method.signature()),
argNameList,
method.name(),
name,
new InstructionList(method.bytecodes()),
poolGen);
// TODO: line numbers
// TODO: LVT
// TODO: LVTT
//method.variables();
methodGen.setMaxStack();
methodGen.setMaxLocals();
String genericSignature = method.genericSignature();
if (genericSignature != null && genericSignature.length() > 0) {
methodGen.addAttribute(new Signature(poolGen.lookupUtf8("Signature"), 2, poolGen.lookupUtf8(genericSignature), poolGen.getConstantPool()));
}
classGen.addMethod(methodGen.getMethod());
}
if (name.endsWith("class_310")) {
classGen.getJavaClass().dump(new File("test.class"));
break;
}
}
vm.dispose();
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment