/*
* Copyright (C) 2012 Sony Mobile Communications AB
*
* This file is part of ApkAnalyser.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package jerl.bcm.util;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.PrintStream;
import java.lang.reflect.Constructor;
import java.util.Enumeration;
import java.util.List;
import java.util.Vector;
import jerl.bcm.inj.Injection;
import jerl.bcm.inj.InjectionMethod;
import jerl.bcm.inj.impl.MethodCallCrash;
import jerl.bcm.inj.impl.MethodCallGC;
import jerl.bcm.inj.impl.MethodCallOut;
import jerl.bcm.inj.impl.MethodEntryCrash;
import jerl.bcm.inj.impl.MethodEntryOut;
import jerl.bcm.inj.impl.MethodExceptionHandlerPrintStackTrace;
import jerl.bcm.inj.impl.MethodExitCrash;
import jerl.bcm.inj.impl.MethodExitOut;
import jerl.bcm.inj.impl.MethodOffsetGC;
public class InjectionUtil {
public static final String STRING_TYPE = "java.lang.String";
public static final String INT_TYPE = "int";
public static final String BOOLEAN_TYPE = "boolean";
public static void deconstructClassToStream(ClassInjContainer cic, PrintStream out) {
out.println("\\begin{class}[" + cic.getClassName() + "]");
Enumeration<InjectionMethod> en = cic.methodInjections();
while (en.hasMoreElements()) {
Injection inj = en.nextElement();
List<String> l = deconstructInjection(inj);
if (l.size() < 2) {
// invalid
continue;
}
out.println("\t" + l.get(0));
for (int i = 1; i < l.size() - 1; i++) {
out.println("\t\t" + l.get(i));
}
out.println("\t" + l.get(l.size() - 1));
}
out.println("\\end{class}");
}
public static List<String> deconstructInjection(Injection inj) {
Vector<String> ret = new Vector<String>();
Class<?> c = inj.getClass();
List<String> l = inj.getInstanceData();
Constructor<?> constructor = getDefaultConstructor(c);
int numArgs = constructor.getParameterTypes().length;
String argTypes = createTypeString(constructor);
ret.add("\\begin{injection}[" + numArgs + "]");
ret.add("ClassName=" + c.getName());
ret.add("ArgTypes=" + argTypes);
for (int i = 0; i < l.size(); i++) {
ret.add("ArgValue[" + i + "]=" + l.get(i));
}
ret.add("\\end{injection}");
return ret;
}
public static Constructor<?> getDefaultConstructor(Class<?> c) {
Constructor<?>[] constList = c.getConstructors();
if (constList.length != 1) {
throw new IllegalArgumentException("Unable to find default constructor of class=" + c.getName());
}
return constList[0];
}
public static String createTypeString(Constructor<?> constructor) {
StringBuffer sb = new StringBuffer();
Class<?>[] classList = constructor.getParameterTypes();
for (int i = 0; i < classList.length; i++) {
String name = classList[i].getName();
// if (name.equals(STRING_TYPE) || name.equals(INT_TYPE) || name.equals(BOOLEAN_TYPE)) {
sb.append(name);
if (i < classList.length - 1) {
sb.append(",");
}
// } else {
// throw new IllegalArgumentException("Invalid argument type in constructor");
// }
}
return sb.toString();
}
public static byte[] writeTest() {
ByteArrayOutputStream baos = new ByteArrayOutputStream(1024);
PrintStream ps = new PrintStream(baos);
ClassInjContainer cic = new ClassInjContainer("com/sun/Test");
cic.addMethodInjection(new MethodEntryOut("a(III[I)V", "desc"));
cic.addMethodInjection(new MethodOffsetGC("a(III[I)V", 30));
cic.addMethodInjection(new MethodExceptionHandlerPrintStackTrace("a(III[I)V"));
cic.addMethodInjection(new MethodCallCrash("a(III[I)V", "java/io/DataInputStream.readInt()I", true));
cic.addMethodInjection(new MethodCallOut("a(Lv1;)V", "java/io/DataInputStream.readInt()I", true, "message"));
cic.addMethodInjection(new MethodExitCrash("a(III[I)V"));
cic.addMethodInjection(new MethodExitOut("a(III[I)V", "message"));
cic.addMethodInjection(new MethodEntryCrash("c(I)I"));
ClassInjContainer cic2 = new ClassInjContainer("com/sun/Test2");
cic2.addMethodInjection(new MethodEntryOut("e(III[I)V", "desc2"));
cic2.addMethodInjection(new MethodEntryOut("e(III[I)V", "desc2"));
cic2.addMethodInjection(new MethodEntryOut("e(III[I)V", "desc2"));
cic2.addMethodInjection(new MethodEntryOut("f(III[I)V", "desc2"));
cic2.addMethodInjection(new MethodEntryOut("b(III[I)V", "desc2"));
cic2.addMethodInjection(new MethodEntryOut("d(III[I)V", "desc2"));
cic2.addMethodInjection(new MethodOffsetGC("k(I)I", 10));
cic2.addMethodInjection(new MethodExceptionHandlerPrintStackTrace("a(III[I)V"));
cic2.addMethodInjection(new MethodCallCrash("f(III[I)V", "java/lang/System.currentTimeMillis()J", true));
cic2.addMethodInjection(new MethodCallGC("f(III[I)V", "java/lang/System.currentTimeMillis()J", true));
cic2.addMethodInjection(new MethodCallOut("a(Lv1;)V", "java/lang/System.currentTimeMillis()J", true, "message2"));
cic2.addMethodInjection(new MethodExitCrash("b(III[I)V"));
cic2.addMethodInjection(new MethodExitOut("d(III[I)V", "message2"));
cic2.addMethodInjection(new MethodEntryCrash("k(I)I"));
ClassInjContainer cic3 = new ClassInjContainer("b");
cic3.addMethodInjection(new MethodEntryOut("a(III)Ljavax/microedition/lcdui/Font;", "desc2"));
cic3.addMethodInjection(new MethodOffsetGC("a(Ljava/lang/String;)Ljava/io/InputStream;", 10));
cic3.addMethodInjection(new MethodCallOut("a(Ljava/lang/String;)Ljavax/microedition/lcdui/Image;", "javax/microedition/lcdui/Image.createImage(Ljava/lang/String;)Ljavax/microedition/lcdui/Image;", true, "message"));
deconstructClassToStream(cic, System.out);
deconstructClassToStream(cic2, System.out);
deconstructClassToStream(cic3, System.out);
deconstructClassToStream(cic, ps);
deconstructClassToStream(cic2, ps);
deconstructClassToStream(cic3, ps);
ps.flush();
byte[] bBuf = baos.toByteArray();
return bBuf;
}
public static void main(String[] args) {
// simulate construction of Injections and writing them to a stream.
byte[] bBuf = writeTest();
System.out.println("*****************************");
// load injections and also print them, just to verify
try {
InjectionBuilder ib = new InjectionBuilder(new ByteArrayInputStream(bBuf));
Enumeration<String> enumClassNames = ib.getClassNamesForInjections();
while (enumClassNames.hasMoreElements()) {
String className = enumClassNames.nextElement();
ClassInjContainer cic = ib.getClassInjContainer(className);
deconstructClassToStream(cic, System.out);
// when applying injections we just need this:
cic.methodInjectionsToArray();
// to be passed in to InjectionEngine.preformInjection()
}
} catch (Exception e) {
e.printStackTrace();
}
}
}