package com.highway2urhell.transformer;
import com.highway2urhell.domain.EntryPathData;
import javassist.*;
import javassist.bytecode.CodeAttribute;
import javassist.bytecode.LocalVariableAttribute;
import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.IllegalClassFormatException;
import java.security.ProtectionDomain;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class EntryPointTransformer implements ClassFileTransformer {
private Map<String, List<EntryPathData>> mapToTransform = null;
private Boolean performance = false;
public EntryPointTransformer(Map<String, List<EntryPathData>> mapTransform, Boolean perf) {
mapToTransform = mapTransform;
performance = perf;
}
public byte[] transform(ClassLoader loader, String className,
Class<?> classBeingRedefined, ProtectionDomain protectionDomain,
byte[] classfileBuffer) throws IllegalClassFormatException {
String classNameToTransform = null;
if (!mapToTransform.get(className).isEmpty()) {
try {
List<EntryPathData> listbd = mapToTransform.get(className);
ClassPool cp = ClassPool.getDefault();
cp.appendClassPath(new LoaderClassPath(loader));
addImportPackage(cp);
classNameToTransform = listbd.get(0).getClassName();
CtClass cc = cp.get(classNameToTransform);
for (EntryPathData entry : listbd) {
if (performance) {
insertCodeWithPerf(entry, cc);
} else {
insertCode(entry, cc);
}
}
classfileBuffer = cc.toBytecode();
cc.detach();
} catch (Exception ex) {
System.err.println("Fail to Transform " + classNameToTransform+ex);
}
}
return classfileBuffer;
}
private void insertCodeWithPerf(EntryPathData entry, CtClass cc) {
System.out.println(
"Going to Transform insertCodeWithPerf "+entry.getClassName()+"with methodName "+ entry.getMethodName()+" and signature "+entry.getSignatureName());
CtMethod m;
try {
m = cc.getMethod(entry.getMethodName(), entry.getSignatureName());
m.addLocalVariable("startH2H", CtClass.longType);
CtClass ss = ClassPool.getDefault().get("java.lang.String");
m.addLocalVariable("listParamsH2H", ss);
m.insertBefore(generateCmd(m, entry.getClassName(), entry.getMethodName()) + "startH2H = System.currentTimeMillis();");
m.insertAfter("final long endH2H = System.currentTimeMillis();" + generateCmdPerf(m, entry.getClassName(), entry.getMethodName()));
} catch (Exception e) {
System.err.println("Insert Code for className " + entry.getClassName() + " and methodName " + entry.getMethodName() + " fails msg "+e);
}
}
private void insertCode(EntryPathData entry, CtClass cc) {
System.out.println(
"Going to Transform insertCodeWithPerf "+entry.getClassName()+"with methodName "+ entry.getMethodName()+" and signature "+entry.getSignatureName());
CtMethod m;
try {
m = cc.getMethod(entry.getMethodName(), entry.getSignatureName());
CtClass ss = ClassPool.getDefault().get("java.lang.String");
m.addLocalVariable("listParamsH2H", ss);
m.insertBefore(generateCmd(m, entry.getClassName(), entry.getMethodName()));
} catch (Exception e) {
System.err.println("Insert Code for className " + entry.getClassName() + " and methodName " + entry.getMethodName() + " fails msg "+ e);
}
}
private String generateCmd(CtMethod m, String className, String methodName) throws NotFoundException {
StringBuilder sbs = new StringBuilder();
sbs.append(generateParamsLeech(m));
sbs.append("GatherService.getInstance().gatherInvocation(\"" + className + "." + methodName + "\",listParamsH2H);");
return sbs.toString();
}
private String generateCmdPerf(CtMethod m, String className, String methodName) throws NotFoundException {
StringBuilder sbs = new StringBuilder();
sbs.append("GatherService.getInstance().gatherPerformance(\"" + className + "." + methodName + "\",(endH2H-startH2H),listParamsH2H);");
return sbs.toString();
}
private void addImportPackage(ClassPool cp) {
cp.importPackage("com.highway2urhell");
cp.importPackage("javax.servlet");
cp.importPackage("com.highway2urhell.domain");
cp.importPackage("com.highway2urhell.service");
cp.importPackage("com.google.gson.Gson");
cp.importPackage("com.google.gson.GsonBuilder");
cp.importPackage("com.highway2urhell.service.impl");
}
private String generateParamsLeech(CtMethod m) {
StringBuilder sbs = new StringBuilder();
sbs.append("listParamsH2H=\"\";");
try {
Map<Integer, String> hashNameParam = extractNameParameter(m);
CtClass[] pTypes = m.getParameterTypes();
sbs.append("Gson gson = new GsonBuilder().setExclusionStrategies(new StrategyGsonH2H()).create();");
for (int i = 0; i < pTypes.length; i++) {
sbs.append(" LeechParamMethodData leech" + i + " = new LeechParamMethodData();");
sbs.append(" String val" + i + "=\"\";");
sbs.append(" try{");
sbs.append(" leech" + i + ".setNameParameter(\"" + hashNameParam.get((i + 2)) + "\");");
sbs.append(" leech" + i + ".setNameClass($" + (i + 1) + ".getClass().getName());");
//hack
sbs.append(" if(leech" + i + ".getNameParameter()!=null && leech" + i + ".getNameClass()!=null){");
sbs.append(" if($" + (i + 1) + " instanceof ServletRequest || ");
sbs.append(" $" + (i + 1) + " instanceof ServletResponse || ");
sbs.append(" $" + (i + 1) + " instanceof Filter || ");
sbs.append(" $" + (i + 1) + " instanceof FilterChain || ");
sbs.append(" leech" + i + ".getNameClass().contains(\"Page\") ){");
sbs.append(" if ($" + (i + 1) + " instanceof ServletRequest){");
sbs.append(" leech" + i + ".setData(((ServletRequest)$" + (i + 1) + ").getParameterMap());");
sbs.append(" }else{");
sbs.append(" leech" + i + ".setData(\"data is a stream\");");
sbs.append(" }");
sbs.append(" }else{");
sbs.append(" leech" + i + ".setData($" + (i + 1) + ");");
sbs.append(" }");
sbs.append(" }else{");
sbs.append(" leech" + i + ".setData(\"data is not convertible\");");
sbs.append(" }");
sbs.append(" val" + i + " = gson.toJson(leech" + i + ").toString();");
sbs.append(" }catch(Throwable e) {");
sbs.append(" System.err.println(\"name : " + hashNameParam.get((i + 2)) + " class : \" + $" + (i + 1) + ".getClass().getName() );");
sbs.append(" leech" + i + ".setNameParameter(\"" + hashNameParam.get((i + 2)) + "\");");
sbs.append(" leech" + i + ".setNameClass($" + (i + 1) + ".getClass().getName());");
sbs.append(" leech" + i + ".setData(\"ERROR_PARAM\");");
sbs.append(" val" + i + " = gson.toJson(leech" + i + ").toString();");
sbs.append(" }");
}
sbs.append(" listParamsH2H=");
if (pTypes.length == 0) {
sbs.append("\"\";");
}
for (int i = 0; i < pTypes.length; i++) {
sbs.append("val" + i + "+\"@@@@@\"");
if (i == pTypes.length - 1) {
sbs.append(";");
} else {
sbs.append("+");
}
}
} catch (NotFoundException nf) {
sbs = new StringBuilder();
sbs.append("listParamsH2H = \"\";");
}
//LOGGER.error("INSERTION BORDEL DE MERDE " + sbs.toString());
return sbs.toString();
}
private Map<Integer, String> extractNameParameter(CtMethod m) throws NotFoundException {
Map<Integer, String> hashNameParam = new HashMap<Integer, String>();
CodeAttribute codeAttribute = (CodeAttribute) m.getMethodInfo().getAttribute("Code");
if (codeAttribute != null) {
LocalVariableAttribute localVariableAttribute = (LocalVariableAttribute) codeAttribute.getAttribute("LocalVariableTable");
if (localVariableAttribute != null && localVariableAttribute.tableLength() >= m.getParameterTypes().length) {
for (int i = 0; i < m.getParameterTypes().length + 2; i++) {
String name = localVariableAttribute.getConstPool().getUtf8Info(localVariableAttribute.nameIndex(i));
if (!name.equals("this")) {
hashNameParam.put(i, name);
}
}
}
}
return hashNameParam;
}
public void toto() {
}
}