This commit is contained in:
Konloch 2019-05-31 19:04:07 -06:00
parent 9f3302f7a9
commit f76b31d8e7
12 changed files with 398 additions and 55 deletions

View file

@ -16,12 +16,8 @@ import java.net.URL;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Paths; import java.nio.file.Paths;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.jar.JarOutputStream;
import javax.swing.JDialog; import javax.swing.JDialog;
import javax.swing.JFileChooser; import javax.swing.JFileChooser;
@ -118,7 +114,7 @@ import the.bytecode.club.bytecodeviewer.util.*;
public class BytecodeViewer public class BytecodeViewer
{ {
/*per version*/ /*per version*/
public static final String VERSION = "2.9.19"; public static final String VERSION = "2.9.20";
public static String krakatauVersion = "12"; public static String krakatauVersion = "12";
public static String enjarifyVersion = "4"; public static String enjarifyVersion = "4";
public static final boolean BLOCK_TAB_MENU = true; public static final boolean BLOCK_TAB_MENU = true;
@ -145,12 +141,13 @@ public class BytecodeViewer
public static boolean currentlyDumping = false; public static boolean currentlyDumping = false;
public static boolean needsReDump = true; public static boolean needsReDump = true;
public static boolean warnForEditing = false; public static boolean warnForEditing = false;
public static ArrayList<FileContainer> files = new ArrayList<FileContainer>(); //all of BCV's loaded files/classes/etc public static List<FileContainer> files = new ArrayList<FileContainer>(); //all of BCV's loaded files/classes/etc
private static int maxRecentFiles = 25; private static int maxRecentFiles = 25;
public static String fs = System.getProperty("file.separator"); public static String fs = System.getProperty("file.separator");
public static String nl = System.getProperty("line.separator"); public static String nl = System.getProperty("line.separator");
private static File BCVDir = new File(System.getProperty("user.home") + fs + ".Bytecode-Viewer"); private static File BCVDir = new File(System.getProperty("user.home") + fs + ".Bytecode-Viewer");
public static File RJ_JAR = new File(System.getProperty("java.home") + fs + "lib" + fs + "rt.jar"); public static File RT_JAR = new File(System.getProperty("java.home") + fs + "lib" + fs + "rt.jar");
public static File RT_JAR_DUMPED = new File(getBCVDirectory() + fs + "rt.jar");
private static String filesName = getBCVDirectory() + fs + "recentfiles.json"; private static String filesName = getBCVDirectory() + fs + "recentfiles.json";
private static String pluginsName = getBCVDirectory() + fs + "recentplugins.json"; private static String pluginsName = getBCVDirectory() + fs + "recentplugins.json";
public static String settingsName = getBCVDirectory() + fs + "settings.bcv"; public static String settingsName = getBCVDirectory() + fs + "settings.bcv";
@ -161,15 +158,15 @@ public class BytecodeViewer
public static boolean runningObfuscation = false; public static boolean runningObfuscation = false;
private static long start = System.currentTimeMillis(); private static long start = System.currentTimeMillis();
public static String lastDirectory = "."; public static String lastDirectory = ".";
public static ArrayList<Process> createdProcesses = new ArrayList<Process>(); public static List<Process> createdProcesses = new ArrayList<Process>();
public static Refactorer refactorer = new Refactorer(); public static Refactorer refactorer = new Refactorer();
public static boolean pingback = false; public static boolean pingback = false;
public static boolean deleteForeignLibraries = true; public static boolean deleteForeignLibraries = true;
public static boolean canExit = false; public static boolean canExit = false;
public static Gson gson; public static Gson gson;
private static ArrayList<String> recentPlugins; private static List<String> recentPlugins;
private static ArrayList<String> recentFiles; private static List<String> recentFiles;
static static
{ {
@ -669,6 +666,10 @@ public class BytecodeViewer
return null; return null;
} }
public static List<FileContainer> getFiles() {
return files;
}
public static ClassNode getClassNode(FileContainer container, String name) { public static ClassNode getClassNode(FileContainer container, String name) {
for (ClassNode c : container.classes) for (ClassNode c : container.classes)
if (c.name.equals(name)) if (c.name.equals(name))
@ -943,7 +944,7 @@ public class BytecodeViewer
if (viewer.decodeAPKResources.isSelected()) { if (viewer.decodeAPKResources.isSelected()) {
File decodedResources = new File(tempDirectory + fs + MiscUtils.randomString(32) + ".apk"); File decodedResources = new File(tempDirectory + fs + MiscUtils.randomString(32) + ".apk");
APKTool.decodeResources(tempCopy, decodedResources); APKTool.decodeResources(tempCopy, decodedResources, container);
container.files = JarUtils.loadResources(decodedResources); container.files = JarUtils.loadResources(decodedResources);
} }
@ -1080,7 +1081,7 @@ public class BytecodeViewer
the.bytecode.club.bytecodeviewer.api.BytecodeViewer.getClassNodeLoader().clear(); the.bytecode.club.bytecodeviewer.api.BytecodeViewer.getClassNodeLoader().clear();
} }
private static ArrayList<String> killList = new ArrayList<String>(); private static List<String> killList = new ArrayList<String>();
/** /**
* Add the recent file * Add the recent file
@ -1109,7 +1110,7 @@ public class BytecodeViewer
resetRecentFilesMenu(); resetRecentFilesMenu();
} }
private static ArrayList<String> killList2 = new ArrayList<String>(); private static List<String> killList2 = new ArrayList<String>();
/** /**
* Add to the recent plugin list * Add to the recent plugin list
@ -1187,7 +1188,7 @@ public class BytecodeViewer
tempF.mkdir(); tempF.mkdir();
} }
public static ArrayList<String> createdRandomizedNames = new ArrayList<String>(); public static List<String> createdRandomizedNames = new ArrayList<String>();
/** /**
* Ensures it will only return a uniquely generated names, contains a dupe checker to be sure * Ensures it will only return a uniquely generated names, contains a dupe checker to be sure
@ -1254,7 +1255,7 @@ public class BytecodeViewer
* @param a array * @param a array
* @return string with newline per array object * @return string with newline per array object
*/ */
private static String quickConvert(ArrayList<String> a) { private static String quickConvert(List<String> a) {
return gson.toJson(a); return gson.toJson(a);
} }
@ -1471,11 +1472,30 @@ public class BytecodeViewer
return files; return files;
} }
public static void rtCheck() public synchronized static void rtCheck()
{ {
if(rt.equals("") && RJ_JAR.exists()) if(rt.equals(""))
{ {
rt = RJ_JAR.getAbsolutePath(); if(RT_JAR.exists())
{
rt = RT_JAR.getAbsolutePath();
}
else if(RT_JAR_DUMPED.exists())
{
rt = RT_JAR_DUMPED.getAbsolutePath();
}
else
{
try
{
JRTExtractor.extractRT(RT_JAR_DUMPED.getAbsolutePath());
rt = RT_JAR_DUMPED.getAbsolutePath();
}
catch (Throwable t)
{
t.printStackTrace();
}
}
} }
} }

View file

@ -4,6 +4,7 @@ import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.File; import java.io.File;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List;
import javax.imageio.ImageIO; import javax.imageio.ImageIO;
import javax.swing.ImageIcon; import javax.swing.ImageIcon;
@ -37,7 +38,7 @@ import org.imgscalr.Scalr;
public class Resources { public class Resources {
public static ArrayList<BufferedImage> iconList; public static List<BufferedImage> iconList;
public static BufferedImage icon; public static BufferedImage icon;
public static ImageIcon nextIcon; public static ImageIcon nextIcon;
public static ImageIcon prevIcon; public static ImageIcon prevIcon;

View file

@ -44,6 +44,7 @@ public class SecurityMan extends SecurityManager {
executedClass.equals("the.bytecode.club.bytecodeviewer.decompilers.JDGUIDecompiler") || executedClass.equals("the.bytecode.club.bytecodeviewer.decompilers.JDGUIDecompiler") ||
executedClass.equals("the.bytecode.club.bytecodeviewer.compilers.KrakatauAssembler") || executedClass.equals("the.bytecode.club.bytecodeviewer.compilers.KrakatauAssembler") ||
executedClass.equals("the.bytecode.club.bytecodeviewer.util.Enjarify") || executedClass.equals("the.bytecode.club.bytecodeviewer.util.Enjarify") ||
executedClass.equals("the.bytecode.club.bytecodeviewer.util.APKTool") ||
executedClass.equals("the.bytecode.club.bytecodeviewer.BytecodeViewer") || executedClass.equals("the.bytecode.club.bytecodeviewer.BytecodeViewer") ||
executedClass.equals("the.bytecode.club.bytecodeviewer.compilers.JavaCompiler")) { executedClass.equals("the.bytecode.club.bytecodeviewer.compilers.JavaCompiler")) {
blocking = false; blocking = false;
@ -60,7 +61,8 @@ public class SecurityMan extends SecurityManager {
"attrib", "attrib",
"python", "python",
"pypy", "pypy",
"java" "java",
"brut_util",
}; };
boolean allow = false; boolean allow = false;
@ -71,7 +73,7 @@ public class SecurityMan extends SecurityManager {
if (allow && !blocking) { if (allow && !blocking) {
System.out.println("Allowing exec:" + cmd); System.out.println("Allowing exec:" + cmd);
} else throw new SecurityException("BCV is awesome, blocking " + cmd); } else throw new SecurityException("BCV is awesome, blocking("+blocking+") exec " + cmd);
} }
@Override @Override

View file

@ -44,7 +44,7 @@ public class SmaliAssembler extends Compiler {
tempSmaliFolder.mkdir(); tempSmaliFolder.mkdir();
File tempSmali = new File(tempSmaliFolder.getAbsolutePath() + BytecodeViewer.fs + fileNumber + ".smali"); File tempSmali = new File(tempSmaliFolder.getAbsolutePath() + BytecodeViewer.fs + fileNumber + ".smali");
File tempDex = new File(fileStart + fileNumber + ".dex"); File tempDex = new File("./out.dex");
File tempJar = new File(fileStart + fileNumber + ".jar"); File tempJar = new File(fileStart + fileNumber + ".jar");
File tempJarFolder = new File(fileStart + fileNumber + "-jar" + BytecodeViewer.fs); File tempJarFolder = new File(fileStart + fileNumber + "-jar" + BytecodeViewer.fs);
@ -68,6 +68,7 @@ public class SmaliAssembler extends Compiler {
Enjarify.apk2Jar(tempDex, tempJar); Enjarify.apk2Jar(tempDex, tempJar);
try { try {
System.out.println("Unzipping to " + tempJarFolder.getAbsolutePath());
ZipUtils.unzipFilesToPath(tempJar.getAbsolutePath(), tempJarFolder.getAbsolutePath()); ZipUtils.unzipFilesToPath(tempJar.getAbsolutePath(), tempJarFolder.getAbsolutePath());
File outputClass = null; File outputClass = null;

View file

@ -41,8 +41,7 @@ public class SmaliDisassembler extends Decompiler {
public String decompileClassNode(FileContainer container, ClassNode cn, byte[] b) { public String decompileClassNode(FileContainer container, ClassNode cn, byte[] b) {
String exception = ""; String exception = "";
String fileStart = BytecodeViewer.tempDirectory + BytecodeViewer.fs String fileStart = BytecodeViewer.tempDirectory + BytecodeViewer.fs + "temp";
+ "temp";
String start = MiscUtils.getUniqueName(fileStart, ".class"); String start = MiscUtils.getUniqueName(fileStart, ".class");
@ -62,9 +61,7 @@ public class SmaliDisassembler extends Decompiler {
//ZipUtils.zipFile(tempClass, tempZip); //ZipUtils.zipFile(tempClass, tempZip);
Dex2Jar.saveAsDex(container.file, tempDex, false); Dex2Jar.saveAsDex(tempClass, tempDex, true);
System.out.println("FOR SHOW: " + tempDex.getName().replaceFirst("\\.dex", "-out")); //tempSmali.getAbsolutePath()
try try
{ {
@ -94,9 +91,6 @@ public class SmaliDisassembler extends Decompiler {
exception += "Bytecode Viewer Version: " + BytecodeViewer.VERSION + BytecodeViewer.nl + BytecodeViewer.nl + sw.toString(); exception += "Bytecode Viewer Version: " + BytecodeViewer.VERSION + BytecodeViewer.nl + BytecodeViewer.nl + sw.toString();
} }
System.out.println("FOR SHOW1: " + rename.getAbsolutePath());
System.out.println("FOR SHOW2: " + tempSmali.getAbsolutePath());
File outputSmali = null; File outputSmali = null;
boolean found = false; boolean found = false;

View file

@ -9,6 +9,7 @@ import java.awt.KeyboardFocusManager;
import java.awt.event.*; import java.awt.event.*;
import java.io.File; import java.io.File;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List;
import javax.swing.BoxLayout; import javax.swing.BoxLayout;
import javax.swing.ButtonGroup; import javax.swing.ButtonGroup;
@ -261,7 +262,8 @@ public class MainViewerGUI extends JFrame implements FileChangeNotifier
} }
} }
public final JMenuItem mntmSaveAsApk = new JMenuItem("Save As DEX.."); public final JMenuItem mntmSaveAsDEX = new JMenuItem("Save As DEX..");
public final JMenuItem mntmSaveAsAPK = new JMenuItem("Save As APK..");
public final JMenuItem mntmCodeSequenceDiagram = new JMenuItem("Code Sequence Diagram"); public final JMenuItem mntmCodeSequenceDiagram = new JMenuItem("Code Sequence Diagram");
public final JSeparator separator_7 = new JSeparator(); public final JSeparator separator_7 = new JSeparator();
public final JSeparator separator_8 = new JSeparator(); public final JSeparator separator_8 = new JSeparator();
@ -842,7 +844,7 @@ public class MainViewerGUI extends JFrame implements FileChangeNotifier
mnNewMenu.add(separator_18); mnNewMenu.add(separator_18);
mnNewMenu.add(mntmNewMenuItem_3); mnNewMenu.add(mntmNewMenuItem_3);
mntmSaveAsApk.addActionListener(new ActionListener() mntmSaveAsDEX.addActionListener(new ActionListener()
{ {
@Override @Override
public void actionPerformed(ActionEvent arg0) public void actionPerformed(ActionEvent arg0)
@ -940,8 +942,151 @@ public class MainViewerGUI extends JFrame implements FileChangeNotifier
t.start(); t.start();
} }
}); });
mntmSaveAsAPK.addActionListener(new ActionListener()
{
@Override
public void actionPerformed(ActionEvent arg0)
{
if (BytecodeViewer.getLoadedClasses().isEmpty())
{
BytecodeViewer.showMessage("First open a class, jar, zip, apk or dex file.");
return;
}
mnNewMenu.add(mntmSaveAsApk); //if theres only one file in the container don't bother asking
List<FileContainer> containers = BytecodeViewer.getFiles();
List<FileContainer> validContainers = new ArrayList<>();
List<String> validContainersNames = new ArrayList<>();
FileContainer container = null;
for(FileContainer fileContainer : containers)
{
if(fileContainer.APKToolContents != null && fileContainer.APKToolContents.exists())
{
validContainersNames.add(fileContainer.name);
validContainers.add(fileContainer);
}
}
if(!validContainers.isEmpty())
{
container = validContainers.get(0);
if(validContainers.size() >= 2)
{
JOptionPane pane = new JOptionPane("Which file would you like to export as an APK?");
Object[] options = validContainersNames.toArray(new String[0]);
pane.setOptions(options);
JDialog dialog = pane.createDialog(BytecodeViewer.viewer, "Bytecode Viewer - Select APK");
dialog.setVisible(true);
Object obj = pane.getValue();
int result = -1;
for (int k = 0; k < options.length; k++)
if (options[k].equals(obj))
result = k;
container = containers.get(result);
}
}
else
{
BytecodeViewer.showMessage("You can only export as APK from a valid APK file. Make sure Settings>Decode Resources is ticked on.\n\nTip: Try exporting as DEX, it doesn't rely on decoded APK resources");
return;
}
final FileContainer finalContainer = container;
Thread t = new Thread()
{
public void run()
{
if (compileOnSave.isSelected() && !BytecodeViewer.compile(false))
return;
JFileChooser fc = new JFileChooser();
fc.setFileFilter(new FileFilter()
{
@Override
public boolean accept(File f)
{
return f.isDirectory() || MiscUtils.extension(f.getAbsolutePath()).equals("apk");
}
@Override
public String getDescription()
{
return "Android APK";
}
});
fc.setFileHidingEnabled(false);
fc.setAcceptAllFileFilterUsed(false);
int returnVal = fc.showSaveDialog(MainViewerGUI.this);
if (returnVal == JFileChooser.APPROVE_OPTION)
{
final File file = fc.getSelectedFile();
String output = file.getAbsolutePath();
if (!output.endsWith(".apk"))
output = output + ".apk";
final File file2 = new File(output);
if (file2.exists())
{
JOptionPane pane = new JOptionPane(
"Are you sure you wish to overwrite this existing file?");
Object[] options = new String[]{"Yes", "No"};
pane.setOptions(options);
JDialog dialog = pane.createDialog(BytecodeViewer.viewer,
"Bytecode Viewer - Overwrite File");
dialog.setVisible(true);
Object obj = pane.getValue();
int result = -1;
for (int k = 0; k < options.length; k++)
if (options[k].equals(obj))
result = k;
if (result == 0)
{
file.delete();
}
else
{
return;
}
}
Thread t = new Thread()
{
@Override
public void run()
{
BytecodeViewer.viewer.setIcon(true);
final String input = BytecodeViewer.tempDirectory + BytecodeViewer.fs + BytecodeViewer.getRandomizedName() + ".jar";
JarUtils.saveAsJar(BytecodeViewer.getLoadedClasses(), input);
Thread t = new Thread()
{
@Override
public void run()
{
APKTool.buildAPK(new File(input), file2, finalContainer);
BytecodeViewer.viewer.setIcon(false);
}
};
t.start();
}
};
t.start();
}
}
};
t.start();
}
});
//mnNewMenu.add(mntmSaveAsAPK);
mnNewMenu.add(mntmSaveAsDEX);
mnNewMenu.add(mntmSave); mnNewMenu.add(mntmSave);
mntmNewMenuItem.addActionListener(new ActionListener() mntmNewMenuItem.addActionListener(new ActionListener()
{ {

View file

@ -231,9 +231,7 @@ public class EZInjection extends Plugin {
MethodInsnNode mn = (MethodInsnNode) m.instructions MethodInsnNode mn = (MethodInsnNode) m.instructions
.get(1); .get(1);
if (mn.owner if (mn.owner
.equals("the/bytecode/club/bytecodeviewer/plugins/EZInjection")) // already .equals(EZInjection.class.getName().replace(".", "/")))//"the/bytecode/club/bytecodeviewer/plugins/EZInjection")) // already been injected
// been
// injected
inject = false; inject = false;
} }
if (inject) { if (inject) {
@ -241,7 +239,7 @@ public class EZInjection extends Plugin {
m.instructions m.instructions
.insert(new MethodInsnNode( .insert(new MethodInsnNode(
Opcodes.INVOKESTATIC, Opcodes.INVOKESTATIC,
"the/bytecode/club/bytecodeviewer/plugins/EZInjection", EZInjection.class.getName().replace(".", "/"),//"the/bytecode/club/bytecodeviewer/plugins/EZInjection",
"hook", "(Ljava/lang/String;)V")); "hook", "(Ljava/lang/String;)V"));
m.instructions.insert(new LdcInsnNode(classNode.name m.instructions.insert(new LdcInsnNode(classNode.name
+ "." + m.name + m.desc)); + "." + m.name + m.desc));

View file

@ -1,9 +1,17 @@
package the.bytecode.club.bytecodeviewer.util; package the.bytecode.club.bytecodeviewer.util;
import java.io.File; import java.io.*;
import java.nio.file.Files;
import java.util.Map;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;
import me.konloch.kontainer.io.DiskWriter;
import org.apache.commons.io.FileUtils; import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import the.bytecode.club.bytecodeviewer.BytecodeViewer; import the.bytecode.club.bytecodeviewer.BytecodeViewer;
import the.bytecode.club.bytecodeviewer.SecurityMan;
/*************************************************************************** /***************************************************************************
* Bytecode Viewer (BCV) - Java & Android Reverse Engineering Suite * * Bytecode Viewer (BCV) - Java & Android Reverse Engineering Suite *
@ -23,28 +31,60 @@ import the.bytecode.club.bytecodeviewer.BytecodeViewer;
* along with this program. If not, see <http://www.gnu.org/licenses/>. * * along with this program. If not, see <http://www.gnu.org/licenses/>. *
***************************************************************************/ ***************************************************************************/
/**
* @author Konloch
*/
public class APKTool { public class APKTool {
public static synchronized void decodeResources(File input, File output) { public static synchronized void decodeResources(File input, File output, FileContainer container) {
try { try {
File dir = new File(BytecodeViewer.tempDirectory + BytecodeViewer.fs + "Decoded Resources"); File dir = new File(BytecodeViewer.tempDirectory + BytecodeViewer.fs + MiscUtils.randomString(32)+BytecodeViewer.fs+"Decoded Resources");
FileUtils.deleteDirectory(dir); dir.mkdirs();
File temp = new File(BytecodeViewer.tempDirectory + BytecodeViewer.fs + MiscUtils.randomString(12));
temp.mkdirs(); File tempAPKPath = new File(BytecodeViewer.tempDirectory + BytecodeViewer.fs + MiscUtils.randomString(12));
brut.apktool.Main.main(new String[]{"--frame-path", temp.getAbsolutePath(), "-s", "-f", "-o", dir.getAbsolutePath(), "decode", input.getAbsolutePath()}); tempAPKPath.mkdirs();
File original = new File(dir.getAbsolutePath() + BytecodeViewer.fs + "original"); brut.apktool.Main.main(new String[]{"r", "--frame-path", tempAPKPath.getAbsolutePath(), "d", input.getAbsolutePath(), "-o", dir.getAbsolutePath(), "-f"});
FileUtils.deleteDirectory(original);
File classes = new File(dir.getAbsolutePath() + BytecodeViewer.fs + "classes.dex");
classes.delete();
File apktool = new File(dir.getAbsolutePath() + BytecodeViewer.fs + "apktool.yml");
apktool.delete();
File zip = new File(BytecodeViewer.tempDirectory + BytecodeViewer.fs + MiscUtils.randomString(12) + ".zip"); File zip = new File(BytecodeViewer.tempDirectory + BytecodeViewer.fs + MiscUtils.randomString(12) + ".zip");
ZipUtils.zipFolder(dir.getAbsolutePath(), zip.getAbsolutePath(), null); ZipUtils.zipFolderAPKTool(dir.getAbsolutePath(), zip.getAbsolutePath());
if (zip.exists()) if (zip.exists())
zip.renameTo(output); zip.renameTo(output);
FileUtils.deleteDirectory(dir);
container.APKToolContents = dir;
tempAPKPath.delete();
} catch (Exception e) { } catch (Exception e) {
new the.bytecode.club.bytecodeviewer.api.ExceptionUI(e); new the.bytecode.club.bytecodeviewer.api.ExceptionUI(e);
} }
} }
public static synchronized void buildAPK(File input, File output, FileContainer container)
{
String name = container.file.getName().toLowerCase();
String temp = BytecodeViewer.tempDirectory + BytecodeViewer.fs;
File tempDir = new File(temp+BytecodeViewer.fs+BytecodeViewer.getRandomizedName()+BytecodeViewer.fs);
tempDir.mkdirs();
File tempAPKPath = new File(BytecodeViewer.tempDirectory + BytecodeViewer.fs + MiscUtils.randomString(12));
tempAPKPath.mkdirs();
try
{
File smaliFolder = new File(container.APKToolContents.getAbsolutePath()+BytecodeViewer.fs+"smali");
FileUtils.deleteDirectory(smaliFolder);
//save entire jar as smali files
System.out.println("Building!");
BytecodeViewer.sm.stopBlocking();
brut.apktool.Main.main(new String[]{"b", container.APKToolContents.getAbsolutePath(), "--frame-path", tempAPKPath.getAbsolutePath(), "-o", output.getAbsolutePath()});
BytecodeViewer.sm.setBlocking();
tempAPKPath.delete();
}
catch (Exception e)
{
new the.bytecode.club.bytecodeviewer.api.ExceptionUI(e);
}
}
} }

View file

@ -1,8 +1,21 @@
package the.bytecode.club.bytecodeviewer.util; package the.bytecode.club.bytecodeviewer.util;
import me.konloch.kontainer.io.DiskReader;
import me.konloch.kontainer.io.DiskWriter;
import org.apache.commons.io.IOUtils;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.tree.ClassNode;
import the.bytecode.club.bytecodeviewer.BytecodeViewer; import the.bytecode.club.bytecodeviewer.BytecodeViewer;
import java.io.File; import java.io.*;
import java.nio.file.Files;
import java.util.Map;
import java.util.jar.JarEntry;
import java.util.jar.JarInputStream;
import java.util.jar.JarOutputStream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;
/*************************************************************************** /***************************************************************************
* Bytecode Viewer (BCV) - Java & Android Reverse Engineering Suite * * Bytecode Viewer (BCV) - Java & Android Reverse Engineering Suite *
@ -81,6 +94,10 @@ public class Dex2Jar {
{ {
currentDexLocation = new File(currentDexLocation.getAbsolutePath().replaceFirst("\\.zip", "-jar2dex.dex")); currentDexLocation = new File(currentDexLocation.getAbsolutePath().replaceFirst("\\.zip", "-jar2dex.dex"));
} }
else if(currentDexLocation.getAbsolutePath().toLowerCase().endsWith(".class"))
{
currentDexLocation = new File(currentDexLocation.getAbsolutePath().replaceFirst("\\.class", "-jar2dex.dex"));
}
currentDexLocation.renameTo(output); currentDexLocation.renameTo(output);

View file

@ -44,6 +44,7 @@ public class FileContainer {
public File file; public File file;
public String name; public String name;
public File APKToolContents = null;
public HashMap<String, byte[]> files = new HashMap<>(); public HashMap<String, byte[]> files = new HashMap<>();
public ArrayList<ClassNode> classes = new ArrayList<>(); public ArrayList<ClassNode> classes = new ArrayList<>();

View file

@ -0,0 +1,59 @@
package the.bytecode.club.bytecodeviewer.util;
// Copyright 2017 Robert Grosse
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
// http://www.apache.org/licenses/LICENSE-2.0
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
import java.net.*;
import java.nio.file.*;
import java.util.*;
import java.util.zip.*;
public class JRTExtractor
{
public static void extractRT(String path) throws Throwable
{
FileSystem fs = FileSystems.getFileSystem(URI.create("jrt:/"));
try(ZipOutputStream zipStream = new ZipOutputStream(Files.newOutputStream(Paths.get(path))))
{
Files.walk(fs.getPath("/")).forEach(p -> {
if (!Files.isRegularFile(p)) {return;}
try
{
byte[] data = Files.readAllBytes(p);
List<String> list = new ArrayList<>();
p.iterator().forEachRemaining(p2 -> list.add(p2.toString()));
assert list.remove(0).equals("modules");
if (!list.get(list.size()-1).equals("module-info.class"))
{
list.remove(0);
}
list.remove(0);
String outPath = String.join("/", list);
if(!outPath.endsWith("module-info.class"))
{
ZipEntry ze = new ZipEntry(outPath);
zipStream.putNextEntry(ze);
zipStream.write(data);
}
} catch (Throwable t) {throw new RuntimeException(t);}
});
}
}
}

View file

@ -43,7 +43,7 @@ public final class ZipUtils {
// fist get all directories, // fist get all directories,
// then make those directory on the destination Path // then make those directory on the destination Path
for (Enumeration<JarEntry> enums = jar.entries(); enums.hasMoreElements(); ) { /*for (Enumeration<JarEntry> enums = jar.entries(); enums.hasMoreElements(); ) {
JarEntry entry = (JarEntry) enums.nextElement(); JarEntry entry = (JarEntry) enums.nextElement();
String fileName = destinationDir + File.separator + entry.getName(); String fileName = destinationDir + File.separator + entry.getName();
@ -53,7 +53,7 @@ public final class ZipUtils {
f.mkdirs(); f.mkdirs();
} }
} }*/
//now create all files //now create all files
for (Enumeration<JarEntry> enums = jar.entries(); enums.hasMoreElements(); ) { for (Enumeration<JarEntry> enums = jar.entries(); enums.hasMoreElements(); ) {
@ -62,6 +62,12 @@ public final class ZipUtils {
String fileName = destinationDir + File.separator + entry.getName(); String fileName = destinationDir + File.separator + entry.getName();
File f = new File(fileName); File f = new File(fileName);
File parent = f.getParentFile();
if(!parent.exists())
{
parent.mkdirs();
}
if (!fileName.endsWith("/")) { if (!fileName.endsWith("/")) {
InputStream is = jar.getInputStream(entry); InputStream is = jar.getInputStream(entry);
FileOutputStream fos = new FileOutputStream(f); FileOutputStream fos = new FileOutputStream(f);
@ -119,6 +125,18 @@ public final class ZipUtils {
zip.close(); zip.close();
} }
public static void zipFolderAPKTool(String srcFolder, String destZipFile) throws Exception {
ZipOutputStream zip = null;
FileOutputStream fileWriter = null;
fileWriter = new FileOutputStream(destZipFile);
zip = new ZipOutputStream(fileWriter);
addFolderToZipAPKTool("", srcFolder, zip);
zip.flush();
zip.close();
}
public static void addFileToZip(String path, String srcFile, ZipOutputStream zip, String ignore) public static void addFileToZip(String path, String srcFile, ZipOutputStream zip, String ignore)
throws Exception { throws Exception {
@ -142,6 +160,38 @@ public final class ZipUtils {
} }
} }
public static void addFileToZipAPKTool(String path, String srcFile, ZipOutputStream zip) throws Exception
{
File folder = new File(srcFile);
String check = path.toLowerCase();
//if(check.startsWith("decoded resources/unknown") || check.startsWith("decoded resources/lib") || check.startsWith("decoded resources/assets") || check.startsWith("decoded resources/original") || check.startsWith("decoded resources/smali") || check.startsWith("decoded resources/apktool.yml"))
if(check.startsWith("decoded resources/original") || check.startsWith("decoded resources/smali") || check.startsWith("decoded resources/apktool.yml"))
return;
//if(path.equals("original") || path.equals("classes.dex") || path.equals("apktool.yml"))
// continue;
if (folder.isDirectory())
{
addFolderToZipAPKTool(path, srcFile, zip);
} else {
byte[] buf = new byte[1024];
int len;
FileInputStream in = new FileInputStream(srcFile);
ZipEntry entry = null;
entry = new ZipEntry(path + "/" + folder.getName());
zip.putNextEntry(entry);
while ((len = in.read(buf)) > 0)
{
zip.write(buf, 0, len);
}
in.close();
}
}
public static void addFolderToZip(String path, String srcFolder, ZipOutputStream zip, String ignore) public static void addFolderToZip(String path, String srcFolder, ZipOutputStream zip, String ignore)
throws Exception { throws Exception {
File folder = new File(srcFolder); File folder = new File(srcFolder);
@ -154,4 +204,19 @@ public final class ZipUtils {
} }
} }
} }
public static void addFolderToZipAPKTool(String path, String srcFolder, ZipOutputStream zip) throws Exception
{
File folder = new File(srcFolder);
for (String fileName : folder.list())
{
if (path.equals(""))
{
addFileToZipAPKTool(folder.getName(), srcFolder + "/" + fileName, zip);
} else {
addFileToZipAPKTool(path + "/" + folder.getName(), srcFolder + "/" + fileName, zip);
}
}
}
} }