mirror of
https://github.com/pxb1988/dex2jar.git
synced 2024-11-27 07:00:51 +00:00
delete unused functions
--HG-- branch : 2.x
This commit is contained in:
parent
e2404c1805
commit
84a7ac9c2e
@ -1,103 +0,0 @@
|
||||
package com.googlecode.d2j.map;
|
||||
|
||||
import com.googlecode.dex2jar.ir.IrMethod;
|
||||
import com.googlecode.dex2jar.ir.expr.*;
|
||||
import com.googlecode.dex2jar.ir.stmt.Stmt;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
public class AntiObf {
|
||||
private boolean initEnumNames = false;
|
||||
private boolean initSourceNames = false;
|
||||
private boolean initAssertionNames = false;
|
||||
|
||||
public AntiObf initEnumNames() {
|
||||
this.initEnumNames = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
public AntiObf initSourceNames() {
|
||||
this.initSourceNames = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
public AntiObf initAssertionNames() {
|
||||
this.initAssertionNames = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
static class CodeResolver {
|
||||
IrMethod find(String owner, String name, String[] pas, String ret) {
|
||||
return null;
|
||||
};
|
||||
}
|
||||
|
||||
public void suggestNames(InheritanceTree tree, CodeResolver codeResolver) {
|
||||
if (initEnumNames) {
|
||||
for (InheritanceTree.Clz clz : tree.clzMap.values()) {
|
||||
if (clz.stat == InheritanceTree.Stat.APP) {
|
||||
if (clz.superClz.name.oldValue.equals("Ljava/lang/Enum;")) {
|
||||
String clzDesc = clz.name.oldValue;
|
||||
|
||||
Set<String> enumClzs = new HashSet<>();
|
||||
enumClzs.add(clzDesc);
|
||||
for (InheritanceTree.Clz d : clz.children) {
|
||||
enumClzs.add(d.name.oldValue);
|
||||
}
|
||||
|
||||
IrMethod ir = codeResolver.find(clzDesc, "<clinit>", new String[0], "V");
|
||||
// InheritanceTree$Stat.UNKNOW = new InheritanceTree$Stat("UNKNOW",0)
|
||||
// InheritanceTree$Stat.LIBRARY = new InheritanceTree$Stat("LIBRARY",1)
|
||||
// InheritanceTree$Stat.APP = new InheritanceTree$Stat("APP",2)
|
||||
// InheritanceTree$Stat.ENUM$VALUES = new InheritanceTree$Stat[]{InheritanceTree$Stat.UNKNOW,
|
||||
// InheritanceTree$Stat.LIBRARY, InheritanceTree$Stat.APP}
|
||||
|
||||
for (Stmt stmt : ir.stmts) {
|
||||
if (stmt.st == Stmt.ST.ASSIGN && stmt.getOp1().vt == Value.VT.STATIC_FIELD) {
|
||||
StaticFieldExpr sfe = (StaticFieldExpr) stmt.getOp1();
|
||||
if (sfe.owner.equals(clzDesc)) {
|
||||
if (stmt.getOp2().vt == Value.VT.INVOKE_NEW) {
|
||||
InvokeExpr n = (InvokeExpr) stmt.getOp2();
|
||||
if (enumClzs.contains(n.owner) && n.args.length >= 2
|
||||
&& n.args[0].equals("Ljava/lang/String;") && n.args[1].equals("I")) {
|
||||
if (n.ops[0].vt == Value.VT.CONSTANT) {
|
||||
String cst = (String) ((Constant) n.ops[0]).value;
|
||||
InheritanceTree.Fld fld = clz.fields.get(InheritanceTree.toFieldKey(
|
||||
sfe.name, sfe.type));
|
||||
if (!cst.equals(fld.name.oldValue)) {
|
||||
if (fld.name.newValue != null && !fld.name.newValue.equals(cst)) {
|
||||
System.err.println(String.format(
|
||||
"WARN: %s->%s is suggest different names: %s, %s",
|
||||
sfe.owner, sfe.name, fld.name.newValue, cst));
|
||||
}
|
||||
fld.name.newValue = cst;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (stmt.getOp2().vt == Value.VT.FILLED_ARRAY) {
|
||||
FilledArrayExpr fae = (FilledArrayExpr) stmt.getOp2();
|
||||
if (fae.type.equals("[" + clzDesc)) {
|
||||
// TODO check more
|
||||
InheritanceTree.Fld fld = clz.fields.get(InheritanceTree.toFieldKey(
|
||||
sfe.name, sfe.type));
|
||||
String cst = "ENUM$VALUES";
|
||||
if (!cst.equals(fld.name.oldValue)) {
|
||||
if (fld.name.newValue != null && !fld.name.newValue.equals(cst)) {
|
||||
System.err.println(String.format(
|
||||
"WARN: %s->%s is suggest different names: %s, %s",
|
||||
sfe.owner, sfe.name, fld.name.newValue, cst));
|
||||
}
|
||||
fld.name.newValue = cst;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,60 +0,0 @@
|
||||
/*
|
||||
* dex2jar - Tools to work with android .dex and java .class files
|
||||
* Copyright (c) 2009-2013 Panxiaobo
|
||||
*
|
||||
* 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 com.googlecode.d2j.map;
|
||||
|
||||
|
||||
import org.objectweb.asm.*;
|
||||
|
||||
public class AsmInheritanceClassVisitor extends ClassVisitor {
|
||||
final InheritanceTree tree;
|
||||
InheritanceTree.Clz clz;
|
||||
|
||||
public AsmInheritanceClassVisitor(InheritanceTree tree) {
|
||||
super(Opcodes.ASM4);
|
||||
this.tree = tree;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
|
||||
clz = tree.addClz(access, "L" + name + ";");
|
||||
if (superName != null) {
|
||||
clz.relateSuper("L" + superName + ";");
|
||||
}
|
||||
if (interfaces != null) {
|
||||
for (String s : interfaces) {
|
||||
clz.relateInterface("L" + s + ";");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public FieldVisitor visitField(int access, String name, String desc, String signature, Object value) {
|
||||
clz.addField(access, name, desc);
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
|
||||
Type[] aT = Type.getArgumentTypes(desc);
|
||||
String[] aS = new String[aT.length];
|
||||
for (int i = 0; i < aT.length; i++) {
|
||||
aS[i] = aT[i].getDescriptor();
|
||||
}
|
||||
clz.addMethod(access, name, aS, Type.getReturnType(desc).getDescriptor());
|
||||
return null;
|
||||
}
|
||||
}
|
@ -1,97 +0,0 @@
|
||||
/*
|
||||
* dex2jar - Tools to work with android .dex and java .class files
|
||||
* Copyright (c) 2009-2013 Panxiaobo
|
||||
*
|
||||
* 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 com.googlecode.d2j.map;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.*;
|
||||
import java.nio.file.attribute.BasicFileAttributes;
|
||||
|
||||
import com.googlecode.dex2jar.tools.BaseCmd;
|
||||
|
||||
public class AutoDetectSourceProcess {
|
||||
|
||||
public final void process(String file) throws IOException {
|
||||
Path path = new File(file).toPath();
|
||||
if (Files.isDirectory(path)) {
|
||||
Files.walkFileTree(path, new SimpleFileVisitor<Path>() {
|
||||
|
||||
@Override
|
||||
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
|
||||
onFile(file, true);
|
||||
return FileVisitResult.CONTINUE;
|
||||
}
|
||||
|
||||
});
|
||||
} else if (Files.isRegularFile(path)) {
|
||||
onFile(path, true);
|
||||
}
|
||||
}
|
||||
|
||||
void onFile(Path file, boolean unzip) throws IOException {
|
||||
String name = file.getFileName().toString().toLowerCase();
|
||||
if (unzip) {
|
||||
if (name.endsWith(".apk") || name.endsWith(".zip") || name.endsWith(".jar")) {
|
||||
try (FileSystem fs = BaseCmd.openZip(file)) {
|
||||
Path dex = fs.getPath("/", "classes.dex");
|
||||
if (Files.exists(dex)) {
|
||||
onFile(dex, true);
|
||||
} else {
|
||||
for (Path root : fs.getRootDirectories()) {
|
||||
Files.walkFileTree(root, new SimpleFileVisitor<Path>() {
|
||||
|
||||
@Override
|
||||
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs)
|
||||
throws IOException {
|
||||
onFile(file, false);
|
||||
return FileVisitResult.CONTINUE;
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (name.endsWith(".dex")) {
|
||||
onDex(file);
|
||||
}
|
||||
}
|
||||
if (name.endsWith(".class")) {
|
||||
onClass(file);
|
||||
} else if (name.endsWith(".j")) {
|
||||
onJasmin(file);
|
||||
} else if (name.endsWith(".smali")) {
|
||||
onSmali(file);
|
||||
}
|
||||
}
|
||||
|
||||
protected void onDex(Path file) throws IOException {
|
||||
|
||||
}
|
||||
|
||||
protected void onClass(Path file) throws IOException {
|
||||
|
||||
}
|
||||
|
||||
protected void onSmali(Path file) throws IOException {
|
||||
|
||||
}
|
||||
|
||||
protected void onJasmin(Path file) throws IOException {
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -1,63 +0,0 @@
|
||||
/*
|
||||
* dex2jar - Tools to work with android .dex and java .class files
|
||||
* Copyright (c) 2009-2013 Panxiaobo
|
||||
*
|
||||
* 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 com.googlecode.d2j.map;
|
||||
|
||||
|
||||
import com.googlecode.d2j.Field;
|
||||
import com.googlecode.d2j.Method;
|
||||
import com.googlecode.d2j.visitors.DexClassVisitor;
|
||||
import com.googlecode.d2j.visitors.DexFieldVisitor;
|
||||
import com.googlecode.d2j.visitors.DexFileVisitor;
|
||||
import com.googlecode.d2j.visitors.DexMethodVisitor;
|
||||
|
||||
public class DexInheritanceFileVisitor extends DexFileVisitor {
|
||||
final InheritanceTree tree;
|
||||
|
||||
public DexInheritanceFileVisitor(InheritanceTree tree) {
|
||||
this.tree = tree;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public DexClassVisitor visit(int access_flags, String className, String superClass, String[] interfaceNames) {
|
||||
final InheritanceTree.Clz clz = tree.addClz(access_flags, className);
|
||||
if(clz == null) { // skip the class
|
||||
return null;
|
||||
}
|
||||
if (superClass != null) {
|
||||
clz.relateSuper(superClass);
|
||||
}
|
||||
if (interfaceNames != null) {
|
||||
for (String s : interfaceNames) {
|
||||
clz.relateInterface(s);
|
||||
}
|
||||
}
|
||||
return new DexClassVisitor() {
|
||||
@Override
|
||||
public DexFieldVisitor visitField(int accessFlags, Field field, Object value) {
|
||||
clz.addField(accessFlags, field.getName(), field.getType());
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DexMethodVisitor visitMethod(int accessFlags, Method method) {
|
||||
clz.addMethod(accessFlags, method.getName(), method.getParameterTypes(), method.getReturnType());
|
||||
return null;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
@ -1,518 +0,0 @@
|
||||
/*
|
||||
* dex2jar - Tools to work with android .dex and java .class files
|
||||
* Copyright (c) 2009-2013 Panxiaobo
|
||||
*
|
||||
* 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 com.googlecode.d2j.map;
|
||||
|
||||
import com.googlecode.d2j.*;
|
||||
import com.googlecode.d2j.node.DexAnnotationNode;
|
||||
import com.googlecode.d2j.reader.Op;
|
||||
import com.googlecode.d2j.util.Mapper;
|
||||
import com.googlecode.d2j.util.Types;
|
||||
import com.googlecode.d2j.visitors.*;
|
||||
import org.objectweb.asm.signature.SignatureReader;
|
||||
import org.objectweb.asm.signature.SignatureWriter;
|
||||
|
||||
public class DexMappingAdapter extends DexFileVisitor {
|
||||
protected Mapper mapper;
|
||||
|
||||
public DexMappingAdapter(Mapper mapper, DexFileVisitor visitor) {
|
||||
super(visitor);
|
||||
this.mapper = mapper;
|
||||
}
|
||||
|
||||
static String mapClassName(Mapper map, String oldDesc) {
|
||||
if (oldDesc == null) {
|
||||
return null;
|
||||
}
|
||||
int count = 0;
|
||||
while (count < oldDesc.length() && oldDesc.charAt(count) == '[') {
|
||||
count++;
|
||||
}
|
||||
if (count + 1 == oldDesc.length()) {// simple type
|
||||
return oldDesc;
|
||||
}
|
||||
if (count > 0) {
|
||||
String n = map.mapClassName(oldDesc.substring(count));
|
||||
if (n == null) {
|
||||
return oldDesc;
|
||||
}
|
||||
return oldDesc.substring(0, count) + n;
|
||||
} else {
|
||||
String n = map.mapClassName(oldDesc);
|
||||
if (n == null) {
|
||||
return oldDesc;
|
||||
}
|
||||
return n;
|
||||
}
|
||||
}
|
||||
|
||||
static String mapAnnotationElementName(Mapper map, String owner, String name) {
|
||||
String n = map.mapMethodName(owner, name, null, null);
|
||||
if (n == null) {
|
||||
return name;
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
static String[] mapClassNames(Mapper map, String[] oldDescs) {
|
||||
if (oldDescs != null && oldDescs.length > 0) {
|
||||
String copy[] = new String[oldDescs.length];
|
||||
for (int i = 0; i < oldDescs.length; i++) {
|
||||
copy[i] = mapClassName(map, oldDescs[i]);
|
||||
}
|
||||
return copy;
|
||||
} else {
|
||||
return oldDescs;
|
||||
}
|
||||
}
|
||||
|
||||
static String mapFieldName(Mapper map, String owner, String name, String type) {
|
||||
String n = map.mapFieldName(owner, name, type);
|
||||
if (n == null) {
|
||||
return name;
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
static Field mapField(Mapper map, Field f) {
|
||||
String n = map.mapFieldName(f.getOwner(), f.getName(), f.getType());
|
||||
if (n == null) {
|
||||
n = f.getName();
|
||||
}
|
||||
return new Field(mapClassName(map, f.getOwner()), n, mapClassName(map, f.getType()));
|
||||
}
|
||||
|
||||
static Field mapFieldNameAndOwner(Mapper map, Field f) {
|
||||
String n = map.mapFieldName(f.getOwner(), f.getName(), f.getType());
|
||||
if (n == null) {
|
||||
n = f.getName();
|
||||
}
|
||||
return new Field(mapFieldOwner(map, f.getOwner(), f.getName(), f.getType()), n, mapClassName(map, f.getType()));
|
||||
}
|
||||
|
||||
private static String mapFieldOwner(Mapper map, String owner, String name, String type) {
|
||||
String n = map.mapFieldOwner(owner, name, type);
|
||||
if (n == null) {
|
||||
return owner;
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
private static Method mapMethod(Mapper map, Method m) {
|
||||
String n = map.mapMethodName(m.getOwner(), m.getName(), m.getParameterTypes(), m.getReturnType());
|
||||
if (n == null) {
|
||||
n = m.getName();
|
||||
}
|
||||
return new Method(mapClassName(map, m.getOwner()), n, mapClassNames(map, m.getParameterTypes()), mapClassName(
|
||||
map, m.getReturnType()));
|
||||
}
|
||||
|
||||
private static Method mapMethodNameAndOwner(Mapper map, Method m) {
|
||||
String n = map.mapMethodName(m.getOwner(), m.getName(), m.getParameterTypes(), m.getReturnType());
|
||||
if (n == null) {
|
||||
n = m.getName();
|
||||
}
|
||||
String owner = map.mapMethodOwner(m.getOwner(), m.getName(), m.getParameterTypes(), m.getReturnType());
|
||||
if (owner == null) {
|
||||
owner = m.getOwner();
|
||||
}
|
||||
return new Method(owner, n, mapClassNames(map, m.getParameterTypes()), mapClassName(map, m.getReturnType()));
|
||||
}
|
||||
|
||||
static Object mapObject(Mapper map, Object value) {
|
||||
if (value instanceof DexType) {
|
||||
value = new DexType(mapClassName(map, ((DexType) value).desc));
|
||||
} else if (value instanceof Field) {
|
||||
Field f = (Field) value;
|
||||
value = mapField(map, f);
|
||||
} else if (value instanceof Method) {
|
||||
Method m = (Method) value;
|
||||
value = mapMethod(map, m);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DexClassVisitor visit(int access_flags, final String className, String superClass, String[] interfaceNames) {
|
||||
DexClassVisitor dcv = super.visit(access_flags, mapClassName(mapper, className),
|
||||
mapClassName(mapper, superClass), mapClassNames(mapper, interfaceNames));
|
||||
if (dcv != null) {
|
||||
return new MappingCV(mapper, className, dcv);
|
||||
}
|
||||
return dcv;
|
||||
}
|
||||
|
||||
public static class MappingAV extends DexAnnotationVisitor {
|
||||
protected Mapper mapper;
|
||||
protected String oldAnnotationClassName;
|
||||
|
||||
public MappingAV(String oldAnnotationClassName, Mapper mapper, DexAnnotationVisitor visitor) {
|
||||
super(visitor);
|
||||
this.mapper = mapper;
|
||||
this.oldAnnotationClassName = oldAnnotationClassName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visit(String name, Object value) {
|
||||
if (name != null && oldAnnotationClassName != null) {
|
||||
name = mapAnnotationElementName(mapper, oldAnnotationClassName, name);
|
||||
}
|
||||
super.visit(name, mapObject(mapper, value));
|
||||
}
|
||||
|
||||
@Override
|
||||
public DexAnnotationVisitor visitAnnotation(String name, String desc) {
|
||||
if (name != null && oldAnnotationClassName != null) {
|
||||
name = mapAnnotationElementName(mapper, oldAnnotationClassName, name);
|
||||
}
|
||||
DexAnnotationVisitor dav = super.visitAnnotation(name, mapClassName(mapper, desc));
|
||||
if (dav != null) {
|
||||
return new MappingAV(desc, mapper, dav);
|
||||
}
|
||||
return dav;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DexAnnotationVisitor visitArray(String name) {
|
||||
if (name != null && oldAnnotationClassName != null) {
|
||||
name = mapAnnotationElementName(mapper, oldAnnotationClassName, name);
|
||||
}
|
||||
DexAnnotationVisitor dav = super.visitArray(name);
|
||||
if (dav != null) {
|
||||
return new MappingAV(null, mapper, dav);
|
||||
}
|
||||
return dav;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitEnum(String name, String desc, String value) {
|
||||
String fn = mapFieldName(mapper, desc, value, desc);
|
||||
if (name != null && oldAnnotationClassName != null) {
|
||||
name = mapAnnotationElementName(mapper, oldAnnotationClassName, name);
|
||||
}
|
||||
super.visitEnum(name, mapClassName(mapper, desc), fn);
|
||||
}
|
||||
}
|
||||
|
||||
public static class MappingCode extends DexCodeVisitor {
|
||||
protected Mapper mapper;
|
||||
|
||||
public MappingCode(Mapper mapper, DexCodeVisitor dcv) {
|
||||
super(dcv);
|
||||
this.mapper = mapper;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DexDebugVisitor visitDebug() {
|
||||
DexDebugVisitor v = super.visitDebug();
|
||||
if (v != null) {
|
||||
return new DexDebugVisitor(v) {
|
||||
@Override
|
||||
public void visitStartLocal(int reg, DexLabel label, String name, String type, String signature) {
|
||||
if (signature != null) {
|
||||
signature = remapSignature(mapper, signature, true);
|
||||
}
|
||||
super.visitStartLocal(reg, label, name, mapClassName(mapper, type), signature);
|
||||
}
|
||||
};
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitConstStmt(Op op, int ra, Object value) {
|
||||
super.visitConstStmt(op, ra, mapObject(mapper, value));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitFieldStmt(Op op, int a, int b, Field field) {
|
||||
super.visitFieldStmt(op, a, b, mapFieldNameAndOwner(mapper, field));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitFilledNewArrayStmt(Op op, int[] args, String type) {
|
||||
super.visitFilledNewArrayStmt(op, args, mapClassName(mapper, type));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitMethodStmt(Op op, int[] args, Method method) {
|
||||
switch (op) {
|
||||
case INVOKE_DIRECT:
|
||||
case INVOKE_DIRECT_RANGE:
|
||||
case INVOKE_STATIC:
|
||||
case INVOKE_STATIC_RANGE:
|
||||
case INVOKE_INTERFACE:
|
||||
case INVOKE_INTERFACE_RANGE:
|
||||
super.visitMethodStmt(op, args, mapMethodNameAndOwner(mapper, method));
|
||||
break;
|
||||
default:
|
||||
super.visitMethodStmt(op, args, mapMethod(mapper, method));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitTryCatch(DexLabel start, DexLabel end, DexLabel[] handler, String[] type) {
|
||||
super.visitTryCatch(start, end, handler, mapClassNames(mapper, type));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitTypeStmt(Op op, int a, int b, String type) {
|
||||
super.visitTypeStmt(op, a, b, mapClassName(mapper, type));
|
||||
}
|
||||
}
|
||||
|
||||
public static class MappingCV extends DexClassVisitor {
|
||||
protected String clzName;
|
||||
protected Mapper mapper;
|
||||
|
||||
public MappingCV(Mapper mapper, String clzName, DexClassVisitor dcv) {
|
||||
super(dcv);
|
||||
this.mapper = mapper;
|
||||
this.clzName = clzName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DexAnnotationVisitor visitAnnotation(String name, Visibility visibility) {
|
||||
final DexAnnotationVisitor dav = super.visitAnnotation(mapClassName(mapper, name), visibility);
|
||||
if (dav != null) {
|
||||
switch (name) {
|
||||
case DexConstants.ANNOTATION_SIGNATURE_TYPE:
|
||||
return new DexAnnotationNode(name, visibility) {
|
||||
@Override
|
||||
public void visitEnd() {
|
||||
super.visitEnd();
|
||||
Item p = super.items.get(0);
|
||||
Object[] newVs = remapSignature(mapper, (Object[]) p.value, false);
|
||||
dav.visit(p.name, newVs);
|
||||
dav.visitEnd();
|
||||
}
|
||||
};
|
||||
case DexConstants.ANNOTATION_INNER_CLASS_TYPE:
|
||||
return new DexAnnotationVisitor(dav) {
|
||||
@Override
|
||||
public void visit(String name, Object value) {
|
||||
if (name.equals("name")) {
|
||||
String simpleName = (String) value;
|
||||
if (simpleName != null) {
|
||||
if (clzName.endsWith("$" + simpleName + ";")) {
|
||||
String nNameDesc = mapClassName(mapper, clzName);
|
||||
String containd = mapClassName(mapper,
|
||||
clzName.substring(0, clzName.length() - 2 - simpleName.length()) + ";");
|
||||
|
||||
String internalNameWitherOwner = nNameDesc.substring(1, nNameDesc.length() - 1);
|
||||
String internalNameOwner = containd.substring(1, containd.length() - 1);
|
||||
|
||||
if (internalNameWitherOwner.startsWith(internalNameOwner + "$")) {
|
||||
value = internalNameWitherOwner.substring(1 + internalNameOwner.length());
|
||||
} else {
|
||||
value = null;
|
||||
}
|
||||
} else {
|
||||
value = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
super.visit(name, value);
|
||||
}
|
||||
};
|
||||
case DexConstants.ANNOTATION_ENCLOSING_CLASS_TYPE:
|
||||
return new DexAnnotationVisitor(dav) {
|
||||
@Override
|
||||
public void visit(String name, Object value) {
|
||||
if (name.equals("value")) {
|
||||
super.visit(name, new DexType(mapClassName(mapper, ((DexType) value).desc)));
|
||||
} else {
|
||||
super.visit(name, value);
|
||||
}
|
||||
}
|
||||
};
|
||||
case DexConstants.ANNOTATION_ENCLOSING_METHOD_TYPE: {
|
||||
return new DexAnnotationVisitor(dav) {
|
||||
@Override
|
||||
public void visit(String name, Object value) {
|
||||
if (name.equals("value")) {
|
||||
Method m = (Method) value;
|
||||
super.visit(name, mapMethod(mapper, m));
|
||||
} else {
|
||||
super.visit(name, value);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
default:
|
||||
return new MappingAV(name, mapper, dav);
|
||||
}
|
||||
}
|
||||
return dav;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DexFieldVisitor visitField(int accessFlags, Field field, Object value) {
|
||||
DexFieldVisitor dfv = super.visitField(accessFlags, mapField(mapper, field), mapObject(mapper, value));
|
||||
if (dfv != null) {
|
||||
return new MappingFV(mapper, dfv);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DexMethodVisitor visitMethod(int accessFlags, Method method) {
|
||||
DexMethodVisitor dmv = super.visitMethod(accessFlags, mapMethod(mapper, method));
|
||||
if (dmv != null) {
|
||||
return new MappingMV(mapper, dmv);
|
||||
}
|
||||
return dmv;
|
||||
}
|
||||
}
|
||||
|
||||
public static class MappingFV extends DexFieldVisitor {
|
||||
protected Mapper mapper;
|
||||
|
||||
public MappingFV(Mapper mapper, DexFieldVisitor dfv) {
|
||||
super(dfv);
|
||||
this.mapper = mapper;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DexAnnotationVisitor visitAnnotation(String name, Visibility visibility) {
|
||||
final DexAnnotationVisitor dav = super.visitAnnotation(mapClassName(mapper, name), visibility);
|
||||
if (dav != null) {
|
||||
if (DexConstants.ANNOTATION_SIGNATURE_TYPE.equals(name)) {
|
||||
return new DexAnnotationNode(name, visibility) {
|
||||
@Override
|
||||
public void visitEnd() {
|
||||
super.visitEnd();
|
||||
Item p = super.items.get(0);
|
||||
Object[] newVs = remapSignature(mapper, (Object[]) p.value, true);
|
||||
dav.visit(p.name, newVs);
|
||||
dav.visitEnd();
|
||||
}
|
||||
};
|
||||
}
|
||||
return new MappingAV(name, mapper, dav);
|
||||
}
|
||||
return dav;
|
||||
}
|
||||
}
|
||||
|
||||
public static class MappingMV extends DexMethodVisitor {
|
||||
protected Mapper mapper;
|
||||
|
||||
public MappingMV(Mapper mapper, DexMethodVisitor dmv) {
|
||||
super(dmv);
|
||||
this.mapper = mapper;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DexAnnotationVisitor visitAnnotation(String name, Visibility visibility) {
|
||||
final DexAnnotationVisitor dav = super.visitAnnotation(mapClassName(mapper, name), visibility);
|
||||
if (dav != null) {
|
||||
if (DexConstants.ANNOTATION_SIGNATURE_TYPE.equals(name)) {
|
||||
return new DexAnnotationNode(name, visibility) {
|
||||
@Override
|
||||
public void visitEnd() {
|
||||
super.visitEnd();
|
||||
Item p = super.items.get(0);
|
||||
Object[] newVs = remapSignature(mapper, (Object[]) p.value, false);
|
||||
dav.visit(p.name, newVs);
|
||||
dav.visitEnd();
|
||||
}
|
||||
};
|
||||
}
|
||||
return new MappingAV(name, mapper, dav);
|
||||
}
|
||||
return dav;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DexCodeVisitor visitCode() {
|
||||
DexCodeVisitor dcv = super.visitCode();
|
||||
if (dcv != null) {
|
||||
return new MappingCode(mapper, dcv);
|
||||
}
|
||||
return dcv;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DexAnnotationAble visitParameterAnnotation(int index) {
|
||||
final DexAnnotationAble a = super.visitParameterAnnotation(index);
|
||||
if (a != null) {
|
||||
return new DexAnnotationAble() {
|
||||
@Override
|
||||
public DexAnnotationVisitor visitAnnotation(String name, Visibility visibility) {
|
||||
DexAnnotationVisitor dav = a.visitAnnotation(mapClassName(mapper, name), visibility);
|
||||
if (dav != null) {
|
||||
return new MappingAV(name, mapper, dav);
|
||||
}
|
||||
return dav;
|
||||
}
|
||||
};
|
||||
}
|
||||
return a;
|
||||
}
|
||||
}
|
||||
|
||||
static Object[] remapSignature(final Mapper mapper, Object vs[], boolean isType) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (Object v0 : vs) {
|
||||
sb.append(v0);
|
||||
}
|
||||
return Types.buildDexStyleSignature(remapSignature(mapper, sb.toString(), isType));
|
||||
}
|
||||
|
||||
static String remapSignature(final Mapper mapper, String sig, boolean isType) {
|
||||
SignatureWriter w = new SignatureWriter() {
|
||||
String clzName;
|
||||
|
||||
@Override
|
||||
public void visitClassType(String name) {
|
||||
super.visitClassType(mapClassName(mapper, name));
|
||||
clzName = name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitInnerClassType(String simpleName) {
|
||||
String value = simpleName;
|
||||
if (simpleName != null) {
|
||||
if (clzName.endsWith("$" + simpleName + ";")) {
|
||||
String nNameDesc = mapClassName(mapper, clzName);
|
||||
String containd = mapClassName(mapper,
|
||||
clzName.substring(0, clzName.length() - 2 - simpleName.length()) + ";");
|
||||
|
||||
String internalNameWitherOwner = nNameDesc.substring(1, nNameDesc.length() - 1);
|
||||
String internalNameOwner = containd.substring(1, containd.length() - 1);
|
||||
|
||||
if (internalNameWitherOwner.startsWith(internalNameOwner + "$")) {
|
||||
value = internalNameWitherOwner.substring(1 + internalNameOwner.length());
|
||||
} else {
|
||||
value = null;
|
||||
}
|
||||
} else {
|
||||
value = null;
|
||||
}
|
||||
}
|
||||
super.visitInnerClassType(value);
|
||||
}
|
||||
};
|
||||
if (isType) {
|
||||
new SignatureReader(sig).acceptType(w);
|
||||
} else {
|
||||
new SignatureReader(sig).accept(w);
|
||||
}
|
||||
return w.toString();
|
||||
}
|
||||
}
|
@ -1,476 +0,0 @@
|
||||
/*
|
||||
* dex2jar - Tools to work with android .dex and java .class files
|
||||
* Copyright (c) 2009-2013 Panxiaobo
|
||||
*
|
||||
* 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 com.googlecode.d2j.map;
|
||||
|
||||
import com.googlecode.d2j.DexConstants;
|
||||
import com.googlecode.d2j.util.Mapper;
|
||||
import com.googlecode.dex2jar.ir.ts.UniqueQueue;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
public class InheritanceTree implements Mapper {
|
||||
Map<String, Clz> clzMap = new HashMap<>();
|
||||
String from;
|
||||
boolean isLibrary;
|
||||
|
||||
public InheritanceTree() {
|
||||
}
|
||||
|
||||
public static void main(String... args) {
|
||||
InheritanceTree tree = new InheritanceTree();
|
||||
Clz a = tree.addClz(0, "La;");
|
||||
a.addMethod(0, "abc", new String[0], "V");
|
||||
Clz b = tree.addClz(0, "Lb;");
|
||||
b.addMethod(0, "abc", new String[0], "V");
|
||||
Clz c = tree.addClz(0, "Lc;");
|
||||
c.relateSuper("Ljava/lang/Object;");
|
||||
c.relateInterface("La;");
|
||||
c.relateInterface("Lb;");
|
||||
tree.link();
|
||||
}
|
||||
|
||||
private static boolean isPrivate(int accessFlags) {
|
||||
return ((DexConstants.ACC_PRIVATE) & accessFlags) != 0;
|
||||
}
|
||||
|
||||
private static boolean isStaticOrPrivate(int accessFlags) {
|
||||
return ((DexConstants.ACC_PRIVATE | DexConstants.ACC_STATIC) & accessFlags) != 0;
|
||||
}
|
||||
|
||||
private static boolean isStaticOrPrivateOrFinal(int accessFlags) {
|
||||
return ((DexConstants.ACC_PRIVATE | DexConstants.ACC_STATIC | DexConstants.ACC_FINAL) & accessFlags) != 0;
|
||||
}
|
||||
|
||||
public void updateFrom(String from, boolean isLibrary) {
|
||||
this.from = from;
|
||||
this.isLibrary = isLibrary;
|
||||
}
|
||||
|
||||
public String mapClassName(String name) {
|
||||
Clz clz = clzMap.get(name);
|
||||
if (clz == null) {
|
||||
return null;
|
||||
}
|
||||
return clz.name.newValue;
|
||||
}
|
||||
|
||||
public void recordClassRenameTo(String old, String newName) {
|
||||
Clz clz = clzMap.get(old);
|
||||
if (clz == null) {
|
||||
WARN("WARN: cant find class %s", old);
|
||||
return;
|
||||
}
|
||||
if (clz.name.noRename) {
|
||||
WARN("WARN: cant rename class %s");
|
||||
return;
|
||||
}
|
||||
clz.name.newValue = newName;
|
||||
}
|
||||
|
||||
public void recordMethodRenameTo(String owner, String oldName, String[] args, String ret, String newName) {
|
||||
Clz clz = clzMap.get(owner);
|
||||
if (clz == null) {
|
||||
WARN("WARN: cant find class %s", owner);
|
||||
return;
|
||||
}
|
||||
String key = toMethodKey(oldName, args, ret);
|
||||
Mtd mtd = clz.methods.get(key);
|
||||
if (mtd == null) {
|
||||
WARN("WARN: cant find method %s->%s", owner, key);
|
||||
return;
|
||||
}
|
||||
if (mtd.name.noRename && !oldName.equals(newName)) {
|
||||
WARN("WARN: cant rename method %s->%s to %s", owner, key, newName);
|
||||
return;
|
||||
}
|
||||
if (mtd.name.newValue == null) {
|
||||
mtd.name.newValue = newName;
|
||||
} else if (!newName.equals(mtd.name.newValue)) {
|
||||
WARN("WARN: cant rename method %s->%s to %s, pre rename to %s", owner, key, newName, mtd.name.newValue);
|
||||
}
|
||||
}
|
||||
|
||||
public void recordFieldRenameTo(String owner, String oldName, String type, String newName) {
|
||||
Clz clz = clzMap.get(owner);
|
||||
if (clz == null) {
|
||||
WARN("WARN: cant find class %s", owner);
|
||||
return;
|
||||
}
|
||||
String key = toFieldKey(oldName, type);
|
||||
Fld fld = clz.fields.get(key);
|
||||
if (fld == null) {
|
||||
WARN("WARN: cant find field %s->%s", owner, key);
|
||||
return;
|
||||
}
|
||||
if (fld.name.noRename && !oldName.equals(newName)) {
|
||||
WARN("WARN: cant rename field %s->%s to %s", owner, key, newName);
|
||||
return;
|
||||
}
|
||||
if (fld.name.newValue == null) {
|
||||
fld.name.newValue = newName;
|
||||
} else if (!newName.equals(fld.name.newValue)) {
|
||||
WARN("WARN: cant rename field %s->%s to %s, pre rename to %s", owner, key, newName, fld.name.newValue);
|
||||
}
|
||||
}
|
||||
|
||||
public String mapFieldName(String owner, String name, String type) {
|
||||
Clz clz = clzMap.get(owner);
|
||||
if (clz == null) {
|
||||
return null;
|
||||
}
|
||||
Fld fld = clz.fields.get(toFieldKey(name, type));
|
||||
if (fld == null) {
|
||||
return null;
|
||||
}
|
||||
return fld.name.newValue;
|
||||
}
|
||||
|
||||
public String mapFieldOwner(String owner, String name, String type) {
|
||||
Clz clz = clzMap.get(owner);
|
||||
if (clz == null) {
|
||||
return null;
|
||||
}
|
||||
Fld fld = clz.fields.get(toFieldKey(name, type));
|
||||
if (fld == null) {
|
||||
return clz.name.newValue;
|
||||
}
|
||||
Name fldName = fld.owner.name;
|
||||
if (fldName.newValue == null) {
|
||||
return fldName.oldValue;
|
||||
} else {
|
||||
return fldName.newValue;
|
||||
}
|
||||
}
|
||||
|
||||
public String mapMethodName(String owner, String name, String[] args, String ret) {
|
||||
Clz clz = clzMap.get(owner);
|
||||
if (clz == null) {
|
||||
return null;
|
||||
}
|
||||
Mtd mtd = null;
|
||||
if (args == null || ret == null) {
|
||||
for (Mtd m : clz.methods.values()) {
|
||||
if (m.args.length == 0 && m.name.oldValue.equals(name)) {
|
||||
mtd = m;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
mtd = clz.methods.get(toMethodKey(name, args, ret));
|
||||
}
|
||||
if (mtd == null) {
|
||||
return null;
|
||||
}
|
||||
return mtd.name.newValue;
|
||||
}
|
||||
|
||||
public String mapMethodOwner(String owner, String name, String[] args, String ret) {
|
||||
Clz clz = clzMap.get(owner);
|
||||
if (clz == null) {
|
||||
return null;
|
||||
}
|
||||
Mtd mtd = null;
|
||||
if (args == null || ret == null) {
|
||||
for (Mtd m : clz.methods.values()) {
|
||||
if (m.args.length == 0 && m.name.oldValue.equals(name)) {
|
||||
mtd = m;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
mtd = clz.methods.get(toMethodKey(name, args, ret));
|
||||
}
|
||||
if (mtd == null) {
|
||||
return clz.name.newValue;
|
||||
}
|
||||
Name mtdName = mtd.owner.name;
|
||||
if (mtdName.newValue == null) {
|
||||
return mtdName.oldValue;
|
||||
} else {
|
||||
return mtdName.newValue;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param accessFlags
|
||||
* the access flags of the class
|
||||
* @param name
|
||||
* the descriptor of the class
|
||||
* @return return null if the class is redefined
|
||||
*/
|
||||
Clz addClz(int accessFlags, String name) {
|
||||
Clz clz = getOrCreateClz(name);
|
||||
if (clz.stat != Stat.UNKNOWN) {
|
||||
if (clz.stat == Stat.LIBRARY && !isLibrary) {
|
||||
WARN("app class %s redefined, org %s, new %s, skiping.", name, clz.from, from);
|
||||
return null;
|
||||
} else {
|
||||
WARN("class %s is defined in %s, skip redefine in %s", name, clz.from, from);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
clz.stat = isLibrary ? Stat.LIBRARY : Stat.APP;
|
||||
clz.accessFlags = accessFlags;
|
||||
clz.from = from;
|
||||
return clz;
|
||||
}
|
||||
|
||||
public void link() {
|
||||
Queue<Clz> q = new UniqueQueue<>();
|
||||
q.addAll(clzMap.values());
|
||||
|
||||
while (!q.isEmpty()) {
|
||||
Clz clz = q.poll();
|
||||
for (Map.Entry<String, Mtd> e : clz.methods.entrySet()) {
|
||||
String key = e.getKey();
|
||||
Mtd mtd = e.getValue();
|
||||
Name name = mtd.name.trim();
|
||||
mtd.name = name;
|
||||
if (name.oldValue.startsWith("<")) {
|
||||
// constructor, skip
|
||||
continue;
|
||||
}
|
||||
if (isPrivate(mtd.accessFlags)) {
|
||||
continue;
|
||||
}
|
||||
if (clz.children.size() > 0) {
|
||||
for (Clz child : clz.children) {
|
||||
Mtd childMtd = child.methods.get(key);
|
||||
if (childMtd != null) {
|
||||
if (isStaticOrPrivateOrFinal(childMtd.accessFlags)) {
|
||||
continue;
|
||||
}
|
||||
childMtd.name = merge(name, childMtd.name);
|
||||
} else {
|
||||
child.methods.put(key, mtd);
|
||||
q.add(child);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (clz.impls.size() > 0) {
|
||||
for (Clz child : clz.impls) {
|
||||
Mtd childMtd = child.methods.get(key);
|
||||
if (childMtd != null) {
|
||||
childMtd.name = merge(name, childMtd.name);
|
||||
} else {
|
||||
child.methods.put(key, mtd);
|
||||
q.add(child);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
q.addAll(clzMap.values());
|
||||
|
||||
while (!q.isEmpty()) {
|
||||
Clz clz = q.poll();
|
||||
if (clz.fields.size() > 0) {
|
||||
for (Map.Entry<String, Fld> e : clz.fields.entrySet()) {
|
||||
String key = e.getKey();
|
||||
Fld fld = e.getValue();
|
||||
if (isPrivate(fld.accessFlags)) { // also copy static method to sub
|
||||
continue;
|
||||
}
|
||||
if (clz.children.size() > 0) {
|
||||
for (Clz child : clz.children) {
|
||||
if (!child.fields.containsKey(key)) {
|
||||
child.fields.put(key, fld);
|
||||
q.add(child);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (Clz clz : clzMap.values()) {
|
||||
if (clz.stat == Stat.UNKNOWN) {
|
||||
WARN("clz %s is unknow", clz.name);
|
||||
}
|
||||
|
||||
boolean noRename = clz.stat == Stat.UNKNOWN || clz.stat == Stat.LIBRARY;
|
||||
clz.name.noRename = noRename;
|
||||
if (clz.methods.size() > 0) {
|
||||
for (Mtd mtd : clz.methods.values()) {
|
||||
Name name = mtd.name.trim();
|
||||
mtd.name = name;
|
||||
if (noRename) {
|
||||
name.noRename = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (noRename && clz.fields.size() > 0) {
|
||||
for (Fld fld : clz.fields.values()) {
|
||||
fld.name.noRename = true;
|
||||
}
|
||||
}
|
||||
|
||||
// relationship is useless now
|
||||
clz.children = null;
|
||||
clz.impls = null;
|
||||
clz.superClz = null;
|
||||
clz.interfaces = null;
|
||||
}
|
||||
}
|
||||
|
||||
private Name merge(Name name, Name childMtd) {
|
||||
childMtd = childMtd.trim();
|
||||
if (childMtd != name) {
|
||||
childMtd.next = name;
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
private boolean isPrivateOrFinal(int accessFlags) {
|
||||
return ((DexConstants.ACC_PRIVATE | DexConstants.ACC_FINAL) & accessFlags) != 0;
|
||||
}
|
||||
|
||||
private void WARN(String s, Object... args) {
|
||||
System.err.println(String.format(s, args));
|
||||
}
|
||||
|
||||
Clz getOrCreateClz(String name) {
|
||||
Clz clz = clzMap.get(name);
|
||||
if (clz == null) {
|
||||
clz = new Clz(name);
|
||||
clzMap.put(name, clz);
|
||||
}
|
||||
return clz;
|
||||
}
|
||||
|
||||
public static String toFieldKey(String name, String type) {
|
||||
return name + ":" + type;
|
||||
}
|
||||
|
||||
public static String toMethodKey(String name, String args[], String ret) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(name).append("(");
|
||||
for (String arg : args) {
|
||||
sb.append(arg);
|
||||
}
|
||||
sb.append(")").append(ret);
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public enum Stat {
|
||||
UNKNOWN, LIBRARY, APP
|
||||
}
|
||||
|
||||
public static class Name {
|
||||
final String oldValue;
|
||||
boolean noRename = false;
|
||||
String newValue;
|
||||
Name next;
|
||||
|
||||
public Name(String name) {
|
||||
this.oldValue = name;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return oldValue;
|
||||
}
|
||||
|
||||
public Name trim() {
|
||||
Name n = this;
|
||||
while (n.next != null) {
|
||||
n = n.next;
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static class Fld {
|
||||
public int accessFlags;
|
||||
public Name name;
|
||||
public Clz owner;
|
||||
public String type;
|
||||
}
|
||||
|
||||
public static class Mtd {
|
||||
public int accessFlags;
|
||||
public Name name;
|
||||
public Clz owner;
|
||||
public String ret;
|
||||
public String[] args;
|
||||
}
|
||||
|
||||
public class Clz {
|
||||
public final Name name;
|
||||
public Stat stat = Stat.UNKNOWN;
|
||||
public String from;
|
||||
public int accessFlags;
|
||||
public Clz superClz;
|
||||
public Set<Clz> interfaces = new HashSet<>();
|
||||
public Set<Clz> children = new HashSet<>();
|
||||
public Set<Clz> impls = new HashSet<>();
|
||||
public Map<String, Mtd> methods = new HashMap<>();
|
||||
public Map<String, Fld> fields = new HashMap<>();
|
||||
|
||||
Clz(String name) {
|
||||
this.name = new Name(name);
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return name.toString();
|
||||
}
|
||||
|
||||
public void relateSuper(String name) {
|
||||
Clz s = getOrCreateClz(name);
|
||||
superClz = s;
|
||||
s.children.add(this);
|
||||
}
|
||||
|
||||
public void relateInterface(String itf) {
|
||||
Clz s = getOrCreateClz(itf);
|
||||
interfaces.add(s);
|
||||
s.impls.add(this);
|
||||
}
|
||||
|
||||
public void addMethod(int accessFlags, String name, String args[], String ret) {
|
||||
String key = toMethodKey(name, args, ret);
|
||||
if (methods.containsKey(key)) {
|
||||
WARN("DUP method: %s in class %s, skiping.", key, this.name);
|
||||
return;
|
||||
}
|
||||
Mtd mtd = new Mtd();
|
||||
mtd.owner = this;
|
||||
mtd.accessFlags = accessFlags;
|
||||
mtd.name = new Name(name);
|
||||
mtd.ret = ret;
|
||||
mtd.args = args;
|
||||
methods.put(key, mtd);
|
||||
}
|
||||
|
||||
public void addField(int accessFlags, String name, String type) {
|
||||
String key = toFieldKey(name, type);
|
||||
if (fields.containsKey(key)) {
|
||||
WARN("DUP field: %s in class %s, skiping.", key, this.name);
|
||||
return;
|
||||
}
|
||||
Fld fld = new Fld();
|
||||
fld.owner = this;
|
||||
fld.name = new Name(name);
|
||||
fld.accessFlags = accessFlags;
|
||||
fld.type = type;
|
||||
fields.put(key, fld);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -1,110 +0,0 @@
|
||||
/*
|
||||
* dex2jar - Tools to work with android .dex and java .class files
|
||||
* Copyright (c) 2009-2013 Panxiaobo
|
||||
*
|
||||
* 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 com.googlecode.d2j.map;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.Reader;
|
||||
|
||||
public class ProguardMappingParser {
|
||||
private String j2d(String type) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
while (type.endsWith("[]")) {
|
||||
sb.append("[");
|
||||
type = type.substring(0, type.length() - 2);
|
||||
}
|
||||
switch (type) {
|
||||
case "boolean":
|
||||
sb.append("Z");
|
||||
break;
|
||||
case "byte":
|
||||
sb.append("B");
|
||||
break;
|
||||
case "short":
|
||||
sb.append("S");
|
||||
break;
|
||||
case "char":
|
||||
sb.append("C");
|
||||
break;
|
||||
case "int":
|
||||
sb.append("I");
|
||||
break;
|
||||
case "float":
|
||||
sb.append("F");
|
||||
break;
|
||||
case "long":
|
||||
sb.append("J");
|
||||
break;
|
||||
case "double":
|
||||
sb.append("D");
|
||||
break;
|
||||
case "void":
|
||||
sb.append("V");
|
||||
break;
|
||||
default:
|
||||
sb.append("L").append(type.replace('.', '/')).append(";");
|
||||
break;
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public void parse(Reader in, InheritanceTree tree) throws IOException {
|
||||
BufferedReader r = new BufferedReader(in);
|
||||
String currentClz = null;
|
||||
for (String ln = r.readLine(); ln != null; ln = r.readLine()) {
|
||||
if (ln.startsWith(" ")) { // member mapping
|
||||
// java.lang.String data -> a
|
||||
// boolean equals(java.lang.Object) -> equals
|
||||
ln = ln.trim();
|
||||
String as[] = ln.split(" ");
|
||||
String fieldDescOrMethodRet = j2d(as[0]);
|
||||
String fieldNameOrMethodNameDesc = as[1];
|
||||
String newName = as[3];
|
||||
|
||||
if (fieldNameOrMethodNameDesc.contains("(")) { // a method
|
||||
|
||||
int idx = fieldNameOrMethodNameDesc.indexOf('(');
|
||||
String mName = fieldNameOrMethodNameDesc.substring(0, idx);
|
||||
String args = fieldNameOrMethodNameDesc.substring(idx + 1,
|
||||
fieldNameOrMethodNameDesc.length() - 1);
|
||||
String[] ps;
|
||||
if (args.length() != 0) {
|
||||
ps = args.split(",");
|
||||
for (int i = 0; i < ps.length; i++) {
|
||||
ps[i] = j2d(ps[i]);
|
||||
}
|
||||
} else {
|
||||
ps = new String[0];
|
||||
}
|
||||
tree.recordMethodRenameTo(currentClz, mName, ps, fieldDescOrMethodRet, newName);
|
||||
} else {
|
||||
tree.recordFieldRenameTo(currentClz, fieldNameOrMethodNameDesc, fieldDescOrMethodRet, newName);
|
||||
}
|
||||
|
||||
} else { // clz mapping
|
||||
// clz -> n:
|
||||
String as[] = ln.split(" ");
|
||||
currentClz = j2d(as[0]);
|
||||
String newName = as[2];
|
||||
if (newName.endsWith(":")) {
|
||||
newName = newName.substring(0, newName.length() - 1);
|
||||
}
|
||||
tree.recordClassRenameTo(currentClz, j2d(newName));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,132 +0,0 @@
|
||||
package com.googlecode.dex2jar.tools;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.Reader;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
|
||||
import org.objectweb.asm.ClassReader;
|
||||
import org.objectweb.asm.tree.ClassNode;
|
||||
|
||||
import com.googlecode.d2j.dex.writer.DexFileWriter;
|
||||
import com.googlecode.d2j.jasmin.Jasmins;
|
||||
import com.googlecode.d2j.map.*;
|
||||
import com.googlecode.d2j.reader.DexFileReader;
|
||||
import com.googlecode.d2j.reader.zip.ZipUtil;
|
||||
import com.googlecode.d2j.smali.Smali;
|
||||
import com.googlecode.d2j.visitors.DexFileVisitor;
|
||||
import com.googlecode.dex2jar.tools.BaseCmd.Syntax;
|
||||
|
||||
@Syntax(cmd = "d2j-dex-mapping", syntax = "[options] <dex>", desc = "remap names in dex file")
|
||||
public class DexRemapCmd extends BaseCmd {
|
||||
@Opt(opt = "o", longOpt = "output", description = "the name of the dex file that will be written. The default is out.dex", argName = "FILE")
|
||||
private File output;
|
||||
@Opt(opt = "L", longOpt = "library", description = "libraries we want load ',' separated")
|
||||
private String library;
|
||||
@Opt(opt = "C", longOpt = "config-file", description = "the config file generated by proguard", argName = "conf")
|
||||
private Path config;
|
||||
|
||||
public static void main(String[] args) {
|
||||
new DexRemapCmd().doMain(args);
|
||||
}
|
||||
|
||||
void V(String fmt, Object... args) {
|
||||
System.err.println(String.format(fmt, args));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doCommandLine() throws Exception {
|
||||
|
||||
if (remainingArgs.length < 1) {
|
||||
System.err.println("ERROR: no file to process");
|
||||
return;
|
||||
}
|
||||
|
||||
if (config == null) {
|
||||
System.err.println("ERROR: please set the config file -L,--config-file");
|
||||
return;
|
||||
}
|
||||
|
||||
if (output == null) {
|
||||
output = new File("out.dex");
|
||||
}
|
||||
|
||||
final InheritanceTree tree = buildRenameTree();
|
||||
|
||||
DexFileWriter fw = new DexFileWriter();
|
||||
|
||||
DexFileVisitor fv = new DexFileVisitor(fw) {
|
||||
@Override
|
||||
public void visitEnd() {
|
||||
//
|
||||
}
|
||||
};
|
||||
|
||||
fv = new DexMappingAdapter(tree, fv);
|
||||
|
||||
for (String s : remainingArgs) {
|
||||
V(">> Remap %s -> %s", s, output);
|
||||
DexFileReader reader = new DexFileReader(ZipUtil.readDex(new File(s)));
|
||||
reader.accept(fv);
|
||||
}
|
||||
fw.visitEnd();
|
||||
|
||||
byte[] data = fw.toByteArray();
|
||||
Files.write(output.toPath(),data);
|
||||
}
|
||||
|
||||
private InheritanceTree buildRenameTree() throws IOException {
|
||||
|
||||
final InheritanceTree tree = new InheritanceTree();
|
||||
AutoDetectSourceProcess processer = new AutoDetectSourceProcess() {
|
||||
DexInheritanceFileVisitor dfv = new DexInheritanceFileVisitor(tree);
|
||||
AsmInheritanceClassVisitor acv = new AsmInheritanceClassVisitor(tree);
|
||||
|
||||
@Override
|
||||
protected void onDex(Path file) throws IOException {
|
||||
DexFileReader r = new DexFileReader(ZipUtil.readDex(Files.readAllBytes(file)));
|
||||
r.accept(dfv, DexFileReader.SKIP_CODE | DexFileReader.SKIP_ANNOTATION
|
||||
| DexFileReader.SKIP_FIELD_CONSTANT);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onClass(Path file) throws IOException {
|
||||
ClassReader cr = new ClassReader(Files.readAllBytes(file));
|
||||
cr.accept(acv, ClassReader.SKIP_CODE | ClassReader.SKIP_DEBUG | ClassReader.SKIP_FRAMES);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onJasmin(Path file) throws IOException {
|
||||
ClassNode cn = Jasmins.parse(file);
|
||||
cn.accept(acv);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onSmali(Path file) throws IOException {
|
||||
Smali smali = new Smali();
|
||||
smali.smaliFile(file, dfv);
|
||||
}
|
||||
};
|
||||
|
||||
for (String lib : library.split(",")) {
|
||||
V("<< Load Lib %s", lib);
|
||||
tree.updateFrom(lib, true);
|
||||
processer.process(lib);
|
||||
}
|
||||
for (String s : remainingArgs) {
|
||||
V("<< Load App %s", s);
|
||||
tree.updateFrom(s, false);
|
||||
processer.process(s);
|
||||
}
|
||||
V("<< Link for rename");
|
||||
tree.link();
|
||||
|
||||
V("<< Apply config file %s", config);
|
||||
try (Reader configReadre = Files.newBufferedReader(config, StandardCharsets.UTF_8)) {
|
||||
new ProguardMappingParser().parse(configReadre, tree);
|
||||
}
|
||||
return tree;
|
||||
}
|
||||
}
|
@ -1,72 +0,0 @@
|
||||
/*
|
||||
* dex2jar - Tools to work with android .dex and java .class files
|
||||
* Copyright (c) 2009-2012 Panxiaobo
|
||||
*
|
||||
* 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 com.googlecode.dex2jar.tools;
|
||||
|
||||
import java.io.File;
|
||||
import java.nio.file.Path;
|
||||
|
||||
import com.googlecode.dex2jar.tools.BaseCmd.Syntax;
|
||||
|
||||
@Syntax(cmd = "d2j-jar-remap", syntax = "[options] jar", desc = "rename package/class/method/field name in a jar", onlineHelp = "https://code.google.com/p/dex2jar/wiki/DeObfuscateJarWithDexTool")
|
||||
public class JarRemap extends BaseCmd {
|
||||
public static void main(String... args) {
|
||||
new JarRemap().doMain(args);
|
||||
}
|
||||
|
||||
@Opt(opt = "f", longOpt = "force", hasArg = false, description = "force overwrite")
|
||||
private boolean forceOverwrite = false;
|
||||
@Opt(opt = "o", longOpt = "output", description = "output .jar file, default is $current_dir/[jar-name]-remap.jar", argName = "out-jar")
|
||||
private File output;
|
||||
@Opt(opt = "c", longOpt = "config", required = true, description = "config file for remap, this is REQUIRED", argName = "config")
|
||||
private Path config;
|
||||
@Opt(opt = "L", longOpt = "library", description = "libraries we want load ',' separated")
|
||||
private String library;
|
||||
@Opt(opt = "C", longOpt = "config-file", description = "the config file generated by proguard", argName = "conf")
|
||||
private Path proguardConfig;
|
||||
|
||||
@Override
|
||||
protected void doCommandLine() throws Exception {
|
||||
if (remainingArgs.length != 1) {
|
||||
usage();
|
||||
return;
|
||||
}
|
||||
|
||||
File jar = new File(remainingArgs[0]);
|
||||
if (!jar.exists()) {
|
||||
System.err.println(jar + " is not exists");
|
||||
usage();
|
||||
return;
|
||||
}
|
||||
|
||||
if (output == null) {
|
||||
if (jar.isDirectory()) {
|
||||
output = new File(jar.getName() + "-remap.jar");
|
||||
} else {
|
||||
output = new File(getBaseName(jar.getName()) + "-remap.jar");
|
||||
}
|
||||
}
|
||||
|
||||
if (output.exists() && !forceOverwrite) {
|
||||
System.err.println(output + " exists, use --force to overwrite");
|
||||
usage();
|
||||
return;
|
||||
}
|
||||
|
||||
System.out.println("remap " + jar + " -> " + output);
|
||||
// new ReName().from(jar).withConfig(config).to(output);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user