v2.9.20
This commit is contained in:
parent
9f3302f7a9
commit
f76b31d8e7
12 changed files with 398 additions and 55 deletions
|
@ -16,12 +16,8 @@ import java.net.URL;
|
|||
import java.nio.file.Files;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Enumeration;
|
||||
import java.util.HashMap;
|
||||
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.JFileChooser;
|
||||
|
@ -118,7 +114,7 @@ import the.bytecode.club.bytecodeviewer.util.*;
|
|||
public class BytecodeViewer
|
||||
{
|
||||
/*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 enjarifyVersion = "4";
|
||||
public static final boolean BLOCK_TAB_MENU = true;
|
||||
|
@ -145,12 +141,13 @@ public class BytecodeViewer
|
|||
public static boolean currentlyDumping = false;
|
||||
public static boolean needsReDump = true;
|
||||
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;
|
||||
public static String fs = System.getProperty("file.separator");
|
||||
public static String nl = System.getProperty("line.separator");
|
||||
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 pluginsName = getBCVDirectory() + fs + "recentplugins.json";
|
||||
public static String settingsName = getBCVDirectory() + fs + "settings.bcv";
|
||||
|
@ -161,15 +158,15 @@ public class BytecodeViewer
|
|||
public static boolean runningObfuscation = false;
|
||||
private static long start = System.currentTimeMillis();
|
||||
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 boolean pingback = false;
|
||||
public static boolean deleteForeignLibraries = true;
|
||||
public static boolean canExit = false;
|
||||
public static Gson gson;
|
||||
|
||||
private static ArrayList<String> recentPlugins;
|
||||
private static ArrayList<String> recentFiles;
|
||||
private static List<String> recentPlugins;
|
||||
private static List<String> recentFiles;
|
||||
|
||||
static
|
||||
{
|
||||
|
@ -669,6 +666,10 @@ public class BytecodeViewer
|
|||
return null;
|
||||
}
|
||||
|
||||
public static List<FileContainer> getFiles() {
|
||||
return files;
|
||||
}
|
||||
|
||||
public static ClassNode getClassNode(FileContainer container, String name) {
|
||||
for (ClassNode c : container.classes)
|
||||
if (c.name.equals(name))
|
||||
|
@ -943,7 +944,7 @@ public class BytecodeViewer
|
|||
|
||||
if (viewer.decodeAPKResources.isSelected()) {
|
||||
File decodedResources = new File(tempDirectory + fs + MiscUtils.randomString(32) + ".apk");
|
||||
APKTool.decodeResources(tempCopy, decodedResources);
|
||||
APKTool.decodeResources(tempCopy, decodedResources, container);
|
||||
container.files = JarUtils.loadResources(decodedResources);
|
||||
}
|
||||
|
||||
|
@ -1080,7 +1081,7 @@ public class BytecodeViewer
|
|||
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
|
||||
|
@ -1109,7 +1110,7 @@ public class BytecodeViewer
|
|||
resetRecentFilesMenu();
|
||||
}
|
||||
|
||||
private static ArrayList<String> killList2 = new ArrayList<String>();
|
||||
private static List<String> killList2 = new ArrayList<String>();
|
||||
|
||||
/**
|
||||
* Add to the recent plugin list
|
||||
|
@ -1187,7 +1188,7 @@ public class BytecodeViewer
|
|||
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
|
||||
|
@ -1254,7 +1255,7 @@ public class BytecodeViewer
|
|||
* @param a array
|
||||
* @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);
|
||||
}
|
||||
|
||||
|
@ -1471,11 +1472,30 @@ public class BytecodeViewer
|
|||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@ import java.awt.image.BufferedImage;
|
|||
import java.io.ByteArrayInputStream;
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
import javax.swing.ImageIcon;
|
||||
|
@ -37,7 +38,7 @@ import org.imgscalr.Scalr;
|
|||
|
||||
public class Resources {
|
||||
|
||||
public static ArrayList<BufferedImage> iconList;
|
||||
public static List<BufferedImage> iconList;
|
||||
public static BufferedImage icon;
|
||||
public static ImageIcon nextIcon;
|
||||
public static ImageIcon prevIcon;
|
||||
|
|
|
@ -44,6 +44,7 @@ public class SecurityMan extends SecurityManager {
|
|||
executedClass.equals("the.bytecode.club.bytecodeviewer.decompilers.JDGUIDecompiler") ||
|
||||
executedClass.equals("the.bytecode.club.bytecodeviewer.compilers.KrakatauAssembler") ||
|
||||
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.compilers.JavaCompiler")) {
|
||||
blocking = false;
|
||||
|
@ -60,7 +61,8 @@ public class SecurityMan extends SecurityManager {
|
|||
"attrib",
|
||||
"python",
|
||||
"pypy",
|
||||
"java"
|
||||
"java",
|
||||
"brut_util",
|
||||
};
|
||||
boolean allow = false;
|
||||
|
||||
|
@ -71,7 +73,7 @@ public class SecurityMan extends SecurityManager {
|
|||
|
||||
if (allow && !blocking) {
|
||||
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
|
||||
|
|
|
@ -44,7 +44,7 @@ public class SmaliAssembler extends Compiler {
|
|||
tempSmaliFolder.mkdir();
|
||||
|
||||
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 tempJarFolder = new File(fileStart + fileNumber + "-jar" + BytecodeViewer.fs);
|
||||
|
||||
|
@ -68,6 +68,7 @@ public class SmaliAssembler extends Compiler {
|
|||
Enjarify.apk2Jar(tempDex, tempJar);
|
||||
|
||||
try {
|
||||
System.out.println("Unzipping to " + tempJarFolder.getAbsolutePath());
|
||||
ZipUtils.unzipFilesToPath(tempJar.getAbsolutePath(), tempJarFolder.getAbsolutePath());
|
||||
|
||||
File outputClass = null;
|
||||
|
|
|
@ -41,8 +41,7 @@ public class SmaliDisassembler extends Decompiler {
|
|||
|
||||
public String decompileClassNode(FileContainer container, ClassNode cn, byte[] b) {
|
||||
String exception = "";
|
||||
String fileStart = BytecodeViewer.tempDirectory + BytecodeViewer.fs
|
||||
+ "temp";
|
||||
String fileStart = BytecodeViewer.tempDirectory + BytecodeViewer.fs + "temp";
|
||||
|
||||
String start = MiscUtils.getUniqueName(fileStart, ".class");
|
||||
|
||||
|
@ -62,9 +61,7 @@ public class SmaliDisassembler extends Decompiler {
|
|||
|
||||
//ZipUtils.zipFile(tempClass, tempZip);
|
||||
|
||||
Dex2Jar.saveAsDex(container.file, tempDex, false);
|
||||
|
||||
System.out.println("FOR SHOW: " + tempDex.getName().replaceFirst("\\.dex", "-out")); //tempSmali.getAbsolutePath()
|
||||
Dex2Jar.saveAsDex(tempClass, tempDex, true);
|
||||
|
||||
try
|
||||
{
|
||||
|
@ -94,9 +91,6 @@ public class SmaliDisassembler extends Decompiler {
|
|||
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;
|
||||
|
||||
boolean found = false;
|
||||
|
|
|
@ -9,6 +9,7 @@ import java.awt.KeyboardFocusManager;
|
|||
import java.awt.event.*;
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import javax.swing.BoxLayout;
|
||||
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 JSeparator separator_7 = 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(mntmNewMenuItem_3);
|
||||
mntmSaveAsApk.addActionListener(new ActionListener()
|
||||
mntmSaveAsDEX.addActionListener(new ActionListener()
|
||||
{
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent arg0)
|
||||
|
@ -940,8 +942,151 @@ public class MainViewerGUI extends JFrame implements FileChangeNotifier
|
|||
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);
|
||||
mntmNewMenuItem.addActionListener(new ActionListener()
|
||||
{
|
||||
|
|
|
@ -231,9 +231,7 @@ public class EZInjection extends Plugin {
|
|||
MethodInsnNode mn = (MethodInsnNode) m.instructions
|
||||
.get(1);
|
||||
if (mn.owner
|
||||
.equals("the/bytecode/club/bytecodeviewer/plugins/EZInjection")) // already
|
||||
// been
|
||||
// injected
|
||||
.equals(EZInjection.class.getName().replace(".", "/")))//"the/bytecode/club/bytecodeviewer/plugins/EZInjection")) // already been injected
|
||||
inject = false;
|
||||
}
|
||||
if (inject) {
|
||||
|
@ -241,7 +239,7 @@ public class EZInjection extends Plugin {
|
|||
m.instructions
|
||||
.insert(new MethodInsnNode(
|
||||
Opcodes.INVOKESTATIC,
|
||||
"the/bytecode/club/bytecodeviewer/plugins/EZInjection",
|
||||
EZInjection.class.getName().replace(".", "/"),//"the/bytecode/club/bytecodeviewer/plugins/EZInjection",
|
||||
"hook", "(Ljava/lang/String;)V"));
|
||||
m.instructions.insert(new LdcInsnNode(classNode.name
|
||||
+ "." + m.name + m.desc));
|
||||
|
|
|
@ -1,9 +1,17 @@
|
|||
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.IOUtils;
|
||||
import the.bytecode.club.bytecodeviewer.BytecodeViewer;
|
||||
import the.bytecode.club.bytecodeviewer.SecurityMan;
|
||||
|
||||
/***************************************************************************
|
||||
* 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/>. *
|
||||
***************************************************************************/
|
||||
|
||||
/**
|
||||
* @author Konloch
|
||||
*/
|
||||
public class APKTool {
|
||||
|
||||
public static synchronized void decodeResources(File input, File output) {
|
||||
public static synchronized void decodeResources(File input, File output, FileContainer container) {
|
||||
try {
|
||||
File dir = new File(BytecodeViewer.tempDirectory + BytecodeViewer.fs + "Decoded Resources");
|
||||
FileUtils.deleteDirectory(dir);
|
||||
File temp = new File(BytecodeViewer.tempDirectory + BytecodeViewer.fs + MiscUtils.randomString(12));
|
||||
temp.mkdirs();
|
||||
brut.apktool.Main.main(new String[]{"--frame-path", temp.getAbsolutePath(), "-s", "-f", "-o", dir.getAbsolutePath(), "decode", input.getAbsolutePath()});
|
||||
File original = new File(dir.getAbsolutePath() + BytecodeViewer.fs + "original");
|
||||
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 dir = new File(BytecodeViewer.tempDirectory + BytecodeViewer.fs + MiscUtils.randomString(32)+BytecodeViewer.fs+"Decoded Resources");
|
||||
dir.mkdirs();
|
||||
|
||||
File tempAPKPath = new File(BytecodeViewer.tempDirectory + BytecodeViewer.fs + MiscUtils.randomString(12));
|
||||
tempAPKPath.mkdirs();
|
||||
brut.apktool.Main.main(new String[]{"r", "--frame-path", tempAPKPath.getAbsolutePath(), "d", input.getAbsolutePath(), "-o", dir.getAbsolutePath(), "-f"});
|
||||
|
||||
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())
|
||||
zip.renameTo(output);
|
||||
FileUtils.deleteDirectory(dir);
|
||||
|
||||
container.APKToolContents = dir;
|
||||
tempAPKPath.delete();
|
||||
} catch (Exception 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,8 +1,21 @@
|
|||
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 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 *
|
||||
|
@ -81,6 +94,10 @@ public class Dex2Jar {
|
|||
{
|
||||
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);
|
||||
|
||||
|
|
|
@ -44,6 +44,7 @@ public class FileContainer {
|
|||
|
||||
public File file;
|
||||
public String name;
|
||||
public File APKToolContents = null;
|
||||
|
||||
public HashMap<String, byte[]> files = new HashMap<>();
|
||||
public ArrayList<ClassNode> classes = new ArrayList<>();
|
||||
|
|
59
src/the/bytecode/club/bytecodeviewer/util/JRTExtractor.java
Normal file
59
src/the/bytecode/club/bytecodeviewer/util/JRTExtractor.java
Normal 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);}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
|
@ -43,7 +43,7 @@ public final class ZipUtils {
|
|||
|
||||
// fist get all directories,
|
||||
// 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();
|
||||
|
||||
String fileName = destinationDir + File.separator + entry.getName();
|
||||
|
@ -53,7 +53,7 @@ public final class ZipUtils {
|
|||
f.mkdirs();
|
||||
}
|
||||
|
||||
}
|
||||
}*/
|
||||
|
||||
//now create all files
|
||||
for (Enumeration<JarEntry> enums = jar.entries(); enums.hasMoreElements(); ) {
|
||||
|
@ -62,6 +62,12 @@ public final class ZipUtils {
|
|||
String fileName = destinationDir + File.separator + entry.getName();
|
||||
File f = new File(fileName);
|
||||
|
||||
File parent = f.getParentFile();
|
||||
if(!parent.exists())
|
||||
{
|
||||
parent.mkdirs();
|
||||
}
|
||||
|
||||
if (!fileName.endsWith("/")) {
|
||||
InputStream is = jar.getInputStream(entry);
|
||||
FileOutputStream fos = new FileOutputStream(f);
|
||||
|
@ -119,6 +125,18 @@ public final class ZipUtils {
|
|||
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)
|
||||
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)
|
||||
throws Exception {
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue