Merge pull request #379 from ThexXTURBOXx/master

Fixes and Updates
This commit is contained in:
Konloch 2022-01-11 11:29:52 -08:00 committed by GitHub
commit 81e9e444be
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
15 changed files with 266 additions and 294 deletions

View file

@ -1,6 +1,5 @@
import org.objectweb.asm.tree.ClassNode import org.objectweb.asm.tree.ClassNode
import the.bytecode.club.bytecodeviewer.api.Plugin import the.bytecode.club.bytecodeviewer.api.*
import the.bytecode.club.bytecodeviewer.api.PluginConsole
class Skeleton extends Plugin { class Skeleton extends Plugin {

View file

@ -1,13 +1,14 @@
import the.bytecode.club.bytecodeviewer.api.*; import java.util.List;
import java.util.ArrayList;
import org.objectweb.asm.tree.ClassNode; import org.objectweb.asm.tree.ClassNode;
import the.bytecode.club.bytecodeviewer.api.*;
public class Skeleton extends Plugin { public class Skeleton extends Plugin {
@Override @Override
public void execute(ArrayList<ClassNode> classNodesList) { public void execute(List<ClassNode> classNodesList) {
PluginConsole gui = new PluginConsole("Skeleton"); PluginConsole gui = new PluginConsole("Skeleton");
gui.setVisible(true); gui.setVisible(true);
gui.appendText("executed skeleton"); gui.appendText("executed skeleton");
} }
} }

View file

@ -1,5 +1,4 @@
function execute(classNodeList) function execute(classNodeList) {
{
var PluginConsole = Java.type("the.bytecode.club.bytecodeviewer.api.PluginConsole"); var PluginConsole = Java.type("the.bytecode.club.bytecodeviewer.api.PluginConsole");
var gui = new PluginConsole("Skeleton"); var gui = new PluginConsole("Skeleton");
gui.setVisible(true); gui.setVisible(true);

View file

@ -1,4 +1,3 @@
import java.awt.*;
import java.io.BufferedWriter; import java.io.BufferedWriter;
import java.io.File; import java.io.File;
import java.io.FileWriter; import java.io.FileWriter;
@ -12,10 +11,8 @@ import javax.swing.Box;
import javax.swing.JComboBox; import javax.swing.JComboBox;
import javax.swing.JOptionPane; import javax.swing.JOptionPane;
import javax.swing.JPanel; import javax.swing.JPanel;
import org.objectweb.asm.tree.ClassNode; import org.objectweb.asm.tree.ClassNode;
import the.bytecode.club.bytecodeviewer.*; import the.bytecode.club.bytecodeviewer.*;
import the.bytecode.club.bytecodeviewer.util.*;
import the.bytecode.club.bytecodeviewer.api.*; import the.bytecode.club.bytecodeviewer.api.*;
import the.bytecode.club.bytecodeviewer.decompilers.impl.FernFlowerDecompiler; import the.bytecode.club.bytecodeviewer.decompilers.impl.FernFlowerDecompiler;
import the.bytecode.club.bytecodeviewer.gui.resourceviewer.viewer.ResourceViewer; import the.bytecode.club.bytecodeviewer.gui.resourceviewer.viewer.ResourceViewer;
@ -23,39 +20,35 @@ import the.bytecode.club.bytecodeviewer.gui.resourceviewer.viewer.ResourceViewer
/** /**
* @author jowasp * @author jowasp
*/ */
public class XposedGenerator extends Plugin public class XposedGenerator extends Plugin {
{
//PRIVATE //PRIVATE
private static List<String> methodsNames = new ArrayList<String>(); private static final List<String> methodsNames = new ArrayList<>();
private static List<String> cleanMethodsNames = new ArrayList<String>(); private static final List<String> cleanMethodsNames = new ArrayList<>();
private static String foundpckg; private static String foundPckg;
public XposedGenerator() {} public XposedGenerator() {
}
@Override @Override
public void execute(ArrayList<ClassNode> classNodeList) public void execute(List<ClassNode> classNodeList) {
{
//Get actual file class content //Get actual file class content
ResourceViewer viewer = BytecodeViewer.getActiveResource(); ResourceViewer viewer = BytecodeViewer.getActiveResource();
if(viewer == null) if (viewer == null) {
{ BytecodeViewer.showMessage("Open A Class First");
BytecodeViewer.showMessage("Open A Class First"); return;
return; }
}
String className = viewer.getName(); String className = viewer.getName();
String containerName = viewer.name; //String containerName = viewer.getName();
ClassNode classnode = BytecodeViewer.getCurrentlyOpenedClassNode(); ClassNode classnode = BytecodeViewer.getCurrentlyOpenedClassNode();
//Call XposedGenerator class //Call XposedGenerator class
ParseChosenFileContent(className,containerName,classnode); ParseChosenFileContent(className, classnode);
} }
public static void ParseChosenFileContent(String classname, String containerName, ClassNode classNode) public static void ParseChosenFileContent(String classname, ClassNode classNode) {
{ try {
try
{
//Parse content - Extract methods after APK /JAR has been extracted //Parse content - Extract methods after APK /JAR has been extracted
byte[] cont = ASMUtil.nodeToBytes(classNode); byte[] cont = ASMUtil.nodeToBytes(classNode);
@ -64,22 +57,21 @@ public class XposedGenerator extends Plugin
FernFlowerDecompiler decompilefern = new FernFlowerDecompiler(); FernFlowerDecompiler decompilefern = new FernFlowerDecompiler();
//Decompile using Fern //Decompile using Fern
String decomp = decompilefern.decompileClassNode(classNode, cont); String decomp = decompilefern.decompileClassNode(classNode, cont);
String[] xposedTemplateTypes = {"Empty","Parameters","Helper"}; String[] xposedTemplateTypes = {"Empty", "Parameters", "Helper"};
@SuppressWarnings({ "unchecked", "rawtypes" }) @SuppressWarnings({"unchecked", "rawtypes"})
JComboBox xposedTemplateList = new JComboBox(xposedTemplateTypes); JComboBox xposedTemplateList = new JComboBox(xposedTemplateTypes);
//Set results of parsed methods into an a list //Set results of parsed methods into a list
List<String> methodsExtracted = ProcessContentExtractedClass(decomp); List<String> methodsExtracted = ProcessContentExtractedClass(decomp);
String packgExtracted = ProcessContentExtractedPackage(decomp); String packgExtracted = ProcessContentExtractedPackage(decomp);
System.out.println("PACKAGE NAME: " +packgExtracted); System.out.println("PACKAGE NAME: " + packgExtracted);
//Get a clean list //Get a clean list
List<String> cleanMethods = null; List<String> cleanMethods;
//clear list //clear list
cleanMethods = ProcessCleanMethodsAll(methodsExtracted); cleanMethods = ProcessCleanMethodsAll(methodsExtracted);
if (!cleanMethods.isEmpty()) if (!cleanMethods.isEmpty()) {
{ JComboBox<String> cb = new JComboBox<>(cleanMethods.toArray(new String[0]));
JComboBox<String> cb = new JComboBox<>(cleanMethods.toArray(new String[cleanMethods.size()]));
//Add Panel elements //Add Panel elements
//Start Panel //Start Panel
@ -94,56 +86,54 @@ public class XposedGenerator extends Plugin
if (result == JOptionPane.OK_OPTION) { if (result == JOptionPane.OK_OPTION) {
//Read Chosen Class //Read Chosen Class
System.out.println("SELECTED CLASS is" + cb.getSelectedItem()); Object cbItem = cb.getSelectedItem();
String selectedClass = cb.getSelectedItem().toString(); Object xPosedItem = xposedTemplateList.getSelectedItem();
String selectedXposedTemplate = xposedTemplateList.getSelectedItem().toString(); System.out.println("SELECTED CLASS is" + cbItem);
if (cbItem != null && xPosedItem != null) {
String selectedClass = cbItem.toString();
String selectedXposedTemplate = xPosedItem.toString();
//WriteXposed Class with extracted data //WriteXposed Class with extracted data
try{ try {
WriteXposedModule(selectedClass, packgExtracted, classname, selectedXposedTemplate); WriteXposedModule(selectedClass, packgExtracted, classname, selectedXposedTemplate);
} } catch (IllegalArgumentException e) {
catch(IllegalArgumentException e) e.printStackTrace();
{ JOptionPane.showMessageDialog(null, "Error" + e);
e.printStackTrace(); }
JOptionPane.showMessageDialog(null,"Error" + e.toString());
} }
} }
} else {
JOptionPane.showMessageDialog(null, "Class Not Suitable");
} }
else } catch (IllegalArgumentException e) {
{
JOptionPane.showMessageDialog(null,"Class Not Suitable");
}
}
catch (IllegalArgumentException e)
{
e.printStackTrace(); e.printStackTrace();
JOptionPane.showMessageDialog(null,"Error" + e.toString()); JOptionPane.showMessageDialog(null, "Error" + e);
} }
} }
public static void WriteXposedModule(String functionToHook, String packageName, String classToHook, String template) { public static void WriteXposedModule(String functionToHook, String packageName, String classToHook,
System.out.println("TEMPLATE: " + template); String template) {
if (template != null && !template.equals("Empty")) System.out.println("TEMPLATE: " + template);
{ if (template != null && !template.equals("Empty")) {
try { try {
//TODO: Prompt save dialog //TODO: Prompt save dialog
File file = new File("./XposedClassTest.java"); File file = new File("./XposedClassTest.java");
// if file doesn't exists, then create it // if file doesn't exist, then create it
if (!file.exists()) { if (!file.exists()) {
file.createNewFile(); file.createNewFile();
} }
//Extract the package name only //Extract the package name only
String packageNameOnly = packageName.substring(8,packageName.length() - 2 ).trim(); String packageNameOnly = packageName.substring(8, packageName.length() - 2).trim();
String classToHookNameOnly = classToHook; String classToHookNameOnly = classToHook;
if(classToHookNameOnly.endsWith(".class")) if (classToHookNameOnly.endsWith(".class"))
classToHookNameOnly = classToHook.substring(0, classToHookNameOnly.length() - 6); classToHookNameOnly = classToHook.substring(0, classToHookNameOnly.length() - 6);
String[] classClean = classToHookNameOnly.split("\\/"); String[] classClean = classToHookNameOnly.split("/");
String[] functionSplitValues = functionToHook.split("\\s+"); String[] functionSplitValues = functionToHook.split("\\s+");
//select //select
String onlyClass = classClean[classClean.length-1]; String onlyClass = classClean[classClean.length - 1];
//String onlyFunctionParateses = functionSplitValues[functionSplitValues.length-2]; //String onlyFunctionParateses = functionSplitValues[functionSplitValues.length-2];
String onlyFunction = CleanUpFunction(functionSplitValues); String onlyFunction = CleanUpFunction(functionSplitValues);
@ -153,30 +143,34 @@ public class XposedGenerator extends Plugin
//Write Xposed Class //Write Xposed Class
String XposedClassText = String XposedClassText =
"package androidpentesting.com.xposedmodule;"+ "\r\n" + "package androidpentesting.com.xposedmodule;" + "\r\n" +
"import de.robv.android.xposed.IXposedHookLoadPackage;" + "\r\n" + "import de.robv.android.xposed.IXposedHookLoadPackage;" + "\r\n" +
"\r\n" + "\r\n" +
"import de.robv.android.xposed.XC_MethodHook;" +"\r\n" + "import de.robv.android.xposed.XC_MethodHook;" + "\r\n" +
"import de.robv.android.xposed.XposedBridge;" +"\r\n" + "import de.robv.android.xposed.XposedBridge;" + "\r\n" +
"import de.robv.android.xposed.callbacks.XC_LoadPackage.LoadPackageParam;"+"\r\n" + "import de.robv.android.xposed.callbacks.XC_LoadPackage.LoadPackageParam;" + "\r\n" +
"import static de.robv.android.xposed.XposedHelpers.findAndHookMethod;"+"\r\n" +"\r\n" + "import static de.robv.android.xposed.XposedHelpers.findAndHookMethod;" + "\r\n" +
"public class XposedClassTest implements IXposedHookLoadPackage {"+"\r\n" +"\r\n" + "\r\n" +
" public void handleLoadPackage(final LoadPackageParam lpparam) throws Throwable {" + "\r\n" +"\r\n" + "public class XposedClassTest implements IXposedHookLoadPackage {" + "\r\n" + "\r\n" +
" String classToHook = " + "\"" + packageNameOnly + "." + onlyClass + "\";" + "\r\n" + " public void handleLoadPackage(final LoadPackageParam lpparam) throws Throwable {" + "\r\n" + "\r\n" +
" String functionToHook = "+"\""+ onlyFunction+"\";"+"\r\n" + " String classToHook = " + "\"" + packageNameOnly + "." + onlyClass + "\";" +
" if (lpparam.packageName.equals("+"\""+packageNameOnly+ "\""+")){"+ "\r\n" + "\r\n" +
" XposedBridge.log(" + "\" Loaded app: \" " + " + lpparam.packageName);"+ "\r\n" +"\r\n" + " String functionToHook = " + "\"" + onlyFunction + "\";" + "\r\n" +
" findAndHookMethod("+"\""+onlyClass+"\"" + ", lpparam.classLoader, "+" \"" +onlyFunction + "\""+", int.class,"+ "\r\n" + " if (lpparam.packageName.equals(" + "\"" + packageNameOnly + "\"" + ")){" + "\r"
" new XC_MethodHook() {"+ "\r\n" + + "\n" +
" @Override"+ "\r\n" + " XposedBridge.log(" + "\" Loaded app: \" " + " + lpparam.packageName);" +
" protected void beforeHookedMethod(MethodHookParam param) throws Throwable {"+ "\r\n" + "\r\n" + "\r\n" +
" //TO BE FILLED BY ANALYST"+ "\r\n" + " findAndHookMethod(" + "\"" + onlyClass + "\"" + ", lpparam.classLoader, " + " \"" + onlyFunction + "\"" + ", int.class," + "\r\n" +
" }"+ "\r\n" + " new XC_MethodHook() {" + "\r\n" +
" });"+"\r\n" + " @Override" + "\r\n" +
" }"+ "\r\n" + " protected void beforeHookedMethod(MethodHookParam param) throws "
" }"+ "\r\n" + + "Throwable {" + "\r\n" +
"}"+ "\r\n" " //TO BE FILLED BY ANALYST" + "\r\n" +
; " }" + "\r\n" +
" });" + "\r\n" +
" }" + "\r\n" +
" }" + "\r\n" +
"}" + "\r\n";
FileWriter fw = new FileWriter(file.getAbsoluteFile()); FileWriter fw = new FileWriter(file.getAbsoluteFile());
BufferedWriter bw = new BufferedWriter(fw); BufferedWriter bw = new BufferedWriter(fw);
bw.write(XposedClassText); bw.write(XposedClassText);
@ -184,21 +178,19 @@ public class XposedGenerator extends Plugin
bw.close(); bw.close();
System.out.println("Done"); System.out.println("Done");
JOptionPane.showMessageDialog(null,"Xposed Module Generated"); JOptionPane.showMessageDialog(null, "Xposed Module Generated");
} catch (IOException e) { } catch (IOException e) {
JOptionPane.showMessageDialog(null,"Error" + e.toString()); JOptionPane.showMessageDialog(null, "Error" + e);
e.printStackTrace(); e.printStackTrace();
} }
} else {
JOptionPane.showMessageDialog(null, "Empty Template Chosen, Did Not Generate");
} }
else
{
JOptionPane.showMessageDialog(null,"Empty Template Chosen, Did Not Generate");
}
} }
private static List <String> ProcessContentExtractedClass(String contentFile){ private static List<String> ProcessContentExtractedClass(String contentFile) {
Scanner scanner = null; Scanner scanner = null;
try{ try {
scanner = new Scanner(contentFile); scanner = new Scanner(contentFile);
//@TODO : Improve patterns to match other excepts 'public' //@TODO : Improve patterns to match other excepts 'public'
String regexclass = "public"; String regexclass = "public";
@ -212,16 +204,13 @@ public class XposedGenerator extends Plugin
String line = scanner.nextLine(); String line = scanner.nextLine();
// process the line // process the line
Matcher matcher = pattern.matcher(line); Matcher matcher = pattern.matcher(line);
while (matcher.find()){ while (matcher.find()) {
if (matcher.group() != null) if (matcher.group() != null) {
{
System.out.println("find() found the pattern \"" + quote(line.trim())); System.out.println("find() found the pattern \"" + quote(line.trim()));
System.out.println("Function: " + CleanUpFunction(line.trim().split("\\s+"))); System.out.println("Function: " + CleanUpFunction(line.trim().split("\\s+")));
methodsNames.add(quote(line.trim())); methodsNames.add(quote(line.trim()));
} } else {
else
{
methodsNames.add("No methods found"); methodsNames.add("No methods found");
} }
@ -229,34 +218,23 @@ public class XposedGenerator extends Plugin
} }
if (methodsNames.isEmpty()) if (methodsNames.isEmpty()) {
{
methodsNames.add("No methods found"); methodsNames.add("No methods found");
} } else {
else
{
return methodsNames; return methodsNames;
} }
return methodsNames; return methodsNames;
} } finally {
finally { if (scanner != null)
if (scanner!=null)
scanner.close(); scanner.close();
} }
} }
private static List <String> ProcessCleanMethodsAll(List<String> rawMethods) private static List<String> ProcessCleanMethodsAll(List<String> rawMethods) {
{ for (String m : rawMethods) {
for (String m:rawMethods)
{
//Exclude class declaration //Exclude class declaration
//TODO:add a list containing all possible types //TODO:add a list containing all possible types
if (m.contains("extends") || (m.contains("implements") || (!m.contains("(")))) if (!m.contains("extends") && (!m.contains("implements") && (m.contains("(")))) {
{
continue;
}
else
{
cleanMethodsNames.add(m); cleanMethodsNames.add(m);
} }
@ -266,19 +244,12 @@ public class XposedGenerator extends Plugin
} }
private static String CleanUpFunction(String[] rawFunction) private static String CleanUpFunction(String[] rawFunction) {
{
String onlyFunc = "functiondummy"; String onlyFunc = "functiondummy";
for (String m:rawFunction) for (String m : rawFunction) {
{ if (m.contains("(")) {
if(m.contains("("))
{
String[] split = m.split("\\(")[0].split(" "); String[] split = m.split("\\(")[0].split(" ");
return split[split.length-1]; return split[split.length - 1];
}
else
{
continue;
} }
} }
@ -286,61 +257,50 @@ public class XposedGenerator extends Plugin
} }
private static String ProcessContentExtractedPackage(String contentFile){ private static String ProcessContentExtractedPackage(String contentFile) {
Scanner scanner = null; Scanner scanner = null;
try { try {
scanner = new Scanner(contentFile); scanner = new Scanner(contentFile);
String regexPkg = "package"; String regexPkg = "package";
Pattern patternPkg = Pattern.compile(regexPkg , Pattern.CASE_INSENSITIVE); Pattern patternPkg = Pattern.compile(regexPkg, Pattern.CASE_INSENSITIVE);
String line = scanner.nextLine(); String line = scanner.nextLine();
// process the line // process the line
Matcher matcher = patternPkg.matcher(line); Matcher matcher = patternPkg.matcher(line);
while (matcher.find()){ while (matcher.find()) {
if (matcher.group() != null) if (matcher.group() != null) {
{ System.out.println("find() found the pattern \"" + quote(line.trim()));
System.out.println("find() found the pattern \"" + quote(line.trim())) ; foundPckg = quote(line.trim());
foundpckg = quote(line.trim());
} } else {
else foundPckg = "";
{
foundpckg = "";
} }
} }
try try
// //
{ {
if (foundpckg == null || foundpckg.isEmpty()) if (foundPckg == null || foundPckg.isEmpty())
foundpckg = "No Package Found"; foundPckg = "No Package Found";
} catch (NullPointerException e) {
JOptionPane.showMessageDialog(null,
"Error - no package was found in the selected class: " + e);
} finally {
scanner.close();
} }
catch(NullPointerException e) } catch (IllegalArgumentException e) {
{ JOptionPane.showMessageDialog(null, "Error" + e);
JOptionPane.showMessageDialog(null,"Error - no package was found in the selected class: " + e.toString()); if (scanner != null)
} scanner.close();
finally } finally {
{ if (scanner != null)
if(scanner != null)
scanner.close();
}
}
catch(IllegalArgumentException e)
{
JOptionPane.showMessageDialog(null,"Error" + e.toString());
if(scanner != null)
scanner.close(); scanner.close();
} }
finally return foundPckg;
{
if(scanner != null)
scanner.close();
}
return foundpckg;
} }
private static String quote(String aText){ private static String quote(String aText) {
String QUOTE = "'"; String QUOTE = "'";
return QUOTE + aText + QUOTE; return QUOTE + aText + QUOTE;
} }

View file

@ -6,10 +6,8 @@ var PluginConsole = Java.type("the.bytecode.club.bytecodeviewer.api.PluginConsol
var gui = new PluginConsole("Example Plugin Print Loaded Classes"); var gui = new PluginConsole("Example Plugin Print Loaded Classes");
function execute(classNodeList) function execute(classNodeList) {
{ for (index = 0; index < classNodeList.length; index++) {
for (index = 0; index < classNodeList.length; index++)
{
var cn = classNodeList[index]; var cn = classNodeList[index];
gui.appendText("Resource: " + cn.name + ".class"); gui.appendText("Resource: " + cn.name + ".class");
} }

View file

@ -23,30 +23,25 @@ class ExampleStringDecrypter extends Plugin {
+ nl + "for each class. IF THE FILE YOU'RE LOADING IS MALICIOUS, DO NOT CONTINUE.", + nl + "for each class. IF THE FILE YOU'RE LOADING IS MALICIOUS, DO NOT CONTINUE.",
new String[]{"Continue", "Cancel"}) new String[]{"Continue", "Cancel"})
if(dialog.promptChoice() == 0) if (dialog.promptChoice() == 0) {
{ for (ClassNode cn : classNodesList) {
for(ClassNode cn : classNodesList)
{
BCV.getClassNodeLoader().addClass(cn) BCV.getClassNodeLoader().addClass(cn)
for(Object o : cn.fields.toArray()) for (Object o : cn.fields.toArray()) {
{
FieldNode f = (FieldNode) o FieldNode f = (FieldNode) o
if(f.name == "z") {// && f.desc.equals("([Ljava/lang/String;)V")) { if (f.name == "z") {// && f.desc.equals("([Ljava/lang/String;)V")) {
try try {
{ for (Field f2 : BCV.getClassNodeLoader().nodeToClass(cn).getFields()) {
for(Field f2 : BCV.getClassNodeLoader().nodeToClass(cn).getFields())
{
String s = f2.get(null) String s = f2.get(null)
if(s != null && !s.empty) if (s != null && !s.empty)
gui.appendText(cn + ":" + s) gui.appendText(cn + ":" + s)
} }
} catch(Exception | StackOverflowError ignored) {} } catch (Exception | StackOverflowError ignored) {
}
} }
} }
} }
gui.setVisible(true) gui.setVisible(true)
} }
} }

View file

@ -1,10 +1,9 @@
import the.bytecode.club.bytecodeviewer.api.*
import the.bytecode.club.bytecodeviewer.gui.components.MultipleChoiceDialog;
import java.util.ArrayList;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.util.List;
import org.objectweb.asm.tree.ClassNode; import org.objectweb.asm.tree.ClassNode;
import org.objectweb.asm.tree.FieldNode import org.objectweb.asm.tree.FieldNode;
import the.bytecode.club.bytecodeviewer.api.*;
import the.bytecode.club.bytecodeviewer.gui.components.MultipleChoiceDialog;
import static the.bytecode.club.bytecodeviewer.Constants.nl; import static the.bytecode.club.bytecodeviewer.Constants.nl;
@ -14,7 +13,7 @@ import static the.bytecode.club.bytecodeviewer.Constants.nl;
public class ExampleStringDecrypter extends Plugin { public class ExampleStringDecrypter extends Plugin {
@Override @Override
public void execute(ArrayList<ClassNode> classNodesList) { public void execute(List<ClassNode> classNodesList) {
PluginConsole gui = new PluginConsole("Example String Decrypter"); PluginConsole gui = new PluginConsole("Example String Decrypter");
MultipleChoiceDialog dialog = new MultipleChoiceDialog("Bytecode Viewer - WARNING", MultipleChoiceDialog dialog = new MultipleChoiceDialog("Bytecode Viewer - WARNING",
@ -22,25 +21,21 @@ public class ExampleStringDecrypter extends Plugin {
+ nl + "for each class. IF THE FILE YOU'RE LOADING IS MALICIOUS, DO NOT CONTINUE.", + nl + "for each class. IF THE FILE YOU'RE LOADING IS MALICIOUS, DO NOT CONTINUE.",
new String[]{"Continue", "Cancel"}); new String[]{"Continue", "Cancel"});
if(dialog.promptChoice() == 0) if (dialog.promptChoice() == 0) {
{ for (ClassNode cn : classNodesList) {
for(ClassNode cn : classNodesList) BCV.getClassNodeLoader().addClass(cn);
{
the.bytecode.club.bytecodeviewer.api.BCV.getClassNodeLoader().addClass(cn);
for(Object o : cn.fields.toArray()) for (Object o : cn.fields.toArray()) {
{
FieldNode f = (FieldNode) o; FieldNode f = (FieldNode) o;
if(f.name.equals("z")) {// && f.desc.equals("([Ljava/lang/String;)V")) { if (f.name.equals("z")) {// && f.desc.equals("([Ljava/lang/String;)V")) {
try try {
{ for (Field f2 : BCV.getClassNodeLoader().nodeToClass(cn).getFields()) {
for(Field f2 : the.bytecode.club.bytecodeviewer.api.BCV.getClassNodeLoader().nodeToClass(cn).getFields()) String s = (String) f2.get(null);
{ if (s != null && !s.isEmpty())
String s = f2.get(null); gui.appendText(cn + ":" + s);
if(s != null && !s.empty())
gui.appendText(cn+":"+s);
} }
} catch(Exception | StackOverflowError e) {} } catch (Exception ignored) {
}
} }
} }
@ -49,4 +44,5 @@ public class ExampleStringDecrypter extends Plugin {
gui.setVisible(true); gui.setVisible(true);
} }
} }
} }

View file

@ -7,67 +7,58 @@ var MultipleChoiceDialog = Java.type("the.bytecode.club.bytecodeviewer.gui.compo
var BytecodeViewer = Java.type("the.bytecode.club.bytecodeviewer.api.BCV") var BytecodeViewer = Java.type("the.bytecode.club.bytecodeviewer.api.BCV")
var dialog = new MultipleChoiceDialog("Bytecode Viewer - WARNING", var dialog = new MultipleChoiceDialog("Bytecode Viewer - WARNING",
"WARNING: This will load the classes into the JVM and execute the initialize function" "WARNING: This will load the classes into the JVM and execute the initialize function"
+ "\nfor each class. IF THE FILE YOU'RE LOADING IS MALICIOUS, DO NOT CONTINUE.", + "\nfor each class. IF THE FILE YOU'RE LOADING IS MALICIOUS, DO NOT CONTINUE.",
["Continue", "Cancel"]); ["Continue", "Cancel"]);
var gui; var gui;
function execute(classNodeList) function execute(classNodeList) {
{
gui = new PluginConsole("Skeleton"); gui = new PluginConsole("Skeleton");
if(dialog.promptChoice() == 0) if (dialog.promptChoice() == 0) {
{
var needsWarning = false; var needsWarning = false;
for (cnIndex = 0; cnIndex < classNodeList.length; cnIndex++) for (cnIndex = 0; cnIndex < classNodeList.length; cnIndex++) {
{ try {
try
{
var cn = classNodeList[cnIndex]; var cn = classNodeList[cnIndex];
var fields = cn.fields.toArray();
//load the class node into the classloader //load the class node into the classloader
BytecodeViewer.loadClassIntoClassLoader(cn); BytecodeViewer.getClassNodeLoader().addClass(cn);
for (fieldIndex = 0; fieldIndex < fields.length; fieldIndex++) var fields = cn.fields.toArray();
{ for (fieldIndex = 0; fieldIndex < fields.length; fieldIndex++) {
var field = fields[fieldIndex]; var field = fields[fieldIndex];
//if the class contains the field z, get the class object from the class node //if the class contains the field z, get the class object from the class node
//then print out the value of the fields inside the class //then print out the value of the fields inside the class
//if the strings get decrypted on init, this allows you to dump the current values //if the strings get decrypted on init, this allows you to dump the current values
if(field.name.equals("z")) {// && f.desc.equals("([Ljava/lang/String;)V")) { if (field.name.equals("z")) {// && f.desc.equals("([Ljava/lang/String;)V")) {
try try {
{
var loadedClass = BytecodeViewer.getClassNodeLoader().nodeToClass(cn); var loadedClass = BytecodeViewer.getClassNodeLoader().nodeToClass(cn);
var reflectedFields = loadedClass.getFields(); var reflectedFields = loadedClass.getFields();
for (reflectedFieldIndex = 0; reflectedFieldIndex < reflectedFields.length; reflectedFieldIndex++) for (reflectedFieldIndex = 0; reflectedFieldIndex < reflectedFields.length; reflectedFieldIndex++) {
{
var reflectedField = reflectedFields[fieldIndex]; var reflectedField = reflectedFields[fieldIndex];
var s = reflectedField.get(null); var s = reflectedField.get(null);
if(s != null && !s.empty()) if (s != null && !s.empty())
gui.appendText(cn + "->" + s); gui.appendText(cn + "->" + s);
} }
} catch(e) {} } catch (e) {
}
} }
} }
} } catch (e) {
catch(e) gui.appendText("Failed loading class " + cn.name);
{
gui.appendText("Failed loading class " + cn.getName());
e.printStackTrace(); e.printStackTrace();
needsWarning = true; needsWarning = true;
} }
} }
if (needsWarning) if (needsWarning) {
{ BytecodeViewer.showMessage("Some classes failed to decrypt, if you'd like to decrypt all of them\n"
BytecodeViewer.showMessage("Some classes failed to decrypt, if you'd like to decrypt all of them" + "makes sure you include ALL the libraries it requires.");
+ nl + "makes sure you include ALL the libraries it requires.");
} }
gui.setVisible(true); gui.setVisible(true);

34
pom.xml
View file

@ -31,7 +31,7 @@
<darklaf.version>2.7.3</darklaf.version> <darklaf.version>2.7.3</darklaf.version>
<darklaf-extensions-rsta.version>0.3.4</darklaf-extensions-rsta.version> <darklaf-extensions-rsta.version>0.3.4</darklaf-extensions-rsta.version>
<decompiler-fernflower.version>5.2.1.Final</decompiler-fernflower.version> <decompiler-fernflower.version>5.2.1.Final</decompiler-fernflower.version>
<dex2jar.version>v41</dex2jar.version> <dex2jar.version>v42</dex2jar.version>
<fernflower.version>eda981d</fernflower.version> <fernflower.version>eda981d</fernflower.version>
<gson.version>2.8.9</gson.version> <gson.version>2.8.9</gson.version>
<guava.version>31.0.1-jre</guava.version> <guava.version>31.0.1-jre</guava.version>
@ -44,7 +44,9 @@
<objenesis.version>3.2</objenesis.version> <objenesis.version>3.2</objenesis.version>
<paged-data.version>0.2.0</paged-data.version> <paged-data.version>0.2.0</paged-data.version>
<procyon.version>0.5.36</procyon.version> <procyon.version>0.5.36</procyon.version>
<rsyntaxtextarea.version>3.1.5</rsyntaxtextarea.version> <!-- TODO: Remove snapshot version when 0.6 stable is released -->
<procyon-snapshot.version>10b32a4</procyon-snapshot.version>
<rsyntaxtextarea.version>3.1.6</rsyntaxtextarea.version>
<semantic-version.version>2.1.1</semantic-version.version> <semantic-version.version>2.1.1</semantic-version.version>
<slf4j.version>1.7.32</slf4j.version> <slf4j.version>1.7.32</slf4j.version>
<smali.version>2.5.2</smali.version> <smali.version>2.5.2</smali.version>
@ -237,6 +239,7 @@
<artifactId>paged_data</artifactId> <artifactId>paged_data</artifactId>
<version>${paged-data.version}</version> <version>${paged-data.version}</version>
</dependency> </dependency>
<!-- TODO: Add back when 0.6 stable is released
<dependency> <dependency>
<groupId>org.bitbucket.mstrobel</groupId> <groupId>org.bitbucket.mstrobel</groupId>
<artifactId>procyon-core</artifactId> <artifactId>procyon-core</artifactId>
@ -257,6 +260,27 @@
<artifactId>procyon-compilertools</artifactId> <artifactId>procyon-compilertools</artifactId>
<version>${procyon.version}</version> <version>${procyon.version}</version>
</dependency> </dependency>
-->
<dependency>
<groupId>com.github.mstrobel.procyon</groupId>
<artifactId>procyon-compilertools</artifactId>
<version>${procyon-snapshot.version}</version>
</dependency>
<dependency>
<groupId>com.github.mstrobel.procyon</groupId>
<artifactId>procyon-core</artifactId>
<version>${procyon-snapshot.version}</version>
</dependency>
<dependency>
<groupId>com.github.mstrobel.procyon</groupId>
<artifactId>procyon-expressions</artifactId>
<version>${procyon-snapshot.version}</version>
</dependency>
<dependency>
<groupId>com.github.mstrobel.procyon</groupId>
<artifactId>procyon-reflection</artifactId>
<version>${procyon-snapshot.version}</version>
</dependency>
<dependency> <dependency>
<groupId>com.fifesoft</groupId> <groupId>com.fifesoft</groupId>
<artifactId>rsyntaxtextarea</artifactId> <artifactId>rsyntaxtextarea</artifactId>
@ -379,8 +403,8 @@
<artifactId>maven-compiler-plugin</artifactId> <artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version> <version>3.8.1</version>
<configuration> <configuration>
<source>${java.version}</source> <source>${maven.compiler.source}</source>
<target>${java.version}</target> <target>${maven.compiler.target}</target>
<showDeprecation>true</showDeprecation> <showDeprecation>true</showDeprecation>
</configuration> </configuration>
</plugin> </plugin>
@ -389,7 +413,7 @@
<artifactId>maven-javadoc-plugin</artifactId> <artifactId>maven-javadoc-plugin</artifactId>
<version>3.3.1</version> <version>3.3.1</version>
<configuration> <configuration>
<source>${java.version}</source> <source>${maven.compiler.source}</source>
</configuration> </configuration>
</plugin> </plugin>
<plugin> <plugin>

View file

@ -93,7 +93,7 @@ public abstract class Plugin extends Thread
* On plugin start each resource container is iterated through, * On plugin start each resource container is iterated through,
* then this is called with the resource container classes * then this is called with the resource container classes
* *
* @param classNodeList all of the loaded classes for easy access. * @param classNodeList all the loaded classes for easy access.
*/ */
public abstract void execute(List<ClassNode> classNodeList); public abstract void execute(List<ClassNode> classNodeList);
} }

View file

@ -83,7 +83,7 @@ public class HTMLPane extends JEditorPane
if (is == null) if (is == null)
return null; return null;
try (InputStream stream = is; try (InputStream stream = is;
Scanner s = new Scanner(stream).useDelimiter("\\A")) { Scanner s = new Scanner(stream, "UTF-8").useDelimiter("\\A")) {
return s.hasNext() ? s.next() : ""; return s.hasNext() ? s.next() : "";
} }
} }

View file

@ -35,6 +35,7 @@ import java.util.zip.ZipOutputStream;
*/ */
public final class ZipUtils { public final class ZipUtils {
// TODO: Maybe migrate to org.apache.commons.compress.archivers.examples.Expander?
/** /**
* Unzip files to path. * Unzip files to path.
* *
@ -43,6 +44,11 @@ public final class ZipUtils {
* @throws IOException Signals that an I/O exception has occurred. * @throws IOException Signals that an I/O exception has occurred.
*/ */
public static void unzipFilesToPath(String jarPath, String destinationDir) throws IOException { public static void unzipFilesToPath(String jarPath, String destinationDir) throws IOException {
String canonicalDestDir = new File(destinationDir).getCanonicalPath();
if (!canonicalDestDir.endsWith(File.separator)) {
canonicalDestDir += File.separator;
}
File file = new File(jarPath); File file = new File(jarPath);
try (JarFile jar = new JarFile(file)) { try (JarFile jar = new JarFile(file)) {
@ -67,6 +73,11 @@ 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);
if (!f.getCanonicalPath().startsWith(canonicalDestDir)) {
System.out.println("Zip Slip exploit detected. Skipping entry " + entry.getName());
continue;
}
File parent = f.getParentFile(); File parent = f.getParentFile();
if (!parent.exists()) { if (!parent.exists()) {
parent.mkdirs(); parent.mkdirs();
@ -106,7 +117,7 @@ public final class ZipUtils {
public static void zipFolder(String srcFolder, String destZipFile, String ignore) throws Exception { public static void zipFolder(String srcFolder, String destZipFile, String ignore) throws Exception {
try (FileOutputStream fileWriter = new FileOutputStream(destZipFile); try (FileOutputStream fileWriter = new FileOutputStream(destZipFile);
ZipOutputStream zip = new ZipOutputStream(fileWriter)){ ZipOutputStream zip = new ZipOutputStream(fileWriter)) {
addFolderToZip("", srcFolder, zip, ignore); addFolderToZip("", srcFolder, zip, ignore);
zip.flush(); zip.flush();
} }
@ -114,7 +125,7 @@ public final class ZipUtils {
public static void zipFolderAPKTool(String srcFolder, String destZipFile) throws Exception { public static void zipFolderAPKTool(String srcFolder, String destZipFile) throws Exception {
try (FileOutputStream fileWriter = new FileOutputStream(destZipFile); try (FileOutputStream fileWriter = new FileOutputStream(destZipFile);
ZipOutputStream zip = new ZipOutputStream(fileWriter)){ ZipOutputStream zip = new ZipOutputStream(fileWriter)) {
addFolderToZipAPKTool("", srcFolder, zip); addFolderToZipAPKTool("", srcFolder, zip);
zip.flush(); zip.flush();
} }

View file

@ -1,45 +1,43 @@
import the.bytecode.club.bytecodeviewer.api.*; import java.util.List;
import java.util.ArrayList;
import org.objectweb.asm.tree.ClassNode; import org.objectweb.asm.tree.ClassNode;
import the.bytecode.club.bytecodeviewer.api.*;
public class Template extends Plugin {
public class Template extends Plugin
{
PluginConsole gui; PluginConsole gui;
/** /**
* Main function * Main function
*/ */
@Override @Override
public void execute(ArrayList<ClassNode> classNodeList) public void execute(List<ClassNode> classNodeList) {
{ // Create console
//create console
gui = new PluginConsole("Java Template"); gui = new PluginConsole("Java Template");
gui.setVisible(true); //show the console gui.setVisible(true); // Show the console
//debug text // Debug text
out("Class Nodes: " + classNodeList.size()); out("Class Nodes: " + classNodeList.size());
//iterate through each class node // Iterate through each class node
for(ClassNode cn : classNodeList) for (ClassNode cn : classNodeList)
process(cn); process(cn);
BCV.hideFrame(gui, 10000); //hides the console after 10 seconds BCV.hideFrame(gui, 10000); // Hides the console after 10 seconds
} }
/** /**
* Process each class node * Process each class node
*/ */
public void process(ClassNode cn) public void process(ClassNode cn) {
{
out("Node: " + cn.name + ".class"); out("Node: " + cn.name + ".class");
//TODO developer plugin code goes here // TODO developer plugin code goes here
} }
/** /**
* Print to console * Print to console
*/ */
public void out(String text) public void out(String text) {
{
gui.appendText(text); gui.appendText(text);
} }
} }