/** * Writes an annotated hex dump of the given dex file to output. * * @param dexFile The dex file to dump * @param output An OutputStream to write the annotated hex dump to. The caller is responsible for closing this * when needed. * * @throws IOException */ public static void dump(@Nonnull DexBackedDexFile dexFile, @Nonnull OutputStream output) throws IOException { Writer writer = new BufferedWriter(new OutputStreamWriter(output)); try { int consoleWidth = ConsoleUtil.getConsoleWidth(); if (consoleWidth <= 0) { consoleWidth = 120; } RawDexFile rawDexFile = new RawDexFile(dexFile.getOpcodes(), dexFile); DexAnnotator annotator = new DexAnnotator(rawDexFile, consoleWidth); annotator.writeAnnotations(writer); } finally { writer.close(); } } }
public static String[] getStrings(@Nonnull RawDexFile dexFile) { MapItem mapItem = dexFile.getMapItemForSection(ItemType.STRING_ID_ITEM); if (mapItem == null) { return new String[0]; } int stringCount = mapItem.getItemCount(); String[] ret = new String[stringCount]; for (int i=0; i<stringCount; i++) { ret[i] = dexFile.getString(i); } return ret; } }
@Override protected void annotateItem(@Nonnull AnnotatedBytes out, int itemIndex, @Nullable String itemIdentity) { int itemType = dexFile.readUshort(out.getCursor()); out.annotate(2, "type = 0x%x: %s", itemType, ItemType.getItemTypeName(itemType)); out.annotate(2, "unused"); int size = dexFile.readSmallUint(out.getCursor()); out.annotate(4, "size = %d", size); int offset = dexFile.readSmallUint(out.getCursor()); out.annotate(4, "offset = 0x%x", offset); }
@Nonnull public byte[] readByteRange(int start, int length) { return Arrays.copyOfRange(getBuf(), getBaseOffset() + start, getBaseOffset() + start + length); }
@Override public void annotateItem(@Nonnull AnnotatedBytes out, int itemIndex, @Nullable String itemIdentity) { int stringDataOffset = dexFile.readSmallUint(out.getCursor()); try { String stringValue = dexFile.getString(itemIndex); out.annotate(4, "string_data_item[0x%x]: \"%s\"", stringDataOffset, StringUtils.escapeString(stringValue)); return; } catch (Exception ex) { System.err.print("Error while resolving string value at index: "); System.err.print(itemIndex); ex.printStackTrace(System.err); } out.annotate(4, "string_id_item[0x%x]", stringDataOffset); } };
public int getHeaderSize() { return dexFile.readSmallUint(HEADER_SIZE_OFFSET); }
@Override protected void annotateItem(@Nonnull AnnotatedBytes out, int itemIndex, @Nullable String itemIdentity) { int classIndex = dexFile.readSmallUint(out.getCursor()); out.annotate(4, "class_idx = %s", TypeIdItem.getReferenceAnnotation(dexFile, classIndex)); int accessFlags = dexFile.readInt(out.getCursor()); out.annotate(4, "access_flags = 0x%x: %s", accessFlags, Joiner.on('|').join(AccessFlags.getAccessFlagsForClass(accessFlags))); int superclassIndex = dexFile.readOptionalUint(out.getCursor()); out.annotate(4, "superclass_idx = %s", TypeIdItem.getOptionalReferenceAnnotation(dexFile, superclassIndex)); int interfacesOffset = dexFile.readSmallUint(out.getCursor()); out.annotate(4, "interfaces_off = %s", TypeListItem.getReferenceAnnotation(dexFile, interfacesOffset)); int sourceFileIdx = dexFile.readOptionalUint(out.getCursor()); out.annotate(4, "source_file_idx = %s", StringIdItem.getOptionalReferenceAnnotation(dexFile, sourceFileIdx)); int annotationsOffset = dexFile.readSmallUint(out.getCursor()); if (annotationsOffset == 0) { out.annotate(4, "annotations_off = annotations_directory_item[NO_OFFSET]"); int classDataOffset = dexFile.readSmallUint(out.getCursor()); if (classDataOffset == 0) { out.annotate(4, "class_data_off = class_data_item[NO_OFFSET]"); } else { out.annotate(4, "class_data_off = class_data_item[0x%x]", classDataOffset); addClassDataIdentity(classDataOffset, dexFile.getType(classIndex));
public static String[] getFields(@Nonnull RawDexFile dexFile) { MapItem mapItem = dexFile.getMapItemForSection(ItemType.FIELD_ID_ITEM); if (mapItem == null) { return new String[0]; } int fieldCount = mapItem.getItemCount(); String[] ret = new String[fieldCount]; for (int i=0; i<fieldCount; i++) { ret[i] = asString(dexFile, i); } return ret; } }
public static String[] getTypes(@Nonnull RawDexFile dexFile) { MapItem mapItem = dexFile.getMapItemForSection(ItemType.TYPE_ID_ITEM); if (mapItem == null) { return new String[0]; } int typeCount = mapItem.getItemCount(); String[] ret = new String[typeCount]; for (int i=0; i<typeCount; i++) { ret[i] = dexFile.getType(i); } return ret; } }
public void writeAnnotations(Writer out) throws IOException { List<MapItem> mapItems = dexFile.getMapItems(); // sort the map items based on the order defined by sectionAnnotationOrder Ordering<MapItem> ordering = Ordering.from(new Comparator<MapItem>() { @Override public int compare(MapItem o1, MapItem o2) { return Ints.compare(sectionAnnotationOrder.get(o1.getType()), sectionAnnotationOrder.get(o2.getType())); } }); mapItems = ordering.immutableSortedCopy(mapItems); try { for (MapItem mapItem: mapItems) { SectionAnnotator annotator = annotators.get(mapItem.getType()); annotator.annotateSection(this); } } finally { dexFile.writeAnnotations(out, this); } }
dexPool.reset(); dexPool.writeTo(dataStore); dexFile1 = new RawDexFile(Opcodes.getDefault(), dataStore.getBuffer()); dexPool.internClass(class1); dexPool.writeTo(dataStore); dexFile2 = new RawDexFile(Opcodes.getDefault(), dataStore.getBuffer()); List<MapItem> mapItems1 = dexFile1.getMapItems(); List<MapItem> mapItems2 = dexFile2.getMapItems(); for (int i=0; i<mapItems1.size(); i++) { Assert.assertEquals(mapItems1.get(i).getType(), mapItems2.get(i).getType());
magicBuilder.append((char)dexFile.readUbyte(startOffset + i)); out.annotate(4, "checksum"); out.annotate(20, "signature"); out.annotate(4, "file_size: %d", dexFile.readInt(out.getCursor())); headerSize = dexFile.readInt(out.getCursor()); out.annotate(4, "header_size: %d", headerSize); int endianTag = dexFile.readInt(out.getCursor()); out.annotate(4, "endian_tag: 0x%x (%s)", endianTag, getEndianText(endianTag)); out.annotate(4, "link_size: %d", dexFile.readInt(out.getCursor())); out.annotate(4, "link_offset: 0x%x", dexFile.readInt(out.getCursor())); out.annotate(4, "map_off: 0x%x", dexFile.readInt(out.getCursor())); out.annotate(4, "string_ids_size: %d", dexFile.readInt(out.getCursor())); out.annotate(4, "string_ids_off: 0x%x", dexFile.readInt(out.getCursor())); out.annotate(4, "type_ids_size: %d", dexFile.readInt(out.getCursor())); out.annotate(4, "type_ids_off: 0x%x", dexFile.readInt(out.getCursor())); out.annotate(4, "proto_ids_size: %d", dexFile.readInt(out.getCursor())); out.annotate(4, "proto_ids_off: 0x%x", dexFile.readInt(out.getCursor())); out.annotate(4, "field_ids_size: %d", dexFile.readInt(out.getCursor())); out.annotate(4, "field_ids_off: 0x%x", dexFile.readInt(out.getCursor()));
@Nullable public MapItem getMapItemForSection(int itemType) { for (MapItem mapItem: getMapItems()) { if (mapItem.getType() == itemType) { return mapItem; } } return null; }
public void writeAnnotations(@Nonnull Writer out, @Nonnull AnnotatedBytes annotatedBytes) throws IOException { // TODO: need to pass in the offset annotatedBytes.writeAnnotations(out, getBuf()); } }
@Override protected void annotateItem(@Nonnull AnnotatedBytes out, int itemIndex, @Nullable String itemIdentity) { int methodHandleType = dexFile.readUshort(out.getCursor()); out.annotate(2, "type = %s", MethodHandleType.toString(methodHandleType)); out.annotate(2, "unused"); int fieldOrMethodId = dexFile.readUshort(out.getCursor()); String fieldOrMethodDescriptor; switch (methodHandleType) { case MethodHandleType.STATIC_PUT: case MethodHandleType.STATIC_GET: case MethodHandleType.INSTANCE_PUT: case MethodHandleType.INSTANCE_GET: fieldOrMethodDescriptor = FieldIdItem.getReferenceAnnotation(dexFile, fieldOrMethodId); break; case MethodHandleType.INVOKE_STATIC: case MethodHandleType.INVOKE_INSTANCE: case MethodHandleType.INVOKE_CONSTRUCTOR: case MethodHandleType.INVOKE_DIRECT: case MethodHandleType.INVOKE_INTERFACE: fieldOrMethodDescriptor = MethodIdItem.getReferenceAnnotation(dexFile, fieldOrMethodId); break; default: throw new ExceptionWithContext("Invalid method handle type: %d", methodHandleType); } out.annotate(2, "field_or_method_id = %s", fieldOrMethodDescriptor); out.annotate(2, "unused"); } };
@Nonnull public byte[] getSignature() { return dexFile.readByteRange(SIGNATURE_OFFSET, SIGNATURE_SIZE); }
public int getTypeCount() { return dexFile.readSmallUint(TYPE_COUNT_OFFSET); }
@Override protected void annotateItem(@Nonnull AnnotatedBytes out, int itemIndex, @Nullable String itemIdentity) { int classIndex = dexFile.readSmallUint(out.getCursor()); out.annotate(4, "class_idx = %s", TypeIdItem.getReferenceAnnotation(dexFile, classIndex)); int accessFlags = dexFile.readInt(out.getCursor()); out.annotate(4, "access_flags = 0x%x: %s", accessFlags, Joiner.on('|').join(AccessFlags.getAccessFlagsForClass(accessFlags))); int superclassIndex = dexFile.readOptionalUint(out.getCursor()); out.annotate(4, "superclass_idx = %s", TypeIdItem.getOptionalReferenceAnnotation(dexFile, superclassIndex)); int interfacesOffset = dexFile.readSmallUint(out.getCursor()); out.annotate(4, "interfaces_off = %s", TypeListItem.getReferenceAnnotation(dexFile, interfacesOffset)); int sourceFileIdx = dexFile.readOptionalUint(out.getCursor()); out.annotate(4, "source_file_idx = %s", StringIdItem.getOptionalReferenceAnnotation(dexFile, sourceFileIdx)); int annotationsOffset = dexFile.readSmallUint(out.getCursor()); if (annotationsOffset == 0) { out.annotate(4, "annotations_off = annotations_directory_item[NO_OFFSET]"); int classDataOffset = dexFile.readSmallUint(out.getCursor()); if (classDataOffset == 0) { out.annotate(4, "class_data_off = class_data_item[NO_OFFSET]"); } else { out.annotate(4, "class_data_off = class_data_item[0x%x]", classDataOffset); addClassDataIdentity(classDataOffset, dexFile.getType(classIndex));
public static String[] getClasses(@Nonnull RawDexFile dexFile) { MapItem mapItem = dexFile.getMapItemForSection(ItemType.CLASS_DEF_ITEM); if (mapItem == null) { return new String[0]; } int classCount = mapItem.getItemCount(); String[] ret = new String[classCount]; for (int i=0; i<classCount; i++) { ret[i] = asString(dexFile, i); } return ret; } }
@Override public void annotateItem(@Nonnull AnnotatedBytes out, int itemIndex, @Nullable String itemIdentity) { int stringDataOffset = dexFile.readSmallUint(out.getCursor()); try { String stringValue = dexFile.getString(itemIndex); out.annotate(4, "string_data_item[0x%x]: \"%s\"", stringDataOffset, StringUtils.escapeString(stringValue)); return; } catch (Exception ex) { System.err.print("Error while resolving string value at index: "); System.err.print(itemIndex); ex.printStackTrace(System.err); } out.annotate(4, "string_id_item[0x%x]", stringDataOffset); } };