package com.aspect.snoop.util;
/*
* Copyright, Aspect Security, Inc.
*
* This file is part of JavaSnoop.
*
* JavaSnoop is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* JavaSnoop is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with JavaSnoop. If not, see <http://www.gnu.org/licenses/>.
*/
import com.aspect.snoop.SnoopSession;
import com.aspect.snoop.agent.AgentCommunicationException;
import java.io.IOException;
import java.lang.management.ManagementFactory;
import com.aspect.snoop.agent.AgentJarCreator;
import com.sun.tools.attach.AgentInitializationException;
import com.sun.tools.attach.AgentLoadException;
import com.sun.tools.attach.AttachNotSupportedException;
import com.sun.tools.attach.VirtualMachine;
import java.io.File;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.logging.Level;
import org.apache.log4j.Logger;
/**
* Utility methods for launching JVMs and using the Attach API.
*
* @author David Anderson
*/
public class AttachUtil {
private static Logger logger = Logger.getLogger(AttachUtil.class);
public static void attachToVM() throws AttachNotSupportedException, IOException, AgentLoadException, AgentInitializationException, AgentCommunicationException {
// Use the process id of this VM
String agentJarPath = AgentJarCreator.createAgentJar(false);
loadAgentInOtherVM(agentJarPath, ManagementFactory.getRuntimeMXBean().getName().split("@")[0]);
}
public static void loadAgentInOtherVM(String agentJarPath, String pid) throws AttachNotSupportedException, IOException, AgentLoadException, AgentInitializationException, AgentCommunicationException {
VirtualMachine vm = VirtualMachine.attach(pid);
/*
* Agent is expecting arguments in the form of:
* <javasnoop install dir>|number|[LookAndFeelClass]
* Where number represents the number of seconds to wait before
* loading the JavaSnoop GUI. Attaching to an existing process
* requires no waiting, so we hardcode to 0.
*/
vm.loadAgent(agentJarPath, new File(".").getAbsolutePath() + "|0|");
vm.detach();
}
public static void launchInNewVM(String agentJarPath, SnoopSession session) throws AttachNotSupportedException, ClassNotFoundException, NoSuchMethodException, IOException, AttachNotSupportedException,AgentCommunicationException {
boolean isJar = session.getMainClass().trim().length() == 0 &&
session.getClasspathString().trim().length() > 0 &&
session.getClasspathString().trim().endsWith(".jar");
String javaHome = System.getProperty("java.home") + File.separator + "bin";
List<String> arguments = new ArrayList<String>();
String command = javaHome + File.separator + "java";
arguments.add(command);
/*
* Agent is expecting arguments in the form of:
* <javasnoop install dir>|number
* Where number represents the number of seconds to wait before
* loading the JavaSnoop GUI. Starting up a new process requires
* to wait for the application to initialize its own GUI. The user
* specified this value in the NewProcessInfoView form.
*/
String agent =
"-javaagent:" + agentJarPath +
"=" + new File(".").getAbsolutePath() +
"|" + session.getGuiDelay() +
"|" + session.getLookAndFeel();
arguments.add(agent);
String javaArgs = session.getJavaArguments().trim();
if ( javaArgs.length() > 0) {
String[] args = parseArguments(javaArgs);
arguments.addAll(Arrays.asList(args));
}
String cp = session.getClasspathString();
if ( cp.trim().length() >0) {
if ( isJar ) {
arguments.add("-jar");
} else {
arguments.add("-cp");
}
arguments.add(cp);
}
if ( ! isJar ) {
arguments.add(session.getMainClass());
}
if (session.getArguments().length()>0) {
String[] args = parseArguments(session.getArguments());
arguments.addAll(Arrays.asList(args));
}
String[] commandArgs = arguments.toArray( new String[]{} );
StringBuilder sb = new StringBuilder();
for(String s : commandArgs) {
sb.append(s).append(" ");
}
String workingDir = new File(".").getPath();
if ( session.getWorkingDir().trim().length() > 0 ) {
workingDir = session.getWorkingDir().trim();
}
sb = new StringBuilder();
for(String arg : commandArgs) {
sb.append(arg);
sb.append(" ");
}
logger.debug(sb.toString());
final String fWorkingDir = workingDir;
final String[] fCommandArgs = commandArgs;
new Thread("Executing ") {
@Override
public void run() {
try {
Process p = Runtime.getRuntime().exec(fCommandArgs, null, new File(fWorkingDir));
JadUtil.doWaitFor(p);
} catch (IOException ex) {
logger.error(ex);
}
}
}.start();
}
private static String[] parseArguments(String args) {
List<String> arguments = new ArrayList<String>();
boolean quoted = false;
String currentArg = "";
for (int i = 0; i < args.length(); i++) {
char c = args.charAt(i);
if (!quoted && c == ' ') {
arguments.add(currentArg);
currentArg = "";
} else if (quoted && c == '"') {
arguments.add(currentArg);
currentArg = "";
quoted = false;
i++; // skip over the space
} else if (c == '"') {
quoted = true;
} else {
currentArg += c;
}
if ( i == args.length()-1 ) {
arguments.add(currentArg);
}
}
String[] toReturn = new String[arguments.size()];
for (int i = 0; i < arguments.size(); i++) {
toReturn[i] = arguments.get(i);
}
return toReturn;
}
}