代码拉取完成,页面将自动刷新
//-----------------------------------
//--- 010 Editor v2.0 Binary Template
//
// File: OATTemplate.bt
// Author: tomken
// Update: liumin0
// Revision: 1.2
// Purpose: Defines a template for
// parsing OAT files.
// Support: Android L, Android M,
// Mutidex is supported too
//-----------------------------------
LittleEndian();
local char global_version[4];
#define NO_INDEX (0xFFFFFFFF)
typedef uint32 Elf32_Addr; // Program address
typedef uint32 Elf32_Off; // File offset
typedef uint16 Elf32_Half;
typedef uint32 Elf32_Word;
typedef int Elf32_Sword;
// Object file magic string.
// static const char ElfMagic[] = { 0x7f, 'E', 'L', 'F', '\0' };
// e_ident size and indices.
typedef enum <uint32> {
EI_MAG0 = 0, // File identification index.
EI_MAG1 = 1, // File identification index.
EI_MAG2 = 2, // File identification index.
EI_MAG3 = 3, // File identification index.
EI_CLASS = 4, // File class.
EI_DATA = 5, // Data encoding.
EI_VERSION = 6, // File version.
EI_OSABI = 7, // OS/ABI identification.
EI_ABIVERSION = 8, // ABI version.
EI_PAD = 9, // Start of padding bytes.
EI_NIDENT = 16 // Number of bytes in e_ident.
} EI_Type;
typedef struct {
unsigned char e_ident[EI_NIDENT]; // ELF Identification bytes
Elf32_Half e_type; // Type of file (see ET_* below)
Elf32_Half e_machine; // Required architecture for this file (see EM_*)
Elf32_Word e_version; // Must be equal to 1
Elf32_Addr e_entry; // Address to jump to in order to start program
Elf32_Off e_phoff; // Program header table's file offset, in bytes
Elf32_Off e_shoff; // Section header table's file offset, in bytes
Elf32_Word e_flags; // Processor-specific flags
Elf32_Half e_ehsize; // Size of ELF header, in bytes
Elf32_Half e_phentsize; // Size of an entry in the program header table
Elf32_Half e_phnum; // Number of entries in the program header table
Elf32_Half e_shentsize; // Size of an entry in the section header table
Elf32_Half e_shnum; // Number of entries in the section header table
Elf32_Half e_shstrndx; // Sect hdr table index of sect name string table
} Elf32_Ehdr;
// Segment types.
enum {
PT_NULL = 0, // Unused segment.
PT_LOAD = 1, // Loadable segment.
PT_DYNAMIC = 2, // Dynamic linking information.
PT_INTERP = 3, // Interpreter pathname.
PT_NOTE = 4, // Auxiliary information.
PT_SHLIB = 5, // Reserved.
PT_PHDR = 6, // The program header table itself.
PT_TLS = 7, // The thread-local storage template.
PT_LOOS = 0x60000000, // Lowest operating system-specific pt entry type.
PT_HIOS = 0x6fffffff, // Highest operating system-specific pt entry type.
PT_LOPROC = 0x70000000, // Lowest processor-specific program hdr entry type.
PT_HIPROC = 0x7fffffff, // Highest processor-specific program hdr entry type.
// x86-64 program header types.
// These all contain stack unwind tables.
PT_GNU_EH_FRAME = 0x6474e550,
PT_SUNW_EH_FRAME = 0x6474e550,
PT_SUNW_UNWIND = 0x6464e550,
PT_GNU_STACK = 0x6474e551, // Indicates stack executability.
PT_GNU_RELRO = 0x6474e552, // Read-only after relocation.
// ARM program header types.
PT_ARM_ARCHEXT = 0x70000000, // Platform architecture compatibility info
// These all contain stack unwind tables.
PT_ARM_EXIDX = 0x70000001,
PT_ARM_UNWIND = 0x70000001
};
string ReadPhdrType(Elf32_Word flag) {
switch (flag) {
case PT_NULL: return "null";
case PT_LOAD: return "load";
case PT_DYNAMIC: return "dynamic";
case PT_INTERP: return "interp";
case PT_NOTE: return "note";
case PT_SHLIB: return "shlib";
case PT_PHDR: return "phdr";
case PT_TLS: return "tls";
case PT_LOOS: return "loos";
case PT_HIOS: return "hios";
case PT_LOPROC: return "loproc";
case PT_HIPROC: return "hiproc";
}
return "ERROR";
}
// Program header for ELF32.
typedef struct {
Elf32_Word p_type <read=ReadPhdrType>; // Type of segment
Elf32_Off p_offset; // File offset where segment is located, in bytes
Elf32_Addr p_vaddr; // Virtual address of beginning of segment
Elf32_Addr p_paddr; // Physical address of beginning of segment (OS-specific)
Elf32_Word p_filesz; // Num. of bytes in file image of segment (may be zero)
Elf32_Word p_memsz; // Num. of bytes in mem image of segment (may be zero)
Elf32_Word p_flags; // Segment flags
Elf32_Word p_align; // Segment alignment constraint
} Elf32_Phdr;
local uint section_name_off = 0;
local uint dynsym_name_off = 0;
local uint oatdata_off = 0;
local uint oatexec_off = 0;
typedef struct {
Elf32_Word off;
local quad curroff = FTell();
FSeek( section_name_off + off );
string s_name_str;
FSeek( curroff );
} Elf32_Shdr_Name;
// Section header.
typedef struct {
Elf32_Word sh_name <read=ReadShdrName>; // Section name (index into string table)
Elf32_Word sh_type; // Section type (SHT_*)
Elf32_Word sh_flags; // Section flags (SHF_*)
Elf32_Addr sh_addr; // Address where section is to be loaded
Elf32_Off sh_offset; // File offset of section data, in bytes
Elf32_Word sh_size; // Size of section, in bytes
Elf32_Word sh_link; // Section type-specific header table index link
Elf32_Word sh_info; // Section type-specific extra information
Elf32_Word sh_addralign; // Section address alignment
Elf32_Word sh_entsize; // Size of records contained within the section
} Elf32_Shdr;
string ReadShdrName(Elf32_Word off) {
return ReadString(section_name_off + off);
}
string ReadDynsymName(Elf32_Word off) {
return ReadString(dynsym_name_off + off);
}
typedef struct {
Elf32_Word st_name; // Symbol name (index into string table)
Elf32_Addr st_value; // Value or address associated with the symbol
Elf32_Word st_size; // Size of the symbol
unsigned char st_info; // Symbol's type and binding attributes
unsigned char st_other; // Must be zero; reserved
Elf32_Half st_shndx; // Which section (header table index) it's defined in
} Elf32_Sym_Fixed;
typedef struct {
Elf32_Word st_name <read=ReadDynsymName>; // Symbol name (index into string table)
Elf32_Addr st_value; // Value or address associated with the symbol
Elf32_Word st_size; // Size of the symbol
unsigned char st_info; // Symbol's type and binding attributes
unsigned char st_other; // Must be zero; reserved
Elf32_Half st_shndx; // Which section (header table index) it's defined in
if (st_size) {
local quad off = FTell();
FSeek( SectionVAddrOffset(st_shndx, st_value) );
uchar data[st_size];
FSeek( off );
}
local string name = ReadDynsymName(st_name);
if (Strcmp(name, "oatdata") == 0) {
oatdata_off = SectionVAddrOffset(st_shndx, st_value);
}
} Elf32_Sym <optimize=false>;
quad SectionVAddrOffset( Elf32_Half s_index, Elf32_Addr s_vaddr ) {
if( s_index < file.elf_header.e_shnum ) {
local quad ret = file.elf_section_header[s_index].sh_offset + s_vaddr -
file.elf_section_header[s_index].sh_addr;
return ret;
}
return 0;
}
// local int iter;
int FindNamedSection( string sect ) {
local int i;
local string shdr_nn;
for(i=0; i<file.elf_header.e_shnum; i++ ) {
shdr_nn = ReadShdrName(file.elf_section_header[i].sh_name);
if( Strcmp( shdr_nn, sect ) == 0 ) {
return i;
}
}
return -1;
}
string ReadSection(Elf32_Shdr &shdr) {
// Printf("section_name_off=%x", shdr.sh_name);
return ReadShdrName(shdr.sh_name);
}
string ReadDynsymItem(Elf32_Sym &sym) {
// Printf("section_name_off=%x", shdr.sh_name);
return ReadDynsymName(sym.st_name);
}
typedef enum {
kNone,
kArm,
kThumb2,
kX86,
kMips
} InstructionSet;
/////////////////////////////////////////////////////////////////////////////////
// DexFile format
/////////////////////////////////////////////////////////////////////////////////
LittleEndian();
#define NO_INDEX (0xFFFFFFFF)
#define ENDIAN_CONSTANT (0x12345678)
#define REVERSE_ENDIAN_CONSTANT (0x78563412);
// offset used when seeking within a dex file inside of an odex wrapper
//local int odexpad = 0;
local int dexCount = 0;
local int odex = 0;
local quad dexOffs[100];
local quad defsSize[100];
local quad oatClassOffs;
// utility type to show the SHA1 hash in the value column
typedef ubyte SHA1[20] <read=SHA1Read, format=hex>;
local int warnings = 0;
local string temp_warning;
// A hack to get warning messages to both "Warn" (show in status) and output to the "output" window
void PrintWarning(string message) {
Warning(temp_warning);
// Ensure new-line, "Warning" statuses should not have them
SPrintf(temp_warning, "%s\n", message);
Printf(temp_warning);
// Hack to trigger a more generic "look at warnings in output"
warnings++;
}
string SHA1Read(SHA1 sig) {
string ret;
string tmp;
int i;
for(i = 0; i<20; i++) {
SPrintf(tmp, "%.2X", sig[i]);
ret += tmp;
}
return ret;
}
// utility for reading/checking the magic value
typedef struct {
char dex[3];
char newline;
char ver[3];
char zero;
// XXX not checking the version, but it should be 035
if((Strcmp(dex, "dex") && Strcmp(dex, "dey")) ||
newline != '\n' ||
zero != 0) {
PrintWarning("Invalid DEX file");
return -1;
}
} dex_magic <read=DexMagicRead, size=8>;
string DexMagicRead(dex_magic &m) {
string s;
SPrintf(s, "%s %s", m.dex, m.ver);
return s;
}
//////////////////////////////////////////////////
// LEB128 stuff
//////////////////////////////////////////////////
// struct to read a uleb128 value. uleb128's are a variable-length encoding for
// a 32 bit value. some of the uleb128/sleb128 code was adapted from dalvik's
// libdex/Leb128.h
typedef struct {
ubyte val <comment="uleb128 element">;
if(val > 0x7f) {
ubyte val <comment="uleb128 element">;
if (val > 0x7f) {
ubyte val <comment="uleb128 element">;
if(val > 0x7f) {
ubyte val <comment="uleb128 element">;
if(val > 0x7f) {
ubyte val <comment="uleb128 element">;
}
}
}
}
} uleb128 <read=ULeb128Read, comment="Unsigned little-endian base 128 value">;
// get the actual uint value of the uleb128
uint uleb128_value(uleb128 &u) {
local uint result;
local ubyte cur;
result = u.val[0];
if(result > 0x7f) {
cur = u.val[1];
result = (result & 0x7f) | (uint)((cur & 0x7f) << 7);
if(cur > 0x7f) {
cur = u.val[2];
result |= (uint)(cur & 0x7f) << 14;
if(cur > 0x7f) {
cur = u.val[3];
result |= (uint)(cur & 0x7f) << 21;
if(cur > 0x7f) {
cur = u.val[4];
result |= (uint)cur << 28;
}
}
}
}
return result;
}
typedef struct uleb128 uleb128p1;
int uleb128p1_value(uleb128 &u) {
return (int)uleb128_value(u) - 1;
}
string ULeb128Read(uleb128 &u) {
local string s;
s = SPrintf(s, "0x%X", uleb128_value(u));
return s;
}
// sleb128
typedef struct {
ubyte val <comment="sleb128 element">;
if(val > 0x7f) {
ubyte val <comment="sleb128 element">;
if (val > 0x7f) {
ubyte val <comment="sleb128 element">;
if(val > 0x7f) {
ubyte val <comment="sleb128 element">;
if(val > 0x7f) {
ubyte val <comment="sleb128 element">;
}
}
}
}
} sleb128 <read=SLeb128Read, comment="Signed little-endian base 128 value">;
// get the actual uint value of the uleb128
int sleb128_value(sleb128 &u) {
local int result;
local ubyte cur;
result = u.val[0];
if(result <= 0x7f) {
result = (result << 25) >> 25;
} else {
cur = u.val[1];
result = (result & 0x7f) | ((uint)(cur & 0x7f) << 7);
if(cur <= 0x7f) {
result = (result << 18) >> 18;
} else {
cur = u.val[2];
result |= (uint)(cur & 0x7f) << 14;
if(cur <= 0x7f) {
result = (result << 11) >> 11;
} else {
cur = u.val[3];
result |= (uint)(cur & 0x7f) << 21;
if(cur <= 0x7f) {
result = (result << 4) >> 4;
} else {
cur = u.val[4];
result |= (uint)cur << 28;
}
}
}
}
return result;
}
string SLeb128Read(sleb128 &u) {
local string s;
s = SPrintf(s, "%i", sleb128_value(u));
return s;
}
//////////////////////////////////////////////////
// encoded_value type
//////////////////////////////////////////////////
typedef enum <ubyte> {
VALUE_BYTE = 0x00,
VALUE_SHORT = 0x02,
VALUE_CHAR = 0x03,
VALUE_INT = 0x04,
VALUE_LONG = 0x06,
VALUE_FLOAT = 0x10,
VALUE_DOUBLE = 0x11,
VALUE_STRING = 0x17,
VALUE_TYPE = 0x18,
VALUE_FIELD = 0x19,
VALUE_METHOD = 0x1a,
VALUE_ENUM = 0x1b,
VALUE_ARRAY = 0x1c,
VALUE_ANNOTATION = 0x1d,
VALUE_NULL = 0x1e,
VALUE_BOOLEAN = 0x1f
} VALUE;
// variable-width integer used by encoded_value types
typedef struct (int size, VALUE type) {
local quad baseAddr = parentof(this).baseAddr;
local int dexIndex = parentof(this).dexIndex;
local int s = size + 1;
local VALUE t = type;
local int i;
for(i=0; i<s; i++) {
ubyte val <comment="Encoded value element">;
}
} EncodedValue <read=EncodedValueRead, optimize=false>;
string EncodedValueRead(EncodedValue &v) {
local string s = "";
switch(v.t) {
case VALUE_BYTE:
case VALUE_SHORT:
case VALUE_INT:
case VALUE_LONG:
case VALUE_FLOAT:
case VALUE_DOUBLE:
SPrintf(s, "0x%X", EncodedValueValue(v));
break;
case VALUE_STRING:
s = StringIdRead(v.dexIndex, EncodedValueValue(v));
break;
case VALUE_TYPE:
s = LongTypeIdRead(v.dexIndex, EncodedValueValue(v));
break;
case VALUE_FIELD:
s = FieldIdRead(v.dexIndex, EncodedValueValue(v));
break;
case VALUE_ENUM:
s = FieldIdRead(v.dexIndex, EncodedValueValue(v));
break;
case VALUE_ARRAY:
case VALUE_ANNOTATION:
case VALUE_BOOLEAN:
case VALUE_NULL:
s = "NULL";
break;
}
return s;
}
int64 EncodedValueValue(EncodedValue &v) {
local int shift = 0;
local int i;
local int64 ret;
if(v.s == 1) {
return v.val;
}
for(i=0; i<v.s; i++) {
ret |= (uint64)v.val[i] << shift;
shift += 8;
}
return ret;
}
typedef struct {
local quad baseAddr = parentof(this).baseAddr;
local int dexIndex = parentof(this).dexIndex;
VALUE value_type:5 <comment="Value type">;
ubyte value_arg:3 <comment="Value clarifying argument">;
local string valstr = "";
local string typestr = "";
switch (value_type) {
case VALUE_BYTE:
ubyte value <comment="Byte value">;
SPrintf(valstr, "0x%.2X", value);
typestr = "byte";
break;
case VALUE_SHORT:
// value_arg has size-1, either 0 or 1
EncodedValue value(value_arg, value_type) <comment="Short value">;
SPrintf(valstr, "%i", EncodedValueValue(value));
typestr = "short";
break;
case VALUE_CHAR:
EncodedValue value(value_arg, value_type) <comment="Char value">;
SPrintf(valstr, "'%c'", EncodedValueValue(value));
typestr = "char";
break;
case VALUE_INT:
EncodedValue value(value_arg, value_type) <comment="Int value">;
SPrintf(valstr, "%i", EncodedValueValue(value));
typestr = "int";
break;
case VALUE_LONG:
EncodedValue value(value_arg, value_type) <comment="Long value">;
SPrintf(valstr, "%li", EncodedValueValue(value));
typestr = "long";
break;
case VALUE_FLOAT: // XXX this doesn't work
EncodedValue value(value_arg, value_type) <comment="Float value">;
SPrintf(valstr, "%f", EncodedValueValue(value));
typestr = "float";
break;
case VALUE_DOUBLE:
EncodedValue value(value_arg, value_type) <comment="Double value">;
SPrintf(valstr, "%li", EncodedValueValue(value));
typestr = "double";
break;
case VALUE_STRING:
EncodedValue value(value_arg, value_type) <comment="String value">;
valstr = "\"" + GetStringById(dexIndex, EncodedValueValue(value)) + "\"";
typestr = "string";
break;
case VALUE_TYPE:
EncodedValue value(value_arg, value_type) <comment="Type value">;
valstr = GetLongTypeById(dexIndex, EncodedValueValue(value));
typestr = "type";
break;
case VALUE_FIELD:
EncodedValue value(value_arg, value_type) <comment="Field value">;
valstr = GetFieldById(dexIndex, EncodedValueValue(value));
typestr = "field";
break;
case VALUE_METHOD:
EncodedValue value(value_arg, value_type) <comment="Method value">;
valstr = GetMethodById(dexIndex, EncodedValueValue(value));
typestr = "method";
break;
case VALUE_ENUM:
EncodedValue value(value_arg, value_type) <comment="Enum value">;
valstr = GetFieldById(dexIndex, EncodedValueValue(value));
typestr = "enum";
break;
case VALUE_ARRAY:
struct encoded_array array <comment="Encoded array">;
break;
case VALUE_ANNOTATION:
struct encoded_annotation annotation <comment="Encoded annotation">;
break;
case VALUE_NULL:
// no additional bytes used by null
typestr = valstr = "NULL";
break;
case VALUE_BOOLEAN:
// no additional bytes used by boolean
typestr = "boolean";
if(value_arg == 0) {
valstr = "false";
} else {
valstr = "true";
}
break;
default:
SPrintf(temp_warning, "Unknown type for encoded value 0x%X", value_type);
PrintWarning(temp_warning);
break;
}
} encoded_value <read=EncodedValueStructRead, optimize=false>;
string EncodedValueStructRead(encoded_value &v) {
return v.typestr + ": " + v.valstr;
}
typedef struct {
local quad baseAddr = parentof(this).baseAddr;
local int dexIndex = parentof(this).dexIndex;
uleb128 size <comment="Number of elements in array">;
local uint valueSize = uleb128_value(size);
if (valueSize != 0) {
encoded_value values[uleb128_value(size)] <comment="Encoded value element">;
}
} encoded_array <read=EncodedArrayRead>;
// show first 5 elements of the array
string EncodedArrayRead(encoded_array &a) {
local int count = 5;
local int dots = 1;
local int i;
if(uleb128_value(a.size) < 5) {
count = uleb128_value(a.size);
dots = 0;
}
string val = "[";
for(i=0; i<count; i++) {
val += EncodedValueStructRead(a.values[i]);
if(i < (count-1) || dots) {
val += ", ";
}
}
if(dots) {
val += "...";
}
val += "]";
return val;
}
typedef struct {
local quad baseAddr = parentof(this).baseAddr;
local int dexIndex = parentof(this).dexIndex;
uleb128 name_idx <read=StringIdReadUleb, comment="String ID of annotation element name">;
encoded_value value <comment="Encoded value">;
} annotation_element <read=AnnotationElementRead, optimize=false>;
string AnnotationElementRead(annotation_element &e) {
string name = GetStringById(e.dexIndex, uleb128_value(e.name_idx));
return name + " = " + e.value.valstr;
}
typedef struct {
local quad baseAddr = parentof(this).baseAddr;
local int dexIndex = parentof(this).dexIndex;
uleb128 type_idx <read=LongTypeIdReadUleb, comment="Annotation type">;
uleb128 size <comment="Number of name-value mappings in annotation">;
if(uleb128_value(size) > 0) {
annotation_element elements[uleb128_value(size)] <comment="Encoded annotation contents">;
}
} encoded_annotation <read=EncodedAnnotationRead>;
string EncodedAnnotationRead(encoded_annotation &a) {
string s;
SPrintf(s, "%i annotations for %s", uleb128_value(a.size), GetLongTypeById(a.dexIndex, uleb128_value(a.type_idx)));
return s;
}
//////////////////////////////////////////////////
// dex file header
//////////////////////////////////////////////////
typedef struct {
local int i;
local quad parentAddr = startof(parentof(this));
for (i=0; i<dexCount; i++) {
if (parentAddr == dexOffs[i])
break;
}
local quad baseAddr = parentAddr;
local int dexIndex = i;
dex_magic magic <comment="Magic value">;
// local uint file_start = 0;
// if(odex) {
// file_start = dexopt_header.dex_offset;
// }
// Printf("odexpad: %x", odexpad);
// // Temp variable for expected file_length
// local uint temp_expected_file_size = ReadUInt(odexpad + 32);
// // If the size is less than the actual file - lets just set it to be filesize and let other
// // things fail nicely than hit out of bound errors
// if(temp_expected_file_size > FileSize()) {
// temp_expected_file_size = FileSize();
// }
// local uint temp_checksum = Checksum(CHECKSUM_ADLER32, odexpad + 12, temp_expected_file_size - 12, -1, -1);
// if(temp_checksum != ReadUInt(FTell())) {
// SetBackColor(cLtRed);
// SPrintf(temp_warning, "Alder32 checksum did not match, expected %08X but got %08X", ReadUInt(FTell()), temp_checksum);
// PrintWarning(temp_warning);
// }
uint checksum <format=hex, comment="Alder32 checksum of rest of file">;
// Ensure we reset color to not bleed
SetBackColor(cLtGreen);
// // Odex files kill the sha1, but the above checksum is changed
// if(!odex) {
// // Preemptively read the sha1 in for comparison
// local string temp_expected_sha1, temp_char;
// local int i;
// for(i = 0; i < 20; i++) {
// SPrintf(temp_char, "%.2X", ReadUByte(FTell()+i));
// temp_expected_sha1 += temp_char;
// }
// local string temp_prepared_sha1 = "";
// ChecksumAlgStr(CHECKSUM_SHA1, temp_prepared_sha1, odexpad + 32, temp_expected_file_size - 32, "", -1, -1);
// if(temp_expected_sha1 != temp_prepared_sha1) {
// SetBackColor(cLtRed);
// SPrintf(temp_warning, "Sha1 checksum did not match, expected %s but got %s", temp_expected_sha1, temp_prepared_sha1);
// PrintWarning(temp_warning);
// }
// }
SHA1 signature <comment="SHA-1 signature of rest of file">;
// Ensure we reset color to not bleed
SetBackColor(cLtGreen);
// local uint temp_file_size = ReadUInt(FTell());
// if(temp_file_size > FileSize()) {
// PrintWarning("File size appears be to smaller than expected - invalid dex file");
// SetBackColor(cLtRed);
// } else if(odex && temp_file_size != dexopt_header.dex_length) {
// PrintWarning("File size does not match what odex header says it should be");
// SetBackColor(cLtRed);
// } else if(!odex && temp_file_size < FileSize()) {
// // This could still technically be a valid dex file according to code paths in the verifier
// PrintWarning("File size appears be to larger than expected");
// SetBackColor(cLtRed);
// }
uint file_size <comment="File size in bytes">;
// Ensure we reset color to not bleed
SetBackColor(cLtGreen);
if(ReadUInt(FTell()) != 0x70) {
SetBackColor(cLtRed);
}
uint header_size <comment="Header size in bytes">;
if(header_size > 0x70) {
PrintWarning("Header size appears be to larger than expected");
}
// Ensure we reset color to not bleed
SetBackColor(cLtGreen);
uint endian_tag <format=hex, comment="Endianness tag">;
if(endian_tag != ENDIAN_CONSTANT) {
// XXX we don't handle big endian files
SPrintf(temp_warning, "Invalid endian_tag %.8X, should be %.8X", endian_tag, ENDIAN_CONSTANT);
PrintWarning(temp_warning);
}
if(ReadUInt(FTell()) != 0 && ReadUInt(FTell() + 4) != 0) {
SetBackColor(cLtRed);
}
uint link_size <comment="Size of link section">;
uint link_off <comment="File offset of link section">;
if(link_size != 0 || link_off != 0) {
PrintWarning("A link section appears to be set, this is not supported");
}
// Ensure we reset color to not bleed
SetBackColor(cLtGreen);
uint map_off <comment="File offset of map list">;
uint string_ids_size <comment="Count of strings in the string ID list">;
uint string_ids_off <comment="File offset of string ID list">;
uint type_ids_size <comment="Count of types in the type ID list">;
uint type_ids_off <comment="File offset of type ID list">;
uint proto_ids_size <comment="Count of items in the method prototype ID list">;
uint proto_ids_off <comment="File offset of method prototype ID list">;
uint field_ids_size <comment="Count of items in the field ID list">;
uint field_ids_off <comment="File offset of field ID list">;
uint method_ids_size <comment="Count of items in the method ID list">;
uint method_ids_off <comment="File offset of method ID list">;
uint class_defs_size <comment="Count of items in the class definitions list">;
uint class_defs_off <comment="File offset of class definitions list">;
uint data_size <comment="Size of data section in bytes">;
uint data_off <comment="File offset of data section">;
// Anything after the rest of this, but before the other sections is essentiall
// just "padding", so lets create an array variable to contain it and color it
// properly
if(header_size > 0x70) {
SetBackColor(cLtRed);
char extra_padding[header_size - 0x70];
}
} header_item <optimize=false, size=readHeaderItemSize>;
int readHeaderItemSize(header_item &item) {
return ReadUInt(startof(item)+36);
}
//////////////////////////////////////////////////
// odex file header
//////////////////////////////////////////////////
// Keeping this enum, but it shouldn't ever happen that the flag
// will be anything other than 0x0 or DEX_OPT_FLAG_BIG
// https://android.googlesource.com/platform/dalvik.git/+/57fd399d1265ec627d28a15b3d4b98e5f239ac88%5E!/
typedef enum <uint> {
DEX_FLAG_VERIFIED = 0x1,
DEX_OPT_FLAG_BIG = 0x2,
DEX_OPT_FLAG_FIELDS = 0x4,
DEX_OPT_FLAG_INVOCATIONS = 0x8
} DEX_OPT_FLAGS;
typedef struct {
dex_magic magic <comment="Magic value">;
uint dex_offset <comment="File offset of DEX header">;
uint dex_length <comment="Size of DEX file">;
uint deps_offset <comment="File offset of optimized DEX dependency table">;
uint deps_length <comment="Size of DEX dependency table">;
uint opt_offset <comment="File offset of optimized data tables">;
uint opt_length <comment="Size of optimized data tables">;
DEX_OPT_FLAGS flags <read=DexOptFlagsRead, comment="Flags">;
// This is a potentially sloppy way of getting the size of the section to be checksum'ed,
// though I haven't bothered to look up how the padding is done on the end of the
// deps + opt section
local uint temp_checksum = Checksum(CHECKSUM_ADLER32, deps_offset,FileSize() - deps_offset, -1, -1);
if(temp_checksum != ReadUInt(FTell())) {
SetBackColor(cLtRed);
SPrintf(temp_warning, "Alder32 checksum for optimized dependancies did not match, expected %08X but got %08X", ReadUInt(FTell()), temp_checksum);
PrintWarning(temp_warning);
}
uint checksum <comment="Alder32 checksum of dependency table and optimization table">;
} dexopt_header_item <size=40>;
string DexOptFlagsRead(DEX_OPT_FLAGS f) {
string ret = "";
string flags = "";
DEX_OPT_FLAGS i = 1;
while(i <= DEX_OPT_FLAG_INVOCATIONS) {
if (f & i) {
flags += EnumToString(i) + " ";
}
i = i << 1;
}
SPrintf(ret, "(0x%X) %s", f, flags);
return ret;
}
//////////////////////////////////////////////////
// strings
//////////////////////////////////////////////////
typedef struct {
local quad baseAddr = parentof(this).baseAddr;
local int dexIndex = parentof(this).dexIndex;
uleb128 utf16_size <comment="Size of string in UTF-16 code units">;
string data <comment="A string in MUTF-8 format">;
} string_item;
typedef struct {
local quad baseAddr = parentof(this).baseAddr;
local int dexIndex = parentof(this).dexIndex;
uint string_data_off <comment="File offset of string data">;
local int64 pos = FTell();
FSeek(baseAddr + string_data_off);
string_item string_data <comment="String item">;
FSeek(pos);
} string_id_item <read=StringDataReader, optimize=false>;
string StringDataReader(string_id_item &i) {
return i.string_data.data;
}
typedef struct (int size) {
local int i;
local quad parentAddr = startof(parentof(this));
for (i=0; i<dexCount; i++) {
if (parentAddr == dexOffs[i])
break;
}
local quad baseAddr = dexOffs[i];
local int dexIndex = i;
local int s = size;
string_id_item string_id[size] <comment="String ID">;
} string_id_list <read=StringIDListRead, comment="String ID list">;
string StringIDListRead(string_id_list &l) {
string s;
s = SPrintf(s, "%d strings", l.s);
return s;
}
//////////////////////////////////////////////////
// type IDs
//////////////////////////////////////////////////
typedef struct {
local quad baseAddr = parentof(this).baseAddr;
local int dexIndex = parentof(this).dexIndex;
uint idx <comment = "id">;
} id_string <read = id_stringRead, optimize = false>;
string id_stringRead(id_string &s) {
return StringIdRead(s.dexIndex, s.idx);
}
typedef struct {
local quad baseAddr = parentof(this).baseAddr;
local int dexIndex = parentof(this).dexIndex;
id_string descriptor_idx <comment="String ID for this type descriptor">;
} type_id_item <read=TypeIDItemRead, optimize=false>;
string TypeIDItemRead(type_id_item &i) {
return GetLongTypeDescriptor(GetStringById(i.dexIndex, i.descriptor_idx.idx));
}
typedef struct (int size) {
local int i;
local quad parentAddr = startof(parentof(this));
for (i=0; i<dexCount; i++) {
if (parentAddr == dexOffs[i])
break;
}
local quad baseAddr = dexOffs[i];
local int dexIndex = i;
local int s = size;
type_id_item type_id[size] <comment="Type ID">;
} type_id_list <read=TypeIDListRead, optimize=false>;
string TypeIDListRead(type_id_list &l) {
string s;
s = SPrintf(s, "%d types", l.s);
return s;
}
//////////////////////////////////////////////////
// type list
//////////////////////////////////////////////////
typedef struct {
local quad baseAddr = parentof(this).baseAddr;
local int dexIndex = parentof(this).dexIndex;
ushort type_idx <comment="Index into type_ids list">;
} type_item <optimize=false>;
typedef struct {
local quad baseAddr = parentof(this).baseAddr;
local int dexIndex = parentof(this).dexIndex;
uint size <comment="Number of entries in type list">;
if(size != 0) {
type_item list[size] <read=TypeItemRead, comment="Type entry">;
}
} type_item_list <read=TypeItemListRead, optimize=false>;
string TypeItemRead(type_item &t) {
return GetTypeById(t.dexIndex, t.type_idx);
}
string TypeItemListRead(type_item_list &l) {
string s = "";
string tmp;
int i;
for(i = 0; i < l.size; i++) {
s += GetTypeById(l.dexIndex, l.list[i].type_idx);
if(i+1 < l.size) {
s += ", ";
}
}
return s;
}
string GetLongTypeDescriptor(string descriptor) {
local string desc = "";
local string post = "";
local int i = 0;
local int len = Strlen(descriptor);
// array descriptors
while(descriptor[i] == '[') {
post += "[]";
i++;
if(i >= len) return "ERROR";
}
if(descriptor[i] == 'L') {
// fully qualified class descriptors
i++;
while(i < len) {
if(descriptor[i] == '/') desc += ".";
else if(descriptor[i] == ';') break;
else desc += descriptor[i];
i++;
}
} else {
// simple type descriptors
switch(descriptor[i]) {
case 'V': desc = "void"; break;
case 'Z': desc = "boolean"; break;
case 'B': desc = "byte"; break;
case 'S': desc = "short"; break;
case 'C': desc = "char"; break;
case 'I': desc = "int"; break;
case 'J': desc = "long"; break;
case 'F': desc = "float"; break;
case 'D': desc = "double"; break;
}
}
return desc + post;
}
//////////////////////////////////////////////////
// protoypes
//////////////////////////////////////////////////
typedef struct {
local quad baseAddr = parentof(this).baseAddr;
local int dexIndex = parentof(this).dexIndex;
uint idx <comment="id">;
} type_string <read=type_stringRead, optimize=false>;
string type_stringRead(type_string &s) {
return TypeIdRead(s.dexIndex, s.idx);
}
typedef struct {
local quad baseAddr = parentof(this).baseAddr;
local int dexIndex = parentof(this).dexIndex;
uint shorty_idx <comment="String ID of short-form descriptor">;
type_string return_type_idx <comment="Type ID of the return type">;
uint parameters_off <comment="File offset of parameter type list">;
if(parameters_off != 0) {
local int64 pos = FTell();
FSeek(baseAddr + parameters_off);
type_item_list parameters <comment="Prototype parameter data">;
FSeek(pos);
}
} proto_id_item <read=ProtoIDItemRead, optimize=false>;
string ProtoIDItemRead(proto_id_item &i) {
return GetPrototypeSignature(i);
}
typedef struct (int size) {
local int i;
local quad parentAddr = startof(parentof(this));
for (i=0; i<dexCount; i++) {
if (parentAddr == dexOffs[i])
break;
}
local quad baseAddr = dexOffs[i];
local int dexIndex = i;
local int s = size;
proto_id_item proto_id[size] <comment="Prototype ID">;
} proto_id_list <read=ProtoIDListRead, optimize=true>;
string ProtoIDListRead(proto_id_list &l) {
string s;
s = SPrintf(s, "%d prototypes", l.s);
return s;
}
string GetParameterListString(type_item_list &l) {
local string s = "(";
local string tmp;
local int i;
for(i = 0; i < l.size; i++) {
s += GetLongTypeDescriptor(GetTypeById(l.dexIndex, l.list[i].type_idx));
if(i+1 < l.size) {
s += ", ";
}
}
return s + ")";
}
string GetPrototypeSignature(proto_id_item &item) {
string ret = GetLongTypeDescriptor(GetTypeById(item.dexIndex, item.return_type_idx.idx));
string params = "()";
if(exists(item.parameters)) {
params = GetParameterListString(item.parameters);
}
return ret + " " + params;
}
//////////////////////////////////////////////////
// fields
//////////////////////////////////////////////////
typedef struct {
local quad baseAddr = parentof(this).baseAddr;
local int dexIndex = parentof(this).dexIndex;
ushort idx <comment = "id">;
} long_type_string <read = long_type_stringRead, optimize = false>;
string long_type_stringRead(long_type_string &s) {
return LongTypeIdRead(s.dexIndex, s.idx);
}
typedef struct {
local quad baseAddr = parentof(this).baseAddr;
local int dexIndex = parentof(this).dexIndex;
long_type_string class_idx <comment="Type ID of the class that defines this field">;
long_type_string type_idx <comment="Type ID for the type of this field">;
id_string name_idx <comment="String ID for the field's name">;
} field_id_item <read=FieldIdItemRead, optimize=false>;
string FieldIdItemRead(field_id_item &i) {
local string type = GetLongTypeDescriptor(GetTypeById(i.dexIndex, i.type_idx.idx));
local string class = GetLongTypeDescriptor(GetTypeById(i.dexIndex, i.class_idx.idx));
local string name = GetStringById(i.dexIndex, i.name_idx.idx);
return type + " " + class + "." + name;
}
typedef struct (int size) {
local int i;
local quad parentAddr = startof(parentof(this));
for (i=0; i<dexCount; i++) {
if (parentAddr == dexOffs[i])
break;
}
local quad baseAddr = dexOffs[i];
local int dexIndex = i;
local int s = size;
field_id_item field_id[size] <comment="Field ID">;
} field_id_list <read=FieldIDListRead, optimize=true>;
string FieldIDListRead(field_id_list &l) {
string s;
s = SPrintf(s, "%d fields", l.s);
return s;
}
//////////////////////////////////////////////////
// methods
//////////////////////////////////////////////////
typedef struct {
local quad baseAddr = parentof(this).baseAddr;
local int dexIndex = parentof(this).dexIndex;
ushort idx <comment = "id">;
} proto_id_string <read = proto_id_stringRead, optimize = false>;
string proto_id_stringRead(proto_id_string &s) {
return ProtoIdxRead(s.dexIndex, s.idx);
}
typedef struct {
local quad baseAddr = parentof(this).baseAddr;
local int dexIndex = parentof(this).dexIndex;
long_type_string class_idx <comment="Type ID of the class that defines this method">;
proto_id_string proto_idx <comment="Prototype ID for this method">;
id_string name_idx <comment="String ID for the method's name">;
} method_id_item <read=MethodIdItemRead, optimize=false>;
string ProtoIdxRead(int dexIndex, ushort p) {
string s;
SPrintf(s, "(0x%X) %s", p, GetPrototypeSignature(file.dex_files[dexIndex].dex_proto_ids.proto_id[p]));
return s;
}
string MethodIdItemRead(method_id_item &m) {
local string retval = GetLongTypeDescriptor(GetTypeById(m.dexIndex, file.dex_files[m.dexIndex].dex_proto_ids.proto_id[m.proto_idx.idx].return_type_idx.idx));
local string classname = GetLongTypeDescriptor(GetStringById(m.dexIndex, file.dex_files[m.dexIndex].dex_type_ids.type_id[m.class_idx.idx].descriptor_idx.idx));
local string methodname = GetStringById(m.dexIndex, m.name_idx.idx);
local string params = "()";
if(exists(file.dex_files[m.dexIndex].dex_proto_ids.proto_id[m.proto_idx.idx].parameters)) {
params = GetParameterListString(file.dex_files[m.dexIndex].dex_proto_ids.proto_id[m.proto_idx.idx].parameters);
}
return retval + " " + classname + "." + methodname + params;
}
typedef struct (int size) {
local int i;
local quad parentAddr = startof(parentof(this));
for (i=0; i<dexCount; i++) {
if (parentAddr == dexOffs[i])
break;
}
local quad baseAddr = dexOffs[i];
local int dexIndex = i;
local int s = size;
method_id_item method_id[size] <comment="Method ID">;
} method_id_list <read=MethodIDListRead, optimize=true>;
string MethodIDListRead(method_id_list &l) {
string s;
s = SPrintf(s, "%d methods", l.s);
return s;
}
//////////////////////////////////////////////////
// annotations
//////////////////////////////////////////////////
typedef struct {
local quad baseAddr = parentof(this).baseAddr;
local int dexIndex = parentof(this).dexIndex;
uint idx <comment = "id">;
} field_uint_string <read = field_uint_stringRead, optimize = false>;
string field_uint_stringRead(field_uint_string &s) {
return FieldIdRead(s.dexIndex, s.idx);
}
typedef struct {
local quad baseAddr = parentof(this).baseAddr;
local int dexIndex = parentof(this).dexIndex;
field_uint_string field_idx;
uint annotations_off;
if(annotations_off != 0) {
local int64 pos = FTell();
FSeek(baseAddr + annotations_off);
struct annotation_set_item field_annotations;
FSeek(pos);
}
} field_annotation <read=FieldAnnotationRead, optimize=false>;
string FieldAnnotationRead(field_annotation &f) {
return GetFieldById(f.dexIndex, f.field_idx.idx);
}
typedef struct {
local quad baseAddr = parentof(this).baseAddr;
local int dexIndex = parentof(this).dexIndex;
uint idx <comment = "id">;
} method_id_string <read = method_id_stringRead, optimize = false>;
string method_id_stringRead(method_id_string &s) {
return MethodIdRead(s.dexIndex, s.idx);
}
typedef struct {
local quad baseAddr = parentof(this).baseAddr;
local int dexIndex = parentof(this).dexIndex;
method_id_string method_idx;
uint annotations_off;
if(annotations_off != 0) {
local int64 pos = FTell();
FSeek(baseAddr + annotations_off);
struct annotation_set_item method_annotations;
FSeek(pos);
}
} method_annotation <read=MethodAnnotationRead, optimize=false>;
string MethodAnnotationRead(method_annotation &m) {
return GetMethodById(m.dexIndex, m.method_idx.idx);
}
typedef struct {
local quad baseAddr = parentof(this).baseAddr;
local int dexIndex = parentof(this).dexIndex;
method_id_string method_idx;
uint annotations_off;
if(annotations_off != 0) {
local int64 pos = FTell();
FSeek(baseAddr + annotations_off);
struct annotation_set_ref_list annotations_list;
FSeek(pos);
}
} parameter_annotation <read=ParameterAnnotationRead, optimize=false>;
string ParameterAnnotationRead(parameter_annotation &p) {
return GetParameterListString(dex_proto_ids.proto_id[dex_method_ids.method_id[p.method_idx.idx].proto_idx.idx].parameters);
}
typedef enum <ubyte> {
VISIBILITY_BUILD = 0x0,
VISIBILITY_RUNTIME = 0x1,
VISIBILITY_SYSTEM = 0x2
} VISIBILITY;
typedef struct {
local quad baseAddr = parentof(this).baseAddr;
local int dexIndex = parentof(this).dexIndex;
VISIBILITY visibility <comment="Visibility of item">;
encoded_annotation annotation <comment="Encoded annotation contents">;
} annotation_item <read=AnnotationItemRead, optimize=false>;
string AnnotationItemRead(annotation_item &i) {
return EncodedAnnotationRead(i.annotation);
}
typedef struct {
local quad baseAddr = parentof(this).baseAddr;
local int dexIndex = parentof(this).dexIndex;
uint annotation_off <comment="File offset of this annotation entry">;
if(annotation_off != 0) {
local int64 pos = FTell();
FSeek(baseAddr + annotation_off);
annotation_item item <comment="Annotation item">;
FSeek(pos);
}
} annotation_off_item <read=AnnotationOffItemRead, optimize=true>;
string AnnotationOffItemRead(annotation_off_item &i) {
if(exists(i.item)) {
return AnnotationItemRead(i.item);
} else {
return "";
}
}
typedef struct {
local quad baseAddr = parentof(this).baseAddr;
local int dexIndex = parentof(this).dexIndex;
uint size <comment="Number of entries in set">;
if(size > 0) {
annotation_off_item entries[size] <comment="Annotation entry elements">;
}
} annotation_set_item <read=AnnotationSetItemRead, optimize=false>;
string AnnotationSetItemRead(annotation_set_item &i) {
local string s;
SPrintf(s, "%i annotation entries", i.size);
return s;
}
typedef struct {
local quad baseAddr = parentof(this).baseAddr;
local int dexIndex = parentof(this).dexIndex;
uint class_annotations_off <comment="File offset to class annotations">;
if(class_annotations_off != 0) {
local int64 pos = FTell();
FSeek(baseAddr + class_annotations_off);
annotation_set_item class_annotations <comment="Class annotations">;
FSeek(pos);
}
uint fields_size <comment="Number of fields annotated by this item">;
uint methods_size <comment="Number of methods annotated by this item">;
uint parameters_size <comment="Number of method parameter lists annotated by this item">;
if(fields_size > 0) {
field_annotation field_annotations[fields_size] <comment="List of field annotations">;
}
if(methods_size > 0) {
method_annotation method_annotations[methods_size] <comment="List of method annotations">;
}
if(parameters_size > 0) {
parameter_annotation parameter_annotations[parameters_size] <comment="List of method parameter annotations">;
}
} annotations_directory_item <read=AnnotationsDirectoryItemRead, optimize=true>;
string AnnotationsDirectoryItemRead(annotations_directory_item &i) {
local string s;
local int classes = 0;
if(exists(i.class_annotations)) {
classes = i.class_annotations.size;
}
SPrintf(s, "%i class annotations, %i field annotations, %i method annotations, %i parameter annotations",
classes, i.fields_size, i.methods_size, i.parameters_size);
return s;
}
typedef struct {
local quad baseAddr = parentof(this).baseAddr;
local int dexIndex = parentof(this).dexIndex;
uint annotations_off <comment="File offset of annotation">;
if(annotations_off != 0) {
local int64 pos = FTell();
FSeek(baseAddr + annotations_off);
struct annotation_set_item item <comment="Annotation set item">;
FSeek(pos);
}
} annotation_set_ref_item <optimize=false>;
typedef struct {
local quad baseAddr = parentof(this).baseAddr;
local int dexIndex = parentof(this).dexIndex;
uint size <comment="Number of entries in annotation list">;
if(size > 0) {
annotation_set_ref_item list[size] <comment="Annotation set elements">;
}
} annotation_set_ref_list;
//////////////////////////////////////////////////
// classes
//////////////////////////////////////////////////
// access flags. some of these mean different things for different items (class/field/method)
typedef enum <uint> {
ACC_PUBLIC = 0x1,
ACC_PRIVATE = 0x2,
ACC_PROTECTED = 0x4,
ACC_STATIC = 0x8,
ACC_FINAL = 0x10,
ACC_SYNCHRONIZED = 0x20,
ACC_VOLATILE = 0x40, // field
//ACC_BRIDGE = 0x40, // method
ACC_TRANSIENT = 0x80, // field
//ACC_VARARGS = 0x80, // method
ACC_NATIVE = 0x100,
ACC_INTERFACE = 0x200,
ACC_ABSTRACT = 0x400,
ACC_STRICT = 0x800,
ACC_SYNTHETIC = 0x1000,
ACC_ANNOTATION = 0x2000,
ACC_ENUM = 0x4000,
ACC_CONSTRUCTOR = 0x10000,
ACC_DECLARED_SYNCHRONIZED = 0x20000
} ACCESS_FLAGS <read=AccessFlagsRead>;
string AccessFlagsRead(ACCESS_FLAGS f) {
string ret = "";
string flags = "";
ACCESS_FLAGS i = 1;
while(i <= ACC_DECLARED_SYNCHRONIZED) {
if (f & i) {
flags += EnumToString(i) + " ";
}
i = i << 1;
}
SPrintf(ret, "(0x%X) %s", f, flags);
return ret;
}
string AccessFlagsReadUleb(uleb128 &f) {
return AccessFlagsRead(uleb128_value(f));
}
typedef enum {
AF_CLASS, AF_FIELD, AF_METHOD
} AF_TYPE;
string GetFriendlyAccessFlag(int flag, AF_TYPE type) {
switch (flag) {
case ACC_PUBLIC: return "public";
case ACC_PRIVATE: return "private";
case ACC_PROTECTED: return "protected";
case ACC_STATIC: return "static";
case ACC_FINAL: return "final";
case ACC_SYNCHRONIZED: return "synchronized";
case ACC_VOLATILE:
if(type == AF_FIELD) return "volatile";
else return "bridge"; // 0x40 is 'bridge' for methods
case ACC_TRANSIENT:
if(type == AF_FIELD) return "transient";
else return "varargs"; // 0x80 is 'varargs' for methods
case ACC_NATIVE: return "native";
case ACC_INTERFACE: return "interface";
case ACC_ABSTRACT: return "abstract";
case ACC_STRICT: return "strict";
case ACC_SYNTHETIC: return "synthetic";
case ACC_ANNOTATION: return "annotation";
case ACC_ENUM: return "enum";
case ACC_CONSTRUCTOR: return "constructor";
case ACC_DECLARED_SYNCHRONIZED: return "declared-synchronized";
}
return "ERROR";
}
string GetFriendlyAccessFlags(ACCESS_FLAGS f, AF_TYPE type) {
string flags = "";
ACCESS_FLAGS i = 1;
while(i <= ACC_DECLARED_SYNCHRONIZED) {
if (f & i) {
flags += GetFriendlyAccessFlag(i, type) + " ";
}
i = i << 1;
}
return flags;
}
// encoded fields
typedef struct (int previd) {
local quad baseAddr = parentof(this).baseAddr;
local int dexIndex = parentof(this).dexIndex;
local int p = previd;
uleb128 field_idx_diff <comment="Field ID for this field, represented as the difference from the previous index">;
uleb128 access_flags <read=AccessFlagsReadUleb, comment="Access flags">;
} encoded_field <read=EncodedFieldRead, optimize=false>;
string EncodedFieldRead(encoded_field &f) {
local int realid = f.p + uleb128_value(f.field_idx_diff);
return GetFriendlyAccessFlags(uleb128_value(f.access_flags), AF_FIELD) + GetFieldById(f.dexIndex, realid);
}
typedef struct (int size) {
local quad baseAddr = parentof(this).baseAddr;
local int dexIndex = parentof(this).dexIndex;
local int s = size;
local int i;
local int fieldid = 0;
for(i=0; i<size; i++) {
encoded_field field(fieldid) <comment="Encoded field">;
fieldid = fieldid + uleb128_value(field.field_idx_diff);
}
} encoded_field_list <read=EncodedFieldListRead>;
string EncodedFieldListRead(encoded_field_list &l) {
local string s;
SPrintf(s, "%i fields", l.s);
return s;
}
// encoded methods
typedef struct (int previd) {
local quad baseAddr = parentof(this).baseAddr;
local int dexIndex = parentof(this).dexIndex;
local int p = previd;
uleb128 method_idx_diff <comment="Method ID for this method, represented as the difference from the previous index">;
uleb128 access_flags <read=AccessFlagsReadUleb, comment="Access flags">;
uleb128 code_off <comment="File offset to the code for this method">;
if(uleb128_value(code_off) != 0) {
local int64 pos = FTell();
FSeek(baseAddr + uleb128_value(code_off));
struct code_item code <comment="Code structure for this method">;
FSeek(pos);
}
} encoded_method <read=EncodedMethodRead, optimize=false>;
string EncodedMethodRead(encoded_method &m) {
local int realid = m.p + uleb128_value(m.method_idx_diff);
return GetFriendlyAccessFlags(uleb128_value(m.access_flags), AF_METHOD) + GetMethodById(m.dexIndex, realid);
}
typedef struct (int size) {
local quad baseAddr = parentof(this).baseAddr;
local int dexIndex = parentof(this).dexIndex;
local int s = size;
local int i;
local int methodid = 0;
for(i=0; i<size; i++) {
encoded_method method(methodid) <comment="Encoded method">;
methodid = methodid + uleb128_value(method.method_idx_diff);
}
} encoded_method_list <read=EncodedMethodListRead>;
string EncodedMethodListRead(encoded_method_list &l) {
local string s;
SPrintf(s, "%i methods", l.s);
return s;
}
typedef struct {
local quad baseAddr = parentof(this).baseAddr;
local int dexIndex = parentof(this).dexIndex;
uleb128 static_fields_size <comment="The number of static fields">;
uleb128 instance_fields_size <comment="The number of instance fields">;
uleb128 direct_methods_size <comment="The number of direct methods">;
uleb128 virtual_methods_size <comment="The number of virtual methods">;
if(uleb128_value(static_fields_size) > 0) {
encoded_field_list static_fields(uleb128_value(static_fields_size)) <comment="Encoded sequence of static fields">;
}
if(uleb128_value(instance_fields_size) > 0) {
encoded_field_list instance_fields(uleb128_value(instance_fields_size)) <comment="Encoded sequence of instance fields">;
}
if(uleb128_value(direct_methods_size) > 0) {
encoded_method_list direct_methods(uleb128_value(direct_methods_size)) <comment="Encoded sequence of direct methods">;
}
if(uleb128_value(virtual_methods_size) > 0) {
encoded_method_list virtual_methods(uleb128_value(virtual_methods_size)) <comment="Encoded sequence of virtual methods">;
}
} class_data_item <read=ClassDataItemRead>;
string ClassDataItemRead(class_data_item &i) {
local string s;
SPrintf(s, "%i static fields, %i instance fields, %i direct methods, %i virtual methods",
uleb128_value(i.static_fields_size), uleb128_value(i.instance_fields_size),
uleb128_value(i.direct_methods_size), uleb128_value(i.virtual_methods_size));
return s;
}
typedef struct {
local quad baseAddr = parentof(this).baseAddr;
local int dexIndex = parentof(this).dexIndex;
uint idx;
} long_type_uint_string <read = long_type_uint_stringRead, optimize = false>;
string long_type_uint_stringRead(long_type_uint_string &s) {
return LongTypeIdRead(s.dexIndex, s.idx);
}
typedef struct {
local quad baseAddr = parentof(this).baseAddr;
local int dexIndex = parentof(this).dexIndex;
local int64 pos;
long_type_uint_string class_idx <comment="Type ID for this class">;
// local string name = GetLongTypeDescriptor(GetTypeById(dexIndex, class_idx));
ACCESS_FLAGS access_flags <comment="Access flags">;
long_type_uint_string superclass_idx <comment="Type ID for this class's superclass">;
uint interfaces_off <comment="File offset to interface list">;
if(interfaces_off != 0) {
pos = FTell();
FSeek(baseAddr + interfaces_off);
type_item_list interfaces <read=InterfacesRead, comment="Interface data">;
FSeek(pos);
}
id_string source_file_idx <comment="String ID for the name of the file with this class defined">;
uint annotations_off <comment="File offset to the annotation structure for this class">;
if(annotations_off != 0) {
pos = FTell();
FSeek(baseAddr + annotations_off);
annotations_directory_item annotations <comment="Annotation data">;
FSeek(pos);
}
uint class_data_off <comment="File offset to the class data for this class">;
if(class_data_off != 0) {
pos = FTell();
FSeek(baseAddr + class_data_off);
class_data_item class_data <comment="Class data">;
FSeek(pos);
}
uint static_values_off <comment="File offset to static field data">;
if(static_values_off != 0) {
pos = FTell();
FSeek(baseAddr + static_values_off);
struct encoded_array_item static_values <comment="Static values">;
FSeek(pos);
}
} class_def_item <read=ClassDefItemRead, optimize=false>;
string ClassDefItemRead(class_def_item &i) {
local string name = GetLongTypeById(i.dexIndex, i.class_idx.idx);
local string flags = GetFriendlyAccessFlags(i.access_flags, AF_CLASS);
return flags + name;
}
string InterfacesRead(type_item_list &l) {
string s = "";
int i;
for(i = 0; i < l.size; i++) {
s += GetLongTypeDescriptor(GetTypeById(l.dexIndex, l.list[i].type_idx));
if(i+1 < l.size) {
s += ", ";
}
}
return s;
}
typedef struct (int size) {
local int i;
local quad parentAddr = startof(parentof(this));
for (i=0; i<dexCount; i++) {
if (parentAddr == dexOffs[i])
break;
}
local quad baseAddr = dexOffs[i];
local int dexIndex = i;
local int s = size;
class_def_item class_def[size] <comment="Class ID">;
} class_def_item_list <read=ClassDefItemListRead>;
string ClassDefItemListRead(class_def_item_list &l) {
string s;
s = SPrintf(s, "%d classes", l.s);
return s;
}
typedef struct {
local quad baseAddr = parentof(this).baseAddr;
local int dexIndex = parentof(this).dexIndex;
uint start_addr <comment="Start address of code block covered by this entry, in 16-bit code units from the start of the first instruction">;
ushort insn_count <comment="Number of 16-bit code units covered by this entry">;
ushort handler_off <comment="Offset to the catch_handler_item for this entry">;
} try_item <optimize=false>;
typedef struct {
local quad baseAddr = parentof(this).baseAddr;
local int dexIndex = parentof(this).dexIndex;
sleb128 size <comment="Number of catch types in the list">;
local int s = sleb128_value(size);
local int numhandlers = 0;
if(s != 0) {
numhandlers = Abs(s);
struct encoded_type_addr_pair handlers[numhandlers] <comment="Exception handler pairs">;
}
if(s <= 0) {
uleb128 catch_all_addr <comment="Address of catch-all handler">;
numhandlers++;
}
} encoded_catch_handler <read=EncodedCatchHandlerRead, optimize=false>;
string EncodedCatchHandlerRead(encoded_catch_handler &h) {
local string s;
SPrintf(s, "%i handlers", h.numhandlers);
return s;
}
typedef struct {
local quad baseAddr = parentof(this).baseAddr;
local int dexIndex = parentof(this).dexIndex;
uleb128 size <comment="Number of handler lists">;
encoded_catch_handler list[uleb128_value(size)] <comment="List of handler lists">;
} encoded_catch_handler_list <read=EncodedCatchHandlerListRead>;
string EncodedCatchHandlerListRead(encoded_catch_handler_list &l) {
local string s;
SPrintf(s, "%i handler lists", uleb128_value(l.size));
return s;
}
typedef struct {
local quad baseAddr = parentof(this).baseAddr;
local int dexIndex = parentof(this).dexIndex;
ushort registers_size <comment="Number of registers used by this code">;
ushort ins_size <comment="Number of words of incoming arguments for this code's method">;
ushort outs_size <comment="Number of words of outgoing arguments for this code's method">;
ushort tries_size <comment="Number of try_item entries for this code">;
uint debug_info_off <comment="File offset for the debug information">;
if(debug_info_off != 0) {
local int64 pos = FTell();
FSeek(baseAddr + debug_info_off);
struct debug_info_item debug_info <comment="Debug information for this method">;
FSeek(pos);
}
uint insns_size <comment="Size of instruction list, in 16-bit code units">;
if(insns_size != 0) {
ushort insns[insns_size] <comment="Instruction">;
}
if(tries_size != 0) {
if (insns_size & 1 == 1) {
ushort padding <comment="Padding...">;
}
try_item tries[tries_size] <comment="Array of code try block addresses">;
encoded_catch_handler_list handlers <comment="Array of catch types and handler addresses">;
}
} code_item <read=CodeItemRead>;
string CodeItemRead(code_item &i) {
local string s;
SPrintf(s, "%i registers, %i in arguments, %i out arguments, %i tries, %i instructions",
i.registers_size, i.ins_size, i.outs_size, i.tries_size, i.insns_size);
return s;
}
typedef struct {
local quad baseAddr = parentof(this).baseAddr;
local int dexIndex = parentof(this).dexIndex;
uleb128 type_idx <read=LongTypeIdReadUleb, comment="Type ID for the type of exception to catch">;
uleb128 addr <comment="Bytecode address of exception handler">;
} encoded_type_addr_pair <read=EncodedTypeAddrPairRead, optimize=false>;
string EncodedTypeAddrPairRead(encoded_type_addr_pair &p) {
string s;
SPrintf(s, "%s at 0x%X", GetLongTypeById(p.dexIndex, uleb128_value(p.type_idx)), uleb128_value(p.addr));
return s;
}
typedef struct {
local quad baseAddr = parentof(this).baseAddr;
local int dexIndex = parentof(this).dexIndex;
encoded_array value <comment="The encoded array value">;
} encoded_array_item <read=EncodedArrayItemRead>;
string EncodedArrayItemRead(encoded_array_item &i) {
local string s;
SPrintf(s, "%i items: %s", uleb128_value(i.value.size), EncodedArrayRead(i.value));
return s;
}
enum <ushort> TYPE_CODES {
TYPE_HEADER_ITEM = 0x0000,
TYPE_STRING_ID_ITEM = 0x0001,
TYPE_TYPE_ID_ITEM = 0x0002,
TYPE_PROTO_ID_ITEM = 0x0003,
TYPE_FIELD_ID_ITEM = 0x0004,
TYPE_METHOD_ID_ITEM = 0x0005,
TYPE_CLASS_DEF_ITEM = 0x0006,
TYPE_MAP_LIST = 0x1000,
TYPE_TYPE_LIST = 0x1001,
TYPE_ANNOTATION_SET_REF_LIST = 0x1002,
TYPE_ANNOTATION_SET_ITEM = 0x1003,
TYPE_CLASS_DATA_ITEM = 0x2000,
TYPE_CODE_ITEM = 0x2001,
TYPE_STRING_DATA_ITEM = 0x2002,
TYPE_DEBUG_INFO_ITEM = 0x2003,
TYPE_ANNOTATION_ITEM = 0x2004,
TYPE_ENCODED_ARRAY_ITEM = 0x2005,
TYPE_ANNOTATIONS_DIRECTORY_ITEM = 0x2006
};
//////////////////////////////////////////////////
// debug info
//////////////////////////////////////////////////
typedef enum <ubyte> {
DBG_END_SEQUENCE = 0x00,
DBG_ADVANCE_PC = 0x01,
DBG_ADVANCE_LINE = 0x02,
DBG_START_LOCAL = 0x03,
DBG_START_LOCAL_EXTENDED = 0x04,
DBG_END_LOCAL = 0x05,
DBG_RESTART_LOCAL = 0x06,
DBG_SET_PROLOGUE_END = 0x07,
DBG_SET_EPILOGUE_BEGIN = 0x08,
DBG_SET_FILE = 0x09
} DBG_OPCODE;
typedef struct {
local quad baseAddr = parentof(this).baseAddr;
local int dexIndex = parentof(this).dexIndex;
DBG_OPCODE opcode <comment="Debug opcode">;
local string args = "";
switch (opcode) {
case DBG_END_SEQUENCE:
break;
case DBG_ADVANCE_PC:
uleb128 addr_diff <comment="Amount to add to address register">;
SPrintf(args, "%i", uleb128_value(addr_diff));
break;
case DBG_ADVANCE_LINE:
sleb128 line_diff <comment="Amount to change line register by">;
SPrintf(args, "%i", sleb128_value(line_diff));
break;
case DBG_START_LOCAL:
uleb128 register_num <comment="Register that will contain local">;
uleb128p1 name_idx <read=StringIdReadUlebp1, comment="String index of name">;
uleb128p1 type_idx <read=LongTypeIdReadUlebp1,comment="Type index of type">;
SPrintf(args, "%i, %s, %s", uleb128_value(register_num), StringIdReadUlebp1(name_idx),
LongTypeIdReadUlebp1(type_idx));
break;
case DBG_START_LOCAL_EXTENDED:
uleb128 register_num <comment="Register that will contain local">;
uleb128p1 name_idx <read=StringIdReadUlebp1, comment="String index of name">;
uleb128p1 type_idx <read=LongTypeIdReadUlebp1, comment="Type index of type">;
uleb128p1 sig_idx <read=StringIdReadUlebp1, comment="String index of type signature">;
SPrintf(args, "%i, %s, %s, %s", uleb128_value(register_num), StringIdReadUlebp1(name_idx),
LongTypeIdReadUlebp1(type_idx), StringIdReadUlebp1(sig_idx));
break;
case DBG_END_LOCAL:
uleb128 register_num <comment="Register that contained local">;
SPrintf(args, "%i", uleb128_value(register_num));
break;
case DBG_RESTART_LOCAL:
uleb128 register_num <comment="Register to restart">;
SPrintf(args, "%i", uleb128_value(register_num));
break;
case DBG_SET_PROLOGUE_END:
case DBG_SET_EPILOGUE_BEGIN:
break;
case DBG_SET_FILE:
uleb128p1 name_idx <read=StringIdReadUlebp1, comment="String index of source file name">;
SPrintf(args, "%s", StringIdReadUlebp1(name_idx));
}
} debug_opcode <read=DebugOpcodeRead, optimize=false>;
#define DBG_FIRST_SPECIAL 0x0a
#define DBG_LINE_BASE -4
#define DBG_LINE_RANGE 15
string DebugOpcodeRead(debug_opcode &opcode) {
local string s;
if(opcode.opcode >= DBG_FIRST_SPECIAL) {
local ubyte adjusted = opcode.opcode - DBG_FIRST_SPECIAL;
SPrintf(s, "Special opcode: line + %i, address + %i", DBG_LINE_BASE + (adjusted % DBG_LINE_RANGE), (adjusted / DBG_LINE_RANGE));
} else {
s = EnumToString(opcode.opcode);
}
if(opcode.args != "") {
s += " (" + opcode.args + ")";
}
return s;
}
typedef struct {
local quad baseAddr = parentof(this).baseAddr;
local int dexIndex = parentof(this).dexIndex;
uleb128 line_start <comment="Initial value for state machine 'line' register">;
uleb128 parameters_size <comment="Number of encoded parameter names">;
if(uleb128_value(parameters_size) > 0) {
uleb128p1 parameter_names[uleb128_value(parameters_size)] <comment="String ID of method parameter names", optimize=false>; // actually uleb128p1
}
do {
debug_opcode opcode <comment="A debug opcode">;
} while (opcode.opcode != DBG_END_SEQUENCE);
} debug_info_item;
//////////////////////////////////////////////////
// map list
//////////////////////////////////////////////////
typedef struct {
local quad baseAddr = parentof(this).baseAddr;
local int dexIndex = parentof(this).dexIndex;
TYPE_CODES type;
ushort unused;
uint size;
uint offset;
} map_item <read=MapItemRead, optimize=true>;
string MapItemRead(map_item &m) {
string s;
SPrintf(s, "%s", EnumToString(m.type));
return s;
}
typedef struct {
local int i;
local quad parentAddr = startof(parentof(this));
for (i=0; i<dexCount; i++) {
if (parentAddr == dexOffs[i])
break;
}
local quad baseAddr = dexOffs[i];
local int dexIndex = i;
uint size;
map_item list[size];
} map_list_type <read=MapListTypeRead>;
string MapListTypeRead(map_list_type &t) {
local string s;
SPrintf(s, "%i items", t.size);
return s;
}
//////////////////////////////////////////////////
// utility functions for reading various strings
// note: strings are stored in a format called MUTF-8, and its
// possible they won't always display correctly in the 010 UI
//////////////////////////////////////////////////
// read a value from the string table
string StringIdRead(int dexIndex, int id) {
if(id == NO_INDEX) {
return "NO_INDEX";
}
local string s;
SPrintf(s, "(0x%.X) \"%s\"", id, GetStringById(dexIndex, id));
return s;
}
string StringIdReadUleb(uleb128 &id) {
return StringIdRead(parentof(id).dexIndex, uleb128_value(id));
}
string StringIdReadUlebp1(uleb128p1 &id) {
return StringIdRead(parentof(id).dexIndex, uleb128p1_value(id));
}
// read a value from the type table, return short form
string TypeIdRead(int dexIndex, int id) {
local string s;
return GetIdAndNameString(id, GetTypeById(dexIndex, id));
}
// read a value from the type table, return the long form
string LongTypeIdRead(int dexIndex, int id) {
local string s;
return GetIdAndNameString(id, GetLongTypeById(dexIndex, id));
}
string LongTypeIdReadUleb(uleb128 &id) {
return LongTypeIdRead(parentof(id).dexIndex, uleb128_value(id));
}
string LongTypeIdReadUlebp1(uleb128p1 &id) {
return LongTypeIdRead(parentof(id).dexIndex, uleb128p1_value(id));
}
string FieldIdRead(int dexIndex, int id) {
local string s;
return GetIdAndNameString(id, GetFieldById(dexIndex, id));
}
string MethodIdRead(int dexIndex, int id) {
local string s;
return GetIdAndNameString(id, GetMethodById(dexIndex, id));
}
string GetIdAndNameString(int id, string name) {
local string s;
SPrintf(s, "(0x%X) %s", id, name);
return s;
}
// read a string from the string table
string GetStringById(int dexIndex, int id) {
if(id == NO_INDEX) {
return "NO_INDEX";
}
if(exists(file.dex_files[dexIndex].dex_string_ids.string_id[id])) {
return file.dex_files[dexIndex].dex_string_ids.string_id[id].string_data.data;
} else {
return "***### NO STRING";
}
}
string GetTypeById(int dexIndex, int id) {
if(id == NO_INDEX) {
return "NO_INDEX";
}
if(exists(file.dex_files[dexIndex].dex_type_ids.type_id[id])) {
return GetStringById(dexIndex, file.dex_files[dexIndex].dex_type_ids.type_id[id].descriptor_idx.idx);
} else {
return "*** NO TYPE";
}
}
string GetLongTypeById(int dexIndex, int id) {
return GetLongTypeDescriptor(GetTypeById(dexIndex, id));
}
string GetMethodById(int dexIndex, int id) {
if(id == NO_INDEX) {
return "NO_INDEX";
}
if(exists(file.dex_files[dexIndex].dex_method_ids.method_id[id])) {
return MethodIdItemRead(file.dex_files[dexIndex].dex_method_ids.method_id[id]);
} else {
return "*** NO METHOD";
}
}
string GetFieldById(int dexIndex, int id) {
if(id == NO_INDEX) {
return "NO_INDEX";
}
if(exists(file.dex_files[dexIndex].dex_field_ids.field_id[id])) {
return FieldIdItemRead(file.dex_files[dexIndex].dex_field_ids.field_id[id]);
} else {
return "*** NO FIELD";
}
}
//////////////////////////////////////////////////
// dexopt stuff
//////////////////////////////////////////////////
typedef enum<uint> {
DEX_CHUNK_CLASS_LOOKUP = 0x434c4b50,
DEX_CHUNK_REGISTER_MAPS = 0x524d4150,
DEX_CHUNK_END = 0x41454e44
} DEX_CHUNK_TYPE;
typedef struct {
local quad baseAddr = parentof(this).baseAddr;
local int dexIndex = parentof(this).dexIndex;
DEX_CHUNK_TYPE type <comment="Chunk type">;
uint size <comment="Size of chunk, in bytes">;
local int realsize = (size + 7) & ~7;
if(type == DEX_CHUNK_CLASS_LOOKUP) {
struct dex_class_lookup class_lookup_table <comment="DexOpt class lookup hash table">;
} else if (type == DEX_CHUNK_REGISTER_MAPS) {
ubyte chunkbytes[realsize];
} else if (type == DEX_CHUNK_END) {
//ubyte chunkbytes[realsize];
} else {
SPrintf(temp_warning, "Unknown chunk type 0x%X", type);
PrintWarning(temp_warning);
return;
}
} dexopt_opt_chunk <read=DexOptChunkRead, optimize=false>;
typedef struct {
local quad baseAddr = parentof(this).baseAddr;
local int dexIndex = parentof(this).dexIndex;
local int count = 0;
do {
dexopt_opt_chunk chunk;
count++;
} while(chunk.type != DEX_CHUNK_END);
} dexopt_opt_table <read=DexoptOptTableRead>;
string DexoptOptTableRead(dexopt_opt_table &t) {
local string s;
SPrintf(s, "%i items", t.count);
return s;
}
string DexOptChunkRead(dexopt_opt_chunk &c) {
local string s;
SPrintf(s, "%s chunk: %i bytes", EnumToString(c.type), c.size);
return s;
}
typedef struct {
local quad baseAddr = parentof(this).baseAddr;
local int dexIndex = parentof(this).dexIndex;
int offset;
} class_descriptor <read=readClassDescriptor, optimize=false>;
string readClassDescriptor(class_descriptor &item) {
if(item.offset != 0)
return ReadString(sizeof(dexopt_header) + item.offset);
return "";
}
typedef struct {
local quad baseAddr = parentof(this).baseAddr;
local int dexIndex = parentof(this).dexIndex;
uint class_descriptor_hash <comment="Class descriptor hash code">;
class_descriptor class_descriptor_item <comment="Class descriptor item">;
int class_definition_offset <comment="File offset of class definition">;
} dex_class_lookup_entry <read=DexClassLookupEntryRead, optimize=false>;
string DexClassLookupEntryRead(dex_class_lookup_entry &e) {
local string s;
SPrintf(s, "0x%X: (descriptor 0x%X, definition 0x%X)", e.class_descriptor_hash, e.class_descriptor_item.offset, e.class_definition_offset);
return s;
}
typedef struct {
local quad baseAddr = parentof(this).baseAddr;
local int dexIndex = parentof(this).dexIndex;
int size <comment="Size of dex_class_lookup structure">;
int num_entries <comment="Number of entries in class lookup hashtable">;
if(num_entries > 0) {
dex_class_lookup_entry table[num_entries] <comment="Class lookup table">;
}
} dex_class_lookup;
//////////////////////////////////////////////////
// main stuff
//////////////////////////////////////////////////
// first check file type - dex files start with 'dex', odex files start with 'dey'
//////////////////////////////////////////////////
// dex file
//////////////////////////////////////////////////
typedef struct{
if (global_version[0] == '0' && global_version[1] == '3') {
uint32 code_offset_;
uint32 gc_map_offset_;
} else if (global_version[0] == '0' && global_version[1] == '6') {
uint32 code_offset_;
} else {
uint32 code_offset_;
uint32 frame_size_in_bytes_;
uint32 core_spill_mask_;
uint32 fp_spill_mask_;
uint32 mapping_table_offset_;
uint32 vmap_table_offset_;
uint32 gc_map_offset_;
}
/*
uint32 code_offset_;
uint32 frame_size_in_bytes_;
uint32 core_spill_mask_;
uint32 fp_spill_mask_;
uint32 mapping_table_offset_;
uint32 vmap_table_offset_;
uint32 gc_map_offset_;
*/
/*
local uint32 off = code_offset_ & ~0x1;
if (off > 0) {
Printf("code_offset [%x][%x] = %x\n", code_offset_, off, off + 0x1000);
}
*/
} OatMethodOffsets;
typedef struct (int index) {
local int dexIndex = parentof(this).dexIndex;
local int t_index = index;
if (global_version[0] == '0' && (global_version[1] == '3' || global_version[1] == '6')) {
uint16 status;
uint16 type;
if (type == 0) {
local int methodCount = getClassMethodCount(dexIndex, index);
if (methodCount > 0) {
OatMethodOffsets methodOffset[methodCount] <optimize=false>;
}
} else if (type == 1) {
uint32 bitsize;
ubyte arr[bitsize];
local int i;
local int j;
local int count = 0;
for (i=0; i<bitsize; i++) {
for (j=0; j<8; j++) {
if ((arr[i] & (1<<j)) == (1<<j)) {
// OatMethodOffsets methodOffset(1);
count += 1;
} else {
// OatMethodOffsets methodOffset(0);
}
}
}
if (count > 0) {
OatMethodOffsets methodOffset[count] <optimize=false>;
}
}
} else {
uint32 status;
local int methodCount = getClassMethodCount(dexIndex, index);
if (methodCount > 0) {
OatMethodOffsets methodOffset[methodCount] <optimize=false>;
}
}
//Printf("%x %x %x %x \n", global_version[0], global_version[1], global_version[2], global_version[3]);
//if (methodCount > 0) {
// OatMethodOffsets methodOffset[methodCount] <optimize=false>;
//}
} OatClass <read=ReadOatClass, optimize=false>;
string ReadOatClass(OatClass &c) {
local string name = getClassName(c.dexIndex, c.t_index);
return name;
}
typedef struct (int index, int size) {
local int dexIndex = index;
local int total = size;
local int idx;
for (idx=0; idx<size; idx++) {
OatClass oat_class(idx);
}
} OatClasses <read=ReadOatClasses>;
typedef struct {
// main dex header and structs
local quad addr = FTell();
// local int dexIndex = dexCount;
// dexCount += 1;
SetBackColor(cLtGreen);
header_item header <comment="Dex file header">;
FSeek(header.string_ids_off + addr);
SetBackColor(cLtYellow);
string_id_list dex_string_ids(header.string_ids_size) <comment="String ID list">;
FSeek(header.type_ids_off + addr);
SetBackColor(cLtPurple);
type_id_list dex_type_ids(header.type_ids_size) <comment="Type ID list">;
FSeek(header.proto_ids_off + addr);
SetBackColor(cLtBlue);
proto_id_list dex_proto_ids(header.proto_ids_size) <comment="Method prototype ID list">;
FSeek(header.field_ids_off + addr);
SetBackColor(cYellow);
field_id_list dex_field_ids(header.field_ids_size) <comment="Field ID list">;
FSeek(header.method_ids_off + addr);
SetBackColor(cDkYellow);
method_id_list dex_method_ids(header.method_ids_size) <comment="Method ID list">;
FSeek(header.class_defs_off + addr);
SetBackColor(cLtGray);
class_def_item_list dex_class_defs(header.class_defs_size) <comment="Class definitions list">;
// map list, we don't really do anything with it though
SetBackColor(cLtAqua);
if(header.map_off != 0) {
FSeek(addr + header.map_off);
map_list_type dex_map_list <comment="Map list">;
}
// It's not really useful to see just the last warning, so inform us how many warnings we should see in output
if(warnings > 1) {
Warning("%d warnings have occured and logged to the output box!", warnings);
}
// This will make the template show "Template executed successfully."
if(warnings != 0) {
SPrintf(temp_warning, "%d warnings found, template may not have run successfully!", warnings);
return temp_warning;
}
FSeek(oatClassOffs);
OatClasses oat_classes(header.dexIndex, header.class_defs_size);
oatClassOffs = FTell();
FSeek(addr + header.file_size);
} DexFile <optimize=false, size=readDexFileSize>;
int readDexFileSize(DexFile &item) {
return ReadUInt(startof(item)+32);
}
string ReadOatClasses(OatClasses &oc) {
local string s;
SPrintf(s, "%i classes", oc.total);
return s;
}
string getClassName(int dexIndex, int classIdx) {
if (exists(file.dex_files[dexIndex].dex_class_defs.class_def[classIdx])) {
return GetLongTypeById(dexIndex, file.dex_files[dexIndex].dex_class_defs.class_def[classIdx].class_idx.idx);
}
return "** NO NAME **";
}
int getClassMethodCount(int index, int classIdx) {
if (exists(file.dex_files[dexIndex].dex_class_defs.class_def[classIdx])) {
if (exists(file.dex_files[dexIndex].dex_class_defs.class_def[classIdx].class_data)) {
local int dirNum = uleb128_value(file.dex_files[dexIndex].dex_class_defs.class_def[classIdx].class_data.direct_methods_size);
local int virNum = uleb128_value(file.dex_files[dexIndex].dex_class_defs.class_def[classIdx].class_data.virtual_methods_size);
return dirNum + virNum;
}
}
return 0;
}
typedef struct {
uint32 dex_file_location_size;
char dex_file_location_data[dex_file_location_size];
uint32 dex_file_checksum;
uint32 dex_file_offset;
dexOffs[dexCount] = dex_file_offset + oatdata_off;
// local quad off = FTell();
// FSeek(oatdata_off + dex_file_offset);
// // Printf("start dexfile\n");
// DexFile dex_file;
// // Printf("end dexfile\n");
// FSeek(off);
// //local quad method_count = (oatdata_off + dex_file_offset - off) / sizeof(uint32);
// uint32 class_offs[dex_file.class_defs_size];
// FSeek(oatdata_off + dex_file_offset + dex_file.file_size);
// OatClasses oat_classes(dex_file.class_defs_size) ;
// FSeek(off + dex_file.class_defs_size*4);
local uint32 classDefsSize = getClassDefsSize(dex_file_offset);
defsSize[dexCount] = classDefsSize;
dexCount += 1;
uint32 class_offs[classDefsSize];
} OatDexFile <optimize=false>;
uint32 getClassDefsSize(uint32 addr) {
// Printf("SectionVAddrOffset=%x\n", oatdata_off + addr + 0x60);
return ReadUInt(oatdata_off + addr + 0x60);
}
typedef struct {
char magic[4];
char version[4];
uint32 checksum;
InstructionSet instruction_set;
if (version[0] == '0' && (version[1] == '3' || version[1] == '6')) {
uint32 instruction_set_features_;
}
global_version[0] = version[0];
global_version[1] = version[1];
global_version[2] = version[2];
global_version[3] = version[3];
uint32 dex_file_count;
uint32 executable_offset_;
uint32 interpreter_to_interpreter_bridge_offset_;
uint32 interpreter_to_compiled_code_bridge_offset_;
uint32 jni_dlsym_lookup_offset_;
if (version[0] == '0' && version[1] == '6') {
uint32 quick_generic_jni_trampoline_offset_;
uint32 quick_imt_conflict_trampoline_offset_;
uint32 quick_resolution_trampoline_offset_;
uint32 quick_to_interpreter_bridge_offset_;
int32 image_patch_delta_;
uint32 image_file_location_oat_checksum_;
uint32 image_file_location_oat_data_begin_;
uint32 key_value_store_size_;
char key_value_store_[key_value_store_size_];
//uint32 key_value_store_;
//uchar key_value_store_[0];
} else {
// oat 031 begin
if (version[0] == '0' && version[1] == '3') {
uint32 portable_imt_conflict_trampoline_offset_;
}
// oat 031 end
uint32 portable_resolution_trampoline_offset_;
uint32 portable_to_interpreter_bridge_offset_;
// oat 031 begin
if (version[0] == '0' && version[1] == '3') {
uint32 quick_generic_jni_trampoline_offset_;
uint32 quick_imt_conflict_trampoline_offset_;
}
// oat 031 end
uint32 quick_resolution_trampoline_offset_;
uint32 quick_to_interpreter_bridge_offset_;
// oat 039 begin
if (version[0] == '0' && version[1] == '3' && version[2] == '9') {
uint32 image_patch_delta_;
}
// uint32 unknow_3;
// uint32 unknow_4;
// uint32 unknow_5;
// oat 039 end
uint32 image_file_location_oat_checksum_;
uint32 image_file_location_oat_data_begin_;
uint32 image_file_location_size;
char image_file_location_data[image_file_location_size];
}
} OatHeader;
struct {
local int elf = 1;
local char tmp[3];
ReadBytes(tmp, 0, 3);
FSeek(0);
if(!Strcmp(tmp, "oat")) {
elf = 0;
}
if (elf) {
Elf32_Ehdr elf_header;
if (elf_header.e_phnum > 0) {
FSeek(elf_header.e_phoff);
Elf32_Phdr elf_program_header[elf_header.e_phnum];
}
local uint soff = elf_header.e_shoff + elf_header.e_shentsize * elf_header.e_shstrndx;
section_name_off = ReadUInt(soff + 3 * sizeof( Elf32_Word ) + sizeof( Elf32_Addr ));
// Printf("section_name_off=%x", section_name_off);
if (elf_header.e_shnum > 0) {
FSeek(elf_header.e_shoff);
Elf32_Shdr elf_section_header[elf_header.e_shnum] <read=ReadSection>;
local uint strindex = FindNamedSection(".dynstr");
dynsym_name_off = elf_section_header[strindex].sh_offset;
local uint symindex = FindNamedSection(".dynsym");
local uint symcount = elf_section_header[symindex].sh_size / sizeof(Elf32_Sym_Fixed);
FSeek(elf_section_header[symindex].sh_offset);
// dynsym
Elf32_Sym symtab[symcount] <read=ReadDynsymItem>;
// dynstr
if (elf_section_header[strindex].sh_size > 0) {
local quad off = FTell();
FSeek( dynsym_name_off );
char dynstr[elf_section_header[strindex].sh_size];
FSeek( off );
}
// hash
local uint hashindex = FindNamedSection(".hash");
FSeek( elf_section_header[hashindex].sh_offset );
Elf32_Word hash[elf_section_header[hashindex].sh_size];
// rodata
local uint rodataindex = FindNamedSection(".rodata");
FSeek( elf_section_header[rodataindex].sh_offset );
uchar rodata[elf_section_header[rodataindex].sh_size];
// text
local uint textindex = FindNamedSection(".text");
FSeek( elf_section_header[textindex].sh_offset );
uchar text[elf_section_header[textindex].sh_size];
// dynamic
local uint dynamicindex = FindNamedSection(".dynamic");
FSeek( elf_section_header[dynamicindex].sh_offset );
uchar dynamic[elf_section_header[dynamicindex].sh_size];
// shstrtab
local uint shstrtabindex = FindNamedSection(".shstrtab");
FSeek( elf_section_header[shstrtabindex].sh_offset );
char shstrtab[elf_section_header[shstrtabindex].sh_size];
}
}
if (oatdata_off > 0) {
FSeek(oatdata_off);
}
OatHeader oat_header;
OatDexFile oat_dex_files[oat_header.dex_file_count];
FSeek( oat_dex_files[0].dex_file_offset + oatdata_off );
DexFile dex_files[dexCount];
oatClassOffs = FTell();
//local int i;
//for(i=0;i<dexCount;i++) {
// OatClasses oat_classes(i, defsSize[i]);
//}
} file;
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。