
com.googlecode.dex2jar.tools.DexWeaverCmd Maven / Gradle / Ivy
package com.googlecode.dex2jar.tools;
import com.googlecode.d2j.Method;
import com.googlecode.d2j.dex.writer.DexFileWriter;
import com.googlecode.d2j.reader.DexFileReader;
import com.googlecode.d2j.reader.Op;
import com.googlecode.d2j.reader.zip.ZipUtil;
import com.googlecode.d2j.smali.Utils;
import com.googlecode.d2j.visitors.DexClassVisitor;
import com.googlecode.d2j.visitors.DexCodeVisitor;
import com.googlecode.d2j.visitors.DexFileVisitor;
import com.googlecode.d2j.visitors.DexMethodVisitor;
import java.io.File;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.HashMap;
import java.util.Map;
@BaseCmd.Syntax(cmd = "d2j-dex-weaver", syntax = "[options] dex", desc = "replace invoke in dex", onlineHelp = "https"
+ "://sourceforge.net/p/dex2jar/wiki/DexWeaver")
public class DexWeaverCmd extends BaseCmd {
@Opt(opt = "o", longOpt = "output", description = "output .dex file", argName = "out-dex-file")
private Path output;
@Opt(opt = "c", longOpt = "config", description = "config file", argName = "config")
private Path config;
@Opt(opt = "s", longOpt = "stub-dex", description = "stub dex", argName = "stub")
private Path stub;
static Method parseMethod(String str) {
int i = str.indexOf('.');
String owner = str.substring(0, i);
int j = str.indexOf('(', i);
String name = str.substring(i + 1, j);
i = str.indexOf(')', j);
String args = str.substring(j + 1, i);
String ret = str.substring(i + 1);
return new Method(owner, name, Utils.toTypeList(args), ret);
}
@Override
protected void doCommandLine() throws Exception {
if (remainingArgs.length == 0) {
throw new HelpException("no odex");
}
final Map map = new HashMap<>();
for (String ln : Files.readAllLines(config, StandardCharsets.UTF_8)) {
if (ln.startsWith("#") || ln.isEmpty()) {
continue;
}
String[] x = ln.split("=");
map.put(x[0], parseMethod(x[1]));
}
DexFileWriter out = new DexFileWriter();
DexFileVisitor fv = new DexFileVisitor(out) {
@Override
public DexClassVisitor visit(int accessFlags, String className, String superClass,
String[] interfaceNames) {
DexClassVisitor dcv = super.visit(accessFlags, className, superClass, interfaceNames);
if (dcv != null) {
return new DexClassVisitor(dcv) {
@Override
public DexMethodVisitor visitMethod(int accessFlags, Method method) {
DexMethodVisitor dmv = super.visitMethod(accessFlags, method);
if (dmv != null) {
return new DexMethodVisitor(dmv) {
@Override
public DexCodeVisitor visitCode() {
DexCodeVisitor code = super.visitCode();
if (code != null) {
return new DexCodeVisitor(code) {
@Override
public void visitMethodStmt(Op op, int[] args, Method method) {
Method replaceTo = map.get(method.toString());
if (replaceTo != null) {
switch (op) {
case INVOKE_DIRECT:
case INVOKE_INTERFACE:
case INVOKE_STATIC:
case INVOKE_SUPER:
case INVOKE_VIRTUAL:
super.visitMethodStmt(Op.INVOKE_STATIC, args, replaceTo);
break;
case INVOKE_DIRECT_RANGE:
case INVOKE_INTERFACE_RANGE:
case INVOKE_STATIC_RANGE:
case INVOKE_SUPER_RANGE:
case INVOKE_VIRTUAL_RANGE:
super.visitMethodStmt(Op.INVOKE_STATIC_RANGE, args,
replaceTo);
break;
default:
// impossible here
}
} else {
super.visitMethodStmt(op, args, method);
}
}
};
}
return code;
}
};
}
return dmv;
}
};
}
return dcv;
}
@Override
public void visitEnd() {
}
};
for (String f : remainingArgs) {
byte[] data = ZipUtil.readDex(new File(f).toPath());
DexFileReader r = new DexFileReader(data);
r.accept(fv);
}
if (stub != null) {
byte[] data = ZipUtil.readDex(stub);
DexFileReader r = new DexFileReader(data);
r.accept(new DexFileVisitor(out) {
@Override
public void visitEnd() {
}
});
}
out.visitEnd();
byte[] data = out.toByteArray();
Files.write(output, data);
}
public static void main(String... args) {
new DexWeaverCmd().doMain(args);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy