refactor: move all smali libs usage to one utility class
This commit is contained in:
@@ -1,8 +1,6 @@
|
||||
package jadx.api;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.StringWriter;
|
||||
import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
@@ -16,13 +14,6 @@ import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jf.baksmali.Adaptors.ClassDefinition;
|
||||
import org.jf.baksmali.BaksmaliOptions;
|
||||
import org.jf.dexlib2.DexFileFactory;
|
||||
import org.jf.dexlib2.Opcodes;
|
||||
import org.jf.dexlib2.dexbacked.DexBackedClassDef;
|
||||
import org.jf.dexlib2.dexbacked.DexBackedDexFile;
|
||||
import org.jf.util.IndentingWriter;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@@ -35,7 +26,6 @@ import jadx.core.dex.nodes.MethodNode;
|
||||
import jadx.core.dex.nodes.RootNode;
|
||||
import jadx.core.dex.visitors.SaveCode;
|
||||
import jadx.core.export.ExportGradleProject;
|
||||
import jadx.core.utils.Utils;
|
||||
import jadx.core.utils.exceptions.JadxRuntimeException;
|
||||
import jadx.core.utils.files.InputFile;
|
||||
import jadx.core.xmlgen.BinaryXMLParser;
|
||||
@@ -291,30 +281,6 @@ public final class JadxDecompiler {
|
||||
root.getErrorsCounter().printReport();
|
||||
}
|
||||
|
||||
void generateSmali(ClassNode cls) {
|
||||
Path path = cls.dex().getDexFile().getPath();
|
||||
String className = Utils.makeQualifiedObjectName(cls.getClassInfo().getType().getObject());
|
||||
try {
|
||||
DexBackedDexFile dexFile = DexFileFactory.loadDexFile(path.toFile(), Opcodes.getDefault());
|
||||
boolean decompiled = false;
|
||||
for (DexBackedClassDef classDef : dexFile.getClasses()) {
|
||||
if (classDef.getType().equals(className)) {
|
||||
ClassDefinition classDefinition = new ClassDefinition(new BaksmaliOptions(), classDef);
|
||||
StringWriter sw = new StringWriter();
|
||||
classDefinition.writeTo(new IndentingWriter(sw));
|
||||
cls.setSmali(sw.toString());
|
||||
decompiled = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!decompiled) {
|
||||
LOG.error("Failed to find smali class {}", className);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
LOG.error("Error generating smali", e);
|
||||
}
|
||||
}
|
||||
|
||||
RootNode getRoot() {
|
||||
return root;
|
||||
}
|
||||
|
||||
@@ -59,12 +59,6 @@ public final class JavaClass implements JavaNode {
|
||||
}
|
||||
|
||||
public synchronized String getSmali() {
|
||||
if (decompiler == null) {
|
||||
return null;
|
||||
}
|
||||
if (cls.getSmali() == null) {
|
||||
decompiler.generateSmali(cls);
|
||||
}
|
||||
return cls.getSmali();
|
||||
}
|
||||
|
||||
|
||||
@@ -111,9 +111,8 @@ public final class ResourcesLoader {
|
||||
private static ResContainer decodeImage(ResourceFile rf, InputStream inputStream) {
|
||||
String name = rf.getName();
|
||||
if (name.endsWith(".9.png")) {
|
||||
Res9patchStreamDecoder decoder = new Res9patchStreamDecoder();
|
||||
ByteArrayOutputStream os = new ByteArrayOutputStream();
|
||||
try {
|
||||
try (ByteArrayOutputStream os = new ByteArrayOutputStream()) {
|
||||
Res9patchStreamDecoder decoder = new Res9patchStreamDecoder();
|
||||
decoder.decode(inputStream, os);
|
||||
return ResContainer.decodedData(rf.getName(), os.toByteArray());
|
||||
} catch (Exception e) {
|
||||
|
||||
@@ -35,6 +35,7 @@ import jadx.core.dex.nodes.parser.AnnotationsParser;
|
||||
import jadx.core.dex.nodes.parser.FieldInitAttr;
|
||||
import jadx.core.dex.nodes.parser.SignatureParser;
|
||||
import jadx.core.dex.nodes.parser.StaticValuesParser;
|
||||
import jadx.core.utils.SmaliUtils;
|
||||
import jadx.core.utils.exceptions.DecodeException;
|
||||
import jadx.core.utils.exceptions.JadxRuntimeException;
|
||||
|
||||
@@ -45,6 +46,7 @@ public class ClassNode extends LineAttrNode implements ILoadable, ICodeNode {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(ClassNode.class);
|
||||
|
||||
private final DexNode dex;
|
||||
private final int clsDefOffset;
|
||||
private final ClassInfo clsInfo;
|
||||
private AccessInfo accessFlags;
|
||||
private ArgType superClass;
|
||||
@@ -68,6 +70,7 @@ public class ClassNode extends LineAttrNode implements ILoadable, ICodeNode {
|
||||
|
||||
public ClassNode(DexNode dex, ClassDef cls) {
|
||||
this.dex = dex;
|
||||
this.clsDefOffset = cls.getOffset();
|
||||
this.clsInfo = ClassInfo.fromDex(dex, cls.getTypeIndex());
|
||||
try {
|
||||
if (cls.getSupertypeIndex() == DexNode.NO_INDEX) {
|
||||
@@ -135,6 +138,7 @@ public class ClassNode extends LineAttrNode implements ILoadable, ICodeNode {
|
||||
// empty synthetic class
|
||||
public ClassNode(DexNode dex, String name, int accessFlags) {
|
||||
this.dex = dex;
|
||||
this.clsDefOffset = 0;
|
||||
this.clsInfo = ClassInfo.fromName(dex.root(), name);
|
||||
this.interfaces = new ArrayList<>();
|
||||
this.methods = new ArrayList<>();
|
||||
@@ -495,11 +499,10 @@ public class ClassNode extends LineAttrNode implements ILoadable, ICodeNode {
|
||||
return clsInfo.getAliasPkg();
|
||||
}
|
||||
|
||||
public void setSmali(String smali) {
|
||||
this.smali = smali;
|
||||
}
|
||||
|
||||
public String getSmali() {
|
||||
if (smali == null) {
|
||||
smali = SmaliUtils.getSmaliCode(dex, clsDefOffset);
|
||||
}
|
||||
return smali;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
package jadx.core.utils;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.StringWriter;
|
||||
import java.nio.file.Path;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jf.baksmali.Adaptors.ClassDefinition;
|
||||
import org.jf.baksmali.BaksmaliOptions;
|
||||
import org.jf.dexlib2.DexFileFactory;
|
||||
import org.jf.dexlib2.dexbacked.DexBackedClassDef;
|
||||
import org.jf.dexlib2.dexbacked.DexBackedDexFile;
|
||||
import org.jf.smali.Smali;
|
||||
import org.jf.smali.SmaliOptions;
|
||||
import org.jf.util.IndentingWriter;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import jadx.core.dex.nodes.DexNode;
|
||||
import jadx.core.utils.exceptions.JadxRuntimeException;
|
||||
|
||||
// TODO: move smali dependencies out from jadx-core
|
||||
public class SmaliUtils {
|
||||
|
||||
private static final Logger LOG = LoggerFactory.getLogger(SmaliUtils.class);
|
||||
|
||||
public static void assembleDex(String outputDexFile, String inputSmali) {
|
||||
try {
|
||||
SmaliOptions options = new SmaliOptions();
|
||||
options.outputDexFile = outputDexFile;
|
||||
Smali.assemble(options, inputSmali);
|
||||
} catch (Exception e) {
|
||||
throw new JadxRuntimeException("Smali assemble error", e);
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static String getSmaliCode(DexNode dex, int clsDefOffset) {
|
||||
try {
|
||||
Path path = dex.getDexFile().getPath();
|
||||
DexBackedDexFile dexFile = DexFileFactory.loadDexFile(path.toFile(), null);
|
||||
DexBackedClassDef dexBackedClassDef = new DexBackedClassDef(dexFile, clsDefOffset);
|
||||
return getSmaliCode(dexBackedClassDef);
|
||||
} catch (Exception e) {
|
||||
LOG.error("Error generating smali", e);
|
||||
return "Error generating smali code: " + e.getMessage()
|
||||
+ '\n' + Utils.getStackTrace(e);
|
||||
}
|
||||
}
|
||||
|
||||
private static String getSmaliCode(DexBackedClassDef classDef) throws IOException {
|
||||
ClassDefinition classDefinition = new ClassDefinition(new BaksmaliOptions(), classDef);
|
||||
StringWriter sw = new StringWriter();
|
||||
classDefinition.writeTo(new IndentingWriter(sw));
|
||||
return sw.toString();
|
||||
}
|
||||
}
|
||||
@@ -17,7 +17,6 @@
|
||||
package jadx.core.utils.android;
|
||||
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.DataInput;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
@@ -25,27 +24,23 @@ import java.io.OutputStream;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
|
||||
import com.google.common.io.ByteStreams;
|
||||
|
||||
import jadx.core.utils.exceptions.JadxException;
|
||||
import jadx.core.utils.exceptions.JadxRuntimeException;
|
||||
|
||||
/**
|
||||
* @author Ryszard Wiśniewski <brut.alll@gmail.com>
|
||||
*/
|
||||
public class Res9patchStreamDecoder {
|
||||
|
||||
public void decode(InputStream in, OutputStream out) throws JadxException {
|
||||
public void decode(InputStream in, OutputStream out) {
|
||||
try {
|
||||
byte[] data = ByteStreams.toByteArray(in);
|
||||
|
||||
BufferedImage im = ImageIO.read(new ByteArrayInputStream(data));
|
||||
BufferedImage im = ImageIO.read(in);
|
||||
int w = im.getWidth();
|
||||
int h = im.getHeight();
|
||||
|
||||
BufferedImage im2 = new BufferedImage(w + 2, h + 2, BufferedImage.TYPE_INT_ARGB);
|
||||
im2.createGraphics().drawImage(im, 1, 1, w, h, null);
|
||||
|
||||
NinePatch np = getNinePatch(data);
|
||||
NinePatch np = getNinePatch(in);
|
||||
drawHLine(im2, h + 1, np.padLeft + 1, w - np.padRight);
|
||||
drawVLine(im2, w + 1, np.padTop + 1, h - np.padBottom);
|
||||
|
||||
@@ -60,25 +55,25 @@ public class Res9patchStreamDecoder {
|
||||
}
|
||||
|
||||
ImageIO.write(im2, "png", out);
|
||||
} catch (IOException | NullPointerException ex) {
|
||||
throw new JadxException(ex.toString());
|
||||
} catch (Exception e) {
|
||||
throw new JadxRuntimeException("9patch image decode error", e);
|
||||
}
|
||||
}
|
||||
|
||||
private NinePatch getNinePatch(byte[] data) throws JadxException, IOException {
|
||||
ExtDataInput di = new ExtDataInput(new ByteArrayInputStream(data));
|
||||
private NinePatch getNinePatch(InputStream in) throws IOException {
|
||||
ExtDataInput di = new ExtDataInput(in);
|
||||
find9patchChunk(di);
|
||||
return NinePatch.decode(di);
|
||||
}
|
||||
|
||||
private void find9patchChunk(DataInput di) throws JadxException, IOException {
|
||||
private void find9patchChunk(DataInput di) throws IOException {
|
||||
di.skipBytes(8);
|
||||
while (true) {
|
||||
int size;
|
||||
try {
|
||||
size = di.readInt();
|
||||
} catch (IOException ex) {
|
||||
throw new JadxException("Cant find nine patch chunk", ex);
|
||||
throw new JadxRuntimeException("Cant find nine patch chunk", ex);
|
||||
}
|
||||
if (di.readInt() == NP_CHUNK_TYPE) {
|
||||
return;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package jadx.core.utils.files;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.Closeable;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
@@ -122,6 +123,13 @@ public class FileUtils {
|
||||
}
|
||||
}
|
||||
|
||||
public static byte[] streamToByteArray(InputStream input) throws IOException {
|
||||
try (ByteArrayOutputStream out = new ByteArrayOutputStream()) {
|
||||
copyStream(input, out);
|
||||
return out.toByteArray();
|
||||
}
|
||||
}
|
||||
|
||||
public static void close(Closeable c) {
|
||||
if (c == null) {
|
||||
return;
|
||||
|
||||
@@ -14,8 +14,6 @@ import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipFile;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jf.smali.Smali;
|
||||
import org.jf.smali.SmaliOptions;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@@ -23,6 +21,7 @@ import com.android.dex.Dex;
|
||||
import com.android.dex.DexException;
|
||||
|
||||
import jadx.core.utils.AsmUtils;
|
||||
import jadx.core.utils.SmaliUtils;
|
||||
import jadx.core.utils.exceptions.DecodeException;
|
||||
import jadx.core.utils.exceptions.JadxException;
|
||||
import jadx.core.utils.exceptions.JadxRuntimeException;
|
||||
@@ -58,9 +57,7 @@ public class InputFile {
|
||||
}
|
||||
if (fileName.endsWith(".smali")) {
|
||||
Path output = FileUtils.createTempFile(".dex");
|
||||
SmaliOptions options = new SmaliOptions();
|
||||
options.outputDexFile = output.toAbsolutePath().toString();
|
||||
Smali.assemble(options, file.getAbsolutePath());
|
||||
SmaliUtils.assembleDex(output.toAbsolutePath().toString(), file.getAbsolutePath());
|
||||
addDexFile(fileName, output);
|
||||
return;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user