com.googlecode.dex2jar.tools.GenerateCompileStubFromOdex Maven / Gradle / Ivy
The newest version!
package com.googlecode.dex2jar.tools;
import com.googlecode.d2j.dex.ClassVisitorFactory;
import com.googlecode.d2j.dex.Dex2Asm;
import com.googlecode.d2j.node.DexFileNode;
import com.googlecode.d2j.reader.DexFileReader;
import org.objectweb.asm.*;
import java.io.File;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.file.FileSystem;
import java.nio.file.Files;
import java.nio.file.Path;
@BaseCmd.Syntax(cmd = "d2j-generate-stub-from-odex", syntax = "[options] [odex1 ... odexN]", desc = "Genenerate no-code jar from odex")
public class GenerateCompileStubFromOdex extends BaseCmd {
private static final int MAGIC_ODEX = 0x0A796564 & 0x00FFFFFF;// hex for 'dey ', ignore the 0A
private static final int MAGIC_DEX = 0x0A786564 & 0x00FFFFFF;// hex for 'dex ', ignore the 0A
public static void main(String... args) {
new GenerateCompileStubFromOdex().doMain(args);
}
@Opt(opt = "o", longOpt = "output", description = "output .jar file, default is stub.jar", argName = "out-jar-file")
private Path output;
@Opt(opt = "npri", longOpt = "no-private", description = "", hasArg = false)
private boolean noPrivate;
@Override
protected void doCommandLine() throws Exception {
if (remainingArgs.length == 0) {
throw new HelpException("no odex");
}
if (output == null) {
output = new File("stub.jar").toPath();
}
try (FileSystem fs = createZip(output)) {
Path out = fs.getPath("/");
for (String x : remainingArgs) {
System.err.println("process " + x + " ...");
ByteBuffer bs = ByteBuffer.wrap(Files.readAllBytes(new File(x).toPath()))
.order(ByteOrder.LITTLE_ENDIAN);
int magic = bs.getInt(0) & 0x00FFFFFF;
if (magic == MAGIC_ODEX) {
int offset = bs.getInt(8);
int length = bs.getInt(12);
bs.position(offset);
ByteBuffer n = (ByteBuffer) bs.slice().limit(length);
doDex(n, out);
} else if (magic == MAGIC_DEX) {
doDex(bs, out);
} else {
throw new RuntimeException("file " + x + " is not an dex or odex");
}
}
}
}
private void doDex(ByteBuffer bs, final Path out) {
DexFileReader reader = new DexFileReader(bs);
DexFileNode fileNode = new DexFileNode();
reader.accept(fileNode, DexFileReader.SKIP_CODE);
Dex2Asm dex2Asm = new Dex2Asm();
dex2Asm.convertDex(fileNode, new ClassVisitorFactory() {
@Override
public ClassVisitor create(final String classInternalName) {
final Path target = out.resolve(classInternalName + ".class");
if (Files.exists(target)) {
System.err.println("class " + classInternalName + " is already exists, skipping.");
return null;
}
return new ClassVisitor(Opcodes.ASM4, new ClassWriter(ClassWriter.COMPUTE_MAXS)) {
@Override
public void visitEnd() {
super.visitEnd();
ClassWriter cw = (ClassWriter) cv;
byte[] data = cw.toByteArray();
try {
BaseCmd.createParentDirectories(target);
Files.write(target, data);
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public FieldVisitor visitField(int access, String name, String desc, String signature, Object value) {
if (noPrivate && 0 != (access & Opcodes.ACC_PRIVATE)) {
return null;
}
return super.visitField(access, name, desc, signature, value);
}
@Override
public MethodVisitor visitMethod(int access, String name, String desc, String signature,
String[] exceptions) {
if (noPrivate && 0 != (access & Opcodes.ACC_PRIVATE)) {
return null;
}
MethodVisitor mv = super.visitMethod(access, name, desc, signature, exceptions);
if (0 != ((Opcodes.ACC_NATIVE | Opcodes.ACC_ABSTRACT) & access)) {
return mv;
}
mv.visitTypeInsn(Opcodes.NEW, "java/lang/RuntimeException");
mv.visitInsn(Opcodes.DUP);
mv.visitLdcInsn("stub");
mv.visitMethodInsn(Opcodes.INVOKESPECIAL, "java/lang/RuntimeException", "",
"(Ljava/lang/String;)V");
mv.visitInsn(Opcodes.ATHROW);
return mv;
}
};
}
});
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy