目前解压这两种文件的方法都是用apktool,然而还有一种简单的方法。
odex和oat是dex文件的一种优化,但是解压他们的方法是相同的。
首先用WinHex打开一个odex文件,我们可以看到dex 035这个字符串,其实这个地方就是dex文件开始的位置,根据dex文件的数据结构可知向后再偏移32个字节就是dex文件的大小。于是从头的偏移位置向后取出dex大小个字节就是dex文件的内容。
我们再来看boot.oat这个文件,打开后搜索字符串dex,找到dex 035,一个boot.oat中有多个dex文件头,说明boot.oat中有多个dex文件,而普通oat文件里一般只有一个。我们可以用同样的方法将他们解压出来
于是我们可以写一个java程序,用于解压odex和oat文件。基本思想是在内存中搜索dex文件头,记录下偏移。再获取dex文件大小。然后获取这块区域的字节,写出文件。
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
public class DEODEX {
/**
* 从内存中搜索数据,并返回在内存中的偏移
***/
public static int findPos(MappedByteBuffer data, int offset, byte[] found) {
for (int i = offset; i < data.capacity(); i++)
{
boolean bFound = true;
for (int j = 0; j < found.length; j++) {
bFound = bFound && data.get(i + j) == found[j];
}
if (bFound) {
return i;
}
}
return -1;
}
private static void write_to_file(MappedByteBuffer buffer, int offset, int dexsize, int file_count, String out)
throws IOException {
RandomAccessFile file = new RandomAccessFile(String.format("%s%02d.dex", out, file_count), "rw");
FileChannel channel = file.getChannel();
byte[] data = new byte[dexsize];
buffer.position(offset);
buffer.get(data);
ByteBuffer bw = ByteBuffer.wrap(data);
channel.write(bw);
channel.close();
file.close();
}
public static void oat2dex(String in, String out) throws IOException {
RandomAccessFile raf = new RandomAccessFile(in, "rw");
// 内存映射文件
FileChannel channel = raf.getChannel();
MappedByteBuffer buffer = channel.map(FileChannel.MapMode.READ_WRITE, 0, raf.length());
int file_count = 0;
int length = (int) raf.length();
//dex头
byte[] magic = { 0x64, 0x65, 0x78, 0x0A, 0x30, 0x33, 0x35, 0x00 };
int offset = 0;
while (offset != -1) {
offset = findPos(buffer, offset + 8, magic);
if (offset == -1) { // 未发现dex magic
break;
}
int dexsize = (buffer.get(offset + 35) << 24) | (buffer.get(offset + 34) & 0xff) << 16
| (buffer.get(offset + 33) & 0xff) << 8 | (buffer.get(offset + 32) & 0xff);
if (offset + dexsize > length)
continue;
write_to_file(buffer, offset, dexsize, ++file_count, out);
}
channel.close();
raf.close();
}
}
调用这个方法后,我们得到了dex文件
OK,这是boot.oat中的文件,随便拿一个出来测试一下。转换成jar,用jdgui打开
大功告成