Commit db527fbb authored by Skylot's avatar Skylot

core: add api for write tests using smali

parent 8f201f1f
ext.jadxClasspath = 'clsp-data/android-4.3.jar' ext.jadxClasspath = 'clsp-data/android-4.3.jar'
dependencies { dependencies {
runtime files(jadxClasspath)
compile files('lib/dx-1.8.jar') compile files('lib/dx-1.8.jar')
compile 'org.ow2.asm:asm:5.0.3' compile 'org.ow2.asm:asm:5.0.3'
runtime files(jadxClasspath)
testCompile 'org.smali:smali:2.0.3'
} }
task packTests(type: Jar) { task packTests(type: Jar) {
......
...@@ -7,6 +7,7 @@ import jadx.core.dex.nodes.ClassNode; ...@@ -7,6 +7,7 @@ import jadx.core.dex.nodes.ClassNode;
import jadx.core.dex.nodes.MethodNode; import jadx.core.dex.nodes.MethodNode;
import jadx.core.dex.visitors.DepthTraversal; import jadx.core.dex.visitors.DepthTraversal;
import jadx.core.dex.visitors.IDexTreeVisitor; import jadx.core.dex.visitors.IDexTreeVisitor;
import jadx.core.utils.exceptions.JadxException;
import jadx.core.utils.files.FileUtils; import jadx.core.utils.files.FileUtils;
import java.io.File; import java.io.File;
...@@ -30,21 +31,30 @@ public abstract class InternalJadxTest extends TestUtils { ...@@ -30,21 +31,30 @@ public abstract class InternalJadxTest extends TestUtils {
protected boolean outputCFG = false; protected boolean outputCFG = false;
protected boolean isFallback = false; protected boolean isFallback = false;
protected boolean deleteTmpJar = true; protected boolean deleteTmpFiles = true;
protected String outDir = "test-out-tmp"; protected String outDir = "test-out-tmp";
public ClassNode getClassNode(Class<?> clazz) { public ClassNode getClassNode(Class<?> clazz) {
JadxDecompiler d = new JadxDecompiler();
try { try {
d.loadFile(getJarForClass(clazz)); File jar = getJarForClass(clazz);
return getClassNodeFromFile(jar, clazz.getName());
} catch (Exception e) { } catch (Exception e) {
fail(e.getMessage()); fail(e.getMessage());
} }
String clsName = clazz.getName(); return null;
}
public ClassNode getClassNodeFromFile(File file, String clsName) {
JadxDecompiler d = new JadxDecompiler();
try {
d.loadFile(file);
} catch (JadxException e) {
fail(e.getMessage());
}
ClassNode cls = d.getRoot().searchClassByName(clsName); ClassNode cls = d.getRoot().searchClassByName(clsName);
assertNotNull("Class not found: " + clsName, cls); assertNotNull("Class not found: " + clsName, cls);
assertEquals(cls.getFullName(), clazz.getName()); assertEquals(cls.getFullName(), clsName);
cls.load(); cls.load();
for (IDexTreeVisitor visitor : getPasses()) { for (IDexTreeVisitor visitor : getPasses()) {
...@@ -99,16 +109,26 @@ public abstract class InternalJadxTest extends TestUtils { ...@@ -99,16 +109,26 @@ public abstract class InternalJadxTest extends TestUtils {
String path = cls.getPackage().getName().replace('.', '/'); String path = cls.getPackage().getName().replace('.', '/');
List<File> list = getClassFilesWithInners(cls); List<File> list = getClassFilesWithInners(cls);
File temp = File.createTempFile("jadx-tmp-", System.nanoTime() + ".jar"); File temp = createTempFile(".jar");
JarOutputStream jo = new JarOutputStream(new FileOutputStream(temp)); JarOutputStream jo = new JarOutputStream(new FileOutputStream(temp));
for (File file : list) { for (File file : list) {
FileUtils.addFileToJar(jo, file, path + "/" + file.getName()); FileUtils.addFileToJar(jo, file, path + "/" + file.getName());
} }
jo.close(); jo.close();
if (deleteTmpJar) { return temp;
}
protected File createTempFile(String suffix) {
File temp = null;
try {
temp = File.createTempFile("jadx-tmp-", System.nanoTime() + suffix);
if (deleteTmpFiles) {
temp.deleteOnExit(); temp.deleteOnExit();
} else { } else {
System.out.println("Temporary jar file path: " + temp.getAbsolutePath()); System.out.println("Temporary file path: " + temp.getAbsolutePath());
}
} catch (IOException e) {
fail(e.getMessage());
} }
return temp; return temp;
} }
...@@ -135,7 +155,6 @@ public abstract class InternalJadxTest extends TestUtils { ...@@ -135,7 +155,6 @@ public abstract class InternalJadxTest extends TestUtils {
return list; return list;
} }
// Use only for debug purpose // Use only for debug purpose
@Deprecated @Deprecated
protected void setOutputCFG() { protected void setOutputCFG() {
...@@ -151,6 +170,6 @@ public abstract class InternalJadxTest extends TestUtils { ...@@ -151,6 +170,6 @@ public abstract class InternalJadxTest extends TestUtils {
// Use only for debug purpose // Use only for debug purpose
@Deprecated @Deprecated
protected void notDeleteTmpJar() { protected void notDeleteTmpJar() {
this.deleteTmpJar = false; this.deleteTmpFiles = false;
} }
} }
package jadx.api;
import jadx.core.Consts;
import jadx.core.dex.nodes.ClassNode;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import org.jf.smali.main;
import static org.junit.Assert.fail;
public class SmaliTest extends InternalJadxTest {
private static final String SMALI_TESTS_PROJECT = "jadx-core";
private static final String SMALI_TESTS_DIR = "src/test/smali";
private static final String SMALI_TESTS_EXT = ".smali";
protected ClassNode getClassNodeFromSmali(String clsName) {
File smaliFile = getSmaliFile(clsName);
File outDex = createTempFile(".dex");
compileSmali(smaliFile, outDex);
String fullClsName = Consts.DEFAULT_PACKAGE_NAME + "." + clsName;
return getClassNodeFromFile(outDex, fullClsName);
}
private File getSmaliFile(String clsName) {
File smaliFile = new File(SMALI_TESTS_DIR, clsName + SMALI_TESTS_EXT);
if (smaliFile.exists()) {
return smaliFile;
}
smaliFile = new File(SMALI_TESTS_PROJECT, smaliFile.getPath());
if (smaliFile.exists()) {
return smaliFile;
}
fail("Smali file not found: " + SMALI_TESTS_DIR + "/" + clsName + SMALI_TESTS_EXT);
return null;
}
public boolean compileSmali(File input, File output) {
List<String> args = new ArrayList<String>();
args.add(input.getAbsolutePath());
args.add("-o");
args.add(output.getAbsolutePath());
main.main(args.toArray(new String[args.size()]));
return true;
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment