简单的从odex或oat文件中解压出dex文件

目前解压这两种文件的方法都是用apktool,然而还有一种简单的方法。

odex和oat是dex文件的一种优化,但是解压他们的方法是相同的。

首先用WinHex打开一个odex文件,我们可以看到dex 035这个字符串,其实这个地方就是dex文件开始的位置,根据dex文件的数据结构可知向后再偏移32个字节就是dex文件的大小。于是从头的偏移位置向后取出dex大小个字节就是dex文件的内容。

简单的从odex或oat文件中解压出dex文件_第1张图片


我们再来看boot.oat这个文件,打开后搜索字符串dex,找到dex 035,一个boot.oat中有多个dex文件头,说明boot.oat中有多个dex文件,而普通oat文件里一般只有一个。我们可以用同样的方法将他们解压出来

简单的从odex或oat文件中解压出dex文件_第2张图片


于是我们可以写一个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文件

简单的从odex或oat文件中解压出dex文件_第3张图片


简单的从odex或oat文件中解压出dex文件_第4张图片

OK,这是boot.oat中的文件,随便拿一个出来测试一下。转换成jar,用jdgui打开

简单的从odex或oat文件中解压出dex文件_第5张图片


大功告成

你可能感兴趣的:(odex,dex,oat,反编译,安卓)