說明:
===================================================================
1). dex 轉 jar 用的 enjarify,比目前常用的 dex2jar(d2j) 要穩定可靠得多,尤其是在處理重度混淆過的apk時
2). 用於對apk進行代碼修改,掃描目標apk中函數,並在指定函數的開頭部分 添加 調用自定義靜態函數的代碼
3). 省略 jar 轉 smali 再回轉的步驟,轉而使用 objectweb.asm(ow2) 直接對 jar 文件進行 smali 注入
4). dex2jar 的步驟使用的是 google 自家的 enjarify 工具,沒使用老掉牙的、對部分混淆apk處理極不準確極不穩定的 dex2jar(d2j)
5). jar2dex 使用的是 android studio 自帶的 dx.bat 工具,貌似 dex2jar(d2j) 在做jar迴轉的時候也是調用dx.jar
6). 手機無需 root
下載地址:
http://download.csdn.net/detail/jizhitp/9904209
public static int processJarFile(String fnOldjar, String fnNewjar) {
int nFunctionProcess = 0;
try {
JarFile Oldjar = new JarFile(new File(fnOldjar));
File Newjar = new File(fnNewjar);
try (final JarOutputStream output = new JarOutputStream(new FileOutputStream(Newjar))) {
Enumeration<JarEntry> enumeration = Oldjar.entries();
while (enumeration.hasMoreElements()) {
//<editor-fold defaultstate="collapsed" desc="遍歷jar文件中的所有.class文件">
JarEntry next = enumeration.nextElement();
if (next.getName().endsWith(".class")) {
ClassNode cn = new ClassNode(ASM5);
ClassReader cr = new ClassReader(Oldjar.getInputStream(next));
cr.accept(cn, 0);
//<editor-fold defaultstate="collapsed" desc="根據類名來判斷當前類是否爲需要注入smali的類">
if (cn.name.equals("com/test/u/t")) {
for (Object methodNodeObj : cn.methods) {
MethodNode methodNode = (MethodNode) methodNodeObj;
//<editor-fold defaultstate="collapsed" desc="根據函數名判斷該函數是否需要注入">
if (methodNode.name.equals("a")) {
//new MethodHelper(methodNode.access, cn.name, methodNode.name, methodNode.desc, (MethodVisitor) methodNode);
String tmpInject_ClassName = SmaliInjector.pc.Injector.Inject_ClassName.replace(".", "/");
String tmpInjectMethodName = SmaliInjector.pc.Injector.InjectMethodName;
//<editor-fold defaultstate="collapsed" desc="根據函數的參數列表來判斷是否爲需要注入的函數">
if (methodNode.desc.equals("([B[BLcom/test/pointers/PInt;Lcom/test/protocal/c/asb;)[B")) {
System.out.println("\tfound: "+cn.name+"."+methodNode.name+methodNode.desc);
nFunctionProcess++;
InsnList injectCode = new InsnList();
injectCode.add(new VarInsnNode(Opcodes.ALOAD, 1));
injectCode.add(new MethodInsnNode(Opcodes.INVOKESTATIC, tmpInject_ClassName, tmpInjectMethodName, "([B)V", false));
AbstractInsnNode firstIns = methodNode.instructions.get(0);//.getFirst();//
methodNode.instructions.insertBefore(firstIns, injectCode);
} else if (methodNode.desc.equals("(I[B[B)Z")) {
System.out.println("\tfound: "+cn.name+"."+methodNode.name+methodNode.desc);
nFunctionProcess++;
InsnList injectCode = new InsnList();
injectCode.add(new VarInsnNode(Opcodes.ALOAD, 3));
injectCode.add(new MethodInsnNode(Opcodes.INVOKESTATIC, tmpInject_ClassName, tmpInjectMethodName, "([B)V", false));
AbstractInsnNode firstIns = methodNode.instructions.get(0);//.getFirst();//
methodNode.instructions.insertBefore(firstIns, injectCode);
}
//</editor-fold>
}
//</editor-fold>
} // end of methods loop
} // end of java class name filter
//</editor-fold>
ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
cn.accept(cw);
output.putNextEntry(new JarEntry(cn.name.replaceAll("\\.", "/") + ".class"));
output.write(cw.toByteArray());
output.closeEntry();
} // end of if jarEntry == .class
//</editor-fold>
} // end of .class loop
}
Oldjar.close();
} catch (IOException e) {
e.printStackTrace();
}
return nFunctionProcess;
}