说明:
===================================================================
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;
}