Merge branch 'GP-804_GhidraKnight_NewAndroidSupport'

This commit is contained in:
Ryan Kurtz
2021-09-23 12:17:55 -04:00
276 changed files with 21287 additions and 2671 deletions
@@ -23,6 +23,7 @@ import ghidra.app.util.Option;
import ghidra.app.util.bin.BinaryReader;
import ghidra.app.util.bin.ByteProvider;
import ghidra.app.util.importer.MessageLog;
import ghidra.file.formats.android.dex.DexHeaderFactory;
import ghidra.file.formats.android.dex.format.*;
import ghidra.file.formats.android.dex.util.DexUtil;
import ghidra.program.model.address.Address;
@@ -46,7 +47,7 @@ public class DexLoader extends AbstractLibrarySupportLoader {
BinaryReader reader = new BinaryReader(provider, true);
try {
DexHeader header = new DexHeader(reader);
DexHeader header = DexHeaderFactory.getDexHeader(reader);
if (DexConstants.DEX_MAGIC_BASE.equals(new String(header.getMagic()))) {
List<QueryResult> queries =
QueryOpinionService.query(getName(), DexConstants.MACHINE, null);
@@ -80,7 +81,7 @@ public class DexLoader extends AbstractLibrarySupportLoader {
}
BinaryReader reader = new BinaryReader( provider, true );
DexHeader header = new DexHeader( reader );
DexHeader header = DexHeaderFactory.getDexHeader( reader );
monitor.setMessage( "DEX Loader: creating method byte code" );
@@ -0,0 +1,27 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.file.formats.android.apex;
/**
* Android Pony EXpress (ApexContants)
*
* https://source.android.com/devices/tech/ota/apex
*
* https://android.googlesource.com/platform/system/apex/+/refs/heads/master/apexd/apex_constants.h
*/
public class ApexContants {
}
@@ -0,0 +1,102 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.file.formats.android.art;
import ghidra.app.util.bin.*;
import ghidra.app.util.importer.MessageLog;
import ghidra.app.util.opinion.BinaryLoader;
import ghidra.file.analyzers.FileFormatAnalyzer;
import ghidra.file.formats.android.oat.OatConstants;
import ghidra.program.model.address.Address;
import ghidra.program.model.address.AddressSetView;
import ghidra.program.model.data.DataType;
import ghidra.program.model.listing.Program;
import ghidra.util.task.TaskMonitor;
public class ArtAnalyzer extends FileFormatAnalyzer {
@Override
public String getName() {
return "Android ART Header Format";
}
@Override
public boolean getDefaultEnablement(Program program) {
return true;
}
@Override
public String getDescription() {
return "Analyzes the Android ART information in this program.";
}
@Override
public boolean canAnalyze(Program program) {
return ArtConstants.isART(program)
//HACK:
//Make analyzer appear after ART is merged with OAT program
//Currently, analyzers will not recognize the new ART block being added
|| OatConstants.isOAT(program);
}
@Override
public boolean isPrototype() {
return true;
}
@Override
public boolean analyze(Program program, AddressSetView set, TaskMonitor monitor, MessageLog log)
throws Exception {
Address address = ArtConstants.findART(program);
if (address == null) {//ART does not exist so quit, could be OAT
return false;
}
ByteProvider provider = new MemoryByteProvider(program.getMemory(), address);
BinaryReader reader = new BinaryReader(provider, !program.getLanguage().isBigEndian());
try {
ArtHeader header = ArtFactory.newArtHeader(reader);
DataType headerDataType = header.toDataType();
//only set "image base" when ART header not defined at "image begin"
//---this really only opens when ART is "added to" OAT program
Address imageBase = toAddr(program, header.getImageBegin());
if (BinaryLoader.BINARY_NAME.equals(program.getExecutableFormat())) {
program.setImageBase(imageBase, true);
createData(program, imageBase, headerDataType);
}
else {
createData(program, address, headerDataType);
}
header.markup(program, monitor);
return true;
}
catch (UnsupportedArtVersionException e) {
log.appendException(e);
}
catch (Exception e) {
throw e;
}
return false;
}
}
@@ -0,0 +1,99 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.file.formats.android.art;
import java.io.IOException;
import ghidra.app.util.bin.*;
import ghidra.program.model.data.*;
import ghidra.util.exception.DuplicateNameException;
/**
* https://android.googlesource.com/platform/art/+/refs/heads/android10-release/runtime/image.h
*
*
*/
public class ArtBlock implements StructConverter, ArtCompression {
private ArtStorageMode storage_mode_ = ArtStorageMode.kDefaultStorageMode;
private int data_offset_;
private int data_size_;
private int image_offset_;
private int image_size_;
public ArtBlock(BinaryReader reader) throws IOException {
storage_mode_ = ArtStorageMode.get(reader.readNextInt());
data_offset_ = reader.readNextInt();
data_size_ = reader.readNextInt();
image_offset_ = reader.readNextInt();
image_size_ = reader.readNextInt();
}
@Override
public ArtStorageMode getStorageMode() {
return storage_mode_;
}
@Override
public long getCompressedOffset() {
return Integer.toUnsignedLong(data_offset_);
}
@Override
public int getCompressedSize() {
return data_size_;
}
@Override
public long getDecompressedOffset() {
return Integer.toUnsignedLong(image_offset_);
}
@Override
public int getDecompressedSize() {
return image_size_;
}
public int getDataOffset() {
return data_offset_;
}
public int getDataSize() {
return data_size_;
}
public int getImageOffset() {
return image_offset_;
}
public int getImageSize() {
return image_size_;
}
@Override
public DataType toDataType() throws DuplicateNameException, IOException {
String name = StructConverterUtil.parseName(ArtBlock.class);
Structure structure = new StructureDataType(name, 0);
structure.setCategoryPath(new CategoryPath("/art"));
structure.add(DWORD, "storage_mode_", storage_mode_.name());
structure.add(DWORD, "data_offset_", null);
structure.add(DWORD, "data_size_", null);
structure.add(DWORD, "image_offset_", null);
structure.add(DWORD, "image_size_", null);
return structure;
}
}
@@ -0,0 +1,52 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.file.formats.android.art;
public interface ArtCompression {
/**
* Storage method for the image, the image may be compressed.
* @return the storage method
* @throws UnknownArtStorageModeException when an unknown storage mode is encountered
*/
public ArtStorageMode getStorageMode() throws UnknownArtStorageModeException;
/**
* Data size for the image data excluding the bitmap and the header.
* For compressed images, this is the compressed size in the file.
* @return the compressed size
*/
public int getCompressedSize();
/**
* Offset to the start of the compressed bytes.
* Also, offset of where to place the decompressed bytes.
* @return the offset to the compressed bytes
*/
public long getCompressedOffset();
/**
* Expected size of the decompressed bytes.
* @return the expected decompressed size
*/
public int getDecompressedSize();
/**
* Offset to the start of the decompressed bytes.
* @return the offset to the dcompressed bytes
*/
public long getDecompressedOffset();
}
@@ -0,0 +1,127 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.file.formats.android.art;
import ghidra.program.model.address.Address;
import ghidra.program.model.listing.Program;
import ghidra.program.model.mem.MemoryBlock;
/**
* https://android.googlesource.com/platform/art/+/master/runtime/image.cc
*/
public final class ArtConstants {
public final static String ART_NAME = "Android Runtime (ART)";
public final static String MAGIC = "art\n";
public final static int VERSION_LENGTH = 4;
public final static String VERSION_KITKAT_RELEASE = "005";
public final static String VERSION_LOLLIPOP_RELEASE = "009";
public final static String VERSION_LOLLIPOP_MR1_WFC_RELEASE = "012";
public final static String VERSION_MARSHMALLOW_RELEASE = "017";
public final static String VERSION_NOUGAT_RELEASE = "029";
public final static String VERSION_NOUGAT_MR2_PIXEL_RELEASE = "030";
public final static String VERSION_OREO_RELEASE = "043";
public final static String VERSION_OREO_DR1_RELEASE = "044";
public final static String VERSION_OREO_MR1_RELEASE = "046";
public final static String VERSION_PIE_RELEASE = "056";
public final static String VERSION_10_RELEASE = "074";//Q
public final static String VERSION_11_RELEASE = "085";//R
// "005",// kitkat-release
// "009",// lollipop-release
// "012",// lollipop-mr1-wfc-release
// "017",// marshmallow-release
// "029",// nougat-release
// "030",// nougat-mr2-pixel-release
// "043",// oreo-release
// "044",// taimen-op1
// "046",// oreo-mr1-release
// "051",//
// "056",// pie-release
// "059",// android-o-mr1-iot-release-1.0.0
// "060",// android-o-mr1-iot-release-1.0.1
// "061",// android-n-iot-release-polk-at1
/**
* NOTE: only going to support RELEASE versions
*/
public final static String[] SUPPORTED_VERSIONS = new String[] {
//@formatter:off
VERSION_KITKAT_RELEASE,
VERSION_LOLLIPOP_RELEASE,
VERSION_LOLLIPOP_MR1_WFC_RELEASE,
VERSION_MARSHMALLOW_RELEASE,
VERSION_NOUGAT_RELEASE,
VERSION_NOUGAT_MR2_PIXEL_RELEASE,
VERSION_OREO_RELEASE,
VERSION_OREO_DR1_RELEASE,
VERSION_OREO_MR1_RELEASE,
VERSION_PIE_RELEASE,
VERSION_10_RELEASE,
VERSION_11_RELEASE,
//@formatter:on
};
public final static boolean isSupportedVersion(String version) {
for (String supportedVersion : SUPPORTED_VERSIONS) {
if (supportedVersion.equals(version)) {
return true;
}
}
return false;
}
public final static boolean isART(Program program) {
if (program != null) {
for (MemoryBlock block : program.getMemory().getBlocks()) {
try {
byte[] bytes = new byte[ArtConstants.MAGIC.length()];
block.getBytes(block.getStart(), bytes);
String magic = new String(bytes);
if (ArtConstants.MAGIC.equals(magic)) {
return true;
}
}
catch (Exception e) {
//ignore
}
}
}
return false;
}
public final static Address findART(Program program) {
if (program != null) {
for (MemoryBlock block : program.getMemory().getBlocks()) {
try {
byte[] bytes = new byte[ArtConstants.MAGIC.length()];
block.getBytes(block.getStart(), bytes);
String magic = new String(bytes);
if (ArtConstants.MAGIC.equals(magic)) {
return block.getStart();
}
}
catch (Exception e) {
//ignore
}
}
}
return null;
}
}
@@ -0,0 +1,79 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.file.formats.android.art;
import java.io.IOException;
import ghidra.app.util.bin.BinaryReader;
import ghidra.file.formats.android.art.android10.ArtHeader_10;
import ghidra.file.formats.android.art.android11.ArtHeader_11;
import ghidra.file.formats.android.art.kitkat.ArtHeader_KitKat;
import ghidra.file.formats.android.art.lollipop.ArtHeader_Lollipop;
import ghidra.file.formats.android.art.lollipop.ArtHeader_LollipopMR1WFC;
import ghidra.file.formats.android.art.marshmallow.ArtHeader_Marshmallow;
import ghidra.file.formats.android.art.nougat.ArtHeader_Nougat;
import ghidra.file.formats.android.art.nougat.ArtHeader_NougatMR2Pixel;
import ghidra.file.formats.android.art.oreo.ArtHeader_Oreo;
import ghidra.file.formats.android.art.oreo.ArtHeader_OreoMR1;
import ghidra.file.formats.android.art.pie.ArtHeader_Pie;
public final class ArtFactory {
/**
* Returns an ArtHeader of the correct version.
* @param reader the BinaryReader to the ART header
* @return the specific version of the ART header
* @throws IOException should an error occur during reading or parsing
* @throws UnsupportedArtVersionException when the provided version is invalid or not yet implemented.
*/
public final static ArtHeader newArtHeader(BinaryReader reader)
throws IOException, UnsupportedArtVersionException {
String magic = new String(reader.readByteArray(0, ArtConstants.MAGIC.length()));
String version = reader.readAsciiString(4, 4);
if (magic.equals(ArtConstants.MAGIC)) {
if (ArtConstants.isSupportedVersion(version)) {
switch (version ) {
case ArtConstants.VERSION_KITKAT_RELEASE:
return new ArtHeader_KitKat(reader);
case ArtConstants.VERSION_LOLLIPOP_RELEASE:
return new ArtHeader_Lollipop(reader);
case ArtConstants.VERSION_LOLLIPOP_MR1_WFC_RELEASE:
return new ArtHeader_LollipopMR1WFC(reader);
case ArtConstants.VERSION_MARSHMALLOW_RELEASE:
return new ArtHeader_Marshmallow(reader);
case ArtConstants.VERSION_NOUGAT_RELEASE:
return new ArtHeader_Nougat(reader);
case ArtConstants.VERSION_NOUGAT_MR2_PIXEL_RELEASE:
return new ArtHeader_NougatMR2Pixel(reader);
case ArtConstants.VERSION_OREO_RELEASE:
return new ArtHeader_Oreo(reader);
case ArtConstants.VERSION_OREO_DR1_RELEASE:
return new ArtHeader_Oreo(reader);//v043 and v044 are same format
case ArtConstants.VERSION_OREO_MR1_RELEASE:
return new ArtHeader_OreoMR1(reader);
case ArtConstants.VERSION_PIE_RELEASE:
return new ArtHeader_Pie(reader);
case ArtConstants.VERSION_10_RELEASE:
return new ArtHeader_10(reader);
case ArtConstants.VERSION_11_RELEASE:
return new ArtHeader_11(reader);
}
}
}
throw new UnsupportedArtVersionException(magic, version);
}
}
@@ -0,0 +1,71 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.file.formats.android.art;
import java.io.IOException;
import ghidra.app.util.bin.*;
import ghidra.program.model.data.*;
import ghidra.util.exception.DuplicateNameException;
/**
* https://android.googlesource.com/platform/art/+/refs/heads/android10-release/runtime/art_field.h
*
*
*/
public class ArtField implements StructConverter {
private int declaring_class_;
private int access_flags_;
private int field_dex_idx_;
private int offset_;
public ArtField(BinaryReader reader) throws IOException {
declaring_class_ = reader.readNextInt();
access_flags_ = reader.readNextInt();
field_dex_idx_ = reader.readNextInt();
offset_ = reader.readNextInt();
}
public int getDeclaringClass() {
return declaring_class_;
}
public int getAccessFlags() {
return access_flags_;
}
public int getFieldDexIndex() {
return field_dex_idx_;
}
public int getOffset() {
return offset_;
}
@Override
public DataType toDataType() throws DuplicateNameException, IOException {
String name = StructConverterUtil.parseName(ArtField.class);
Structure structure = new StructureDataType(name, 0);
structure.setCategoryPath(new CategoryPath("/art"));
structure.add(new Pointer32DataType(), "declaring_class_", null);
structure.add(DWORD, "access_flags_", null);
structure.add(DWORD, "field_dex_idx_", null);
structure.add(DWORD, "offset_", null);
return structure;
}
}
@@ -0,0 +1,66 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.file.formats.android.art;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import ghidra.app.util.bin.*;
import ghidra.program.model.data.*;
import ghidra.util.exception.DuplicateNameException;
/**
* https://android.googlesource.com/platform/art/+/refs/heads/android10-release/runtime/art_field.h
*
* NOTE: this class does not exist, was created to make field reading easier.
*/
public class ArtFieldGroup implements StructConverter {
private int fieldCount;
private List<ArtField> fieldList = new ArrayList<>();
public ArtFieldGroup(BinaryReader reader) throws IOException {
fieldCount = reader.readNextInt();
if (fieldCount > 0xffff) {//sanity check...
throw new IOException("Too many ART fields: " + fieldCount);
}
for (int i = 0; i < fieldCount; ++i) {
fieldList.add(new ArtField(reader));
}
}
public int getFieldCount() {
return fieldCount;
}
public List<ArtField> getFieldList() {
return fieldList;
}
@Override
public DataType toDataType() throws DuplicateNameException, IOException {
String name = StructConverterUtil.parseName(ArtFieldGroup.class);
Structure structure = new StructureDataType(name + "_" + fieldCount, 0);
structure.setCategoryPath(new CategoryPath("/art"));
structure.add(DWORD, "fieldCount", null);
for (int i = 0; i < fieldCount; ++i) {
structure.add(fieldList.get(i).toDataType(), "field_" + i, null);
}
return structure;
}
}
@@ -0,0 +1,148 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.file.formats.android.art;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import ghidra.app.util.bin.*;
import ghidra.program.model.data.*;
import ghidra.program.model.listing.Program;
import ghidra.util.exception.DuplicateNameException;
import ghidra.util.task.TaskMonitor;
/**
* https://android.googlesource.com/platform/art/+/marshmallow-release/runtime/image.h
*/
public abstract class ArtHeader implements StructConverter {
protected String magic_;
protected String version_;
protected List<Long> imageMethodsList = new ArrayList<>();
protected ArtHeader(BinaryReader reader) throws IOException {
magic_ = new String(reader.readNextByteArray(ArtConstants.MAGIC.length()));
version_ = reader.readNextAsciiString(ArtConstants.VERSION_LENGTH);
}
/**
* Returns the magic string: "art\n".
* @return the magic string
*/
public final String getMagic() {
return magic_;
}
/**
* Returns the version string: eg, "001", "017"
* @return the version
*/
public final String getVersion() {
return version_;
}
/**
* Required base address for mapping the image.
*
* Base address of the ART file.
* -1 indicates unsupported
* @return image base address
*/
abstract public int getImageBegin();
/**
* Required base size for mapping the image.
* -1 indicates unsupported
* @return image size
*/
abstract public int getImageSize();
/**
* Returns the checksum of the matching OAT file.
* The checksum is stored in the OAT header and is generated using Adler32.
* -1 indicates unsupported
* @return oat checksum
*/
abstract public int getOatChecksum();
/**
* -1 indicates unsupported
* @return the oat file begin address
*/
abstract public int getOatFileBegin();
/**
* -1 indicates unsupported
* @return the oat file end address
*/
abstract public int getOatFileEnd();
/**
* Returns the offset to the start of the .oatdata section,
* usually defined within the ".rodata" section.
* -1 indicates unsupported
* @return the oat data begin address
*/
abstract public int getOatDataBegin();
/**
* -1 indicates unsupported
* @return the oat data end address
*/
abstract public int getOatDataEnd();
/**
* Pointer size (in bytes).
* @return the pointer size
*/
abstract public int getPointerSize();
abstract public int getArtMethodCountForVersion();
/**
* Parses the ART header data.
* @param reader the binary reader
* @throws IOException if an error occurs parsing the header
*/
abstract protected void parse(BinaryReader reader) throws IOException;
protected final void parseImageMethods(BinaryReader reader) throws IOException {
for (int i = 0; i < getArtMethodCountForVersion(); ++i) {
imageMethodsList.add(reader.readNextLong());
}
}
/**
* Allows each specific version to mark-up the specified program.
* @param program the program to markup
* @param monitor the task monitor
* @throws Exception if an error occurs while marking up the program
*/
abstract public void markup(Program program, TaskMonitor monitor) throws Exception;
@Override
public DataType toDataType() throws DuplicateNameException, IOException {
String className = StructConverterUtil.parseName(ArtHeader.class);
Structure structure = new StructureDataType(className, 0);
structure.add(STRING, 4, "magic_", null);
structure.add(STRING, 4, "version_", null);
structure.setCategoryPath(new CategoryPath("/art"));
return structure;
}
}
@@ -0,0 +1,53 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.file.formats.android.art;
import java.io.IOException;
import ghidra.app.util.bin.*;
import ghidra.program.model.data.CategoryPath;
import ghidra.program.model.data.DataType;
import ghidra.util.exception.DuplicateNameException;
public class ArtImageSection implements StructConverter {
private int offset_;
private int size_;
public ArtImageSection(BinaryReader reader) throws IOException {
offset_ = reader.readNextInt();
size_ = reader.readNextInt();
}
public int getOffset() {
return offset_;
}
public int getSize() {
return size_;
}
public int getEnd() {
return offset_ + size_;
}
@Override
public DataType toDataType() throws DuplicateNameException, IOException {
DataType dataType = StructConverterUtil.toDataType(ArtImageSection.class);
dataType.setCategoryPath(new CategoryPath("/art"));
return dataType;
}
}
@@ -0,0 +1,402 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.file.formats.android.art;
import java.io.IOException;
import ghidra.app.util.bin.*;
import ghidra.program.model.data.*;
import ghidra.util.exception.DuplicateNameException;
/**
* https://android.googlesource.com/platform/art/+/refs/heads/android10-release/runtime/art_method.h
*
*
*/
public class ArtMethod implements StructConverter {
private final int pointerSize;
private final String artVersion;
private int declaring_class_;
private int access_flags_;
private int dex_code_item_offset_;
private int dex_method_index_;
private short method_index_;
private short hotness_count_;
private short imt_index_;
private short padding_;
private long dex_cache_resolved_methods_;
private long dex_cache_resolved_types_;
private long entry_point_from_interpreter_;
private long entry_point_from_jni_;
private long data_;
private long unknown1_;
private long entry_point_from_quick_compiled_code_;
private int unknown2_;
public ArtMethod(BinaryReader reader, int pointerSize, String artVersion) throws IOException {
this.pointerSize = pointerSize;
this.artVersion = artVersion;
if (ArtConstants.VERSION_MARSHMALLOW_RELEASE.equals(artVersion)) {
if (pointerSize == 4) {
declaring_class_ = reader.readNextInt();
dex_cache_resolved_methods_ = Integer.toUnsignedLong(reader.readNextInt());
dex_cache_resolved_types_ = Integer.toUnsignedLong(reader.readNextInt());
access_flags_ = reader.readNextInt();
dex_code_item_offset_ = reader.readNextInt();
dex_method_index_ = reader.readNextInt();
method_index_ = reader.readNextShort();
padding_ = reader.readNextShort();
entry_point_from_interpreter_ = Integer.toUnsignedLong(reader.readNextInt());
entry_point_from_jni_ = Integer.toUnsignedLong(reader.readNextInt());
entry_point_from_quick_compiled_code_ =
Integer.toUnsignedLong(reader.readNextInt());
}
else if (pointerSize == 8) {
throw new IOException("Unsupported 64-bit ART method format: " + artVersion);
}
}
else if (ArtConstants.VERSION_NOUGAT_RELEASE.equals(artVersion) ||
ArtConstants.VERSION_NOUGAT_MR2_PIXEL_RELEASE.equals(artVersion)) {
if (pointerSize == 4) {
declaring_class_ = reader.readNextInt();
access_flags_ = reader.readNextInt();
dex_code_item_offset_ = reader.readNextInt();
dex_method_index_ = reader.readNextInt();
method_index_ = reader.readNextShort();
hotness_count_ = reader.readNextShort();
dex_cache_resolved_methods_ = Integer.toUnsignedLong(reader.readNextInt());
dex_cache_resolved_types_ = Integer.toUnsignedLong(reader.readNextInt());
entry_point_from_jni_ = Integer.toUnsignedLong(reader.readNextInt());
entry_point_from_quick_compiled_code_ =
Integer.toUnsignedLong(reader.readNextInt());
}
else if (pointerSize == 8) {
declaring_class_ = reader.readNextInt();
access_flags_ = reader.readNextInt();
dex_code_item_offset_ = reader.readNextInt();
dex_method_index_ = reader.readNextInt();
method_index_ = reader.readNextShort();
hotness_count_ = reader.readNextShort();
imt_index_ = reader.readNextShort();
padding_ = reader.readNextShort();
dex_cache_resolved_methods_ = reader.readNextLong();
dex_cache_resolved_types_ = reader.readNextLong();
entry_point_from_jni_ = reader.readNextLong();
entry_point_from_quick_compiled_code_ = reader.readNextLong();
}
}
else if (ArtConstants.VERSION_OREO_RELEASE.equals(artVersion) ||
ArtConstants.VERSION_OREO_DR1_RELEASE.equals(artVersion) ||
ArtConstants.VERSION_OREO_MR1_RELEASE.equals(artVersion)) {
if (pointerSize == 4) {
declaring_class_ = reader.readNextInt();
access_flags_ = reader.readNextInt();
dex_code_item_offset_ = reader.readNextInt();
dex_method_index_ = reader.readNextInt();
method_index_ = reader.readNextShort();
hotness_count_ = reader.readNextShort();
data_ = reader.readNextLong();
entry_point_from_quick_compiled_code_ =
Integer.toUnsignedLong(reader.readNextInt());
}
else if (pointerSize == 8) {
declaring_class_ = reader.readNextInt();
access_flags_ = reader.readNextInt();
dex_code_item_offset_ = reader.readNextInt();
dex_method_index_ = reader.readNextInt();
method_index_ = reader.readNextShort();
hotness_count_ = reader.readNextShort();
imt_index_ = reader.readNextShort();
padding_ = reader.readNextShort();
data_ = reader.readNextLong();
unknown1_ = reader.readNextLong();
entry_point_from_quick_compiled_code_ = reader.readNextLong();
}
}
else if (ArtConstants.VERSION_PIE_RELEASE.equals(artVersion)) {
declaring_class_ = reader.readNextInt();
access_flags_ = reader.readNextInt();
dex_code_item_offset_ = reader.readNextInt();
dex_method_index_ = reader.readNextInt();
method_index_ = reader.readNextShort();
hotness_count_ = reader.readNextShort();
imt_index_ = reader.readNextShort();
padding_ = reader.readNextShort();
if (pointerSize == 4) {
data_ = Integer.toUnsignedLong(reader.readNextInt());
}
else if (pointerSize == 8) {
data_ = reader.readNextLong();
entry_point_from_quick_compiled_code_ = reader.readNextLong();
}
}
else if (ArtConstants.VERSION_10_RELEASE.equals(artVersion)) {
declaring_class_ = reader.readNextInt();
access_flags_ = reader.readNextInt();
dex_code_item_offset_ = reader.readNextInt();
dex_method_index_ = reader.readNextInt();
method_index_ = reader.readNextShort();
hotness_count_ = reader.readNextShort();
imt_index_ = reader.readNextShort();
padding_ = reader.readNextShort();
if (pointerSize == 4) {
data_ = Integer.toUnsignedLong(reader.readNextInt());
}
else if (pointerSize == 8) {
data_ = reader.readNextLong();
entry_point_from_quick_compiled_code_ = reader.readNextLong();
}
}
else if (ArtConstants.VERSION_11_RELEASE.equals(artVersion)) {
declaring_class_ = reader.readNextInt();
access_flags_ = reader.readNextInt();
dex_code_item_offset_ = reader.readNextInt();
dex_method_index_ = reader.readNextInt();
method_index_ = reader.readNextShort();
hotness_count_ = reader.readNextShort();
imt_index_ = reader.readNextShort();
padding_ = reader.readNextShort();
if (pointerSize == 4) {
data_ = Integer.toUnsignedLong(reader.readNextInt());
}
else if (pointerSize == 8) {
data_ = reader.readNextLong();
entry_point_from_quick_compiled_code_ = reader.readNextLong();
}
}
else {
throw new IOException("Unsupported ART method format: " + artVersion);
}
}
public int getDeclaringClass() {
return declaring_class_;
}
public int getAccessFlags() {
return access_flags_;
}
public int getDexCodeItemOffset() {
return dex_code_item_offset_;
}
public int getDexMethodIndex() {
return dex_method_index_;
}
public short getMethodIndex() {
return method_index_;
}
public short getHotnessCount() {
return hotness_count_;
}
public short getImtIndex() {
return imt_index_;
}
public short getPadding() {
return padding_;
}
public long getData() {
return data_;
}
public long getEntryPointFromInterpreter() {
return entry_point_from_interpreter_;
}
public long getEntryPointFromQuickCompiledCode() {
return entry_point_from_quick_compiled_code_;
}
public long getDexCacheResolvedMethods() {
return dex_cache_resolved_methods_;
}
public long getDexCacheResolvedTypes() {
return dex_cache_resolved_types_;
}
public long getEntryPointFromJNI() {
return entry_point_from_jni_;
}
public long getUnknown1() {
return unknown1_;
}
public int getUnknown2() {
return unknown2_;
}
@Override
public DataType toDataType() throws DuplicateNameException, IOException {
DataType ptr32 = new Pointer32DataType();
DataType ptr64 = new Pointer64DataType();
String name = StructConverterUtil.parseName(ArtMethod.class);
Structure struct = new StructureDataType(name, 0);
struct.setCategoryPath(new CategoryPath("/art"));
if (ArtConstants.VERSION_MARSHMALLOW_RELEASE.equals(artVersion)) {
if (pointerSize == 4) {
struct.add(DWORD, "declaring_class_", null);
struct.add(DWORD, "dex_cache_resolved_methods_", null);
struct.add(DWORD, "dex_cache_resolved_types_", null);
struct.add(DWORD, "access_flags_", null);
struct.add(DWORD, "dex_code_item_offset_", null);
struct.add(DWORD, "dex_method_index_", null);
struct.add(WORD, "method_index_", null);
struct.add(WORD, "padding_", null);
struct.add(DWORD, "entry_point_from_interpreter_", null);
struct.add(DWORD, "entry_point_from_jni_", null);
struct.add(DWORD, "entry_point_from_quick_compiled_code_", null);
}
else if (pointerSize == 8) {
throw new IOException("Unsupported 64-bit ART method format: " + artVersion);
}
}
else if (ArtConstants.VERSION_NOUGAT_RELEASE.equals(artVersion) ||
ArtConstants.VERSION_NOUGAT_MR2_PIXEL_RELEASE.equals(artVersion)) {
if (pointerSize == 4) {
struct.add(ptr32, "declaring_class_", null);
struct.add(DWORD, "access_flags_", null);
struct.add(DWORD, "dex_code_item_offset_", null);
struct.add(DWORD, "dex_method_index_", null);
struct.add(WORD, "method_index_", null);
struct.add(WORD, "hotness_count_", null);
struct.add(DWORD, "dex_cache_resolved_methods_", null);
struct.add(DWORD, "dex_cache_resolved_types_", null);
struct.add(ptr32, "entry_point_from_jni_", null);
struct.add(ptr32, "entry_point_from_quick_compiled_code_", null);
}
else if (pointerSize == 8) {
struct.add(ptr32, "declaring_class_", null);
struct.add(DWORD, "access_flags_", null);
struct.add(DWORD, "dex_code_item_offset_", null);
struct.add(DWORD, "dex_method_index_", null);
struct.add(WORD, "method_index_", null);
struct.add(WORD, "hotness_count_", null);
struct.add(WORD, "imt_index_", null);
struct.add(WORD, "padding", null);
struct.add(QWORD, "dex_cache_resolved_methods_", null);
struct.add(QWORD, "dex_cache_resolved_types_", null);
struct.add(ptr64, "entry_point_from_jni_", null);
struct.add(ptr64, "entry_point_from_quick_compiled_code_", null);
}
}
else if (ArtConstants.VERSION_OREO_RELEASE.equals(artVersion) ||
ArtConstants.VERSION_OREO_DR1_RELEASE.equals(artVersion) ||
ArtConstants.VERSION_OREO_MR1_RELEASE.equals(artVersion)) {
if (pointerSize == 4) {
struct.add(ptr32, "declaring_class_", null);
struct.add(DWORD, "access_flags_", null);
struct.add(DWORD, "dex_code_item_offset_", null);
struct.add(DWORD, "dex_method_index_", null);
struct.add(WORD, "method_index_", null);
struct.add(WORD, "hotness_count_", null);
struct.add(QWORD, "data", null);
struct.add(ptr32, "entry_point_from_quick_compiled_code_", null);
}
else if (pointerSize == 8) {
struct.add(ptr32, "declaring_class_", null);
struct.add(DWORD, "access_flags_", null);
struct.add(DWORD, "dex_code_item_offset_", null);
struct.add(DWORD, "dex_method_index_", null);
struct.add(WORD, "method_index_", null);
struct.add(WORD, "hotness_count_", null);
struct.add(WORD, "imt_index_", null);
struct.add(WORD, "padding", null);
struct.add(QWORD, "data", null);
struct.add(QWORD, "unknown1_", null);
struct.add(ptr64, "entry_point_from_quick_compiled_code_", null);
}
}
else if (ArtConstants.VERSION_PIE_RELEASE.equals(artVersion)) {
struct.add(ptr32, "declaring_class_", null);
struct.add(DWORD, "access_flags_", null);
struct.add(DWORD, "dex_code_item_offset_", null);
struct.add(DWORD, "dex_method_index_", null);
struct.add(WORD, "method_index_", null);
struct.add(WORD, "hotness_count_", null);
struct.add(WORD, "imt_index_", null);
struct.add(WORD, "padding", null);
if (pointerSize == 4) {
struct.add(DWORD, "data", null);
}
else if (pointerSize == 8) {
struct.add(QWORD, "data", null);
struct.add(QWORD, "entry_point_from_quick_compiled_code_", null);
}
}
else if (ArtConstants.VERSION_10_RELEASE.equals(artVersion)) {
struct.add(ptr32, "declaring_class_", null);
struct.add(DWORD, "access_flags_", null);
struct.add(DWORD, "dex_code_item_offset_", null);
struct.add(DWORD, "dex_method_index_", null);
struct.add(WORD, "method_index_", null);
struct.add(WORD, "hotness_count_", null);
struct.add(WORD, "imt_index_", null);
struct.add(WORD, "padding", null);
if (pointerSize == 4) {
struct.add(DWORD, "data", null);
}
else if (pointerSize == 8) {
struct.add(QWORD, "data", null);
struct.add(ptr64, "entry_point_from_quick_compiled_code_", null);
}
}
else if (ArtConstants.VERSION_11_RELEASE.equals(artVersion)) {
struct.add(ptr32, "declaring_class_", null);
struct.add(DWORD, "access_flags_", null);
struct.add(DWORD, "dex_code_item_offset_", null);
struct.add(DWORD, "dex_method_index_", null);
struct.add(WORD, "method_index_", null);
struct.add(WORD, "hotness_count_", null);
struct.add(WORD, "imt_index_", null);
struct.add(WORD, "padding", null);
if (pointerSize == 4) {
struct.add(DWORD, "data", null);
}
else if (pointerSize == 8) {
struct.add(QWORD, "data", null);
struct.add(QWORD, "entry_point_from_quick_compiled_code_", null);
}
}
else {
throw new IOException("Unsupported ART method format: " + artVersion);
}
return struct;
}
}
@@ -0,0 +1,83 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.file.formats.android.art;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import ghidra.app.util.bin.*;
import ghidra.program.model.data.*;
import ghidra.util.exception.DuplicateNameException;
/**
* https://android.googlesource.com/platform/art/+/refs/heads/android10-release/runtime/art_method.h
*
* NOTE: this class does not exist, was created to make method reading easier.
*/
public class ArtMethodGroup implements StructConverter {
private int pointerSize;
private long methodCount;
private List<ArtMethod> methodList = new ArrayList<>();
public ArtMethodGroup(BinaryReader reader, int pointerSize, String artVersion)
throws IOException {
this.pointerSize = pointerSize;
if (pointerSize == 8) {
methodCount = reader.readNextLong();
}
else if (pointerSize == 4) {
methodCount = Integer.toUnsignedLong(reader.readNextInt());
}
if (methodCount > 0xffff) {//sanity check...
throw new IOException("Too many ART methods: " + methodCount);
}
for (int i = 0; i < methodCount; ++i) {
methodList.add(new ArtMethod(reader, pointerSize, artVersion));
}
}
public long getMethodCount() {
return methodCount;
}
public List<ArtMethod> getMethodList() {
return methodList;
}
@Override
public DataType toDataType() throws DuplicateNameException, IOException {
String name = StructConverterUtil.parseName(ArtMethodGroup.class);
Structure structure = new StructureDataType(name + "_" + methodCount, 0);
structure.setCategoryPath(new CategoryPath("/art"));
if (pointerSize == 8) {
structure.add(QWORD, "methodCount", null);
}
else if (pointerSize == 4) {
structure.add(DWORD, "methodCount", null);
}
for (int i = 0; i < methodCount; ++i) {
structure.add(methodList.get(i).toDataType(), "method_" + i, null);
}
return structure;
}
}
@@ -0,0 +1,36 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.file.formats.android.art;
/**
* https://android.googlesource.com/platform/art/+/refs/heads/pie-release/runtime/image.h
*/
public enum ArtStorageMode {
kStorageModeUncompressed, kStorageModeLZ4, kStorageModeLZ4HC, kStorageModeCount; // Number of elements in enum.
public final static ArtStorageMode kDefaultStorageMode = kStorageModeUncompressed;
public final static int SIZE = 32;//bits
public static ArtStorageMode get(int value) throws UnknownArtStorageModeException {
for (ArtStorageMode mode : values()) {
if (mode.ordinal() == value) {
return mode;
}
}
throw new UnknownArtStorageModeException(value);
}
}
@@ -0,0 +1,68 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.file.formats.android.art;
import java.math.BigInteger;
import ghidra.program.model.address.Address;
import ghidra.program.model.lang.*;
import ghidra.program.model.listing.*;
public final class ArtUtilities {
static void createFragment(Program program, String fragmentName, Address start,
Address end) throws Exception {
ProgramModule module = program.getListing().getRootModule(0);
ProgramFragment fragment = getFragment(module, fragmentName);
if (fragment == null) {
fragment = module.createFragment(fragmentName);
}
fragment.move(start, end.subtract(1));
}
static ProgramFragment getFragment(ProgramModule module, String fragmentName) {
Group[] groups = module.getChildren();
for (Group group : groups) {
if (group.getName().equals(fragmentName)) {
return (ProgramFragment) group;
}
}
return null;
}
public static Address adjustForThumbAsNeeded(ArtHeader artHeader, Program program,
Address address) {
long displacement = address.getOffset();
if (program.getLanguage()
.getProcessor()
.equals(Processor.findOrPossiblyCreateProcessor("ARM"))) {
if ((displacement & 0x1) == 0x1) {//thumb code?
address = address.subtract(1);
Register register = program.getLanguage().getRegister("TMode");
RegisterValue value = new RegisterValue(register, BigInteger.valueOf(1));
try {
program.getProgramContext().setRegisterValue(address, address, value);
}
catch (ContextChangeException e) {
//log.appendException( e );
//ignore...
}
}
}
return address;
}
}
@@ -0,0 +1,26 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.file.formats.android.art;
import java.io.IOException;
public class UnknownArtStorageModeException extends IOException {
public UnknownArtStorageModeException(int storageMode) {
super("Unrecognized storage mode: 0x" + Integer.toHexString(storageMode));
}
}
@@ -0,0 +1,23 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.file.formats.android.art;
final class UnsupportedArtVersionException extends Exception {
UnsupportedArtVersionException(String magic, String version) {
super("Unsupported ART version: " + version);
}
}
@@ -0,0 +1,234 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.file.formats.android.art.android10;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import ghidra.app.util.bin.BinaryReader;
import ghidra.app.util.bin.StructConverterUtil;
import ghidra.file.formats.android.art.*;
import ghidra.file.formats.android.util.DecompressionManager;
import ghidra.program.model.data.DataType;
import ghidra.program.model.data.Structure;
import ghidra.program.model.listing.Program;
import ghidra.util.InvalidNameException;
import ghidra.util.exception.DuplicateNameException;
import ghidra.util.task.TaskMonitor;
/**
* https://android.googlesource.com/platform/art/+/refs/heads/android10-release/runtime/image.h
*/
public class ArtHeader_10 extends ArtHeader {
private int image_reservation_size_;
private int component_count_;
private int image_begin_;
private int image_size_;
private int image_checksum_;
private int oat_checksum_;
private int oat_file_begin_;
private int oat_data_begin_;
private int oat_data_end_;
private int oat_file_end_;
private int boot_image_begin_;
private int boot_image_size_;
private int image_roots_;
private int pointer_size_;
private long[] image_methods_ = new long[ImageMethod_10.kImageMethodsCount.ordinal()];
private int data_size_;
private int blocks_offset_;
private int blocks_count_;
private List<ArtBlock> blocks = new ArrayList<>();
private ArtImageSections sections;
public ArtHeader_10(BinaryReader reader) throws IOException {
super(reader);
parse(reader);
}
@Override
protected void parse(BinaryReader reader) throws IOException {
image_reservation_size_ = reader.readNextInt();
component_count_ = reader.readNextInt();
image_begin_ = reader.readNextInt();
image_size_ = reader.readNextInt();
image_checksum_ = reader.readNextInt();
oat_checksum_ = reader.readNextInt();
oat_file_begin_ = reader.readNextInt();
oat_data_begin_ = reader.readNextInt();
oat_data_end_ = reader.readNextInt();
oat_file_end_ = reader.readNextInt();
boot_image_begin_ = reader.readNextInt();
boot_image_size_ = reader.readNextInt();
image_roots_ = reader.readNextInt();
pointer_size_ = reader.readNextInt();
sections = new ImageSections_10(reader, this);
sections.parseSections(reader);
parseImageMethods(reader);
data_size_ = reader.readNextInt();
blocks_offset_ = reader.readNextInt();
blocks_count_ = reader.readNextInt();
if (blocks_offset_ > 0 && blocks_count_ > 0) {
reader.setPointerIndex(blocks_offset_);
for (int i = 0; i < blocks_count_; ++i) {
blocks.add(new ArtBlock(reader));
}
}
reader = DecompressionManager.decompress(reader, blocks, TaskMonitor.DUMMY);
// NOTE:
// cannot parse the sections until after the blocks are decompressed!
sections.parse(reader);
}
@Override
public int getArtMethodCountForVersion() {
return ImageMethod_10.kImageMethodsCount.ordinal();
}
@Override
public int getImageBegin() {
return image_begin_;
}
@Override
public int getImageSize() {
return image_size_;
}
public int getImageChecksum_() {
return image_checksum_;
}
@Override
public int getOatChecksum() {
return oat_checksum_;
}
@Override
public int getOatDataBegin() {
return oat_data_begin_;
}
@Override
public int getOatDataEnd() {
return oat_data_end_;
}
@Override
public int getOatFileBegin() {
return oat_file_begin_;
}
@Override
public int getOatFileEnd() {
return oat_file_end_;
}
@Override
public int getPointerSize() {
return pointer_size_;
}
public int getBootImageBegin() {
return boot_image_begin_;
}
/**
* App images currently require a boot image,
* if the size is non zero then it is an app image header.
* @return true if this header represents an app image
*/
public boolean isAppImage() {
return boot_image_size_ != 0x0;
}
public int getImageReservationSize() {
return image_reservation_size_;
}
public int getComponentCount() {
return component_count_;
}
public int getImageRoots() {
return image_roots_;
}
public int getDataSize() {
return data_size_;
}
public List<ArtBlock> getBlocks() {
return blocks;
}
@Override
public void markup(Program program, TaskMonitor monitor) throws Exception {
DecompressionManager.decompressOverMemory(program, blocks, monitor);
sections.markup(program, monitor);
}
@Override
public DataType toDataType() throws DuplicateNameException, IOException {
Structure structure = (Structure) super.toDataType();
String className = StructConverterUtil.parseName(ArtHeader_10.class);
try {
structure.setName(className);
}
catch (InvalidNameException e) {
//ignore, just use original name should this fail
}
structure.add(DWORD, "image_reservation_size_", null);
structure.add(DWORD, "component_count_", null);
structure.add(DWORD, "image_begin_", null);
structure.add(DWORD, "image_size_", null);
structure.add(DWORD, "image_checksum_", null);
structure.add(DWORD, "oat_checksum_", null);
structure.add(DWORD, "oat_file_begin_", null);
structure.add(DWORD, "oat_data_begin_", null);
structure.add(DWORD, "oat_data_end_", null);
structure.add(DWORD, "oat_file_end_", null);
structure.add(DWORD, "boot_image_begin_", null);
structure.add(DWORD, "boot_image_size_", null);
structure.add(DWORD, "image_roots_", null);
structure.add(DWORD, "pointer_size_", null);
for (int i = 0; i < sections.getSectionList().size(); ++i) {
structure.add(sections.getSectionList().get(i).toDataType(), "section_" + i, null);
}
for (int i = 0; i < image_methods_.length; ++i) {
structure.add(QWORD, "image_method_" + i, null);
}
structure.add(DWORD, "data_size_", null);
structure.add(DWORD, "blocks_offset_", null);
structure.add(DWORD, "blocks_count_", null);
return structure;
}
}
@@ -0,0 +1,32 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.file.formats.android.art.android10;
/**
* https://android.googlesource.com/platform/art/+/refs/heads/android10-release/runtime/image.h
*/
public enum ImageMethod_10 {
kResolutionMethod,
kImtConflictMethod,
kImtUnimplementedMethod,
kSaveAllCalleeSavesMethod,
kSaveRefsOnlyMethod,
kSaveRefsAndArgsMethod,
kSaveEverythingMethod,
kSaveEverythingMethodForClinit,
kSaveEverythingMethodForSuspendCheck,
kImageMethodsCount, // Number of elements in enum.
}
@@ -0,0 +1,43 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.file.formats.android.art.android10;
/**
* https://android.googlesource.com/platform/art/+/refs/heads/android10-release/runtime/image.h
*/
public enum ImageRoot_10 {
kDexCaches,
kClassRoots,
/** Pre-allocated OOME when throwing exception.*/
kOomeWhenThrowingException,
/** Pre-allocated OOME when throwing OOME. */
kOomeWhenThrowingOome,
/** Pre-allocated OOME when handling StackOverflowError. */
kOomeWhenHandlingStackOverflow,
/** Pre-allocated NoClassDefFoundError. */
kNoClassDefFoundError,
/** Different for boot image and app image, see aliases below. */
kSpecialRoots,
kImageRootsMax;
//Aliases
/** The class loader used to build the app image.*/
public final static ImageRoot_10 kAppImageClassLoader = kSpecialRoots;
/** Array of boot image objects that must be kept live. */
public final static ImageRoot_10 kBootImageLiveObjects = kSpecialRoots;
}
@@ -0,0 +1,109 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.file.formats.android.art.android10;
import ghidra.app.util.bin.BinaryReader;
import ghidra.file.formats.android.art.ArtHeader;
import ghidra.file.formats.android.art.ArtImageSections;
/**
* https://android.googlesource.com/platform/art/+/refs/heads/android10-release/runtime/image.h
*/
public class ImageSections_10 extends ArtImageSections {
public final static int kSectionObjects = 0;
public final static int kSectionArtFields = 1;
public final static int kSectionArtMethods = 2;
public final static int kSectionRuntimeMethods = 3;
public final static int kSectionImTables = 4;
public final static int kSectionIMTConflictTables = 5;
public final static int kSectionDexCacheArrays = 6;
public final static int kSectionInternedStrings = 7;
public final static int kSectionClassTable = 8;
public final static int kSectionStringReferenceOffsets = 9;
public final static int kSectionMetadata = 10;
public final static int kSectionImageBitmap = 11;
public final static int kSectionCount = 12; // Number of elements in enum.
public ImageSections_10(BinaryReader reader, ArtHeader header) {
super(reader, header);
}
@Override
public int get_kSectionObjects() {
return kSectionObjects;
}
@Override
public int get_kSectionArtFields() {
return kSectionArtFields;
}
@Override
public int get_kSectionArtMethods() {
return kSectionArtMethods;
}
@Override
public int get_kSectionRuntimeMethods() {
return kSectionRuntimeMethods;
}
@Override
public int get_kSectionImTables() {
return kSectionImTables;
}
@Override
public int get_kSectionIMTConflictTables() {
return kSectionIMTConflictTables;
}
@Override
public int get_kSectionDexCacheArrays() {
return kSectionDexCacheArrays;
}
@Override
public int get_kSectionInternedStrings() {
return kSectionInternedStrings;
}
@Override
public int get_kSectionClassTable() {
return kSectionClassTable;
}
@Override
public int get_kSectionStringReferenceOffsets() {
return kSectionStringReferenceOffsets;
}
@Override
public int get_kSectionMetadata() {
return kSectionMetadata;
}
@Override
public int get_kSectionImageBitmap() {
return kSectionImageBitmap;
}
@Override
public int get_kSectionCount() {
return kSectionCount;
}
}
@@ -0,0 +1,250 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.file.formats.android.art.android11;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import ghidra.app.util.bin.BinaryReader;
import ghidra.app.util.bin.StructConverterUtil;
import ghidra.file.formats.android.art.*;
import ghidra.file.formats.android.art.android10.ImageMethod_10;
import ghidra.file.formats.android.art.android10.ImageSections_10;
import ghidra.file.formats.android.util.DecompressionManager;
import ghidra.program.model.data.DataType;
import ghidra.program.model.data.Structure;
import ghidra.program.model.listing.Program;
import ghidra.util.InvalidNameException;
import ghidra.util.exception.DuplicateNameException;
import ghidra.util.task.TaskMonitor;
/**
* https://android.googlesource.com/platform/art/+/refs/heads/android10-release/runtime/image.h
*/
public class ArtHeader_11 extends ArtHeader {
private int image_reservation_size_;
private int component_count_;
private int image_begin_;
private int image_size_;
private int image_checksum_;
private int oat_checksum_;
private int oat_file_begin_;
private int oat_data_begin_;
private int oat_data_end_;
private int oat_file_end_;
private int boot_image_begin_;
private int boot_image_size_;
private int boot_image_component_count_;
private int boot_image_checksum_;
private int image_roots_;
private int pointer_size_;
private long[] image_methods_ = new long[ImageMethod_10.kImageMethodsCount.ordinal()];
private int data_size_;
private int blocks_offset_;
private int blocks_count_;
private List<ArtBlock> blocks = new ArrayList<>();
private ArtImageSections sections;
public ArtHeader_11(BinaryReader reader) throws IOException {
super(reader);
parse(reader);
}
@Override
protected void parse(BinaryReader reader) throws IOException {
image_reservation_size_ = reader.readNextInt();
component_count_ = reader.readNextInt();
image_begin_ = reader.readNextInt();
image_size_ = reader.readNextInt();
image_checksum_ = reader.readNextInt();
oat_checksum_ = reader.readNextInt();
oat_file_begin_ = reader.readNextInt();
oat_data_begin_ = reader.readNextInt();
oat_data_end_ = reader.readNextInt();
oat_file_end_ = reader.readNextInt();
boot_image_begin_ = reader.readNextInt();
boot_image_size_ = reader.readNextInt();
boot_image_component_count_ = reader.readNextInt();
boot_image_checksum_ = reader.readNextInt();
image_roots_ = reader.readNextInt();
pointer_size_ = reader.readNextInt();
sections = new ImageSections_10(reader, this);
sections.parseSections(reader);
parseImageMethods(reader);
data_size_ = reader.readNextInt();
blocks_offset_ = reader.readNextInt();
blocks_count_ = reader.readNextInt();
if (blocks_offset_ > 0 && blocks_count_ > 0) {
reader.setPointerIndex(blocks_offset_);
for (int i = 0; i < blocks_count_; ++i) {
blocks.add(new ArtBlock(reader));
}
}
reader = DecompressionManager.decompress(reader, blocks, TaskMonitor.DUMMY);
// NOTE:
// cannot parse the sections until after the blocks are decompressed!
sections.parse(reader);
}
@Override
public int getArtMethodCountForVersion() {
return ImageMethod_10.kImageMethodsCount.ordinal();
}
@Override
public int getImageBegin() {
return image_begin_;
}
@Override
public int getImageSize() {
return image_size_;
}
public int getImageChecksum_() {
return image_checksum_;
}
@Override
public int getOatChecksum() {
return oat_checksum_;
}
@Override
public int getOatDataBegin() {
return oat_data_begin_;
}
@Override
public int getOatDataEnd() {
return oat_data_end_;
}
@Override
public int getOatFileBegin() {
return oat_file_begin_;
}
@Override
public int getOatFileEnd() {
return oat_file_end_;
}
@Override
public int getPointerSize() {
return pointer_size_;
}
public int getBootImageBegin() {
return boot_image_begin_;
}
public int getBootImageComponentCount() {
return boot_image_component_count_;
}
public int getBootImageChecksum() {
return boot_image_checksum_;
}
/**
* App images currently require a boot image,
* if the size is non zero then it is an app image header.
* @return true if app image
*/
public boolean isAppImage() {
return boot_image_size_ != 0x0;
}
public int getImageReservationSize() {
return image_reservation_size_;
}
public int getComponentCount() {
return component_count_;
}
public int getImageRoots() {
return image_roots_;
}
public int getDataSize() {
return data_size_;
}
public List<ArtBlock> getBlocks() {
return blocks;
}
@Override
public void markup(Program program, TaskMonitor monitor) throws Exception {
DecompressionManager.decompressOverMemory(program, blocks, monitor);
sections.markup(program, monitor);
}
@Override
public DataType toDataType() throws DuplicateNameException, IOException {
Structure structure = (Structure) super.toDataType();
String className = StructConverterUtil.parseName(ArtHeader_11.class);
try {
structure.setName(className);
}
catch (InvalidNameException e) {
//ignore
}
structure.add(DWORD, "image_reservation_size_", null);
structure.add(DWORD, "component_count_", null);
structure.add(DWORD, "image_begin_", null);
structure.add(DWORD, "image_size_", null);
structure.add(DWORD, "image_checksum_", null);
structure.add(DWORD, "oat_checksum_", null);
structure.add(DWORD, "oat_file_begin_", null);
structure.add(DWORD, "oat_data_begin_", null);
structure.add(DWORD, "oat_data_end_", null);
structure.add(DWORD, "oat_file_end_", null);
structure.add(DWORD, "boot_image_begin_", null);
structure.add(DWORD, "boot_image_size_", null);
structure.add(DWORD, "boot_image_component_count_", null);
structure.add(DWORD, "boot_image_checksum_", null);
structure.add(DWORD, "image_roots_", null);
structure.add(DWORD, "pointer_size_", null);
for (int i = 0; i < sections.getSectionList().size(); ++i) {
structure.add(sections.getSectionList().get(i).toDataType(), "section_" + i, null);
}
for (int i = 0; i < image_methods_.length; ++i) {
structure.add(QWORD, "image_method_" + i, null);
}
structure.add(DWORD, "data_size_", null);
structure.add(DWORD, "blocks_offset_", null);
structure.add(DWORD, "blocks_count_", null);
return structure;
}
}
@@ -0,0 +1,34 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.file.formats.android.art.android11;
/**
* https://android.googlesource.com/platform/art/+/refs/heads/android11-release/runtime/image.h
*/
public enum BootImageLiveObjects {
/** Pre-allocated OOME when throwing exception. */
kOomeWhenThrowingException,
/** Pre-allocated OOME when throwing OOME. */
kOomeWhenThrowingOome,
/** Pre-allocated OOME when handling StackOverflowError. */
kOomeWhenHandlingStackOverflow,
/** Pre-allocated NoClassDefFoundError. */
kNoClassDefFoundError,
/** Pre-allocated sentinel for cleared weak JNI references. */
kClearedJniWeakSentinel,
kIntrinsicObjectsStart;
}
@@ -0,0 +1,31 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.file.formats.android.art.android11;
/**
* https://android.googlesource.com/platform/art/+/refs/heads/android11-release/runtime/image.h
*/
public enum ImageRoot_11 {
kDexCaches, kClassRoots, kSpecialRoots, kImageRootsMax;
//Aliases
/** The class loader used to build the app image.*/
public final static ImageRoot_11 kAppImageClassLoader = kSpecialRoots;
/** Array of boot image objects that must be kept live. */
public final static ImageRoot_11 kBootImageLiveObjects = kSpecialRoots;
}
@@ -0,0 +1,176 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.file.formats.android.art.kitkat;
import java.io.IOException;
import ghidra.app.util.bin.BinaryReader;
import ghidra.app.util.bin.StructConverterUtil;
import ghidra.file.formats.android.art.ArtHeader;
import ghidra.program.model.data.DataType;
import ghidra.program.model.data.Structure;
import ghidra.program.model.listing.Program;
import ghidra.util.InvalidNameException;
import ghidra.util.exception.DuplicateNameException;
import ghidra.util.task.TaskMonitor;
/**
* @see https://android.googlesource.com/platform/art/+/refs/heads/kitkat-release/runtime/image.cc
*/
public class ArtHeader_KitKat extends ArtHeader {
protected int image_begin_;
protected int image_size_;
protected int image_bitmap_offset_;
protected int image_bitmap_size_;
protected int oat_checksum_;
protected int oat_file_begin_;
protected int oat_data_begin_;
protected int oat_data_end_;
protected int oat_file_end_;
protected int image_roots_;
public ArtHeader_KitKat(BinaryReader reader) throws IOException {
super(reader);
parse(reader);
}
@Override
protected void parse(BinaryReader reader) throws IOException {
image_begin_ = reader.readNextInt();
image_size_ = reader.readNextInt();
image_bitmap_offset_ = reader.readNextInt();
image_bitmap_size_ = reader.readNextInt();
oat_checksum_ = reader.readNextInt();
oat_file_begin_ = reader.readNextInt();
oat_data_begin_ = reader.readNextInt();
oat_data_end_ = reader.readNextInt();
oat_file_end_ = reader.readNextInt();
image_roots_ = reader.readNextInt();
}
@Override
public int getImageBegin() {
return image_begin_;
}
@Override
public int getImageSize() {
return image_size_;
}
/**
* Image bitmap offset in the file.
*/
public int getImageBitmapOffset() {
return image_bitmap_offset_;
}
/**
* Size of the image bitmap.
*/
public int getImageBitmapSize() {
return image_bitmap_size_;
}
/**
* Checksum of the oat file we link to for load time sanity check.
*/
public int getOatChecksum() {
return oat_checksum_;
}
/**
* Start address for oat file. Will be before oat_data_begin_ for .so files.
*/
@Override
public int getOatFileBegin() {
return oat_file_begin_;
}
/**
* Required oat address expected by image Method::GetCode() pointers.
*/
@Override
public int getOatDataBegin() {
return oat_data_begin_;
}
/**
* End of oat data address range for this image file.
*/
@Override
public int getOatDataEnd() {
return oat_data_end_;
}
/**
* End of oat file address range. will be after oat_data_end_ for
* .so files. Used for positioning a following alloc spaces.
*/
@Override
public int getOatFileEnd() {
return oat_file_end_;
}
/**
* Absolute address of an Object[] of objects needed to reinitialize from an image.
*/
public int getImageRoots() {
return image_roots_;
}
@Override
public int getPointerSize() {
return -1; //unsupported
}
@Override
public void markup(Program program, TaskMonitor monitor) throws Exception {
//do nothing for now
}
@Override
public int getArtMethodCountForVersion() {
throw new UnsupportedOperationException();
}
@Override
public DataType toDataType() throws DuplicateNameException, IOException {
Structure structure = (Structure) super.toDataType();
String className = StructConverterUtil.parseName(ArtHeader_KitKat.class);
try {
structure.setName(className);
}
catch (InvalidNameException e) {
}
structure.add(DWORD, "image_begin_", null);
structure.add(DWORD, "image_size_", null);
structure.add(DWORD, "image_bitmap_offset_", null);
structure.add(DWORD, "image_bitmap_size_", null);
structure.add(DWORD, "oat_checksum_", null);
structure.add(DWORD, "oat_file_begin_", null);
structure.add(DWORD, "oat_data_begin_", null);
structure.add(DWORD, "oat_data_end_", null);
structure.add(DWORD, "oat_file_end_", null);
structure.add(DWORD, "image_roots_", null);
return structure;
}
}
@@ -0,0 +1,30 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.file.formats.android.art.kitkat;
/**
* @see https://android.googlesource.com/platform/art/+/refs/heads/kitkat-release/runtime/image.h
*/
public enum ImageRoot_KitKat {
kResolutionMethod,
kCalleeSaveMethod,
kRefsOnlySaveMethod,
kRefsAndArgsSaveMethod,
kOatLocation,
kDexCaches,
kClassRoots,
kImageRootsMax,
}
@@ -0,0 +1,153 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.file.formats.android.art.lollipop;
import java.io.IOException;
import ghidra.app.util.bin.BinaryReader;
import ghidra.app.util.bin.StructConverterUtil;
import ghidra.file.formats.android.art.ArtHeader;
import ghidra.program.model.data.DataType;
import ghidra.program.model.data.Structure;
import ghidra.program.model.listing.Program;
import ghidra.util.InvalidNameException;
import ghidra.util.exception.DuplicateNameException;
import ghidra.util.task.TaskMonitor;
/**
* @see https://android.googlesource.com/platform/art/+/refs/heads/lollipop-release/runtime/image.cc
*/
public class ArtHeader_Lollipop extends ArtHeader {
protected int image_begin_;
protected int image_size_;
protected int image_bitmap_offset_;
protected int image_bitmap_size_;
protected int oat_checksum_;
protected int oat_file_begin_;
protected int oat_data_begin_;
protected int oat_data_end_;
protected int oat_file_end_;
protected int patch_delta_;
protected int image_roots_;
public ArtHeader_Lollipop(BinaryReader reader) throws IOException {
super(reader);
parse(reader);
}
@Override
protected void parse(BinaryReader reader) throws IOException {
image_begin_ = reader.readNextInt();
image_size_ = reader.readNextInt();
image_bitmap_offset_ = reader.readNextInt();
image_bitmap_size_ = reader.readNextInt();
oat_checksum_ = reader.readNextInt();
oat_file_begin_ = reader.readNextInt();
oat_data_begin_ = reader.readNextInt();
oat_data_end_ = reader.readNextInt();
oat_file_end_ = reader.readNextInt();
patch_delta_ = reader.readNextInt();
image_roots_ = reader.readNextInt();
}
@Override
public int getImageBegin() {
return image_begin_;
}
@Override
public int getImageSize() {
return image_size_;
}
/**
* The total delta that this image has been patched.
*/
public int getPatchDelta() {
return patch_delta_;
}
/**
* Checksum of the oat file we link to for load time sanity check.
*/
@Override
public int getOatChecksum() {
return oat_checksum_;
}
@Override
public int getPointerSize() {
return -1; //unsupported
}
@Override
public int getOatFileBegin() {
return oat_file_begin_;
}
@Override
public int getOatFileEnd() {
return oat_file_end_;
}
@Override
public int getOatDataBegin() {
return oat_data_begin_;
}
@Override
public int getOatDataEnd() {
return oat_data_end_;
}
@Override
public void markup(Program program, TaskMonitor monitor) throws Exception {
//do nothing for now
}
@Override
public int getArtMethodCountForVersion() {
throw new UnsupportedOperationException();
}
@Override
public DataType toDataType() throws DuplicateNameException, IOException {
Structure structure = (Structure) super.toDataType();
String className = StructConverterUtil.parseName(ArtHeader_Lollipop.class);
try {
structure.setName(className);
}
catch (InvalidNameException e) {
}
structure.add(DWORD, "image_begin_", null);
structure.add(DWORD, "image_size_", null);
structure.add(DWORD, "image_bitmap_offset_", null);
structure.add(DWORD, "image_bitmap_size_", null);
structure.add(DWORD, "oat_checksum_", null);
structure.add(DWORD, "oat_file_begin_", null);
structure.add(DWORD, "oat_data_begin_", null);
structure.add(DWORD, "oat_data_end_", null);
structure.add(DWORD, "oat_file_end_", null);
structure.add(DWORD, "patch_delta_", null);
structure.add(DWORD, "image_roots_", null);
return structure;
}
}
@@ -0,0 +1,153 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.file.formats.android.art.lollipop;
import java.io.IOException;
import ghidra.app.util.bin.BinaryReader;
import ghidra.app.util.bin.StructConverterUtil;
import ghidra.file.formats.android.art.ArtHeader;
import ghidra.program.model.data.DataType;
import ghidra.program.model.data.Structure;
import ghidra.program.model.listing.Program;
import ghidra.util.InvalidNameException;
import ghidra.util.exception.DuplicateNameException;
import ghidra.util.task.TaskMonitor;
/**
* @see https://android.googlesource.com/platform/art/+/lollipop-mr1-wfc-release/runtime/image.h
*/
public class ArtHeader_LollipopMR1WFC extends ArtHeader {
protected int image_begin_;
protected int image_size_;
protected int image_bitmap_offset_;
protected int image_bitmap_size_;
protected int oat_checksum_;
protected int oat_file_begin_;
protected int oat_data_begin_;
protected int oat_data_end_;
protected int oat_file_end_;
protected int patch_delta_;
protected int image_roots_;
protected int compile_pic_;
public ArtHeader_LollipopMR1WFC(BinaryReader reader) throws IOException {
super(reader);
parse(reader);
}
@Override
protected void parse(BinaryReader reader) throws IOException {
image_begin_ = reader.readNextInt();
image_size_ = reader.readNextInt();
image_bitmap_offset_ = reader.readNextInt();
image_bitmap_size_ = reader.readNextInt();
oat_checksum_ = reader.readNextInt();
oat_file_begin_ = reader.readNextInt();
oat_data_begin_ = reader.readNextInt();
oat_data_end_ = reader.readNextInt();
oat_file_end_ = reader.readNextInt();
patch_delta_ = reader.readNextInt();
image_roots_ = reader.readNextInt();
compile_pic_ = reader.readNextInt();
}
@Override
public int getImageBegin() {
return image_begin_;
}
@Override
public int getImageSize() {
return image_size_;
}
/**
* Boolean (0 or 1) to denote if the image was compiled with --compile-pic option.
*/
public int getCompilePic() {
return compile_pic_;
}
@Override
public int getOatChecksum() {
return oat_checksum_;
}
@Override
public int getPointerSize() {
return -1; //unsupported
}
@Override
public int getOatFileBegin() {
return oat_file_begin_;
}
@Override
public int getOatFileEnd() {
return oat_file_end_;
}
@Override
public int getOatDataBegin() {
return oat_data_begin_;
}
@Override
public int getOatDataEnd() {
return oat_data_end_;
}
@Override
public void markup(Program program, TaskMonitor monitor) throws Exception {
}
@Override
public int getArtMethodCountForVersion() {
throw new UnsupportedOperationException();
}
@Override
public DataType toDataType() throws DuplicateNameException, IOException {
Structure structure = (Structure) super.toDataType();
String className = StructConverterUtil.parseName(ArtHeader_LollipopMR1WFC.class);
try {
structure.setName(className);
}
catch (InvalidNameException e) {
}
structure.add(DWORD, "image_begin_", null);
structure.add(DWORD, "image_size_", null);
structure.add(DWORD, "image_bitmap_offset_", null);
structure.add(DWORD, "image_bitmap_size_", null);
structure.add(DWORD, "oat_checksum_", null);
structure.add(DWORD, "oat_file_begin_", null);
structure.add(DWORD, "oat_data_begin_", null);
structure.add(DWORD, "oat_data_end_", null);
structure.add(DWORD, "oat_file_end_", null);
structure.add(DWORD, "patch_delta_", null);
structure.add(DWORD, "image_roots_", null);
structure.add(DWORD, "compile_pic_", null);
return structure;
}
}
@@ -0,0 +1,31 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.file.formats.android.art.lollipop;
/**
* @see https://android.googlesource.com/platform/art/+/refs/heads/lollipop-release/runtime/image.h
*/
public enum ImageRoot_Lollipop {
kResolutionMethod,
kImtConflictMethod,
kDefaultImt,
kCalleeSaveMethod,
kRefsOnlySaveMethod,
kRefsAndArgsSaveMethod,
kDexCaches,
kClassRoots,
kImageRootsMax,
}
@@ -0,0 +1,32 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.file.formats.android.art.lollipop;
/**
* @see https://android.googlesource.com/platform/art/+/lollipop-mr1-wfc-release/runtime/image.h
*/
public enum ImageRoot_LollipopMR1WRC {
kResolutionMethod,
kImtConflictMethod,
kImtUnimplementedMethod,
kDefaultImt,
kCalleeSaveMethod,
kRefsOnlySaveMethod,
kRefsAndArgsSaveMethod,
kDexCaches,
kClassRoots,
kImageRootsMax,
}
@@ -0,0 +1,175 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.file.formats.android.art.marshmallow;
import java.io.IOException;
import ghidra.app.util.bin.BinaryReader;
import ghidra.app.util.bin.StructConverterUtil;
import ghidra.file.formats.android.art.ArtHeader;
import ghidra.file.formats.android.art.ArtImageSections;
import ghidra.program.model.data.DataType;
import ghidra.program.model.data.Structure;
import ghidra.program.model.listing.Program;
import ghidra.util.InvalidNameException;
import ghidra.util.exception.DuplicateNameException;
import ghidra.util.task.TaskMonitor;
/**
* @see https://android.googlesource.com/platform/art/+/marshmallow-release/runtime/image.h
*/
public class ArtHeader_Marshmallow extends ArtHeader {
protected int image_begin_;
protected int image_size_;
protected int oat_checksum_;
protected int oat_file_begin_;
protected int oat_data_begin_;
protected int oat_data_end_;
protected int oat_file_end_;
protected int patch_delta_;
protected int image_roots_;
protected int pointer_size_;
protected int compile_pic_;
protected long[] image_methods_ =
new long[ImageMethod_Marshmallow.kImageMethodsCount.ordinal()];
protected ArtImageSections sections;
public ArtHeader_Marshmallow(BinaryReader reader) throws IOException {
super(reader);
parse(reader);
}
@Override
protected void parse(BinaryReader reader) throws IOException {
image_begin_ = reader.readNextInt();
image_size_ = reader.readNextInt();
oat_checksum_ = reader.readNextInt();
oat_file_begin_ = reader.readNextInt();
oat_data_begin_ = reader.readNextInt();
oat_data_end_ = reader.readNextInt();
oat_file_end_ = reader.readNextInt();
patch_delta_ = reader.readNextInt();
image_roots_ = reader.readNextInt();
pointer_size_ = reader.readNextInt();
compile_pic_ = reader.readNextInt();
sections = new ImageSections_Marshmallow(reader, this);
sections.parseSections(reader);
for (int i = 0; i < image_methods_.length; ++i) {
image_methods_[i] = reader.readNextLong();
}
sections.parse(reader);
}
@Override
public int getImageBegin() {
return image_begin_;
}
@Override
public int getImageSize() {
return image_size_;
}
@Override
public int getPointerSize() {
return pointer_size_;
}
/**
* Image methods.
*/
public long[] getImageMethods() {
return image_methods_;
}
/**
* Checksum of the oat file we link to for load time sanity check.
*/
@Override
public int getOatChecksum() {
return oat_checksum_;
}
@Override
public int getOatFileBegin() {
return oat_file_begin_;
}
@Override
public int getOatFileEnd() {
return oat_file_end_;
}
@Override
public int getOatDataBegin() {
return oat_data_begin_;
}
@Override
public int getOatDataEnd() {
return oat_data_end_;
}
@Override
public void markup(Program program, TaskMonitor monitor) throws Exception {
sections.markup(program, monitor);
}
@Override
public int getArtMethodCountForVersion() {
throw new UnsupportedOperationException();
}
@Override
public DataType toDataType() throws DuplicateNameException, IOException {
Structure structure = (Structure) super.toDataType();
String className = StructConverterUtil.parseName(ArtHeader_Marshmallow.class);
try {
structure.setName(className);
}
catch (InvalidNameException e) {
}
structure.add(DWORD, "image_begin_", null);
structure.add(DWORD, "image_size_", null);
structure.add(DWORD, "oat_checksum_", null);
structure.add(DWORD, "oat_file_begin_", null);
structure.add(DWORD, "oat_data_begin_", null);
structure.add(DWORD, "oat_data_end_", null);
structure.add(DWORD, "oat_file_end_", null);
structure.add(DWORD, "patch_delta_", null);
structure.add(DWORD, "image_roots_", null);
structure.add(DWORD, "pointer_size_", null);
structure.add(DWORD, "compile_pic_", null);
for (int i = 0; i < sections.getSectionList().size(); ++i) {
structure.add(sections.getSectionList().get(i).toDataType(), "section_" + i, null);
}
for (int i = 0; i < image_methods_.length; ++i) {
structure.add(QWORD, "image_method_" + i, null);
}
return structure;
}
}
@@ -0,0 +1,29 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.file.formats.android.art.marshmallow;
/**
* https://android.googlesource.com/platform/art/+/refs/heads/pie-release/runtime/image.h
*/
public enum ImageMethod_Marshmallow {
kResolutionMethod,
kImtConflictMethod,
kImtUnimplementedMethod,
kCalleeSaveMethod,
kRefsOnlySaveMethod,
kRefsAndArgsSaveMethod,
kImageMethodsCount, // Number of elements in enum.
}
@@ -0,0 +1,31 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.file.formats.android.art.marshmallow;
/**
* @see https://android.googlesource.com/platform/art/+/marshmallow-release/runtime/image.h
*/
public enum ImageRoot_Marshmallow {
kResolutionMethod,
kImtConflictMethod,
kDefaultImt,
kCalleeSaveMethod,
kRefsOnlySaveMethod,
kRefsAndArgsSaveMethod,
kDexCaches,
kClassRoots,
kImageRootsMax,
}
@@ -0,0 +1,98 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.file.formats.android.art.marshmallow;
import ghidra.app.util.bin.BinaryReader;
import ghidra.file.formats.android.art.ArtHeader;
import ghidra.file.formats.android.art.ArtImageSections;
public class ImageSections_Marshmallow extends ArtImageSections {
public final static int kSectionObjects = 0;
public final static int kSectionArtFields = 1;
public final static int kSectionArtMethods = 2;
public final static int kSectionInternedStrings = 3;
public final static int kSectionImageBitmap = 4;
public final static int kSectionCount = 5; // Number of elements in enum.
public ImageSections_Marshmallow(BinaryReader reader, ArtHeader header) {
super(reader, header);
}
@Override
public int get_kSectionObjects() {
return kSectionObjects;
}
@Override
public int get_kSectionArtFields() {
return kSectionArtFields;
}
@Override
public int get_kSectionArtMethods() {
return kSectionArtMethods;
}
@Override
public int get_kSectionRuntimeMethods() {
return UNSUPPORTED_SECTION;
}
@Override
public int get_kSectionImTables() {
return UNSUPPORTED_SECTION;
}
@Override
public int get_kSectionIMTConflictTables() {
return UNSUPPORTED_SECTION;
}
@Override
public int get_kSectionDexCacheArrays() {
return UNSUPPORTED_SECTION;
}
@Override
public int get_kSectionInternedStrings() {
return kSectionInternedStrings;
}
@Override
public int get_kSectionClassTable() {
return UNSUPPORTED_SECTION;
}
@Override
public int get_kSectionStringReferenceOffsets() {
return UNSUPPORTED_SECTION;
}
@Override
public int get_kSectionMetadata() {
return UNSUPPORTED_SECTION;
}
@Override
public int get_kSectionImageBitmap() {
return kSectionImageBitmap;
}
@Override
public int get_kSectionCount() {
return kSectionCount;
}
}
@@ -0,0 +1,251 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.file.formats.android.art.nougat;
import java.io.IOException;
import ghidra.app.util.bin.BinaryReader;
import ghidra.app.util.bin.StructConverterUtil;
import ghidra.file.formats.android.art.*;
import ghidra.file.formats.android.util.DecompressionManager;
import ghidra.program.model.data.DataType;
import ghidra.program.model.data.Structure;
import ghidra.program.model.listing.Program;
import ghidra.util.InvalidNameException;
import ghidra.util.exception.DuplicateNameException;
import ghidra.util.task.TaskMonitor;
/**
* https://android.googlesource.com/platform/art/+/nougat-release/runtime/image.h
* https://android.googlesource.com/platform/art/+/nougat-release/runtime/image.cc
*/
public class ArtHeader_Nougat extends ArtHeader implements ArtCompression {
protected int image_begin_;
protected int image_size_;
protected int oat_checksum_;
protected int oat_file_begin_;
protected int oat_data_begin_;
protected int oat_data_end_;
protected int oat_file_end_;
protected int boot_image_begin_;
protected int boot_image_size_;
protected int boot_oat_begin_;
protected int boot_oat_size_;
protected int patch_delta_;
protected int image_roots_;
protected int pointer_size_;
protected int compile_pic_;
protected int is_pic_;
protected int storage_mode_;
protected int data_size_;
protected ArtImageSections sections;
private long _compressedOffset;
public ArtHeader_Nougat(BinaryReader reader) throws IOException {
super(reader);
parse(reader);
}
protected ArtImageSections getImageSections(BinaryReader reader) {
return new ImageSections_Nougat(reader, this);
}
@Override
protected void parse(BinaryReader reader) throws IOException {
image_begin_ = reader.readNextInt();
image_size_ = reader.readNextInt();
oat_checksum_ = reader.readNextInt();
oat_file_begin_ = reader.readNextInt();
oat_data_begin_ = reader.readNextInt();
oat_data_end_ = reader.readNextInt();
oat_file_end_ = reader.readNextInt();
boot_image_begin_ = reader.readNextInt();
boot_image_size_ = reader.readNextInt();
boot_oat_begin_ = reader.readNextInt();
boot_oat_size_ = reader.readNextInt();
patch_delta_ = reader.readNextInt();
image_roots_ = reader.readNextInt();
pointer_size_ = reader.readNextInt();
compile_pic_ = reader.readNextInt();
is_pic_ = reader.readNextInt();
sections = getImageSections(reader);
sections.parseSections(reader);
parseImageMethods(reader);
storage_mode_ = reader.readNextInt();
data_size_ = reader.readNextInt();
//The compressed offset is immediately following this header.
_compressedOffset = reader.getPointerIndex();
reader = DecompressionManager.decompress(reader, this, TaskMonitor.DUMMY);
sections.parse(reader);
}
@Override
public int getArtMethodCountForVersion() {
return ImageMethod_Nougat.kImageMethodsCount.ordinal();
}
@Override
public int getImageBegin() {
return image_begin_;
}
@Override
public int getImageSize() {
return image_size_;
}
/**
* Boot oat begin and end (app image headers only).
* @return the boot oat begin address
*/
public int getBootOatBegin() {
return boot_oat_begin_;
}
/**
* Boot oat begin and end (app image headers only).
* @return the boot oat size
*/
public int getBootOatSize() {
return boot_oat_size_;
}
@Override
public int getOatFileBegin() {
return oat_file_begin_;
}
@Override
public int getOatFileEnd() {
return oat_file_end_;
}
@Override
public int getOatDataBegin() {
return oat_data_begin_;
}
@Override
public int getOatDataEnd() {
return oat_data_end_;
}
/**
* Boolean (0 or 1) to denote if the image can be mapped at a random address,
* this only refers to the .art file.
* Currently, app oat files do not depend on their app image.
* There are no pointers from the app oat code to the app image.
* @return true of position independent code, or false if dependent.
*/
public int getIsPic() {
return is_pic_;
}
@Override
public ArtStorageMode getStorageMode() throws UnknownArtStorageModeException {
return ArtStorageMode.get(storage_mode_);
}
@Override
public long getCompressedOffset() {
return _compressedOffset;
}
@Override
public int getCompressedSize() {
return data_size_;
}
@Override
public long getDecompressedOffset() {
return getCompressedOffset();
}
@Override
public int getDecompressedSize() {
return image_size_;
}
/**
* Checksum of the oat file we link to for load time sanity check.
*/
@Override
public int getOatChecksum() {
return oat_checksum_;
}
@Override
public int getPointerSize() {
return pointer_size_;
}
@Override
public void markup(Program program, TaskMonitor monitor) throws Exception {
DecompressionManager.decompressOverMemory(program, this, monitor);
sections.markup(program, monitor);
}
@Override
public DataType toDataType() throws DuplicateNameException, IOException {
Structure structure = (Structure) super.toDataType();
String className = StructConverterUtil.parseName(ArtHeader_Nougat.class);
try {
structure.setName(className);
}
catch (InvalidNameException e) {
//ignore, just use original name should this fail
}
structure.add(DWORD, "image_begin_", null);
structure.add(DWORD, "image_size_", null);
structure.add(DWORD, "oat_checksum_", null);
structure.add(DWORD, "oat_file_begin_", null);
structure.add(DWORD, "oat_data_begin_", null);
structure.add(DWORD, "oat_data_end_", null);
structure.add(DWORD, "oat_file_end_", null);
structure.add(DWORD, "boot_image_begin_", null);
structure.add(DWORD, "boot_image_size_", null);
structure.add(DWORD, "boot_oat_begin_", null);
structure.add(DWORD, "boot_oat_size_", null);
structure.add(DWORD, "patch_delta_", null);
structure.add(DWORD, "image_roots_", null);
structure.add(DWORD, "pointer_size_", null);
structure.add(DWORD, "compile_pic_", null);
structure.add(DWORD, "is_pic_", null);
for (int i = 0; i < sections.getSectionList().size(); ++i) {
structure.add(sections.getSectionList().get(i).toDataType(), "section_" + i, null);
}
for (int i = 0; i < imageMethodsList.size(); ++i) {
structure.add(QWORD, "image_method_" + i, null);
}
structure.add(DWORD, "storage_mode_", null);
structure.add(DWORD, "data_size_", null);
return structure;
}
}
@@ -0,0 +1,59 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.file.formats.android.art.nougat;
import java.io.IOException;
import ghidra.app.util.bin.BinaryReader;
import ghidra.app.util.bin.StructConverterUtil;
import ghidra.file.formats.android.art.ArtImageSections;
import ghidra.program.model.data.DataType;
import ghidra.program.model.data.Structure;
import ghidra.util.InvalidNameException;
import ghidra.util.exception.DuplicateNameException;
/**
* https://android.googlesource.com/platform/art/+/nougat-mr2-pixel-release/runtime/image.h
*/
public class ArtHeader_NougatMR2Pixel extends ArtHeader_Nougat {
public ArtHeader_NougatMR2Pixel(BinaryReader reader) throws IOException {
super(reader);
}
protected ArtImageSections getImageSections(BinaryReader reader) {
return new ImageSections_NougatMR2Pixel(reader, this);
}
@Override
public int getArtMethodCountForVersion() {
return ImageMethod_Nougat.kImageMethodsCount.ordinal();
}
@Override
public DataType toDataType() throws DuplicateNameException, IOException {
Structure structure = (Structure) super.toDataType();
String className = StructConverterUtil.parseName(ArtHeader_NougatMR2Pixel.class);
try {
structure.setName(className);
}
catch (InvalidNameException e) {
//ignore
}
return structure;
}
}
@@ -0,0 +1,29 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.file.formats.android.art.nougat;
/**
* https://android.googlesource.com/platform/art/+/refs/heads/pie-release/runtime/image.h
*/
public enum ImageMethod_Nougat {
kResolutionMethod,
kImtConflictMethod,
kImtUnimplementedMethod,
kCalleeSaveMethod,
kRefsOnlySaveMethod,
kRefsAndArgsSaveMethod,
kImageMethodsCount, // Number of elements in enum.
}
@@ -0,0 +1,23 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.file.formats.android.art.nougat;
/**
* @see https://android.googlesource.com/platform/art/+/nougat-release/runtime/image.h
*/
public enum ImageRoot_Nougat {
kDexCaches, kClassRoots, kImageRootsMax,
}
@@ -0,0 +1,102 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.file.formats.android.art.nougat;
import ghidra.app.util.bin.BinaryReader;
import ghidra.file.formats.android.art.ArtHeader;
import ghidra.file.formats.android.art.ArtImageSections;
public class ImageSections_Nougat extends ArtImageSections {
public final static int kSectionObjects = 0;
public final static int kSectionArtFields = 1;
public final static int kSectionArtMethods = 2;
public final static int kSectionRuntimeMethods = 3;
public final static int kSectionIMTConflictTables = 4;
public final static int kSectionDexCacheArrays = 5;
public final static int kSectionInternedStrings = 6;
public final static int kSectionClassTable = 7;
public final static int kSectionImageBitmap = 8;
public final static int kSectionCount = 9; // Number of elements in enum.
public ImageSections_Nougat(BinaryReader reader, ArtHeader header) {
super(reader, header);
}
@Override
public int get_kSectionObjects() {
return kSectionObjects;
}
@Override
public int get_kSectionArtFields() {
return kSectionArtFields;
}
@Override
public int get_kSectionArtMethods() {
return kSectionArtMethods;
}
@Override
public int get_kSectionRuntimeMethods() {
return kSectionRuntimeMethods;
}
@Override
public int get_kSectionImTables() {
return UNSUPPORTED_SECTION;
}
@Override
public int get_kSectionIMTConflictTables() {
return kSectionIMTConflictTables;
}
@Override
public int get_kSectionDexCacheArrays() {
return kSectionDexCacheArrays;
}
@Override
public int get_kSectionInternedStrings() {
return kSectionInternedStrings;
}
@Override
public int get_kSectionClassTable() {
return kSectionClassTable;
}
@Override
public int get_kSectionStringReferenceOffsets() {
return UNSUPPORTED_SECTION;
}
@Override
public int get_kSectionMetadata() {
return UNSUPPORTED_SECTION;
}
@Override
public int get_kSectionImageBitmap() {
return kSectionImageBitmap;
}
@Override
public int get_kSectionCount() {
return kSectionCount;
}
}
@@ -0,0 +1,103 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.file.formats.android.art.nougat;
import ghidra.app.util.bin.BinaryReader;
import ghidra.file.formats.android.art.ArtHeader;
import ghidra.file.formats.android.art.ArtImageSections;
public class ImageSections_NougatMR2Pixel extends ArtImageSections {
public final static int kSectionObjects = 0;
public final static int kSectionArtFields = 1;
public final static int kSectionArtMethods = 2;
public final static int kSectionRuntimeMethods = 3;
public final static int kSectionImTables = 4;
public final static int kSectionIMTConflictTables = 5;
public final static int kSectionDexCacheArrays = 6;
public final static int kSectionInternedStrings = 7;
public final static int kSectionClassTable = 8;
public final static int kSectionImageBitmap = 9;
public final static int kSectionCount = 10; // Number of elements in enum.
public ImageSections_NougatMR2Pixel(BinaryReader reader, ArtHeader header) {
super(reader, header);
}
@Override
public int get_kSectionObjects() {
return kSectionObjects;
}
@Override
public int get_kSectionArtFields() {
return kSectionArtFields;
}
@Override
public int get_kSectionArtMethods() {
return kSectionArtMethods;
}
@Override
public int get_kSectionRuntimeMethods() {
return kSectionRuntimeMethods;
}
@Override
public int get_kSectionImTables() {
return kSectionImTables;
}
@Override
public int get_kSectionIMTConflictTables() {
return kSectionIMTConflictTables;
}
@Override
public int get_kSectionDexCacheArrays() {
return kSectionDexCacheArrays;
}
@Override
public int get_kSectionInternedStrings() {
return kSectionInternedStrings;
}
@Override
public int get_kSectionClassTable() {
return kSectionClassTable;
}
@Override
public int get_kSectionStringReferenceOffsets() {
return UNSUPPORTED_SECTION;
}
@Override
public int get_kSectionMetadata() {
return UNSUPPORTED_SECTION;
}
@Override
public int get_kSectionImageBitmap() {
return kSectionImageBitmap;
}
@Override
public int get_kSectionCount() {
return kSectionCount;
}
}
@@ -0,0 +1,60 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.file.formats.android.art.oreo;
import java.io.IOException;
import ghidra.app.util.bin.BinaryReader;
import ghidra.app.util.bin.StructConverterUtil;
import ghidra.file.formats.android.art.ArtImageSections;
import ghidra.file.formats.android.art.nougat.ArtHeader_NougatMR2Pixel;
import ghidra.program.model.data.DataType;
import ghidra.program.model.data.Structure;
import ghidra.util.InvalidNameException;
import ghidra.util.exception.DuplicateNameException;
/**
* https://android.googlesource.com/platform/art/+/oreo-release/runtime/image.h
*/
public class ArtHeader_Oreo extends ArtHeader_NougatMR2Pixel {
public ArtHeader_Oreo(BinaryReader reader) throws IOException {
super(reader);
}
protected ArtImageSections getImageSections(BinaryReader reader) {
return new ImageSections_Oreo(reader, this);
}
@Override
public int getArtMethodCountForVersion() {
return ImageMethod_Oreo.kImageMethodsCount.ordinal();
}
@Override
public DataType toDataType() throws DuplicateNameException, IOException {
Structure structure = (Structure) super.toDataType();
String className = StructConverterUtil.parseName(ArtHeader_Oreo.class);
try {
structure.setName(className);
}
catch (InvalidNameException e) {
//ignore
}
return structure;
}
}
@@ -0,0 +1,59 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.file.formats.android.art.oreo;
import java.io.IOException;
import ghidra.app.util.bin.BinaryReader;
import ghidra.app.util.bin.StructConverterUtil;
import ghidra.file.formats.android.art.ArtImageSections;
import ghidra.program.model.data.DataType;
import ghidra.program.model.data.Structure;
import ghidra.util.InvalidNameException;
import ghidra.util.exception.DuplicateNameException;
/**
* https://android.googlesource.com/platform/art/+/oreo-mr1-release/runtime/image.h
*/
public class ArtHeader_OreoMR1 extends ArtHeader_Oreo {
public ArtHeader_OreoMR1(BinaryReader reader) throws IOException {
super(reader);
}
protected ArtImageSections getImageSections(BinaryReader reader) {
return new ImageSections_OreoMR1(reader, this);
}
@Override
public int getArtMethodCountForVersion() {
return ImageMethod_Oreo.kImageMethodsCount.ordinal();
}
@Override
public DataType toDataType() throws DuplicateNameException, IOException {
Structure structure = (Structure) super.toDataType();
String className = StructConverterUtil.parseName(ArtHeader_OreoMR1.class);
try {
structure.setName(className);
}
catch (InvalidNameException e) {
//ignore
}
return structure;
}
}
@@ -0,0 +1,30 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.file.formats.android.art.oreo;
/**
* https://android.googlesource.com/platform/art/+/refs/heads/oreo-release/runtime/image.h
*/
public enum ImageMethod_Oreo {
kResolutionMethod,
kImtConflictMethod,
kImtUnimplementedMethod,
kSaveAllCalleeSavesMethod,
kSaveRefsOnlyMethod,
kSaveRefsAndArgsMethod,
kSaveEverythingMethod,
kImageMethodsCount, // Number of elements in enum.
}
@@ -0,0 +1,26 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.file.formats.android.art.oreo;
/**
* https://android.googlesource.com/platform/art/+/refs/heads/oreo-release/runtime/image.h
*/
public enum ImageRoot_Oreo {
kDexCaches,
kClassRoots,
kClassLoader, // App image only.
kImageRootsMax,
}
@@ -0,0 +1,117 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.file.formats.android.art.oreo;
import ghidra.app.util.bin.BinaryReader;
import ghidra.file.formats.android.art.ArtHeader;
import ghidra.file.formats.android.art.ArtImageSections;
public class ImageSections_Oreo extends ArtImageSections {
public final static int kSectionObjects = 0;
public final static int kSectionArtFields = 1;
public final static int kSectionArtMethods = 2;
public final static int kSectionRuntimeMethods = 3;
public final static int kSectionImTables = 4;
public final static int kSectionIMTConflictTables = 5;
public final static int kSectionDexCacheArrays = 6;
public final static int kSectionInternedStrings = 7;
public final static int kSectionClassTable = 8;
public final static int kSectionImageBitmap = 9;
public final static int kSectionCount = 10; // Number of elements in enum.
enum ImageSections {
kSectionObjects,
kSectionArtFields,
kSectionArtMethods,
kSectionRuntimeMethods,
kSectionImTables,
kSectionIMTConflictTables,
kSectionDexCacheArrays,
kSectionInternedStrings,
kSectionClassTable,
kSectionImageBitmap,
kSectionCount, // Number of elements in enum.
};
public ImageSections_Oreo(BinaryReader reader, ArtHeader header) {
super(reader, header);
}
@Override
public int get_kSectionObjects() {
return kSectionObjects;
}
@Override
public int get_kSectionArtFields() {
return kSectionArtFields;
}
@Override
public int get_kSectionArtMethods() {
return kSectionArtMethods;
}
@Override
public int get_kSectionRuntimeMethods() {
return kSectionRuntimeMethods;
}
@Override
public int get_kSectionImTables() {
return UNSUPPORTED_SECTION;
}
@Override
public int get_kSectionIMTConflictTables() {
return kSectionIMTConflictTables;
}
@Override
public int get_kSectionDexCacheArrays() {
return kSectionDexCacheArrays;
}
@Override
public int get_kSectionInternedStrings() {
return kSectionInternedStrings;
}
@Override
public int get_kSectionClassTable() {
return kSectionClassTable;
}
@Override
public int get_kSectionStringReferenceOffsets() {
return UNSUPPORTED_SECTION;
}
@Override
public int get_kSectionMetadata() {
return UNSUPPORTED_SECTION;
}
@Override
public int get_kSectionImageBitmap() {
return kSectionImageBitmap;
}
@Override
public int get_kSectionCount() {
return kSectionCount;
}
}
@@ -0,0 +1,103 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.file.formats.android.art.oreo;
import ghidra.app.util.bin.BinaryReader;
import ghidra.file.formats.android.art.ArtHeader;
import ghidra.file.formats.android.art.ArtImageSections;
public class ImageSections_OreoMR1 extends ArtImageSections {
public final static int kSectionObjects = 0;
public final static int kSectionArtFields = 1;
public final static int kSectionArtMethods = 2;
public final static int kSectionRuntimeMethods = 3;
public final static int kSectionImTables = 4;
public final static int kSectionIMTConflictTables = 5;
public final static int kSectionDexCacheArrays = 6;
public final static int kSectionInternedStrings = 7;
public final static int kSectionClassTable = 8;
public final static int kSectionImageBitmap = 9;
public final static int kSectionCount = 10; // Number of elements in enum.
public ImageSections_OreoMR1(BinaryReader reader, ArtHeader header) {
super(reader, header);
}
@Override
public int get_kSectionObjects() {
return kSectionObjects;
}
@Override
public int get_kSectionArtFields() {
return kSectionArtFields;
}
@Override
public int get_kSectionArtMethods() {
return kSectionArtMethods;
}
@Override
public int get_kSectionRuntimeMethods() {
return kSectionRuntimeMethods;
}
@Override
public int get_kSectionImTables() {
return kSectionImTables;
}
@Override
public int get_kSectionIMTConflictTables() {
return kSectionIMTConflictTables;
}
@Override
public int get_kSectionDexCacheArrays() {
return kSectionDexCacheArrays;
}
@Override
public int get_kSectionInternedStrings() {
return kSectionInternedStrings;
}
@Override
public int get_kSectionClassTable() {
return kSectionClassTable;
}
@Override
public int get_kSectionStringReferenceOffsets() {
return UNSUPPORTED_SECTION;
}
@Override
public int get_kSectionMetadata() {
return UNSUPPORTED_SECTION;
}
@Override
public int get_kSectionImageBitmap() {
return kSectionImageBitmap;
}
@Override
public int get_kSectionCount() {
return kSectionCount;
}
}
@@ -0,0 +1,244 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.file.formats.android.art.pie;
import java.io.IOException;
import ghidra.app.util.bin.BinaryReader;
import ghidra.app.util.bin.StructConverterUtil;
import ghidra.file.formats.android.art.*;
import ghidra.file.formats.android.util.DecompressionManager;
import ghidra.program.model.data.DataType;
import ghidra.program.model.data.Structure;
import ghidra.program.model.listing.Program;
import ghidra.util.InvalidNameException;
import ghidra.util.exception.DuplicateNameException;
import ghidra.util.task.TaskMonitor;
/**
* https://android.googlesource.com/platform/art/+/refs/heads/pie-release/runtime/image.h
*/
public class ArtHeader_Pie extends ArtHeader implements ArtCompression {
protected int image_begin_;
protected int image_size_;
protected int oat_checksum_;
protected int oat_file_begin_;
protected int oat_data_begin_;
protected int oat_data_end_;
protected int oat_file_end_;
private int boot_image_begin_;
private int boot_image_size_;
private int boot_oat_begin_;
private int boot_oat_size_;
protected int patch_delta_;
protected int image_roots_;
protected int pointer_size_;
protected int compile_pic_;
private int is_pic_;
protected long[] image_methods_ = new long[ImageMethod_Pie.kImageMethodsCount.ordinal()];
private int storage_mode_;
private int data_size_;
private ArtImageSections sections;
private long _compressedOffset;
public ArtHeader_Pie(BinaryReader reader) throws IOException {
super(reader);
parse(reader);
}
@Override
protected void parse(BinaryReader reader) throws IOException {
image_begin_ = reader.readNextInt();
image_size_ = reader.readNextInt();
oat_checksum_ = reader.readNextInt();
oat_file_begin_ = reader.readNextInt();
oat_data_begin_ = reader.readNextInt();
oat_data_end_ = reader.readNextInt();
oat_file_end_ = reader.readNextInt();
boot_image_begin_ = reader.readNextInt();
boot_image_size_ = reader.readNextInt();
boot_oat_begin_ = reader.readNextInt();
boot_oat_size_ = reader.readNextInt();
patch_delta_ = reader.readNextInt();
image_roots_ = reader.readNextInt();
pointer_size_ = reader.readNextInt();
compile_pic_ = reader.readNextInt();
is_pic_ = reader.readNextInt();
sections = new ImageSections_Pie(reader, this);
sections.parseSections(reader);
parseImageMethods(reader);
storage_mode_ = reader.readNextInt();
data_size_ = reader.readNextInt();
_compressedOffset = reader.getPointerIndex();
reader = DecompressionManager.decompress(reader, this, TaskMonitor.DUMMY);
// NOTE:
// cannot parse the sections until after the blocks are decompressed!
sections.parse(reader);
}
@Override
public int getImageBegin() {
return image_begin_;
}
@Override
public int getImageSize() {
return image_size_;
}
@Override
public int getOatChecksum() {
return oat_checksum_;
}
@Override
public int getOatFileBegin() {
return oat_file_begin_;
}
@Override
public int getOatFileEnd() {
return oat_file_end_;
}
@Override
public int getOatDataBegin() {
return oat_data_begin_;
}
@Override
public int getOatDataEnd() {
return oat_data_end_;
}
public int getBootOatBegin() {
return boot_oat_begin_;
}
public int getBootOatSize() {
return boot_oat_size_;
}
public int getBootImageBegin() {
return boot_image_begin_;
}
public int getBootImageSize() {
return boot_image_size_;
}
public int isPIC() {
return is_pic_;
}
public int getCompilePIC() {
return compile_pic_;
}
@Override
public ArtStorageMode getStorageMode() throws UnknownArtStorageModeException {
return ArtStorageMode.get(storage_mode_);
}
@Override
public long getCompressedOffset() {
return _compressedOffset;
}
@Override
public int getCompressedSize() {
return data_size_;
}
@Override
public long getDecompressedOffset() {
return getCompressedOffset();
}
@Override
public int getDecompressedSize() {
return image_size_;
}
@Override
public int getPointerSize() {
return pointer_size_;
}
@Override
public void markup(Program program, TaskMonitor monitor) throws Exception {
DecompressionManager.decompressOverMemory(program, this, monitor);
sections.markup(program, monitor);
}
@Override
public int getArtMethodCountForVersion() {
return ImageMethod_Pie.kImageMethodsCount.ordinal();
}
@Override
public DataType toDataType() throws DuplicateNameException, IOException {
Structure structure = (Structure) super.toDataType();
String className = StructConverterUtil.parseName(ArtHeader_Pie.class);
try {
structure.setName(className);
}
catch (InvalidNameException e) {
//ignore
}
structure.add(DWORD, "image_begin_", null);
structure.add(DWORD, "image_size_", null);
structure.add(DWORD, "oat_checksum_", null);
structure.add(DWORD, "oat_file_begin_", null);
structure.add(DWORD, "oat_data_begin_", null);
structure.add(DWORD, "oat_data_end_", null);
structure.add(DWORD, "oat_file_end_", null);
structure.add(DWORD, "boot_image_begin_", null);
structure.add(DWORD, "boot_image_size_", null);
structure.add(DWORD, "boot_oat_begin_", null);
structure.add(DWORD, "boot_oat_size_", null);
structure.add(DWORD, "patch_delta_", null);
structure.add(DWORD, "image_roots_", null);
structure.add(DWORD, "pointer_size_", null);
structure.add(DWORD, "compile_pic_", null);
structure.add(DWORD, "is_pic_", null);
for (int i = 0; i < sections.getSectionList().size(); ++i) {
structure.add(sections.getSectionList().get(i).toDataType(), "section_" + i, null);
}
for (int i = 0; i < image_methods_.length; ++i) {
structure.add(QWORD, "image_method_" + i, null);
}
structure.add(DWORD, "storage_mode_", null);
structure.add(DWORD, "data_size_", null);
return structure;
}
}
@@ -0,0 +1,32 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.file.formats.android.art.pie;
/**
* https://android.googlesource.com/platform/art/+/refs/heads/pie-release/runtime/image.h
*/
public enum ImageMethod_Pie {
kResolutionMethod,
kImtConflictMethod,
kImtUnimplementedMethod,
kSaveAllCalleeSavesMethod,
kSaveRefsOnlyMethod,
kSaveRefsAndArgsMethod,
kSaveEverythingMethod,
kSaveEverythingMethodForClinit,
kSaveEverythingMethodForSuspendCheck,
kImageMethodsCount, // Number of elements in enum.
}
@@ -0,0 +1,26 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.file.formats.android.art.pie;
/**
* https://android.googlesource.com/platform/art/+/nougat-release/runtime/image.h
*/
public enum ImageRoot_Pie {
kDexCaches,
kClassRoots,
kClassLoader, // App image only.
kImageRootsMax,
}

Some files were not shown because too many files have changed in this diff Show More