public class Program { public static void main(String[] args) throws Exception { String nameOfRunningVM = ManagementFactory.getRuntimeMXBean().getName(); System.out.println(nameOfRunningVM);
int count = 600; for (int i = 0; i < count ; i++ ){ String info = String.format("|%03d| %s remains %03d seconds", i, nameOfRunningVM, (count-i)); System.out.println(info);
Random rand = new Random(System.currentTimeMillis()); int a = rand.nextInt(10); int b = rand.nextInt(10); boolean flag = rand.nextBoolean(); String message; if(flag){ message = String.format("a + b = %d",HelloWorld.add(a,b)); }else{ message = String.format("a - b = %d",HelloWorld.sub(a,b)); } System.out.println(message);
TimeUnit.SECONDS.sleep(1); } } }
PowerShell编译运行
1 2 3
javac .\src\sample\*.java -d .\out\ cd out java sample.Program
/** * This is a java.lang.instrument agent to dump .class files * from a running Java application. */ public class ClassDumpAgent { public static void premain(String agentArgs, Instrumentation inst) { agentmain(agentArgs, inst); } public static void agentmain(String agentArgs, Instrumentation inst) { System.out.println("agentArgs: " + agentArgs); ClassDumpUtils.parseArgs(agentArgs); inst.addTransformer(new ClassDumpTransformer(), true); // by the time we are attached, the classes to be // dumped may have been loaded already. // So, check for candidates in the loaded classes. Class[] classes = inst.getAllLoadedClasses(); List<Class> candidates = new ArrayList<>(); for (Class c : classes) { String className = c.getName();
// 第一步,排除法:不考虑JDK自带的类 if (className.startsWith("java")) continue; if (className.startsWith("javax")) continue; if (className.startsWith("jdk")) continue; if (className.startsWith("sun")) continue; if (className.startsWith("com.sun")) continue;
// 不重要:打印调试信息 String message = String.format("[DEBUG] Loaded Class: %s ---> Modifiable: %s, Candidate: %s", className, isModifiable, isCandidate); System.out.println(message); } try { // 第三步,将具体的class进行dump操作 // if we have matching candidates, then retransform those classes // so that we will get callback to transform. if (!candidates.isEmpty()) { inst.retransformClasses(candidates.toArray(new Class[0]));
public class ClassDumpUtils { // directory where we would write .class files private static String dumpDir; // classes with name matching this pattern will be dumped private static Pattern classes;
// parse agent args of the form arg1=value1,arg2=value2 public static void parseArgs(String agentArgs) { if (agentArgs != null) { String[] args = agentArgs.split(","); for (String arg : args) { String[] tmp = arg.split("="); if (tmp.length == 2) { String name = tmp[0]; String value = tmp[1]; if (name.equals("dumpDir")) { dumpDir = value; } else if (name.equals("classes")) { classes = Pattern.compile(value); } } } } if (dumpDir == null) { dumpDir = "."; } if (classes == null) { classes = Pattern.compile(".*"); } System.out.println("[DEBUG] dumpDir: " + dumpDir); System.out.println("[DEBUG] classes: " + classes); }
public static boolean isCandidate(String className) { // ignore array classes if (className.charAt(0) == '[') { return false; } // convert the class name to external name className = className.replace('/', '.'); // check for name pattern match return classes.matcher(className).matches(); }
public static void dumpClass(String className, byte[] classBuf) { try { // create package directories if needed className = className.replace("/", File.separator); StringBuilder buf = new StringBuilder(); buf.append(dumpDir); buf.append(File.separatorChar); int index = className.lastIndexOf(File.separatorChar); if (index != -1) { String pkgPath = className.substring(0, index); buf.append(pkgPath); } String dir = buf.toString(); new File(dir).mkdirs(); // write .class file String fileName = dumpDir + File.separator + className + ".class"; FileOutputStream fos = new FileOutputStream(fileName); fos.write(classBuf); fos.close(); System.out.println("[DEBUG] FileName: " + fileName); } catch (Exception ex) { ex.printStackTrace(); } }
/** * Simple attach-on-demand client tool * that loads the given agent into the given Java process. */ public class Attach { public static void main(String[] args) throws Exception { if (args.length < 2) { System.out.println("usage: java Attach <pid> <agent-jar-full-path> [<agent-args>]"); System.exit(1); } // JVM is identified by process id (pid). VirtualMachine vm = VirtualMachine.attach(args[0]); String agentArgs = (args.length > 2) ? args[2] : null; // load a specified agent onto the JVM vm.loadAgent(args[1], agentArgs); vm.detach(); } }
//TransClass.java public class TransClass { public int getNumber(){ System.out.println("我返回1, 求HOOK"); return 1; } } //Test.java public class Test { public static void main(String[] args) throws InterruptedException { System.out.println(new TransClass().getNumber()); int count = 0; while (true) { Thread.sleep(500); count++; int number = new TransClass().getNumber(); System.out.println(number); if (count >= 10) { break; } } } }
public class Transformer implements ClassFileTransformer { public static final String classNumberReturns2 = "D:\\Programs\\JavaProjects\\AgentMainTest\\target\\classes\\TransClass.class.2";
public static byte[] getBytesFromFile(String fileName) throws Exception { FileInputStream fileInputStream = new FileInputStream(new File(fileName)); byte[] bytes = new byte[1024]; ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
public class AttachTest { // 一个运行 Attach API 的线程子类 // 每隔半秒时间检查一次所有的 Java 虚拟机 static class AttachThread extends Thread { private final List<VirtualMachineDescriptor> listBefore;
private final String jar;
AttachThread(String attachJar, List<VirtualMachineDescriptor> vms) { listBefore = vms; // 记录程序启动时的 VM 集合 jar = attachJar; }
@Override public void run() { VirtualMachine vm = null; List<VirtualMachineDescriptor> listAfter = null; try { int count = 0; while (true) { listAfter = VirtualMachine.list(); for (VirtualMachineDescriptor vmd : listAfter) { if (vmd.displayName().equals("Test")) { System.out.println("进程ID:" + vmd.id() + ",进程名称:" + vmd.displayName()); System.out.println("捕捉到Test进程,准备Hook"); vm = VirtualMachine.attach(vmd.id()); break; } } Thread.sleep(500); count++;
if (null != vm || count >= 10) { break; } } vm.loadAgent(jar); vm.detach(); } catch (Exception e) {
}
} }
public static void main(String[] args) { new AttachThread("D:\\Programs\\JavaProjects\\AgentMainTest\\target\\AgentMainTest-1.0-SNAPSHOT.jar", VirtualMachine.list()).start(); } }