公司手机团队,用ANDROID开发,为了借鉴学习别人源码,于是找来网上APK反编译的方法。
用的主流的方法,apktools 取资源, 下载地址http://code.google.com/p/android-apktool/downloads/list
用的 dex2jar 把dex 转成 jar
要记命令不说,烦得要命,每次都要先转资源,再用rar 取出classes.dex 然后再把这个文件 用dex2jar 转成 jar文件
然后是用jd-gui 查看。
仔细看了一下 apktools 和dex2jar 发现都是java写的,为什么整合一下呢? why not ?
于是,脑子想一下用什么实现,VC,还是c# ,还是JAVA。VC和C# 如果没有必须用JVM.DLL反向来调一下,比较烦。
还是用JAVA实现,考虑到使用友好,于是采用SWT,晕倒,还没有开始写,导出可执行JAR,就有16M。于是改用SWING写。
好了,废话不说了,直接上代码了
package com.aua.util;
import java.awt.EventQueue;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JTextField;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import brut.androlib.ApkDecoder;
import com.googlecode.dex2jar.v3.Main;
/**
*
* @author crazy_cabbage
*
*/
public class Dec {
private JFrame frmAndroid;
private JFileChooser jFileChooser;
private JTextField txtApk;
private JTextField txtOutDir;
private Executor executor = Executors.newFixedThreadPool(2);
private boolean flag = false;
private JLabel lblTime;
private JLabel lblRemark;
/**
* Launch the application.
*/
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
Dec window = new Dec();
window.frmAndroid.setVisible(true);
} catch (Exception e) {
}
}
});
}
/**
* Create the application.
*
* @throws UnsupportedLookAndFeelException
* @throws IllegalAccessException
* @throws InstantiationException
* @throws ClassNotFoundException
*/
public Dec() throws ClassNotFoundException, InstantiationException,
IllegalAccessException, UnsupportedLookAndFeelException {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
initialize();
}
/**
* Initialize the contents of the frame.
*/
private void initialize() {
frmAndroid = new JFrame();
frmAndroid.setIconImage(Toolkit.getDefaultToolkit().getImage(
Dec.class.getResource("/com/aua/util/ic_launcher.png")));
frmAndroid.setTitle("android \u53CD\u7F16\u8BD1\u5DE5\u5177");
frmAndroid.setBounds(100, 100, 450, 300);
jFileChooser = new JFileChooser();
frmAndroid.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frmAndroid.getContentPane().setLayout(null);
JLabel lblApk = new JLabel("APK\u6587\u4EF6:");
lblApk.setBounds(25, 38, 54, 15);
frmAndroid.getContentPane().add(lblApk);
txtApk = new JTextField();
txtApk.setEditable(false);
txtApk.setBounds(89, 35, 240, 21);
frmAndroid.getContentPane().add(txtApk);
txtApk.setColumns(10);
lblRemark = new JLabel("");
lblRemark.setBounds(25, 127, 160, 15);
frmAndroid.getContentPane().add(lblRemark);
lblTime = new JLabel("");
lblTime.setBounds(205, 127, 130, 15);
frmAndroid.getContentPane().add(lblTime);
JButton btnApk = new JButton("APK\u6587\u4EF6");
btnApk.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
jFileChooser.setMultiSelectionEnabled(false);
jFileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
int method = jFileChooser.showOpenDialog(frmAndroid);
if (JFileChooser.APPROVE_OPTION == method) {
String absolutePath = jFileChooser.getSelectedFile()
.getAbsolutePath();
if (!absolutePath.toLowerCase().endsWith(".apk")) {
JOptionPane.showMessageDialog(frmAndroid, "请选择APK文件");
return;
}
txtApk.setText(jFileChooser.getSelectedFile()
.getAbsolutePath());
}
}
});
btnApk.setBounds(339, 34, 93, 23);
frmAndroid.getContentPane().add(btnApk);
JLabel lblOutDir = new JLabel("\u8F93\u5165\u76EE\u5F55:");
lblOutDir.setBounds(25, 72, 54, 15);
frmAndroid.getContentPane().add(lblOutDir);
txtOutDir = new JTextField();
txtOutDir.setEditable(false);
txtOutDir.setBounds(89, 69, 240, 21);
frmAndroid.getContentPane().add(txtOutDir);
txtOutDir.setColumns(10);
JButton btnOutDir = new JButton("\u8F93\u51FA\u76EE\u5F55");
btnOutDir.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
jFileChooser.setMultiSelectionEnabled(false);
jFileChooser
.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
int method = jFileChooser.showOpenDialog(frmAndroid);
if (JFileChooser.APPROVE_OPTION == method) {
if (jFileChooser.getSelectedFile().listFiles().length != 0) {
JOptionPane.showMessageDialog(frmAndroid, "请选择一个空目录");
return;
}
txtOutDir.setText(jFileChooser.getSelectedFile()
.getAbsolutePath());
}
}
});
btnOutDir.setBounds(339, 68, 93, 23);
frmAndroid.getContentPane().add(btnOutDir);
final JButton btnOK = new JButton("\u5F00\u5DE5");
btnOK.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
if (txtApk.getText().length() == 0) {
JOptionPane.showMessageDialog(frmAndroid, "请选择APK文件");
return;
}
if (txtOutDir.getText().length() == 0) {
JOptionPane.showMessageDialog(frmAndroid, "请选择输出目录");
return;
}
executor.execute(new Runnable() {
@Override
public void run() {
flag = true;
try {
executor.execute(new Runnable() {
@Override
public void run() {
int i = 0;
while (flag) {
i++;
lblTime.setText("已耗时" + i + "秒");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
}
}
}
});
lblRemark.setText("正在解码资源文件");
btnOK.setEnabled(false);
btnOK.setText("解码中");
ApkDecoder decoder = new ApkDecoder();
decoder.setForceDelete(true);
decoder.setApkFile(new File(txtApk.getText()));
decoder.setOutDir(new File(txtOutDir.getText()));
decoder.decode();
File src = new File(txtApk.getText());
ZipFile zipFile = new ZipFile(src);
ZipEntry zipEntry = zipFile.getEntry("classes.dex");
InputStream inputStream = zipFile
.getInputStream(zipEntry);
FileOutputStream fileOutputStream = new FileOutputStream(
new File(txtOutDir.getText(), "classes.dex"));
byte[] b = new byte[1024];
int length = -1;
while ((length = inputStream.read(b)) != -1) {
fileOutputStream.write(b, 0, length);
}
fileOutputStream.close();
lblRemark.setText("正在还原dex 到 classes");
Main.doFile(
new File(txtOutDir.getText(), "classes.dex"),
new File(txtOutDir.getText(), "classes.jar"));
flag = false;
} catch (Exception ex) {
JOptionPane.showMessageDialog(frmAndroid, "反编译出错");
} finally {
lblRemark.setText("");
lblTime.setText("");
btnOK.setText("开工");
btnOK.setEnabled(true);
JOptionPane.showMessageDialog(frmAndroid, "反编译成功");
}
}
});
}
});
btnOK.setBounds(177, 195, 93, 23);
frmAndroid.getContentPane().add(btnOK);
}
}
要点说一下,中途发现一个问题就是 apktools 和dex2jar 的依赖包都用了 commons-io 两者有不兼容,我后来的解决方法是,删了二者中的相关commons-io的类,用上了commons-io 2.0 jar