bcv-vf/plugins/java/XposedGenerator.java

292 lines
12 KiB
Java
Raw Normal View History

2021-07-01 15:14:22 +00:00
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.swing.Box;
import javax.swing.JComboBox;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import org.objectweb.asm.tree.ClassNode;
import the.bytecode.club.bytecodeviewer.*;
import the.bytecode.club.bytecodeviewer.api.*;
import the.bytecode.club.bytecodeviewer.decompilers.impl.FernFlowerDecompiler;
import the.bytecode.club.bytecodeviewer.gui.resourceviewer.viewer.ResourceViewer;
2021-07-01 15:14:22 +00:00
/**
* @author jowasp
*/
2022-01-08 10:48:25 +00:00
public class XposedGenerator extends Plugin {
2022-01-17 23:11:43 +00:00
2022-01-08 10:48:25 +00:00
private static final List<String> methodsNames = new ArrayList<>();
private static final List<String> cleanMethodsNames = new ArrayList<>();
private static String foundPckg;
public XposedGenerator() {
}
2021-07-01 15:14:22 +00:00
@Override
2022-01-08 10:48:25 +00:00
public void execute(List<ClassNode> classNodeList) {
2021-07-01 15:14:22 +00:00
//Get actual file class content
ResourceViewer viewer = BytecodeViewer.getActiveResource();
2022-01-08 10:48:25 +00:00
if (viewer == null) {
BytecodeViewer.showMessage("Open A Class First");
return;
}
String className = viewer.getName();
2021-07-01 15:14:22 +00:00
ClassNode classnode = BytecodeViewer.getCurrentlyOpenedClassNode();
2022-01-08 10:48:25 +00:00
2021-07-01 15:14:22 +00:00
//Call XposedGenerator class
2022-01-08 10:48:25 +00:00
ParseChosenFileContent(className, classnode);
2021-07-01 15:14:22 +00:00
}
2022-01-08 10:48:25 +00:00
public static void ParseChosenFileContent(String classname, ClassNode classNode) {
try {
2021-07-01 15:14:22 +00:00
//Parse content - Extract methods after APK /JAR has been extracted
byte[] cont = ASMUtil.nodeToBytes(classNode);
2022-01-08 10:48:25 +00:00
2021-07-01 15:14:22 +00:00
//Use one of the decompilers
//TODO:Allow users to select other decompilers?
FernFlowerDecompiler decompilefern = new FernFlowerDecompiler();
//Decompile using Fern
2022-01-08 10:48:25 +00:00
String decomp = decompilefern.decompileClassNode(classNode, cont);
String[] xposedTemplateTypes = {"Empty", "Parameters", "Helper"};
@SuppressWarnings({"unchecked", "rawtypes"})
2021-07-01 15:14:22 +00:00
JComboBox xposedTemplateList = new JComboBox(xposedTemplateTypes);
2022-01-08 10:48:25 +00:00
//Set results of parsed methods into a list
2021-07-01 15:14:22 +00:00
List<String> methodsExtracted = ProcessContentExtractedClass(decomp);
String packgExtracted = ProcessContentExtractedPackage(decomp);
//Get a clean list
2022-01-08 10:48:25 +00:00
List<String> cleanMethods;
2021-07-01 15:14:22 +00:00
//clear list
cleanMethods = ProcessCleanMethodsAll(methodsExtracted);
2022-01-08 10:48:25 +00:00
if (!cleanMethods.isEmpty()) {
JComboBox<String> cb = new JComboBox<>(cleanMethods.toArray(new String[0]));
2021-07-01 15:14:22 +00:00
//Add Panel elements
//Start Panel
JPanel myPanel = new JPanel();
myPanel.add(Box.createHorizontalStrut(15));
myPanel.add(xposedTemplateList);
myPanel.add(cb);
//output methods to pane box
int result = JOptionPane.showConfirmDialog(null, myPanel,
"Choose Template and Method for Xposed Module", JOptionPane.OK_CANCEL_OPTION);
if (result == JOptionPane.OK_OPTION) {
//Read Chosen Class
2022-01-08 10:48:25 +00:00
Object cbItem = cb.getSelectedItem();
Object xPosedItem = xposedTemplateList.getSelectedItem();
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
try {
WriteXposedModule(selectedClass, packgExtracted, classname, selectedXposedTemplate);
} catch (IllegalArgumentException e) {
e.printStackTrace();
JOptionPane.showMessageDialog(null, "Error" + e);
}
2021-07-01 15:14:22 +00:00
}
}
2022-01-08 10:48:25 +00:00
} else {
JOptionPane.showMessageDialog(null, "Class Not Suitable");
2021-07-01 15:14:22 +00:00
}
2022-01-08 10:48:25 +00:00
} catch (IllegalArgumentException e) {
2021-07-01 15:14:22 +00:00
e.printStackTrace();
2022-01-08 10:48:25 +00:00
JOptionPane.showMessageDialog(null, "Error" + e);
2021-07-01 15:14:22 +00:00
}
}
2022-01-08 10:48:25 +00:00
public static void WriteXposedModule(String functionToHook, String packageName, String classToHook,
String template) {
if (template != null && !template.equals("Empty")) {
2021-07-01 15:14:22 +00:00
try {
2022-01-17 23:11:43 +00:00
//TODO: Prompt save dialog
2021-07-01 15:14:22 +00:00
File file = new File("./XposedClassTest.java");
2022-01-08 10:48:25 +00:00
// if file doesn't exist, then create it
2022-01-17 23:11:43 +00:00
if (!file.exists())
2021-07-01 15:14:22 +00:00
file.createNewFile();
2022-01-17 23:11:43 +00:00
2021-07-01 15:14:22 +00:00
//Extract the package name only
2022-01-08 10:48:25 +00:00
String packageNameOnly = packageName.substring(8, packageName.length() - 2).trim();
String classToHookNameOnly = classToHook;
2022-01-08 10:48:25 +00:00
if (classToHookNameOnly.endsWith(".class"))
classToHookNameOnly = classToHook.substring(0, classToHookNameOnly.length() - 6);
2022-01-08 10:48:25 +00:00
String[] classClean = classToHookNameOnly.split("/");
2021-07-01 15:14:22 +00:00
String[] functionSplitValues = functionToHook.split("\\s+");
2022-01-17 23:11:43 +00:00
2021-07-01 15:14:22 +00:00
//select
2022-01-08 10:48:25 +00:00
String onlyClass = classClean[classClean.length - 1];
2021-07-01 15:14:22 +00:00
String onlyFunction = CleanUpFunction(functionSplitValues);
2021-07-01 15:14:22 +00:00
//Write Xposed Class
2022-01-17 23:11:43 +00:00
String XposedClassText = "package androidpentesting.com.xposedmodule;" + "\r\n" +
2021-07-01 15:14:22 +00:00
"import de.robv.android.xposed.IXposedHookLoadPackage;" + "\r\n" +
"\r\n" +
2022-01-08 10:48:25 +00:00
"import de.robv.android.xposed.XC_MethodHook;" + "\r\n" +
"import de.robv.android.xposed.XposedBridge;" + "\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" +
"public class XposedClassTest implements IXposedHookLoadPackage {" + "\r\n" + "\r\n" +
" public void handleLoadPackage(final LoadPackageParam lpparam) throws Throwable {" + "\r\n" + "\r\n" +
" String classToHook = " + "\"" + packageNameOnly + "." + onlyClass + "\";" +
"\r\n" +
" String functionToHook = " + "\"" + onlyFunction + "\";" + "\r\n" +
" if (lpparam.packageName.equals(" + "\"" + packageNameOnly + "\"" + ")){" + "\r"
+ "\n" +
" XposedBridge.log(" + "\" Loaded app: \" " + " + lpparam.packageName);" +
"\r\n" + "\r\n" +
" findAndHookMethod(" + "\"" + onlyClass + "\"" + ", lpparam.classLoader, " + " \"" + onlyFunction + "\"" + ", int.class," + "\r\n" +
" new XC_MethodHook() {" + "\r\n" +
" @Override" + "\r\n" +
" protected void beforeHookedMethod(MethodHookParam param) throws "
+ "Throwable {" + "\r\n" +
" //TO BE FILLED BY ANALYST" + "\r\n" +
" }" + "\r\n" +
" });" + "\r\n" +
" }" + "\r\n" +
" }" + "\r\n" +
"}" + "\r\n";
2021-07-01 15:14:22 +00:00
FileWriter fw = new FileWriter(file.getAbsoluteFile());
BufferedWriter bw = new BufferedWriter(fw);
bw.write(XposedClassText);
bw.write("\r\n");
bw.close();
2022-01-08 10:48:25 +00:00
JOptionPane.showMessageDialog(null, "Xposed Module Generated");
2021-07-01 15:14:22 +00:00
} catch (IOException e) {
2022-01-08 10:48:25 +00:00
JOptionPane.showMessageDialog(null, "Error" + e);
2021-07-01 15:14:22 +00:00
e.printStackTrace();
}
2022-01-08 10:48:25 +00:00
} else {
JOptionPane.showMessageDialog(null, "Empty Template Chosen, Did Not Generate");
2021-07-01 15:14:22 +00:00
}
}
2022-01-08 10:48:25 +00:00
private static List<String> ProcessContentExtractedClass(String contentFile) {
2021-07-01 15:14:22 +00:00
Scanner scanner = null;
2022-01-08 10:48:25 +00:00
try {
2021-07-01 15:14:22 +00:00
scanner = new Scanner(contentFile);
//@TODO : Improve patterns to match other excepts 'public'
2022-01-17 23:11:43 +00:00
2021-07-01 15:14:22 +00:00
String regexclass = "public";
Pattern pattern = Pattern.compile(regexclass, Pattern.CASE_INSENSITIVE);
2022-01-17 23:11:43 +00:00
2021-07-01 15:14:22 +00:00
while (scanner.hasNextLine()) {
String line = scanner.nextLine();
2022-01-17 23:11:43 +00:00
2021-07-01 15:14:22 +00:00
// process the line
Matcher matcher = pattern.matcher(line);
2022-01-08 10:48:25 +00:00
while (matcher.find()) {
if (matcher.group() != null) {
System.out.println("find() found the pattern \"" + quote(line.trim()));
System.out.println("Function: " + CleanUpFunction(line.trim().split("\\s+")));
2021-07-01 15:14:22 +00:00
methodsNames.add(quote(line.trim()));
2022-01-08 10:48:25 +00:00
} else {
2021-07-01 15:14:22 +00:00
methodsNames.add("No methods found");
}
}
}
2022-01-08 10:48:25 +00:00
if (methodsNames.isEmpty()) {
2021-07-01 15:14:22 +00:00
methodsNames.add("No methods found");
2022-01-08 10:48:25 +00:00
} else {
2021-07-01 15:14:22 +00:00
return methodsNames;
}
return methodsNames;
2022-01-08 10:48:25 +00:00
} finally {
if (scanner != null)
2021-07-01 15:14:22 +00:00
scanner.close();
}
}
2022-01-08 10:48:25 +00:00
private static List<String> ProcessCleanMethodsAll(List<String> rawMethods) {
for (String m : rawMethods) {
2021-07-01 15:14:22 +00:00
//Exclude class declaration
//TODO:add a list containing all possible types
2022-01-08 10:48:25 +00:00
if (!m.contains("extends") && (!m.contains("implements") && (m.contains("(")))) {
2021-07-01 15:14:22 +00:00
cleanMethodsNames.add(m);
}
}
2022-01-17 23:11:43 +00:00
2021-07-01 15:14:22 +00:00
return cleanMethodsNames;
}
2022-01-08 10:48:25 +00:00
private static String CleanUpFunction(String[] rawFunction) {
2021-07-01 15:14:22 +00:00
String onlyFunc = "functiondummy";
2022-01-08 10:48:25 +00:00
for (String m : rawFunction) {
if (m.contains("(")) {
String[] split = m.split("\\(")[0].split(" ");
2022-01-08 10:48:25 +00:00
return split[split.length - 1];
2021-07-01 15:14:22 +00:00
}
}
return onlyFunc;
}
2022-01-08 10:48:25 +00:00
private static String ProcessContentExtractedPackage(String contentFile) {
2021-07-01 15:14:22 +00:00
Scanner scanner = null;
try {
scanner = new Scanner(contentFile);
String regexPkg = "package";
2022-01-08 10:48:25 +00:00
Pattern patternPkg = Pattern.compile(regexPkg, Pattern.CASE_INSENSITIVE);
2021-07-01 15:14:22 +00:00
String line = scanner.nextLine();
2022-01-17 23:11:43 +00:00
2021-07-01 15:14:22 +00:00
// process the line
Matcher matcher = patternPkg.matcher(line);
2022-01-08 10:48:25 +00:00
while (matcher.find()) {
if (matcher.group() != null) {
System.out.println("find() found the pattern \"" + quote(line.trim()));
foundPckg = quote(line.trim());
} else {
foundPckg = "";
2021-07-01 15:14:22 +00:00
}
}
2022-01-17 23:11:43 +00:00
2021-07-01 15:14:22 +00:00
try
{
2022-01-08 10:48:25 +00:00
if (foundPckg == null || foundPckg.isEmpty())
foundPckg = "No Package Found";
2021-07-01 15:14:22 +00:00
2022-01-08 10:48:25 +00:00
} catch (NullPointerException e) {
JOptionPane.showMessageDialog(null,
"Error - no package was found in the selected class: " + e);
} finally {
scanner.close();
2021-07-01 15:14:22 +00:00
}
2022-01-08 10:48:25 +00:00
} catch (IllegalArgumentException e) {
JOptionPane.showMessageDialog(null, "Error" + e);
if (scanner != null)
2021-07-01 15:14:22 +00:00
scanner.close();
2022-01-08 10:48:25 +00:00
} finally {
if (scanner != null)
2021-07-01 15:14:22 +00:00
scanner.close();
}
2022-01-17 23:11:43 +00:00
2022-01-08 10:48:25 +00:00
return foundPckg;
2021-07-01 15:14:22 +00:00
}
2022-01-08 10:48:25 +00:00
private static String quote(String aText) {
2021-07-01 15:14:22 +00:00
String QUOTE = "'";
return QUOTE + aText + QUOTE;
}
}