Skip to content

Commit d052d0e

Browse files
committed
@jowasp Xposed Generator As Plugin
1 parent c209db4 commit d052d0e

1 file changed

Lines changed: 341 additions & 0 deletions

File tree

plugins/XposedGenerator.java

Lines changed: 341 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,341 @@
1+
import java.awt.*;
2+
import java.io.BufferedWriter;
3+
import java.io.File;
4+
import java.io.FileWriter;
5+
import java.io.IOException;
6+
import java.util.ArrayList;
7+
import java.util.List;
8+
import java.util.Scanner;
9+
import java.util.regex.Matcher;
10+
import java.util.regex.Pattern;
11+
import javax.swing.Box;
12+
import javax.swing.JComboBox;
13+
import javax.swing.JOptionPane;
14+
import javax.swing.JPanel;
15+
16+
import org.objectweb.asm.tree.ClassNode;
17+
import the.bytecode.club.bytecodeviewer.*;
18+
import the.bytecode.club.bytecodeviewer.util.*;
19+
import the.bytecode.club.bytecodeviewer.api.Plugin;
20+
import the.bytecode.club.bytecodeviewer.decompilers.FernFlowerDecompiler;
21+
22+
/**
23+
* @author jowasp
24+
*/
25+
public class XposedGenerator extends Plugin
26+
{
27+
//PRIVATE
28+
private static List<String> methodsNames = new ArrayList<String>();
29+
private static List<String> cleanMethodsNames = new ArrayList<String>();
30+
private static String foundpckg;
31+
32+
public XposedGenerator() {}
33+
34+
@Override
35+
public void execute(ArrayList<ClassNode> classNodeList)
36+
{
37+
//Get actual file class content
38+
final Component tabComp = BytecodeViewer.viewer.workPane.tabs.getSelectedComponent();
39+
40+
if(tabComp == null)
41+
{
42+
JOptionPane.showMessageDialog(null, "Open A Class First");
43+
return;
44+
}
45+
46+
String className = tabComp.getName();
47+
String containerName = ((FileContainer)BytecodeViewer.files.get(0)).name;
48+
ClassNode classnode = BytecodeViewer.getCurrentlyOpenedClassNode();
49+
50+
//Call XposedGenerator class
51+
ParseChosenFileContent(className,containerName,classnode);
52+
}
53+
54+
public static void ParseChosenFileContent(String classname, String containerName, ClassNode classNode){
55+
56+
try{
57+
//Parse content - Extract methods after APK /JAR has been extracted
58+
byte[] cont = BytecodeViewer.getFileContents(classname.toString());
59+
//Use one of the decompilers
60+
//TODO:Allow users to select other decompilers?
61+
FernFlowerDecompiler decompilefern = new FernFlowerDecompiler();
62+
63+
//Decompile using Fern
64+
String decomp = decompilefern.decompileClassNode(classNode, cont);
65+
String[] xposedTemplateTypes = {"Empty","Parameters","Helper"};
66+
@SuppressWarnings({ "unchecked", "rawtypes" })
67+
JComboBox xposedTemplateList = new JComboBox(xposedTemplateTypes);
68+
//Set results of parsed methods into an a list
69+
List<String> methodsExtracted = ProcessContentExtractedClass(decomp);
70+
String packgExtracted = ProcessContentExtractedPackage(decomp);
71+
System.out.println("PACKAGE NAME: " +packgExtracted);
72+
73+
//Get a clean list
74+
List<String> cleanMethods = null;
75+
//clear list
76+
cleanMethods = ProcessCleanMethodsAll(methodsExtracted);
77+
if (!cleanMethods.isEmpty())
78+
{
79+
JComboBox<String> cb = new JComboBox<>(cleanMethods.toArray(new String[cleanMethods.size()]));
80+
81+
//Add Panel elements
82+
//Start Panel
83+
JPanel myPanel = new JPanel();
84+
myPanel.add(Box.createHorizontalStrut(15));
85+
myPanel.add(xposedTemplateList);
86+
myPanel.add(cb);
87+
88+
//output methods to pane box
89+
int result = JOptionPane.showConfirmDialog(null, myPanel,
90+
"Choose Template and Method for Xposed Module", JOptionPane.OK_CANCEL_OPTION);
91+
92+
if (result == JOptionPane.OK_OPTION) {
93+
//Read Chosen Class
94+
System.out.println("SELECTED CLASS is" + cb.getSelectedItem());
95+
String selectedClass = cb.getSelectedItem().toString();
96+
String selectedXposedTemplate = xposedTemplateList.getSelectedItem().toString();
97+
98+
//WriteXposed Class with extracted data
99+
try{
100+
WriteXposedModule(selectedClass, packgExtracted, classname, selectedXposedTemplate);
101+
}
102+
catch(IllegalArgumentException e)
103+
{
104+
e.printStackTrace();
105+
JOptionPane.showMessageDialog(null,"Error" + e.toString());
106+
}
107+
}
108+
}
109+
else
110+
{
111+
JOptionPane.showMessageDialog(null,"Class Not Suitable");
112+
}
113+
}
114+
catch (IllegalArgumentException e)
115+
{
116+
e.printStackTrace();
117+
JOptionPane.showMessageDialog(null,"Error" + e.toString());
118+
}
119+
120+
}
121+
122+
public static void WriteXposedModule(String functionToHook, String packageName, String classToHook, String template) {
123+
System.out.println("TEMPLATE: " + template);
124+
if (template != null && !template.equals("Empty"))
125+
{
126+
try {
127+
//TODO: Prompt save dialogue
128+
File file = new File("./XposedClassTest.java");
129+
130+
// if file doesn't exists, then create it
131+
if (!file.exists()) {
132+
file.createNewFile();
133+
}
134+
//Extract the package name only
135+
String packageNameOnly = packageName.substring(8,packageName.length() - 2 );
136+
String classToHookNameOnly = classToHook.substring(0, packageName.length() - 9);
137+
String[] classClean = classToHookNameOnly.split("\\/");
138+
String[] functionSplitValues = functionToHook.split("\\s+");
139+
//select
140+
String onlyClass = classClean[classClean.length-1];
141+
//String onlyFunctionParateses = functionSplitValues[functionSplitValues.length-2];
142+
143+
String onlyFunction = CleanUpFuunction(functionSplitValues);
144+
//String functionToHookOnly = "dummy function";
145+
System.out.println(onlyClass);
146+
System.out.println(packageNameOnly);
147+
148+
//Write Xposed Class
149+
String XposedClassText =
150+
"package androidpentesting.com.xposedmodule;"+ "\r\n" +
151+
"import de.robv.android.xposed.IXposedHookLoadPackage;" + "\r\n" +
152+
"\r\n" +
153+
"import de.robv.android.xposed.XC_MethodHook;" +"\r\n" +
154+
"import de.robv.android.xposed.XposedBridge;" +"\r\n" +
155+
"import de.robv.android.xposed.callbacks.XC_LoadPackage.LoadPackageParam;"+"\r\n" +
156+
"import static de.robv.android.xposed.XposedHelpers.findAndHookMethod;"+"\r\n" +"\r\n" +
157+
"public class XposedClassTest implements IXposedHookLoadPackage {"+"\r\n" +"\r\n" +
158+
" public void handleLoadPackage(final LoadPackageParam lpparam) throws Throwable {" + "\r\n" +"\r\n" +
159+
" String classToHook = " + "\"" + packageNameOnly + "." + onlyClass + "\" ;" + "\r\n" +
160+
" String functionToHook = "+"\""+ onlyFunction+"\";"+"\r\n" +
161+
" if (lpparam.packageName.equals("+"\""+packageNameOnly+ "\""+")){"+ "\r\n" +
162+
" XposedBridge.log(" + "\" Loaded app: \" " + " + lpparam.packageName);"+ "\r\n" +"\r\n" +
163+
" findAndHookMethod("+"\""+onlyClass+"\"" + ", lpparam.classLoader, "+" \"" +onlyFunction + "\""+", int.class,"+ "\r\n" +
164+
" new XC_MethodHook() {"+ "\r\n" +
165+
" @Override"+ "\r\n" +
166+
" protected void beforeHookedMethod(MethodHookParam param) throws Throwable {"+ "\r\n" +
167+
" //TO BE FILLED BY ANALYST {"+ "\r\n" +
168+
" }"+ "\r\n" +
169+
" });"+"\r\n" +
170+
" }"+ "\r\n" +
171+
"}"+ "\r\n" +
172+
"}"+ "\r\n"
173+
;
174+
FileWriter fw = new FileWriter(file.getAbsoluteFile());
175+
BufferedWriter bw = new BufferedWriter(fw);
176+
bw.write(XposedClassText);
177+
bw.write("\r\n");
178+
bw.close();
179+
180+
System.out.println("Done");
181+
JOptionPane.showMessageDialog(null,"Xposed Module Generated");
182+
} catch (IOException e) {
183+
JOptionPane.showMessageDialog(null,"Error" + e.toString());
184+
e.printStackTrace();
185+
}
186+
}
187+
else
188+
{
189+
JOptionPane.showMessageDialog(null,"Empty Template Chosen, Did Not Generate");
190+
}
191+
}
192+
193+
private static List <String> ProcessContentExtractedClass(String contentFile){
194+
Scanner scanner = null;
195+
try{
196+
scanner = new Scanner(contentFile);
197+
//@TODO : Improve patterns to match other excepts 'public'
198+
String regexclass = "public";
199+
//String regexPkg = "package";
200+
Pattern pattern = Pattern.compile(regexclass, Pattern.CASE_INSENSITIVE);
201+
//Pattern patternVoid = Pattern.compile(regexVoid , Pattern.CASE_INSENSITIVE);
202+
// Pattern patternPkg = Pattern.compile(regexPkg , Pattern.CASE_INSENSITIVE);
203+
//scanner.useDelimiter(";");
204+
while (scanner.hasNextLine()) {
205+
206+
String line = scanner.nextLine();
207+
// process the line
208+
Matcher matcher = pattern.matcher(line);
209+
while (matcher.find()){
210+
211+
if (matcher.group() != null)
212+
{
213+
System.out.println("find() found the pattern \"" + quote(line.trim())) ;
214+
methodsNames.add(quote(line.trim()));
215+
}
216+
else
217+
{
218+
methodsNames.add("No methods found");
219+
}
220+
221+
}
222+
223+
}
224+
225+
if (methodsNames.isEmpty())
226+
{
227+
methodsNames.add("No methods found");
228+
}
229+
else
230+
{
231+
return methodsNames;
232+
}
233+
return methodsNames;
234+
}
235+
finally {
236+
if (scanner!=null)
237+
scanner.close();
238+
}
239+
}
240+
241+
private static List <String> ProcessCleanMethodsAll(List<String> rawMethods)
242+
{
243+
for (String m:rawMethods)
244+
{
245+
//Exclude class declaration
246+
//TODO:add a list containing all possible types
247+
if (m.contains("extends") || (m.contains("implements") || (!m.contains("("))))
248+
{
249+
continue;
250+
}
251+
else
252+
{
253+
cleanMethodsNames.add(m);
254+
}
255+
256+
}
257+
return cleanMethodsNames;
258+
259+
260+
}
261+
262+
private static String CleanUpFuunction(String[] rawFunction)
263+
{
264+
String onlyFunc = "functiondummy";
265+
for (String m:rawFunction)
266+
{
267+
if(m.contains("("))
268+
{
269+
String[] functions = m.split("[ ,()]+");
270+
onlyFunc = functions[functions.length -1];
271+
return onlyFunc;
272+
}
273+
else
274+
{
275+
continue;
276+
}
277+
}
278+
279+
return onlyFunc;
280+
281+
}
282+
283+
private static String ProcessContentExtractedPackage(String contentFile){
284+
Scanner scanner = null;
285+
try {
286+
scanner = new Scanner(contentFile);
287+
String regexPkg = "package";
288+
Pattern patternPkg = Pattern.compile(regexPkg , Pattern.CASE_INSENSITIVE);
289+
String line = scanner.nextLine();
290+
// process the line
291+
Matcher matcher = patternPkg.matcher(line);
292+
while (matcher.find()){
293+
294+
if (matcher.group() != null)
295+
{
296+
System.out.println("find() found the pattern \"" + quote(line.trim())) ;
297+
foundpckg = quote(line.trim());
298+
299+
}
300+
else
301+
{
302+
foundpckg = "";
303+
}
304+
}
305+
try
306+
//
307+
{
308+
if (foundpckg.isEmpty() || foundpckg == null)
309+
foundpckg = "No Package Found";
310+
311+
}
312+
catch(NullPointerException e)
313+
{
314+
JOptionPane.showMessageDialog(null,"Error - no package was found in the selected class: " + e.toString());
315+
}
316+
finally
317+
{
318+
if(scanner != null)
319+
scanner.close();
320+
}
321+
}
322+
catch(IllegalArgumentException e)
323+
{
324+
JOptionPane.showMessageDialog(null,"Error" + e.toString());
325+
if(scanner != null)
326+
scanner.close();
327+
}
328+
finally
329+
{
330+
if(scanner != null)
331+
scanner.close();
332+
}
333+
return foundpckg;
334+
335+
}
336+
337+
private static String quote(String aText){
338+
String QUOTE = "'";
339+
return QUOTE + aText + QUOTE;
340+
}
341+
}

0 commit comments

Comments
 (0)