com.googlecode.dex2jar.tools.ExtractOdexFromCoredumpCmd Maven / Gradle / Ivy
The newest version!
package com.googlecode.dex2jar.tools;
import java.io.File;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.IntBuffer;
import java.nio.channels.FileChannel;
import java.nio.channels.SeekableByteChannel;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardOpenOption;
import java.util.ArrayList;
import java.util.List;
@BaseCmd.Syntax(cmd = "extract-odex-from-coredump", syntax = "", desc = "Extract odex from dalvik memery core dump")
public class ExtractOdexFromCoredumpCmd extends BaseCmd {
public static void main(String... args) {
new ExtractOdexFromCoredumpCmd().doMain(args);
}
@Override
protected void doCommandLine() throws Exception {
if (remainingArgs.length < 1) {
throw new HelpException(" is required.");
}
Path core = new File(remainingArgs[0]).toPath();
try (SeekableByteChannel channel = FileChannel.open(core, StandardOpenOption.READ);) {
List possibleOdexs = findPossibleOdexLocation(channel);
extractDex(channel, possibleOdexs, core.getFileName().toString());
}
}
private static void extractDex(SeekableByteChannel channel, List possibleOdexs, String namePrefix) throws IOException {
int dexIndex = 0;
ByteBuffer odexHead = ByteBuffer.allocate(0x28).order(ByteOrder.LITTLE_ENDIAN);
ByteBuffer copyBuff = ByteBuffer.allocate(512 * 1024).order(ByteOrder.LITTLE_ENDIAN);
final int buffSize = 0x28 + 0x70;
ByteBuffer head = ByteBuffer.allocate(buffSize).order(ByteOrder.LITTLE_ENDIAN); // odex+dex head
for (long pos : possibleOdexs) {
System.err.println(String.format(">> Check for %08x", pos));
channel.position(pos);
head.position(0);
int c = channel.read(head);
head.position(0);
if (c == buffSize) {
int version = head.getInt(4);
if (version == 0x00363330 || version == 0x00353330) { // odexVersion
int dexOffset = head.getInt(8);
int dexLength = head.getInt(12);
int depsOffset = head.getInt(16);
int depsLength = head.getInt(20);
int optOffset = head.getInt(24);
int optLength = head.getInt(28);
int flags = head.getInt(32);
int checksum = head.getInt(36);
if (dexOffset != 0x28) {
System.err.println(String.format(">>> dex offset is not 0x28"));
} else {
int dexMagic = head.getInt(dexOffset + 0);
int dexVersion = head.getInt(dexOffset + 4);
if (dexMagic != 0x0a786564 || !(dexVersion == 0x00363330 || dexVersion == 0x00353330)) {
System.err.println(String.format(">>> dex magic is not dex.036 or dex.035: 0x%08x 0x%08x", dexMagic, dexVersion));
} else {
int fileSize = head.getInt(dexOffset + 32);
if (fileSize != dexLength) {
System.err.println(String.format(">>> dex file size is same with dexLength in odex %d vs %d", fileSize, dexLength));
} else {
int endian = head.getInt(dexOffset + 40);
if (endian != 0x12345678) {
System.err.println(String.format(">>> dex endian is not 0x12345678"));
} else {
// find new dex
Path nFile = new File(String.format("%s-%02d.odex", namePrefix, dexIndex++)).toPath();
System.out.println(String.format(">>>> extract 0x%08x to %s", pos, nFile));
try (SeekableByteChannel channel2 = Files.newByteChannel(nFile, StandardOpenOption.CREATE, StandardOpenOption.WRITE);) {
odexHead.rewind();
odexHead.putInt(0x0a796564);// dey
odexHead.putInt(0x00363330);// 036
odexHead.putInt(0x28);
odexHead.putInt(fileSize);
int nDepsOffset = 0x28 + fileSize;
int nDepsPadding = 0;
if (nDepsOffset % 8 != 0) {
nDepsPadding = 8 - (nDepsOffset % 8);
nDepsOffset += nDepsPadding;
}
odexHead.putInt(nDepsOffset);
odexHead.putInt(depsLength);
int nOptOffset = nDepsOffset + depsLength;
int nOptPadding = 0;
if (nOptOffset % 8 != 0) {
nOptPadding = 8 - (nOptOffset % 8);
nOptOffset += nOptPadding;
}
odexHead.putInt(nOptOffset);
odexHead.putInt(optLength);
odexHead.putInt(flags);
odexHead.putInt(checksum);
odexHead.position(0);
channel2.write(odexHead);
// copy dex
channel.position(pos + dexOffset);
copy(channel, channel2, copyBuff, fileSize);
if (nDepsPadding != 0) {
channel2.write(ByteBuffer.allocate(nDepsPadding));
}
// copy deps
channel.position(pos + depsOffset);
copy(channel, channel2, copyBuff, depsLength);
if (nOptPadding != 0) {
channel2.write(ByteBuffer.allocate(nOptPadding));
}
// copy opts
channel.position(pos + optOffset);
copy(channel, channel2, copyBuff, optLength);
}
}
}
}
}
}
}
}
}
private static void copy(SeekableByteChannel channel, SeekableByteChannel channel2, ByteBuffer copyBuff, int fileSize) throws IOException {
int remain = fileSize;
while (remain > 0) {
copyBuff.rewind();
copyBuff.limit(Math.min(remain, copyBuff.capacity()));
int read = channel.read(copyBuff);
copyBuff.position(0);
channel2.write(copyBuff);
remain -= read;
}
}
private static List findPossibleOdexLocation(SeekableByteChannel channel) throws IOException {
ByteBuffer buffer = ByteBuffer.allocate(1024 * 512).order(ByteOrder.LITTLE_ENDIAN);
IntBuffer intBuffer = buffer.asIntBuffer();
List possibleOdexs = new ArrayList<>();
while (true) {
long position = channel.position();
//System.out.printf("load @%x\n", position);
int count = channel.read(buffer);
if (count <= 0) {
break;
}
int s = count / 4;
for (int i = 0; i < s; i++) {
int u4 = intBuffer.get(i);
if (u4 == 0x0a796564) {// dey
if (i + 1 < s) {
int v4 = intBuffer.get(i + 1);
if (v4 == 0x00363330 || v4 == 0x00353330) {
possibleOdexs.add(position + 4 * i);
System.err.println(String.format("> Possible %08x | %08x %08x", position + i * 4, u4, v4));
}
} else {
possibleOdexs.add(position + 4 * i);
System.err.println(String.format("> Possible %08x | %08x", position + i * 4, u4));
}
}
}
buffer.position(0);
intBuffer.position(0);
}
return possibleOdexs;
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy