Skip to content

Commit

Permalink
Merge pull request #7 from niranjan94/Add_JaDX_decompiler
Browse files Browse the repository at this point in the history
Add JaDX decompiler along with CFR (resolves #4)
  • Loading branch information
niranjan94 committed Aug 31, 2015
2 parents 0c4eb51 + 0aaa52a commit dc67cff
Show file tree
Hide file tree
Showing 238 changed files with 30,366 additions and 68 deletions.
7 changes: 6 additions & 1 deletion app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,6 @@ dependencies {
compile files('libs/dex-reader-1.15.jar')
compile files('libs/dex-tools-0.0.9.15.jar')
compile files('libs/dex-translator-0.0.9.15.jar')
compile files('libs/dx.jar')
compile files('libs/jsr305-1.3.9.jar')

// CLASS FILE READER - JAVA DECOMPILER
Expand All @@ -123,4 +122,10 @@ dependencies {

// FILE PICKER
compile 'com.nononsenseapps:filepicker:2.2.3'

// DEPENDENCIES FOR JaDX
compile files('libs/dx-1.10.jar')
compile 'org.slf4j:slf4j-api:1.7.12'
compile 'uk.com.robust-it:cloning:1.9.2'
compile files('libs/android-5.1-clst-core.jar')
}
Binary file added app/libs/android-5.1-clst-core.jar
Binary file not shown.
Binary file added app/libs/dx-1.10.jar
Binary file not shown.
Binary file removed app/libs/dx.jar
Binary file not shown.
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,9 @@ public void extract() {
public void run() {
loadIgnoredLibs();
apkToDex();
dexToJar();
if(processService.decompilerToUse.equals("cfr")){
dexToJar();
}
startJavaExtractor();
}
};
Expand Down Expand Up @@ -100,6 +102,12 @@ public void apkToDex() {
broadcastStatus("exit");
UIHandler.post(new ToastRunnable("The app you selected cannot be decompiled. Please select another app."));
}

//////
PrintStream printStream = new PrintStream(new ProgressStream());
System.setErr(printStream);
System.setOut(printStream);
//////
}

public void dexToJar() {
Expand All @@ -116,12 +124,6 @@ public void dexToJar() {
boolean printIR = false; // print ir to System.out
boolean optimizeSynchronized = true; // Optimise-synchronised

//////
PrintStream printStream = new PrintStream(new ProgressStream());
System.setErr(printStream);
System.setOut(printStream);
//////

File PerAppWorkingDirectory = new File(sourceOutputDir);
File file = new File(PerAppWorkingDirectory + "/" + packageName + ".jar");

Expand Down
51 changes: 43 additions & 8 deletions app/src/main/java/com/njlabs/showjava/processor/JavaExtractor.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@

import java.io.File;

import jadx.api.JadxDecompiler;

/**
* Created by Niranjan on 29-05-2015.
*/
Expand All @@ -31,18 +33,26 @@ public JavaExtractor(ProcessService processService) {
public void extract() {

broadcastStatus("jar2java");
File JarInput;

Ln.d("jar location:" + sourceOutputDir + "/" + packageName + ".jar");
JarInput = new File(sourceOutputDir + "/" + packageName + ".jar");
final File JavaOutputDir = new File(javaSourceOutputDir);
File dexInputFile = new File(sourceOutputDir + "/optimised_classes.dex");
File jarInputFile = new File(sourceOutputDir + "/" + packageName + ".jar");

final File javaOutputDir = new File(javaSourceOutputDir);

if (!javaOutputDir.isDirectory()) {
javaOutputDir.mkdirs();
}

if (!JavaOutputDir.isDirectory()) {
JavaOutputDir.mkdirs();
if(processService.decompilerToUse.equals("jadx")){
decompileWithJaDX(dexInputFile, javaOutputDir);
} else {
decompileWithCFR(jarInputFile,javaOutputDir);
}

processService.javaSourceOutputDir = JavaOutputDir.toString();
String[] args = {JarInput.toString(), "--outputdir", JavaOutputDir.toString()};
}

private void decompileWithCFR(File jarInputFile, File javaOutputDir){
String[] args = {jarInputFile.toString(), "--outputdir", javaOutputDir.toString()};
GetOptParser getOptParser = new GetOptParser();

Options options = null;
Expand Down Expand Up @@ -75,6 +85,31 @@ public void run() {
javaExtractionThread.start();
}

private void decompileWithJaDX(final File dexInputFile, final File javaOutputDir){

ThreadGroup group = new ThreadGroup("Jar 2 Java Group");
Thread javaExtractionThread = new Thread(group, new Runnable() {
@Override
public void run() {
boolean javaError = false;
try {
JadxDecompiler jadx = new JadxDecompiler();
jadx.setOutputDir(javaOutputDir);
jadx.loadFile(dexInputFile);
jadx.save();
} catch (Exception | StackOverflowError e) {
Ln.e(e);
javaError = true;
}
startXMLExtractor(!javaError);
}
}, "Jar to Java Thread", Constants.STACK_SIZE);

javaExtractionThread.setPriority(Thread.MAX_PRIORITY);
javaExtractionThread.setUncaughtExceptionHandler(exceptionHandler);
javaExtractionThread.start();
}

private void startXMLExtractor(boolean hasJava) {
SourceInfo.setjavaSourceStatus(processService, hasJava);
((new ResourcesExtractor(processService))).extract();
Expand Down
68 changes: 55 additions & 13 deletions app/src/main/java/com/njlabs/showjava/processor/ProcessService.java
Original file line number Diff line number Diff line change
Expand Up @@ -46,41 +46,67 @@ public class ProcessService extends Service {
public Notify processNotify;
public ApkParser apkParser;

public String decompilerToUse = "cfr";

public void onCreate() {
super.onCreate();
}

public int onStartCommand(Intent intent, int flags, int startId) {
super.onStartCommand(intent, flags, startId);

/**
* Initialize a handler for posting runnables that have to run on the UI thread
*/
UIHandler = new Handler();

/**
* Receive action from the intent and decide whether to start or stop the existing process
*/
if (intent.getAction().equals(Constants.ACTION.START_PROCESS)) {

/**
* The intent's actions is {@link Constants.ACTION.START_PROCESS}
* Which means, the process has to start.
*
* We build the notification and start the process as a foreground process (to prevent it
* from being killed on exit)
*/
startForeground(Constants.PROCESS_NOTIFICATION_ID, buildNotification());
handleIntent(intent);

} else if (intent.getAction().equals(Constants.ACTION.STOP_PROCESS)) {
broadcastStatus("exit");
stopForeground(true);
try {
NotificationManager mNotifyManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
mNotifyManager.cancel(Constants.PROCESS_NOTIFICATION_ID);
Utils.killAllProcessorServices(this);
} catch (Exception e) {
Ln.e(e);
}
stopSelf();

/**
* The intent's actions is {@link Constants.ACTION.STOP_PROCESS}
* Which means, the process has to stop and kill itself.
*
* We are broadcasting an 'exit' status so that any activity listening can exit.
* We stop the foreground process.
* And we forcefully kill the service.
*
* Uses the {@link #killSelf()} method.
*/
killSelf();

}

return START_NOT_STICKY;
}

protected void handleIntent(Intent workIntent) {
Ln.i("onHandleIntent ProcessService");

/**
* This is the main starting point of the ProcessorService. The intent is read and handled here
*/
Bundle extras = workIntent.getExtras();
if (extras != null) {
packageFilePath = extras.getString("package_file_path");
Ln.i("package_file_path :" + packageFilePath);

if(extras.containsKey("decompiler")){
decompilerToUse = extras.getString("decompiler");
}

packageFilePath = extras.getString("package_file_path");
(new Thread(new Runnable() {
@Override
public void run() {
Expand All @@ -103,6 +129,7 @@ public void run() {
resultIntent.putExtra("package_name", packageName);
resultIntent.putExtra("package_label", packageLabel);
resultIntent.putExtra("package_file_path", packageFilePath);
resultIntent.putExtra("decompiler", decompilerToUse);

PendingIntent resultPendingIntent =
PendingIntent.getActivity(ProcessService.this, 0, resultIntent, PendingIntent.FLAG_UPDATE_CURRENT);
Expand All @@ -126,6 +153,8 @@ public void run() {
});
}
})).start();
} else {
killSelf();
}
}

Expand Down Expand Up @@ -318,4 +347,17 @@ public void run() {
Toast.makeText(getApplicationContext(), mText, Toast.LENGTH_SHORT).show();
}
}

private void killSelf(){
broadcastStatus("exit");
stopForeground(true);
try {
NotificationManager mNotifyManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
mNotifyManager.cancel(Constants.PROCESS_NOTIFICATION_ID);
Utils.killAllProcessorServices(this);
} catch (Exception e) {
Ln.e(e);
}
stopSelf();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ public ProgressStream() {
public void write(@NonNull byte[] data, int i1, int i2) {
String str = new String(data);
str = str.replace("\n", "").replace("\r", "");
if (!str.equals("") && !str.equals("")) {
if (!str.equals("")) {
broadcastStatus("progress_stream", str);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;

import jadx.api.JadxDecompiler;

/**
* Created by Niranjan on 30-05-2015.
*/
Expand All @@ -39,8 +41,54 @@ public ResourcesExtractor(ProcessService processService) {
}

public void extract() {

broadcastStatus("res");

if(processService.decompilerToUse.equals("jadx")){
extractResourcesWithJadx();
} else {
extractResourcesWithParser();
}
}

private void extractResourcesWithJadx(){
ThreadGroup group = new ThreadGroup("XML Extraction Group");
Thread xmlExtractionThread = new Thread(group, new Runnable() {
@Override
public void run() {
try {

File resDir = new File(sourceOutputDir);

JadxDecompiler jadx = new JadxDecompiler();
jadx.setOutputDir(resDir);
jadx.loadFile(new File(packageFilePath));
jadx.save(false, true);

ZipFile zipFile = new ZipFile(packageFilePath);
Enumeration<? extends ZipEntry> entries = zipFile.entries();
while (entries.hasMoreElements()) {
ZipEntry zipEntry = entries.nextElement();
if (!zipEntry.isDirectory() && (FilenameUtils.getExtension(zipEntry.getName()).equals("png") || FilenameUtils.getExtension(zipEntry.getName()).equals("jpg"))) {
broadcastStatus("progress_stream", zipEntry.getName());
writeFile(zipFile.getInputStream(zipEntry), zipEntry.getName());
}
}
zipFile.close();

saveIcon();
allDone();

} catch (Exception | StackOverflowError e) {
processService.publishProgress("start_activity_with_error");
}
}
}, "XML Extraction Thread", Constants.STACK_SIZE);
xmlExtractionThread.setPriority(Thread.MAX_PRIORITY);
xmlExtractionThread.setUncaughtExceptionHandler(exceptionHandler);
xmlExtractionThread.start();
}

private void extractResourcesWithParser(){
ThreadGroup group = new ThreadGroup("XML Extraction Group");
Thread xmlExtractionThread = new Thread(group, new Runnable() {
@Override
Expand Down Expand Up @@ -70,7 +118,6 @@ public void run() {
xmlExtractionThread.setPriority(Thread.MAX_PRIORITY);
xmlExtractionThread.setUncaughtExceptionHandler(exceptionHandler);
xmlExtractionThread.start();

}

private void writeFile(InputStream fileStream, String path) {
Expand Down
Loading

0 comments on commit dc67cff

Please sign in to comment.