/*
* 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/>.
*/
package com.aspect.snoop.util;
import com.aspect.snoop.FunctionHook;
import com.aspect.snoop.MethodWrapper;
import com.aspect.snoop.agent.AgentLogger;
import com.aspect.snoop.agent.manager.InstrumentationManager;
import com.aspect.snoop.agent.manager.LocalVariable;
import com.aspect.snoop.agent.manager.MethodChanges;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import javassist.ClassClassPath;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.NotFoundException;
public class Hook2JavaUtil {
public static MethodChanges hook2Java(FunctionHook hook, InstrumentationManager manager) {
StringBuilder javaCode = new StringBuilder();
List<LocalVariable> vars = new ArrayList<LocalVariable>();
int id = hook.getId();
String nl = System.getProperty("line.separator");
javaCode.append(nl);
if (hook.shouldPrintParameters()) {
javaCode.append(" com.aspect.snoop.agent.SnoopAgent.getMainView().printParameters(\"" + hook.getClazz().getName() + "\", " + id + ", $args, $sig);");
javaCode.append(nl);
}
if (hook.shouldPrintStackTrace()) {
javaCode.append(" com.aspect.snoop.agent.SnoopAgent.getMainView().printStackTrace(\"" + hook.getClazz().getName() + "\", " + id + ", $args, $sig);");
javaCode.append(nl);
}
if (hook.shouldPause()) {
javaCode.append(" com.aspect.snoop.agent.SnoopAgent.getMainView().pause(\"" + hook.getClazz().getName() + "\", " + id + ", $args, $sig);");
javaCode.append(nl);
}
if (hook.shouldTamperParameters()) {
try {
// need to add a new local variable "mods" before this line will work
Object[] o = new Object[]{};
ClassPool cp = ClassPool.getDefault();
cp.appendClassPath( new ClassClassPath(o.getClass()) );
CtClass type = cp.get(o.getClass().getName());
vars.add(new LocalVariable("mods", type));
javaCode.append(" mods = com.aspect.snoop.agent.SnoopAgent.getMainView().tamperWithParameters(\"" + hook.getClazz().getName() + "\", " + id + ", $args, $sig);");
javaCode.append(nl);
int argLength = hook.getParameterTypes().length;
for (int i = 0; i < argLength; i++) {
String argType = hook.getParameterTypes()[i].getName();
Unwrapper w = unwrappers.get(argType);
if ( w == null ) {
argType = getCastString(argType);
}
String line;
if ( w == null ) {
line = " $" + (i + 1) + " = (" + argType + ")mods[" + i + "];";
} else {
line = " $" + (i + 1) + " = " + w.prefix + "mods[" + i + "]" + w.suffix + ";";
}
line += nl;
javaCode.append(line);
}
} catch (NotFoundException ex) {
//logger.error(ex);
}
}
MethodWrapper method = MethodWrapper.getWrapper(hook.getClazz(), hook.getMethodName(), hook.getParameterTypes());
MethodChanges changes = new MethodChanges(method.getActualMethod());
changes.initialize(vars.toArray(new LocalVariable[vars.size()]), javaCode.toString(), "");
if (hook.shouldRunScript()) {
changes.setNewStartSrc( changes.getNewStartSrc() + hook.getStartScript());
changes.setNewEndSrc( changes.getNewEndSrc() + hook.getEndScript());
}
if ( hook.shouldTamperReturnValue() ) {
String returnType = hook.getReturnType().getName();
Unwrapper w = unwrappers.get(returnType);
if ( w == null ) {
returnType = getCastString(returnType);
}
String line = null;
if ( w == null ) {
line = " $_ = (" + returnType + ")com.aspect.snoop.agent.SnoopAgent.getMainView().tamperWithReturnValue(\"" + hook.getClazz().getName() + "\", " + id + ", $args, $sig, $_, $type);";
} else {
line = " $_ = " + w.prefix + "com.aspect.snoop.agent.SnoopAgent.getMainView().tamperWithReturnValue(\"" + hook.getClazz().getName() + "\", " + id + ", $args, $sig, com.aspect.snoop.util.ReflectionUtil.getObjectFrom($_), $type)" + w.suffix + ";";
}
changes.setNewEndSrc( changes.getNewEndSrc() + nl + line );
}
AgentLogger.debug("START: " + changes.getNewStartSrc());
AgentLogger.debug("END: " + changes.getNewEndSrc());
return changes;
}
public static String getCastString(String argType) {
String toReturn = argType;
if ( ReflectionUtil.primitiveArrayMap.containsKey(argType)) {
toReturn = ReflectionUtil.primitiveArrayMap.get(argType);
} else if ( argType.startsWith("[L") ) {
int len = argType.length() - 1;
toReturn = argType.substring(2,len) + "[]";
}
return toReturn;
}
public static HashMap<String,Unwrapper> unwrappers = new HashMap<String,Unwrapper>();
static {
unwrappers.put( "boolean", new Unwrapper("((Boolean)",").booleanValue()") );
unwrappers.put( "byte", new Unwrapper("((Byte)",").byteValue()") );
unwrappers.put( "char", new Unwrapper("((Character)",").charValue()") );
unwrappers.put( "short", new Unwrapper("((Short)",").shortValue()") );
unwrappers.put( "int", new Unwrapper("((Integer)",").intValue()") );
unwrappers.put( "float", new Unwrapper("((Float)",").floatValue()") );
unwrappers.put( "long", new Unwrapper("((Long)",").longValue()") );
unwrappers.put( "double", new Unwrapper("((Double)",").doubleValue()") );
}
}
class Unwrapper {
String prefix;
String suffix;
public Unwrapper(String prefix, String suffix) {
this.prefix = prefix;
this.suffix = suffix;
}
}