Merge pull request #86 from Szperak/master
Added Allatori string deofuscator
This commit is contained in:
commit
dd7f8a1757
|
@ -63,6 +63,7 @@ public class JarUtils {
|
||||||
try {
|
try {
|
||||||
final String name = entry.getName();
|
final String name = entry.getName();
|
||||||
final byte[] bytes = getBytes(jis);
|
final byte[] bytes = getBytes(jis);
|
||||||
|
if(!files.containsKey(name)){
|
||||||
if (!name.endsWith(".class")) {
|
if (!name.endsWith(".class")) {
|
||||||
if(!entry.isDirectory())
|
if(!entry.isDirectory())
|
||||||
files.put(name, bytes);
|
files.put(name, bytes);
|
||||||
|
@ -81,8 +82,9 @@ public class JarUtils {
|
||||||
} else {
|
} else {
|
||||||
System.out.println(jarFile+">"+name+": Header does not start with CAFEBABE, ignoring.");
|
System.out.println(jarFile+">"+name+": Header does not start with CAFEBABE, ignoring.");
|
||||||
}
|
}
|
||||||
|
files.put(name, bytes);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} catch(Exception e) {
|
} catch(Exception e) {
|
||||||
new the.bytecode.club.bytecodeviewer.api.ExceptionUI(e);
|
new the.bytecode.club.bytecodeviewer.api.ExceptionUI(e);
|
||||||
} finally {
|
} finally {
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package the.bytecode.club.bytecodeviewer.api;
|
package the.bytecode.club.bytecodeviewer.api;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.net.URLClassLoader;
|
import java.net.URLClassLoader;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
@ -62,49 +63,59 @@ public class BytecodeViewer {
|
||||||
return cl;
|
return cl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Re-instances the URLClassLoader and loads a jar to it.
|
* Re-instances the URLClassLoader and loads a jar to it.
|
||||||
* @param path
|
*
|
||||||
|
* @param nodeList
|
||||||
|
* The list of ClassNodes to be loaded
|
||||||
* @return The loaded classes into the new URLClassLoader instance
|
* @return The loaded classes into the new URLClassLoader instance
|
||||||
* @author Cafebabe
|
* @author Cafebabe
|
||||||
|
* @throws IOException
|
||||||
|
* @throws ClassNotFoundException
|
||||||
*/
|
*/
|
||||||
public static List<Class<?>> loadClassesIntoClassLoader() {
|
@SuppressWarnings("deprecation")
|
||||||
try {
|
public static List<Class<?>> loadClassesIntoClassLoader(
|
||||||
|
ArrayList<ClassNode> nodeList) throws IOException,
|
||||||
|
ClassNotFoundException {
|
||||||
|
|
||||||
File f = new File(
|
File f = new File(
|
||||||
the.bytecode.club.bytecodeviewer.BytecodeViewer.tempDirectory +
|
the.bytecode.club.bytecodeviewer.BytecodeViewer.tempDirectory
|
||||||
the.bytecode.club.bytecodeviewer.BytecodeViewer.fs +
|
+ the.bytecode.club.bytecodeviewer.BytecodeViewer.fs
|
||||||
"loaded_temp.jar");
|
+ "loaded_temp.jar");
|
||||||
JarUtils.saveAsJar(BytecodeViewer.getLoadedClasses(), f.getAbsolutePath());
|
JarUtils.saveAsJarClassesOnly(nodeList, f.getAbsolutePath());
|
||||||
|
|
||||||
JarFile jarFile = new JarFile("" + f.getAbsolutePath());
|
JarFile jarFile = new JarFile("" + f.getAbsolutePath());
|
||||||
Enumeration<JarEntry> e = jarFile.entries();
|
Enumeration<JarEntry> e = jarFile.entries();
|
||||||
URL[] urls = { new URL("jar:file:" + ""+f.getAbsolutePath()+"!/") };
|
cl = URLClassLoader.newInstance(new URL[]{ f.toURL() });
|
||||||
cl = URLClassLoader.newInstance(urls);
|
|
||||||
List<Class<?>> ret = new ArrayList<Class<?>>();
|
List<Class<?>> ret = new ArrayList<Class<?>>();
|
||||||
|
|
||||||
while (e.hasMoreElements())
|
while (e.hasMoreElements()) {
|
||||||
{
|
|
||||||
JarEntry je = (JarEntry) e.nextElement();
|
JarEntry je = (JarEntry) e.nextElement();
|
||||||
if (je.isDirectory() || !je.getName().endsWith(".class"))
|
if (je.isDirectory() || !je.getName().endsWith(".class"))
|
||||||
continue;
|
continue;
|
||||||
String className = je.getName().replace("/", ".").replace(".class", "");
|
String className = je.getName().replace("/", ".").replace(".class", "");
|
||||||
className = className.replace('/', '.');
|
className = className.replace('/', '.');
|
||||||
try{
|
|
||||||
ret.add(cl.loadClass(className));
|
ret.add(cl.loadClass(className));
|
||||||
}
|
|
||||||
catch(Exception e2)
|
|
||||||
{
|
|
||||||
new the.bytecode.club.bytecodeviewer.api.ExceptionUI(e2);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
jarFile.close();
|
jarFile.close();
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
}
|
}
|
||||||
catch(Exception e)
|
|
||||||
{
|
|
||||||
new the.bytecode.club.bytecodeviewer.api.ExceptionUI(e);
|
/**
|
||||||
}
|
* Re-instances the URLClassLoader and loads a jar to it.
|
||||||
return null;
|
* @return The loaded classes into the new URLClassLoader instance
|
||||||
|
* @author Cafebabe
|
||||||
|
* @throws IOException
|
||||||
|
* @throws ClassNotFoundException
|
||||||
|
*/
|
||||||
|
public static List<Class<?>> loadAllClassesIntoClassLoader() throws ClassNotFoundException, IOException {
|
||||||
|
return loadClassesIntoClassLoader(getLoadedClasses());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -110,7 +110,7 @@ public final class ClassNodeLoader extends ClassLoader {
|
||||||
if (classes.containsKey(name)) {
|
if (classes.containsKey(name)) {
|
||||||
return nodeToClass(classes.get(name));
|
return nodeToClass(classes.get(name));
|
||||||
} else {
|
} else {
|
||||||
return super.loadClass(name);
|
return super.findClass(name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -304,7 +304,7 @@ public class InstructionPrinter {
|
||||||
|
|
||||||
protected String printInvokeDynamicInsNode(InvokeDynamicInsnNode idin) {
|
protected String printInvokeDynamicInsNode(InvokeDynamicInsnNode idin) {
|
||||||
StringBuilder sb = new StringBuilder();
|
StringBuilder sb = new StringBuilder();
|
||||||
sb.append(nameOpcode(idin.opcode()) + " " + idin.name + "(");
|
sb.append(nameOpcode(idin.opcode()) + " " + idin.bsm.getName() + "(");
|
||||||
|
|
||||||
String desc = idin.desc;
|
String desc = idin.desc;
|
||||||
String partedDesc = idin.desc.substring(2);
|
String partedDesc = idin.desc.substring(2);
|
||||||
|
|
|
@ -0,0 +1,77 @@
|
||||||
|
package the.bytecode.club.bytecodeviewer.gui;
|
||||||
|
|
||||||
|
import java.awt.Dimension;
|
||||||
|
import java.awt.event.ActionEvent;
|
||||||
|
import java.awt.event.ActionListener;
|
||||||
|
|
||||||
|
import javax.swing.JButton;
|
||||||
|
import javax.swing.JFrame;
|
||||||
|
import javax.swing.JLabel;
|
||||||
|
import javax.swing.JTextField;
|
||||||
|
|
||||||
|
import the.bytecode.club.bytecodeviewer.Resources;
|
||||||
|
import the.bytecode.club.bytecodeviewer.plugin.PluginManager;
|
||||||
|
import the.bytecode.club.bytecodeviewer.plugin.preinstalled.AllatoriStringDecrypter;
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
* Bytecode Viewer (BCV) - Java & Android Reverse Engineering Suite *
|
||||||
|
* Copyright (C) 2014 Kalen 'Konloch' Kinloch - http://bytecodeviewer.com *
|
||||||
|
* *
|
||||||
|
* This program is free software: you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the GNU General Public License as published by *
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or *
|
||||||
|
* (at your option) any later version. *
|
||||||
|
* *
|
||||||
|
* This program is distributed in the hope that it will be useful, *
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||||
|
* GNU General Public License for more details. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the GNU General Public License *
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The UI for replace strings plugin.
|
||||||
|
*
|
||||||
|
* @author Konloch
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
public class AllatoriStringDecrypterOptions extends JFrame {
|
||||||
|
public AllatoriStringDecrypterOptions() {
|
||||||
|
this.setIconImages(Resources.iconList);
|
||||||
|
setSize(new Dimension(250, 120));
|
||||||
|
setResizable(false);
|
||||||
|
setTitle("Allatori decrypter");
|
||||||
|
getContentPane().setLayout(null);
|
||||||
|
|
||||||
|
JButton btnNewButton = new JButton("Decrypt");
|
||||||
|
btnNewButton.setBounds(6, 56, 232, 23);
|
||||||
|
getContentPane().add(btnNewButton);
|
||||||
|
|
||||||
|
|
||||||
|
JLabel lblNewLabel = new JLabel("Class:");
|
||||||
|
lblNewLabel.setBounds(6, 20, 67, 14);
|
||||||
|
getContentPane().add(lblNewLabel);
|
||||||
|
|
||||||
|
textField = new JTextField();
|
||||||
|
textField.setToolTipText("* will search all classes");
|
||||||
|
textField.setText("*");
|
||||||
|
textField.setBounds(80, 17, 158, 20);
|
||||||
|
getContentPane().add(textField);
|
||||||
|
textField.setColumns(10);
|
||||||
|
|
||||||
|
|
||||||
|
btnNewButton.addActionListener(new ActionListener() {
|
||||||
|
public void actionPerformed(ActionEvent arg0) {
|
||||||
|
PluginManager.runPlugin(new AllatoriStringDecrypter(textField.getText()));
|
||||||
|
dispose();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
this.setLocationRelativeTo(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final long serialVersionUID = -2662514582647810868L;
|
||||||
|
private JTextField textField;
|
||||||
|
}
|
|
@ -311,36 +311,6 @@ public class FileNavigationPane extends VisibleComponent implements
|
||||||
ImageRenderer renderer = new ImageRenderer();
|
ImageRenderer renderer = new ImageRenderer();
|
||||||
tree.setCellRenderer(renderer);
|
tree.setCellRenderer(renderer);
|
||||||
|
|
||||||
if(!container.classes.isEmpty()) {
|
|
||||||
for(ClassNode c : container.classes) {
|
|
||||||
String name = c.name;
|
|
||||||
final String[] spl = name.split("/");
|
|
||||||
if (spl.length < 2) {
|
|
||||||
root.add(new MyTreeNode(name+".class"));
|
|
||||||
} else {
|
|
||||||
MyTreeNode parent = root;
|
|
||||||
for (int i1 = 0; i1 < spl.length; i1++) {
|
|
||||||
String s = spl[i1];
|
|
||||||
MyTreeNode child = null;
|
|
||||||
for (int i = 0; i < parent.getChildCount(); i++) {
|
|
||||||
if (((MyTreeNode) parent.getChildAt(i)).getUserObject()
|
|
||||||
.equals(s)) {
|
|
||||||
child = (MyTreeNode) parent.getChildAt(i);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (child == null) {
|
|
||||||
if(i1 == spl.length-1)
|
|
||||||
child = new MyTreeNode(s+".class");
|
|
||||||
else
|
|
||||||
child = new MyTreeNode(s);
|
|
||||||
parent.add(child);
|
|
||||||
}
|
|
||||||
parent = child;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!container.files.isEmpty()) {
|
if(!container.files.isEmpty()) {
|
||||||
for (final Entry<String, byte[]> entry : container.files.entrySet()) {
|
for (final Entry<String, byte[]> entry : container.files.entrySet()) {
|
||||||
|
|
|
@ -2029,8 +2029,12 @@ public class MainViewerGUI extends JFrame implements FileChangeNotifier {
|
||||||
});
|
});
|
||||||
mntmNewMenuItem_2.addActionListener(new ActionListener() {
|
mntmNewMenuItem_2.addActionListener(new ActionListener() {
|
||||||
@Override
|
@Override
|
||||||
public void actionPerformed(ActionEvent e) {
|
public void actionPerformed(ActionEvent arg0) {
|
||||||
PluginManager.runPlugin(new AllatoriStringDecrypter());
|
if(BytecodeViewer.getLoadedClasses().isEmpty()) {
|
||||||
|
BytecodeViewer.showMessage("First open a class, jar, zip, apk or dex file.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
new AllatoriStringDecrypterOptions().setVisible(true);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
mntmNewMenuItem_1.addActionListener(new ActionListener() {
|
mntmNewMenuItem_1.addActionListener(new ActionListener() {
|
||||||
|
|
|
@ -1,11 +1,27 @@
|
||||||
package the.bytecode.club.bytecodeviewer.plugin.preinstalled;
|
package the.bytecode.club.bytecodeviewer.plugin.preinstalled;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.lang.reflect.Method;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import javax.swing.JDialog;
|
||||||
|
import javax.swing.JOptionPane;
|
||||||
|
|
||||||
|
import org.objectweb.asm.tree.AbstractInsnNode;
|
||||||
import org.objectweb.asm.tree.ClassNode;
|
import org.objectweb.asm.tree.ClassNode;
|
||||||
|
import org.objectweb.asm.tree.InsnList;
|
||||||
|
import org.objectweb.asm.tree.InvokeDynamicInsnNode;
|
||||||
|
import org.objectweb.asm.tree.LdcInsnNode;
|
||||||
|
import org.objectweb.asm.tree.MethodInsnNode;
|
||||||
|
import org.objectweb.asm.tree.MethodNode;
|
||||||
|
|
||||||
import the.bytecode.club.bytecodeviewer.BytecodeViewer;
|
import the.bytecode.club.bytecodeviewer.BytecodeViewer;
|
||||||
|
import the.bytecode.club.bytecodeviewer.JarUtils;
|
||||||
|
import the.bytecode.club.bytecodeviewer.api.ExceptionUI;
|
||||||
import the.bytecode.club.bytecodeviewer.api.Plugin;
|
import the.bytecode.club.bytecodeviewer.api.Plugin;
|
||||||
|
import the.bytecode.club.bytecodeviewer.api.PluginConsole;
|
||||||
|
|
||||||
/***************************************************************************
|
/***************************************************************************
|
||||||
* Bytecode Viewer (BCV) - Java & Android Reverse Engineering Suite *
|
* Bytecode Viewer (BCV) - Java & Android Reverse Engineering Suite *
|
||||||
|
@ -29,14 +45,218 @@ import the.bytecode.club.bytecodeviewer.api.Plugin;
|
||||||
* Coming soon.
|
* Coming soon.
|
||||||
*
|
*
|
||||||
* @author Konloch
|
* @author Konloch
|
||||||
|
* @author Szperak
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public class AllatoriStringDecrypter extends Plugin {
|
public class AllatoriStringDecrypter extends Plugin {
|
||||||
|
|
||||||
|
PluginConsole frame = new PluginConsole("Allatori decrypter");
|
||||||
|
StringBuilder out = new StringBuilder();
|
||||||
|
|
||||||
|
private String className;
|
||||||
|
|
||||||
|
|
||||||
|
public AllatoriStringDecrypter(String className) {
|
||||||
|
this.className = className;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void execute(ArrayList<ClassNode> classNodeList) {
|
public void execute(ArrayList<ClassNode> classNodeList) {
|
||||||
BytecodeViewer.showMessage("This is a planned feature.");
|
JOptionPane pane = new JOptionPane(
|
||||||
|
"WARNING: This will load the classes into the JVM and execute allatori decrypter function"
|
||||||
|
+ BytecodeViewer.nl
|
||||||
|
+ "for each class. IF THE FILE YOU'RE LOADING IS MALICIOUS, DO NOT CONTINUE.");
|
||||||
|
Object[] options = new String[] { "Continue", "Cancel" };
|
||||||
|
pane.setOptions(options);
|
||||||
|
JDialog dialog = pane.createDialog(BytecodeViewer.viewer,
|
||||||
|
"Bytecode Viewer - WARNING");
|
||||||
|
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) {
|
||||||
|
try {
|
||||||
|
|
||||||
|
if (!className.equals("*")) {
|
||||||
|
for (ClassNode classNode : classNodeList) {
|
||||||
|
if (classNode.name.equals(className))
|
||||||
|
scanClassNode(classNode);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (ClassNode classNode : classNodeList) {
|
||||||
|
scanClassNode(classNode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}catch(Exception e){
|
||||||
|
new ExceptionUI(e, "github.com/Szperak");
|
||||||
|
} finally {
|
||||||
|
frame.appendText(out.toString());
|
||||||
|
frame.setVisible(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void log(String msg){
|
||||||
|
out.append(msg);
|
||||||
|
out.append(BytecodeViewer.nl);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void scanClassNode(ClassNode classNode) throws Exception {
|
||||||
|
for(MethodNode method : classNode.methods){
|
||||||
|
scanMethodNode(classNode, method);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public int readUnsignedShort(byte[] b, final int index) {
|
||||||
|
return ((b[index] & 0xFF) << 8) | (b[index + 1] & 0xFF);
|
||||||
|
}
|
||||||
|
private int getConstantPoolSize(String className){
|
||||||
|
byte[] fileContents = BytecodeViewer.getFileContents(className+".class");
|
||||||
|
return readUnsignedShort(fileContents, 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void scanMethodNode(ClassNode classNode, MethodNode methodNode) throws Exception {
|
||||||
|
InsnList iList = methodNode.instructions;
|
||||||
|
|
||||||
|
log("Scanning method " + methodNode.name+" of " + classNode.name);
|
||||||
|
|
||||||
|
LdcInsnNode laststringldconstack = null;
|
||||||
|
for (AbstractInsnNode i : iList.toArray()) {
|
||||||
|
if(i instanceof LdcInsnNode) {
|
||||||
|
LdcInsnNode ldci = (LdcInsnNode) i;
|
||||||
|
if(ldci.cst instanceof String){
|
||||||
|
laststringldconstack = ldci;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
} else if(i instanceof MethodInsnNode) {
|
||||||
|
MethodInsnNode methodi = (MethodInsnNode) i;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
if(laststringldconstack != null && methodi.opcode() == 0xb8) { // Decryption is always a static call - 0xb8 - invokestatic
|
||||||
|
String decrypterclassname = methodi.owner;
|
||||||
|
String decryptermethodname = methodi.name;
|
||||||
|
|
||||||
|
if(decrypterclassname.contains("$")) { // Decrypter is always a static method of other class's inner class
|
||||||
|
byte[] decrypterFileContents = BytecodeViewer.getFileContents(decrypterclassname+".class");
|
||||||
|
|
||||||
|
// We have to create new node for editing
|
||||||
|
// Also, one decrypter method could be used for multiple methods in code, what gives us only part of string decrypted
|
||||||
|
ClassNode decrypterclassnode = JarUtils.getNode(decrypterFileContents);
|
||||||
|
|
||||||
|
if(decrypterclassnode != null) {
|
||||||
|
MethodNode decryptermethodnode = decrypterclassnode.getMethodByName(decryptermethodname);
|
||||||
|
if(decryptermethodnode != null) {
|
||||||
|
|
||||||
|
String keyString = (getConstantPoolSize(classNode.name)+
|
||||||
|
classNode.name+
|
||||||
|
methodNode.name+
|
||||||
|
getConstantPoolSize(classNode.name)
|
||||||
|
);
|
||||||
|
|
||||||
|
int newHashCode = keyString.hashCode();
|
||||||
|
|
||||||
|
scanDecrypter(decryptermethodnode, newHashCode);
|
||||||
|
|
||||||
|
try {
|
||||||
|
System.out.println("loading " + decrypterclassname);
|
||||||
|
|
||||||
|
List<Class<?>> decrypterclasslist = the.bytecode.club.bytecodeviewer.api.BytecodeViewer
|
||||||
|
.loadClassesIntoClassLoader(new ArrayList<ClassNode>(
|
||||||
|
Arrays.asList(new ClassNode[] { decrypterclassnode })));
|
||||||
|
|
||||||
|
String decrypted = invokeDecrypter(decrypterclasslist.get(0), decryptermethodname, (String) laststringldconstack.cst);
|
||||||
|
|
||||||
|
if (decrypted != null) {
|
||||||
|
log("Succesfully invoked decrypter method: "+decrypted);
|
||||||
|
laststringldconstack.cst = decrypted;
|
||||||
|
iList.remove(methodi);
|
||||||
|
}
|
||||||
|
} catch (IndexOutOfBoundsException | ClassNotFoundException | IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
log("Could not load decrypter class: " + decrypterclassname);
|
||||||
|
}
|
||||||
|
|
||||||
|
}else{
|
||||||
|
log("Could not find decrypter method ("+decryptermethodname+") of class "+decrypterclassname);
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
log("Could not find decrypter ClassNode of class "+decrypterclassname);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}else if(i instanceof InvokeDynamicInsnNode){
|
||||||
|
InvokeDynamicInsnNode methodi = (InvokeDynamicInsnNode) i;
|
||||||
|
if(methodi.opcode() == 0xba){
|
||||||
|
// TODO: Safe-reflection deobfuscator here
|
||||||
|
// Allatori replaces invokeinterface and invokestatic with invokedynamic
|
||||||
|
|
||||||
|
//log(methodi.bsm.getOwner()+" dot "+methodi.bsm.getName());
|
||||||
|
//iList.set(methodi, new MethodInsnNode(0xb8, methodi.bsm.getOwner(), methodi.bsm.getName(), methodi.bsm.getDesc(), false));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
laststringldconstack = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private boolean scanDecrypter(MethodNode decryptermethodnode, int newHashCode){
|
||||||
|
InsnList iList = decryptermethodnode.instructions;
|
||||||
|
|
||||||
|
AbstractInsnNode insn = null, removeInsn = null;
|
||||||
|
for (AbstractInsnNode i : iList.toArray()) {
|
||||||
|
if(i instanceof MethodInsnNode){
|
||||||
|
MethodInsnNode methodi = ((MethodInsnNode) i);
|
||||||
|
if("currentThread".equals(methodi.name)){ // find code form this instruction
|
||||||
|
insn = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
if(insn == null){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
while(insn != null){
|
||||||
|
if(insn instanceof MethodInsnNode){
|
||||||
|
MethodInsnNode methodi = ((MethodInsnNode) insn);
|
||||||
|
if("hashCode".equals(methodi.name)){ // to this instruction
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
removeInsn = insn;
|
||||||
|
insn = insn.getNext();
|
||||||
|
iList.remove(removeInsn); // and remove it
|
||||||
|
}
|
||||||
|
if(insn == null) return false;
|
||||||
|
iList.set(insn, new LdcInsnNode(newHashCode)); // then replace it with pre-computed key LDC
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private String invokeDecrypter(Class<?> decrypterclass, String name, String arg) throws Exception{
|
||||||
|
try {
|
||||||
|
Method decryptermethod = decrypterclass.getDeclaredMethod(name, String.class);
|
||||||
|
|
||||||
|
decryptermethod.setAccessible(true);
|
||||||
|
return (String) decryptermethod.invoke(null, arg);
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
log("Could not invoke decrypter method: "+name+" of class "+decrypterclass.getName());
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@ package the.bytecode.club.bytecodeviewer.plugin.preinstalled;
|
||||||
import org.objectweb.asm.tree.ClassNode;
|
import org.objectweb.asm.tree.ClassNode;
|
||||||
|
|
||||||
import the.bytecode.club.bytecodeviewer.BytecodeViewer;
|
import the.bytecode.club.bytecodeviewer.BytecodeViewer;
|
||||||
|
import the.bytecode.club.bytecodeviewer.api.ExceptionUI;
|
||||||
import the.bytecode.club.bytecodeviewer.api.Plugin;
|
import the.bytecode.club.bytecodeviewer.api.Plugin;
|
||||||
import the.bytecode.club.bytecodeviewer.api.PluginConsole;
|
import the.bytecode.club.bytecodeviewer.api.PluginConsole;
|
||||||
|
|
||||||
|
@ -63,7 +64,8 @@ public class ZStringArrayDecrypter extends Plugin {
|
||||||
|
|
||||||
if (result == 0) {
|
if (result == 0) {
|
||||||
boolean needsWarning = false;
|
boolean needsWarning = false;
|
||||||
for (Class<?> debug : the.bytecode.club.bytecodeviewer.api.BytecodeViewer.loadClassesIntoClassLoader()) {
|
try {
|
||||||
|
for (Class<?> debug : the.bytecode.club.bytecodeviewer.api.BytecodeViewer.loadAllClassesIntoClassLoader()) {
|
||||||
try {
|
try {
|
||||||
Field[] fields = debug.getDeclaredFields();
|
Field[] fields = debug.getDeclaredFields();
|
||||||
for ( Field field : fields ) {
|
for ( Field field : fields ) {
|
||||||
|
@ -84,7 +86,9 @@ public class ZStringArrayDecrypter extends Plugin {
|
||||||
needsWarning = true;
|
needsWarning = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} catch (Exception e){
|
||||||
|
new ExceptionUI(e);
|
||||||
|
}
|
||||||
if(needsWarning) {
|
if(needsWarning) {
|
||||||
BytecodeViewer.showMessage("Some classes failed to decrypt, if you'd like to decrypt all of them"+BytecodeViewer.nl+"makes sure you include ALL the libraries it requires.");
|
BytecodeViewer.showMessage("Some classes failed to decrypt, if you'd like to decrypt all of them"+BytecodeViewer.nl+"makes sure you include ALL the libraries it requires.");
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user