├── ARSCTemplate.bt ├── AXMLTemplate.bt ├── ELFTemplate.bt ├── LICENSE ├── OATTemplate.bt └── README.md /ARSCTemplate.bt: -------------------------------------------------------------------------------- 1 | //-------------------------------------- 2 | //--- 010 Editor v3.1.3 Binary Template 3 | // 4 | // File: 5 | // Author: 6 | // Revision: 7 | // Purpose: 8 | //-------------------------------------- 9 | 10 | LittleEndian(); 11 | 12 | local int UTF8_FLAG = 1<<8; 13 | local int g_offset = 0; 14 | 15 | typedef struct { 16 | local int size; 17 | ubyte hval ; 18 | ubyte lval ; 19 | if((hval & 0x80) != 0) { 20 | size = (((hval & 0x7F) << 8)) | lval; 21 | } else { 22 | size = hval; 23 | } 24 | } utf8size ; 25 | 26 | string Utf8SizeRead(utf8size &u) { 27 | local string s; 28 | s = SPrintf(s, "0x%X", u.size); 29 | return s; 30 | } 31 | 32 | enum { 33 | RES_NULL_TYPE = 0x0000, 34 | RES_STRING_POOL_TYPE = 0x0001, 35 | RES_TABLE_TYPE = 0x0002, 36 | RES_XML_TYPE = 0x0003, 37 | 38 | // Chunk types in RES_XML_TYPE 39 | RES_XML_FIRST_CHUNK_TYPE = 0x0100, 40 | RES_XML_START_NAMESPACE_TYPE= 0x0100, 41 | RES_XML_END_NAMESPACE_TYPE = 0x0101, 42 | RES_XML_START_ELEMENT_TYPE = 0x0102, 43 | RES_XML_END_ELEMENT_TYPE = 0x0103, 44 | RES_XML_CDATA_TYPE = 0x0104, 45 | RES_XML_LAST_CHUNK_TYPE = 0x017f, 46 | // This contains a uint32_t array mapping strings in the string 47 | // pool back to resource identifiers. It is optional. 48 | RES_XML_RESOURCE_MAP_TYPE = 0x0180, 49 | 50 | // Chunk types in RES_TABLE_TYPE 51 | RES_TABLE_PACKAGE_TYPE = 0x0200, 52 | RES_TABLE_TYPE_TYPE = 0x0201, 53 | RES_TABLE_TYPE_SPEC_TYPE = 0x0202, 54 | RES_TABLE_LIBRARY_TYPE = 0x0203 55 | }; 56 | 57 | /* attributes' types */ 58 | typedef enum { 59 | 60 | ATTR_NULL = 0, 61 | ATTR_REFERENCE = 1, 62 | ATTR_ATTRIBUTE = 2, 63 | ATTR_STRING = 3, 64 | ATTR_FLOAT = 4, 65 | ATTR_DIMENSION = 5, 66 | ATTR_FRACTION = 6, 67 | 68 | ATTR_FIRSTINT = 16, 69 | 70 | ATTR_DEC = 16, 71 | ATTR_HEX = 17, 72 | ATTR_BOOLEAN = 18, 73 | 74 | ATTR_FIRSTCOLOR = 28, 75 | ATTR_ARGB8 = 28, 76 | ATTR_RGB8 = 29, 77 | ATTR_ARGB4 = 30, 78 | ATTR_RGB4 = 31, 79 | ATTR_LASTCOLOR = 31, 80 | 81 | ATTR_LASTINT = 31, 82 | } arsc_attr_type; 83 | 84 | typedef struct { 85 | ushort size; 86 | uchar res0; 87 | uchar dateType ; 88 | uint data; 89 | } arsc_value; 90 | 91 | string ArscAttrTypeRead(uchar type) { 92 | if (type == ATTR_NULL) 93 | return EnumToString( ATTR_NULL ); 94 | else if (type == ATTR_REFERENCE) 95 | return EnumToString( ATTR_REFERENCE ); 96 | else if (type == ATTR_ATTRIBUTE) 97 | return EnumToString( ATTR_ATTRIBUTE ); 98 | else if (type == ATTR_STRING) 99 | return EnumToString( ATTR_STRING ); 100 | else if (type == ATTR_FLOAT) 101 | return EnumToString( ATTR_FLOAT ); 102 | else if (type == ATTR_DIMENSION) 103 | return EnumToString( ATTR_DIMENSION ); 104 | else if (type == ATTR_FRACTION) 105 | return EnumToString( ATTR_FRACTION ); 106 | else if (type == ATTR_DEC) 107 | return EnumToString( ATTR_DEC ); 108 | else if (type == ATTR_HEX) 109 | return EnumToString( ATTR_HEX ); 110 | else if (type == ATTR_BOOLEAN) 111 | return EnumToString( ATTR_BOOLEAN ); 112 | else if (type == ATTR_ARGB8) 113 | return EnumToString( ATTR_ARGB8 ); 114 | else if (type == ATTR_RGB8) 115 | return EnumToString( ATTR_RGB8 ); 116 | else if (type == ATTR_ARGB4) 117 | return EnumToString( ATTR_ARGB4 ); 118 | else if (type == ATTR_RGB4) 119 | return EnumToString( ATTR_RGB4 ); 120 | else if (type >= ATTR_FIRSTCOLOR && type <= ATTR_LASTCOLOR4) 121 | return "ATTR_COLOR"; 122 | else if (type >= ATTR_FIRSTINT && type <= ATTR_LASTINT) 123 | return "ATTR_INT"; 124 | else 125 | return "ATTR_UNKNOW"; 126 | } 127 | 128 | typedef struct { 129 | ushort type ; 130 | ushort head_size; 131 | uint size; 132 | } arsc_header; 133 | 134 | typedef struct { 135 | arsc_header header; 136 | uint packageCount; 137 | } arsc_table; 138 | 139 | typedef struct { 140 | ushort len; 141 | if (len > 0) { 142 | wchar_t data[len]; 143 | } 144 | } arsc_string; 145 | 146 | typedef struct arsc_string_offset_st(uint begin) { 147 | uint offset; 148 | 149 | local int64 pos = FTell(); 150 | local int off = begin + offset; 151 | FSeek(g_offset + off); 152 | 153 | arsc_string astr; 154 | 155 | FSeek(pos); 156 | } arsc_string_offset ; 157 | 158 | string ArscStringRead(arsc_string_offset &o) { 159 | if (o.astr.len > 0) 160 | return o.astr.data; 161 | else 162 | return "NULL String"; 163 | } 164 | 165 | typedef struct { 166 | utf8size len; 167 | // Printf( "%d\n", len.size ); 168 | if (len.size > 0) { 169 | char data[len.size]; 170 | } 171 | } arsc_string_utf8; 172 | 173 | typedef struct arsc_string_offset_utf8_st(uint begin) { 174 | uint offset; 175 | 176 | local int64 pos = FTell(); 177 | local int off = begin + offset; 178 | FSeek(g_offset + off); 179 | 180 | arsc_string_utf8 astr; 181 | 182 | FSeek(pos); 183 | } arsc_string_offset_utf8 ; 184 | 185 | string ArscStringUtf8Read(arsc_string_offset_utf8 &o) { 186 | if (o.astr.len.size > 0) 187 | return o.astr.data; 188 | else 189 | return "NULL String"; 190 | } 191 | 192 | typedef struct { 193 | local uint begin = FTell(); 194 | local uint off; 195 | local int i; 196 | 197 | arsc_header header; 198 | int string_count; 199 | int style_count; 200 | int flag; 201 | int string_offset; 202 | int style_offset; 203 | for(i=0; i; 206 | } else { 207 | arsc_string_offset string_offsets(begin+string_offset) ; 208 | } 209 | } 210 | 211 | if (style_count > 0) { 212 | uint style_offsets[style_count]; 213 | off = style_offset - string_offset; 214 | } else { 215 | off = header.size - string_offset; 216 | } 217 | 218 | FSkip(off); 219 | } arsc_strings; 220 | 221 | typedef struct { 222 | ushort size; 223 | ushort flags; 224 | uint keyRef; 225 | } arsc_entry; 226 | 227 | typedef struct { 228 | uint name; 229 | arsc_value value; 230 | } arsc_map; 231 | 232 | typedef struct { 233 | arsc_entry entry; 234 | uint parentRef; 235 | uint count; 236 | if (count > 0) { 237 | arsc_map data[count]; 238 | } 239 | } arsc_mapentry; 240 | 241 | typedef struct { 242 | arsc_header header; 243 | ubyte id; 244 | ubyte res0; 245 | ushort res1; 246 | uint entryCount; 247 | if (entryCount > 0) { 248 | uint entrys[entryCount]; 249 | } 250 | } arsc_typespec; 251 | 252 | typedef struct { 253 | uint size; 254 | uint imsi; 255 | uint locale; 256 | uint screenType; 257 | uint input; 258 | uint screenSize; 259 | uint version; 260 | uint screenConfig; 261 | uint screenSizeDp; 262 | uchar localeScript[4]; 263 | uchar localeVariant[8]; 264 | uint screenConfig2; 265 | } arsc_config; 266 | 267 | typedef struct { 268 | arsc_header header; 269 | ubyte id; 270 | ubyte res0; 271 | ushort res1; 272 | uint entryCount; 273 | uint entriesStart; 274 | 275 | local uint cfgBegin = FTell(); 276 | arsc_config config; 277 | FSeek(cfgBegin + config.size); 278 | 279 | local ushort size; 280 | local ushort flag; 281 | local int i; 282 | local uint entryOff; 283 | if (entryCount > 0) { 284 | uint entryOffsets[entryCount]; 285 | 286 | local uint entryBegin = FTell(); 287 | 288 | for(i=0; i; 341 | } else if (htype == RES_TABLE_TYPE_TYPE) { 342 | arsc_typetype typeType; 343 | } else if (htype == RES_TABLE_LIBRARY_TYPE) { 344 | Printf("unsupported type RES_TABLE_LIBRARY_TYPE\n"); 345 | } else { 346 | Printf("unknow type %x\n", htype); 347 | break; 348 | } 349 | 350 | cur += size; 351 | FSeek(cur); 352 | }; 353 | } arsc_package; 354 | 355 | string AresTypeSpecRead(arsc_typespec &spec) { 356 | // local arsc_package pkg = parentof(spec); 357 | string ret = ""; 358 | SPrintf(ret, "~~"); 359 | return ret; 360 | } 361 | 362 | struct FILE { 363 | arsc_table header; 364 | 365 | local ushort htype; 366 | local ushort hsize; 367 | local uint size = 0; 368 | do { 369 | htype = ReadUShort(FTell()); 370 | hsize = ReadUShort(FTell()+2); 371 | size = ReadUInt(FTell()+4); 372 | 373 | if (htype == RES_STRING_POOL_TYPE) { 374 | arsc_strings strings; 375 | } else if (htype == RES_TABLE_PACKAGE_TYPE) { 376 | arsc_package package; 377 | } else { 378 | Printf("not supported header type %d\n", htype); 379 | break; 380 | } 381 | } while(!FEof()); 382 | 383 | } file; 384 | 385 | string AresStringById(int &index, arsc_strings& strpool) { 386 | string ret = ""; 387 | if (index >= 0 && index < strpool.string_count) { 388 | return strpool.string_offsets[index].astr.data; 389 | } else { 390 | SPrintf(ret, "NULL Out off strings[%d] range %d", file.strings.string_count, index); 391 | return ret; 392 | } 393 | } 394 | -------------------------------------------------------------------------------- /AXMLTemplate.bt: -------------------------------------------------------------------------------- 1 | //-------------------------------------- 2 | //--- 010 Editor v3.1.3 Binary Template 3 | // 4 | // File: 5 | // Author: 6 | // Revision: 7 | // Purpose: 8 | //-------------------------------------- 9 | 10 | LittleEndian(); 11 | 12 | local int g_offset = 0; 13 | 14 | enum { 15 | RES_NULL_TYPE = 0x0000, 16 | RES_STRING_POOL_TYPE = 0x0001, 17 | RES_TABLE_TYPE = 0x0002, 18 | RES_XML_TYPE = 0x0003, 19 | 20 | // Chunk types in RES_XML_TYPE 21 | RES_XML_FIRST_CHUNK_TYPE = 0x0100, 22 | RES_XML_START_NAMESPACE_TYPE= 0x0100, 23 | RES_XML_END_NAMESPACE_TYPE = 0x0101, 24 | RES_XML_START_ELEMENT_TYPE = 0x0102, 25 | RES_XML_END_ELEMENT_TYPE = 0x0103, 26 | RES_XML_CDATA_TYPE = 0x0104, 27 | RES_XML_LAST_CHUNK_TYPE = 0x017f, 28 | // This contains a uint32_t array mapping strings in the string 29 | // pool back to resource identifiers. It is optional. 30 | RES_XML_RESOURCE_MAP_TYPE = 0x0180, 31 | 32 | // Chunk types in RES_TABLE_TYPE 33 | RES_TABLE_PACKAGE_TYPE = 0x0200, 34 | RES_TABLE_TYPE_TYPE = 0x0201, 35 | RES_TABLE_TYPE_SPEC_TYPE = 0x0202 36 | }; 37 | 38 | typedef enum { 39 | CHUNK_HEAD = 0x00080003, 40 | CHUNK_STRING = 0x001c0001, 41 | CHUNK_RESOURCE = 0x00080180, 42 | CHUNK_STARTNS = 0x00100100, 43 | CHUNK_ENDNS = 0x00100101, 44 | CHUNK_STARTTAG = 0x00100102, 45 | CHUNK_ENDTAG = 0x00100103, 46 | CHUNK_TEXT = 0x00100104 47 | } axml_type; 48 | 49 | // DimemsionTable[8] = {"px", "dip", "sp", "pt", "in", "mm", "", ""}; 50 | typedef enum { 51 | px = 0, 52 | dip, 53 | sp, 54 | pt, 55 | in, 56 | mm 57 | } axml_dimension; 58 | 59 | local float RadixTable[8] = {0.00390625f, 3.051758E-005f, 1.192093E-007f, 4.656613E-010f}; 60 | 61 | /* attributes' types */ 62 | typedef enum { 63 | 64 | ATTR_NULL = 0, 65 | ATTR_REFERENCE = 1, 66 | ATTR_ATTRIBUTE = 2, 67 | ATTR_STRING = 3, 68 | ATTR_FLOAT = 4, 69 | ATTR_DIMENSION = 5, 70 | ATTR_FRACTION = 6, 71 | 72 | ATTR_FIRSTINT = 16, 73 | 74 | ATTR_DEC = 16, 75 | ATTR_HEX = 17, 76 | ATTR_BOOLEAN = 18, 77 | 78 | ATTR_FIRSTCOLOR = 28, 79 | ATTR_ARGB8 = 28, 80 | ATTR_RGB8 = 29, 81 | ATTR_ARGB4 = 30, 82 | ATTR_RGB4 = 31, 83 | ATTR_LASTCOLOR = 31, 84 | 85 | ATTR_LASTINT = 31, 86 | } axml_attr_type; 87 | 88 | typedef struct { 89 | ushort type ; 90 | ushort head_size; 91 | int size; 92 | } axml_header; 93 | 94 | typedef struct { 95 | uchar len; 96 | uchar enc_len; 97 | if (len > 0) { 98 | char data[len]; 99 | } 100 | } axml_string8; 101 | 102 | typedef struct { 103 | ushort len; 104 | if (len > 0) { 105 | wchar_t data[len]; 106 | } 107 | } axml_string16; 108 | 109 | typedef struct { 110 | uint offset; 111 | 112 | local int64 pos = FTell(); 113 | local int off = sizeof(file.header) + file.strings.string_offset + offset; 114 | FSeek(g_offset + off); 115 | // Printf("offset=%x\n", off); 116 | 117 | local int isUtf8 = parentof(this).flag & (1<<8); 118 | if (isUtf8) 119 | axml_string8 astr; 120 | else 121 | axml_string16 astr; 122 | 123 | FSeek(pos); 124 | } axml_string_offset ; 125 | 126 | string AxmlStringRead(axml_string_offset &o) { 127 | if (o.astr.len > 0) 128 | return o.astr.data; 129 | else 130 | return "NULL String"; 131 | } 132 | 133 | typedef struct { 134 | axml_header header; 135 | int string_count; 136 | int style_count; 137 | int flag; 138 | int string_offset; 139 | int style_offset; 140 | if (string_count > 0) { 141 | axml_string_offset string_offsets[string_count] ; 142 | } 143 | 144 | if (style_count > 0) { 145 | uint style_offsets[style_count]; 146 | off = style_offset - string_offset; 147 | } else { 148 | off = header.size - string_offset; 149 | } 150 | 151 | FSkip(off); 152 | } axml_strings; 153 | 154 | typedef struct { 155 | axml_header header; 156 | 157 | local int count = (header.size-8) / 4; 158 | uint ids[count] ; 159 | } axml_resources; 160 | 161 | typedef struct { 162 | ushort size; 163 | uchar res0; 164 | uchar dateType ; 165 | uint data; 166 | } axml_value; 167 | 168 | typedef struct { 169 | int url ; 170 | int name ; 171 | int str ; 172 | 173 | axml_value value; 174 | } axml_attr ; 175 | 176 | string AxmlAttrTypeRead(uchar type) { 177 | if (type == ATTR_NULL) 178 | return EnumToString( ATTR_NULL ); 179 | else if (type == ATTR_REFERENCE) 180 | return EnumToString( ATTR_REFERENCE ); 181 | else if (type == ATTR_ATTRIBUTE) 182 | return EnumToString( ATTR_ATTRIBUTE ); 183 | else if (type == ATTR_STRING) 184 | return EnumToString( ATTR_STRING ); 185 | else if (type == ATTR_FLOAT) 186 | return EnumToString( ATTR_FLOAT ); 187 | else if (type == ATTR_DIMENSION) 188 | return EnumToString( ATTR_DIMENSION ); 189 | else if (type == ATTR_FRACTION) 190 | return EnumToString( ATTR_FRACTION ); 191 | else if (type == ATTR_DEC) 192 | return EnumToString( ATTR_DEC ); 193 | else if (type == ATTR_HEX) 194 | return EnumToString( ATTR_HEX ); 195 | else if (type == ATTR_BOOLEAN) 196 | return EnumToString( ATTR_BOOLEAN ); 197 | else if (type == ATTR_ARGB8) 198 | return EnumToString( ATTR_ARGB8 ); 199 | else if (type == ATTR_RGB8) 200 | return EnumToString( ATTR_RGB8 ); 201 | else if (type == ATTR_ARGB4) 202 | return EnumToString( ATTR_ARGB4 ); 203 | else if (type == ATTR_RGB4) 204 | return EnumToString( ATTR_RGB4 ); 205 | else if (type >= ATTR_FIRSTCOLOR && type <= ATTR_LASTCOLOR4) 206 | return "ATTR_COLOR"; 207 | else if (type >= ATTR_FIRSTINT && type <= ATTR_LASTINT) 208 | return "ATTR_INT"; 209 | else 210 | return "ATTR_UNKNOW"; 211 | } 212 | 213 | string AxmlAttrRead(axml_attr &attr) { 214 | local uchar type = attr.value.dateType; 215 | string name = AxmlStringById(attr.name); 216 | string buf = "Unknow"; 217 | 218 | if (type == ATTR_STRING) { 219 | local string val = AxmlStringById(attr.str); 220 | SPrintf(buf, "%s=%s", name, val); 221 | } else if (type == ATTR_NULL) { 222 | SPrintf(buf, "%s=NULL", name); 223 | } else if (type == ATTR_REFERENCE) { 224 | if (attr.value.data>>24 == 1) { 225 | SPrintf(buf, "%s=@android:%08X", name, attr.value.data); 226 | } else { 227 | SPrintf(buf, "%s=@%08X", name, attr.value.data); 228 | } 229 | } else if (type == ATTR_ATTRIBUTE) { 230 | if (attr.value.data>>24 == 1) { 231 | SPrintf(buf, "%s=?android:%08X", name, attr.value.data); 232 | } else { 233 | SPrintf(buf, "%s=?%08X", name, attr.value.data); 234 | } 235 | } else if (type == ATTR_FLOAT) { 236 | SPrintf(buf, "%s=%g", name, (float)attr.value.data); 237 | } else if (type == ATTR_DIMENSION) { 238 | SPrintf(buf, "%s=%f%s", name, 239 | (float)(attr.value.data & 0xffffff00) * RadixTable[(attr.data >> 4) & 0x03], 240 | DimemsionTable[attr.data & 0x0f] ); 241 | } else if (type == ATTR_FRACTION) { 242 | SPrintf(buf, "%s=%f%s", name, 243 | (float)(attr.value.data & 0xffffff00) * RadixTable[(attr.value.data >> 4) & 0x03], 244 | FractionTable[attr.value.data & 0x0f] ); 245 | } else if (type == ATTR_HEX) { 246 | SPrintf(buf, "%s=0x%08x", name, attr.value.data); 247 | } else if (type == ATTR_BOOLEAN) { 248 | if (attr.value.data == 0) { 249 | SPrintf(buf, "%s=false", name); 250 | } else { 251 | SPrintf(buf, "%s=true", name); 252 | } 253 | } else if (type >= ATTR_FIRSTCOLOR && type <= ATTR_LASTCOLOR) { 254 | SPrintf(buf, "%s=#%08x", name, attr.value.data); 255 | } else if (type >= ATTR_FIRSTINT && type <= ATTR_LASTINT) { 256 | SPrintf(buf, "%s=%d", name, attr.value.data); 257 | } else { 258 | SPrintf(buf, "%s=UNKNOW", name); 259 | } 260 | 261 | return buf; 262 | } 263 | 264 | typedef struct { 265 | uint type ; 266 | int chunk_size; 267 | int linenumber; 268 | int comment; 269 | 270 | if (type == CHUNK_STARTTAG) { 271 | int uri ; 272 | int name ; 273 | ushort attr_start; 274 | ushort attr_size; 275 | ushort attr_count; 276 | ushort idIndex; 277 | ushort classIndex; 278 | ushort styleIndex; 279 | if (attr_count > 0) { 280 | axml_attr attrs[attr_count]; 281 | } 282 | } else if (type == CHUNK_ENDTAG) { 283 | int url; 284 | int name ; 285 | } else if (type == CHUNK_STARTNS) { 286 | int prefix ; 287 | int uri ; 288 | } else if (type == CHUNK_ENDNS) { 289 | int prefix ; 290 | int uri ; 291 | } else if (type == CHUNK_TEXT) { 292 | int text; 293 | int unknow; 294 | } 295 | } axml_node ; 296 | 297 | string AxmlNodeRead(axml_node &node) { 298 | string buf = AxmlTypeString(node.type); 299 | if (node.type == CHUNK_STARTNS) { 300 | SPrintf(buf, "", AxmlStringById(node.prefix)); 301 | } else if (node.type == CHUNK_ENDNS) { 302 | SPrintf(buf, "", AxmlStringById(node.prefix)); 303 | } else if (node.type == CHUNK_STARTTAG) { 304 | SPrintf(buf, "<%s>", AxmlStringById(node.name)); 305 | } else if (node.type == CHUNK_ENDTAG) { 306 | SPrintf(buf, "", AxmlStringById(node.name)); 307 | } 308 | return buf; 309 | } 310 | 311 | string AxmlTypeString(uint &type) { 312 | if (type == CHUNK_HEAD) 313 | return "TYPE_HEAD"; 314 | else if (type == CHUNK_STRING) 315 | return "TYPE_STRINGS"; 316 | else if (type == CHUNK_RESOURCE) 317 | return "TYPE_RESOURCES"; 318 | else if (type == CHUNK_STARTNS) 319 | return "TYPE_NS_START"; 320 | else if (type == CHUNK_ENDNS) 321 | return "TYPE_NS_END"; 322 | else if (type == CHUNK_STARTTAG) 323 | return "TYPE_TAG_START"; 324 | else if (type == CHUNK_ENDTAG) 325 | return "TYPE_TAG_END"; 326 | else if (type == CHUNK_TEXT) 327 | return "TYPE_TEXT"; 328 | else 329 | return "TYPE_UNKNOW"; 330 | } 331 | 332 | struct FILE { 333 | local int off; 334 | local int total; 335 | 336 | axml_header header; 337 | axml_strings strings; 338 | axml_resources resources; 339 | 340 | total = 0; 341 | do { 342 | total += 1; 343 | // Printf("total=%d\n", total); 344 | 345 | axml_node node; 346 | } while (!FEof()); 347 | 348 | } file; 349 | 350 | string AxmlStringById(int &index) { 351 | string ret = ""; 352 | if (index >= 0 && index < file.strings.string_count) { 353 | return file.strings.string_offsets[index].astr.data; 354 | } else { 355 | SPrintf(ret, "NULL Out off strings[%d] range %d", file.strings.string_count, index); 356 | return ret; 357 | } 358 | } 359 | 360 | -------------------------------------------------------------------------------- /ELFTemplate.bt: -------------------------------------------------------------------------------- 1 | //---------------------------------------- 2 | //--- 010 Editor v2.0 Binary Template 3 | // 4 | // File: ELFTemplate.bt 5 | // Author: 010Editor (Unknown?) 6 | // Tim "diff" Strazzere 7 | // Revision: 2.5.2 8 | // Purpose: Defines a template for 9 | // parsing ELF 32-bit and 64-bit files. 10 | //---------------------------------------- 11 | // 12 | // Version 2.5.1 / 2.5.2 13 | // FIXED: 14 | // - Some typos and added a out of bounds check 15 | // 16 | // Version 2.5 17 | // ADDED/FIXED: 18 | // - Added actual ELF file checking 19 | // - Fixed indentations 20 | // 21 | // Version 2.4 22 | // ADDED/FIXED: 23 | // - Added a ton more ARM, specific GNU ARM style information 24 | // - Fixed lots of whitespacing issues and consistency issues 25 | // 26 | // Version 2.3 27 | // ADDED: 28 | // - Simple error checking around program headers - skip over invalid ones and keep going 29 | // - Simple warning logging (taken from my DEXTemplate.bt) 30 | // - Lots of comments for template variables to help understand wtf is going on, 31 | // most taken from; 32 | // http://www.ouah.org/RevEng/x430.htm 33 | // http://www.uclibc.org/docs/elf-64-gen.pdf 34 | // 35 | // Version 2.2 36 | // FIXED: 37 | // - Fixed issues if the section header count is greater 38 | // the actual number of sections that exist. 39 | // More information; 40 | // http://dustri.org/b/?p=832 41 | // 42 | // Version 2.1 43 | // FIXED: 44 | // - Fixed issue with local variables so it's actually 45 | // runnable inside v4.0.3 46 | 47 | // Define structures used in ELF files 48 | 49 | // ELF Header Types 50 | // ELF identification element 51 | 52 | local int warnings = 0; 53 | local string temp_warning; 54 | 55 | // A hack to get warning messages to both "Warn" (show in status) and output to the "output" window 56 | void PrintWarning(string message) { 57 | Warning(temp_warning); 58 | 59 | // Ensure new-line, "Warning" statuses should not have them 60 | SPrintf(temp_warning, "%s\n", message); 61 | Printf(temp_warning); 62 | 63 | // Hack to trigger a more generic "look at warnings in output" 64 | warnings++; 65 | } 66 | 67 | // Accelerate a slow lookup with an array 68 | local int sec_tbl_elem[255]; 69 | 70 | typedef enum { 71 | ELFCLASSNONE = 0x0, 72 | ELFCLASS32 = 0x1, 73 | ELFCLASS64 = 0x2, 74 | ELFCLASSNUM = 0x3 75 | } ei_class_2_e; 76 | 77 | typedef enum { 78 | ELFDATANONE = 0x0, 79 | ELFDATA2LSB = 0x1, 80 | ELFDATA2MSB = 0x2, 81 | ELFDATANUM = 0x3 82 | } ei_data_e; 83 | 84 | typedef enum { 85 | E_NONE = 0x0, 86 | E_CURRENT = 0x1, 87 | E_NUM = 0x2 88 | } ei_version_e; 89 | 90 | typedef enum { 91 | ELFOSABI_NONE = 0x0, //No extensions or unspecified 92 | ELFOSABI_HPUX = 0x1, //Hewlett-Packard HP-UX 93 | ELFOSABI_NETBSD = 0x2, //NetBSD 94 | ELFOSABI_LINUX = 0x3, //Linux 95 | ELFOSABI_SOLARIS = 0x6, //Sun Solaris 96 | ELFOSABI_AIX = 0x7, //AIX 97 | ELFOSABI_IRIX = 0x8, //IRIX 98 | ELFOSABI_FREEBSD = 0x9, //FreeBSD 99 | ELFOSABI_TRU64 = 0xA, //Compaq TRU64 UNIX 100 | ELFOSABI_MODESTO = 0xB, //Novell Modesto 101 | ELFOSABI_OPENBSD = 0xC, //Open BSD 102 | ELFOSABI_OPENVMS = 0xD, //Open VMS 103 | ELFOSABI_NSK = 0xE, //Hewlett-Packard Non-Stop Kernel 104 | ELFOSABI_AROS = 0xF, //Amiga Research OS 105 | ELFOSABI_ARM_AEABI = 0x40, //ARM EABI 106 | ELFOSABI_ARM = 0x61, //ARM 107 | ELFOSABI_STANDALONE = 0xFF //Standalone (embedded applications) 108 | } ei_osabi_e; 109 | 110 | typedef struct { 111 | char file_identification[4]; 112 | if(Strcmp(file_identification, "\x7FELF")) { 113 | PrintWarning("Invalid ELF file"); 114 | return -1; 115 | } 116 | 117 | ei_class_2_e ei_class_2; 118 | ei_data_e ei_data; 119 | 120 | if(ei_data == ELFDATA2LSB) { 121 | LittleEndian(); 122 | } else { 123 | BigEndian(); 124 | } 125 | 126 | ei_version_e ei_version; 127 | ei_osabi_e ei_osabi; 128 | uchar ei_abiversion; 129 | uchar ei_pad[6]; 130 | uchar ei_nident_SIZE; 131 | } e_ident_t; 132 | 133 | // Elf Data Types for 32/64 bit 134 | //32 bit 135 | typedef uint32 Elf32_Word; 136 | typedef uint32 Elf32_Off; 137 | typedef uint32 Elf32_Addr ; 138 | typedef uint16 Elf32_Half; 139 | typedef uint32 Elf32_Xword; 140 | typedef int Elf32_Sword; 141 | 142 | typedef enum { 143 | DT_NULL = 0, 144 | DT_NEEDED = 1, 145 | DT_PLTRELSZ = 2, 146 | DT_PLTGOT = 3, 147 | DT_HASH = 4, 148 | DT_STRTAB = 5, 149 | DT_SYMTAB = 6, 150 | DT_RELA = 7, 151 | DT_RELASZ = 8, 152 | DT_RELAENT = 9, 153 | DT_STRSZ = 10, 154 | DT_SYMENT = 11, 155 | DT_INIT = 12, 156 | DT_FINI = 13, 157 | DT_SONAME = 14, 158 | DT_RPATH = 15, 159 | DT_SYMBOLIC = 16, 160 | DT_REL = 17, 161 | DT_RELSZ = 18, 162 | DT_RELENT = 19, 163 | DT_PLTREL = 20, 164 | DT_DEBUG = 21, 165 | DT_TEXTREL = 22, 166 | DT_JMPREL = 23, 167 | DT_BIND_NOW = 24, 168 | DT_INIT_ARRAY = 25, 169 | DT_FINI_ARRAY = 26, 170 | DT_INIT_ARRAYSZ = 27, 171 | DT_FINI_ARRAYSZ = 28, 172 | DT_RUNPATH = 29, 173 | DT_FLAGS = 30, 174 | DT_ENCODING = 32, 175 | OLD_DT_LOOS = 0x60000000, 176 | DT_LOOS = 0x6000000d, 177 | DT_HIOS = 0x6ffff000, 178 | DT_VALRNGLO = 0x6ffffd00, 179 | DT_VALRNGHI = 0x6ffffdff, 180 | DT_ADDRRNGLO = 0x6ffffe00, 181 | DT_ADDRRNGHI = 0x6ffffeff, 182 | DT_VERSYM = 0x6ffffff0, 183 | DT_RELACOUNT = 0x6ffffff9, 184 | DT_RELCOUNT = 0x6ffffffa, 185 | DT_FLAGS_1 = 0x6ffffffb, 186 | DT_VERDEF = 0x6ffffffc, 187 | DT_VERDEFNUM = 0x6ffffffd, 188 | DT_VERNEED = 0x6ffffffe, 189 | DT_VERNEEDNUM = 0x6fffffff, 190 | OLD_DT_HIOS = 0x6fffffff, 191 | DT_LOPROC = 0x70000000, 192 | DT_HIPROC = 0x7fffffff, 193 | DT_GNU_HASH = 0x6ffffef5 194 | } d_type32_e; 195 | typedef struct dynamic{ 196 | d_type32_e d_tag; 197 | union{ 198 | Elf32_Sword d_val; 199 | Elf32_Addr d_ptr; 200 | } d_un; 201 | } Elf32_Dyn ; 202 | //64 bit 203 | typedef uint32 Elf64_Word; 204 | typedef uint64 Elf64_Off; 205 | typedef uint64 Elf64_Addr ; 206 | typedef uint16 Elf64_Half; 207 | typedef uint64 Elf64_Xword; 208 | 209 | string Dyn32(Elf32_Dyn &d) { 210 | return EnumToString(d.d_tag); 211 | } 212 | 213 | string VAddr32(Elf32_Addr &addr) { 214 | local char buf[128]; 215 | SPrintf(buf, "0x%08X", addr); 216 | return buf; 217 | } 218 | 219 | string VAddr64(Elf64_Addr &addr) { 220 | local char buf[128]; 221 | SPrintf(buf, "0x%016LX", addr); 222 | return buf; 223 | } 224 | 225 | typedef enum { 226 | ET_NONE = 0x0, 227 | ET_REL = 0x1, 228 | ET_EXEC = 0x2, 229 | ET_DYN = 0x3, 230 | ET_CORE = 0x4, 231 | ET_LOOS = 0xfe00, 232 | ET_HIOS = 0xfeff, 233 | ET_LOPROC = 0xff00, 234 | ET_HIPROC = 0xffff 235 | } e_type32_e; 236 | typedef e_type32_e e_type64_e; 237 | 238 | typedef enum { // list has to to be completed 239 | EM_NONE = 0, //No machine 240 | EM_M32 = 1, //AT&T WE 32100 241 | EM_SPARC = 2, //SPARC 242 | EM_386 = 3, //Intel 80386 243 | EM_68K = 4, //Motorola 68000 244 | EM_88K = 5, //Motorola 88000 245 | reserved6 = 6, //Reserved for future use (was EM_486) 246 | EM_860 = 7, //Intel 80860 247 | EM_MIPS = 8, //MIPS I Architecture 248 | EM_S370 = 9, //IBM System/370 Processor 249 | EM_MIPS_RS3_LE = 10, //MIPS RS3000 Little-endian 250 | reserved11 = 11, //Reserved for future use 251 | reserved12 = 12, //Reserved for future use 252 | reserved13 = 13, //Reserved for future use 253 | reserved14 = 14, //Reserved for future use 254 | EM_PARISC = 15, //Hewlett-Packard PA-RISC 255 | reserved16 = 16, //Reserved for future use 256 | EM_VPP500 = 17, //Fujitsu VPP500 257 | EM_SPARC32PLUS = 18, //Enhanced instruction set SPARC 258 | EM_960 = 19, //Intel 80960 259 | EM_PPC = 20, //PowerPC 260 | EM_PPC64 = 21, //64-bit PowerPC 261 | EM_S390 = 22, //IBM System/390 Processor 262 | reserved23 = 23, //Reserved for future use 263 | reserved24 = 24, //Reserved for future use 264 | reserved25 = 25, //Reserved for future use 265 | reserved26 = 26, //Reserved for future use 266 | reserved27 = 27, //Reserved for future use 267 | reserved28 = 28, //Reserved for future use 268 | reserved29 = 29, //Reserved for future use 269 | reserved30 = 30, //Reserved for future use 270 | reserved31 = 31, //Reserved for future use 271 | reserved32 = 32, //Reserved for future use 272 | reserved33 = 33, //Reserved for future use 273 | reserved34 = 34, //Reserved for future use 274 | reserved35 = 35, //Reserved for future use 275 | EM_V800 = 36, //NEC V800 276 | EM_FR20 = 37, //Fujitsu FR20 277 | EM_RH32 = 38, //TRW RH-32 278 | EM_RCE = 39, //Motorola RCE 279 | EM_ARM = 40, //Advanced RISC Machines ARM 280 | EM_ALPHA = 41, //Digital Alpha 281 | EM_SH = 42, //Hitachi SH 282 | EM_SPARCV9 = 43, //SPARC Version 9 283 | EM_TRICORE = 44, //Siemens TriCore embedded processor 284 | EM_ARC = 45, //Argonaut RISC Core, Argonaut Technologies Inc. 285 | EM_H8_300 = 46, //Hitachi H8/300 286 | EM_H8_300H = 47, //Hitachi H8/300H 287 | EM_H8S = 48, //Hitachi H8S 288 | EM_H8_500 = 49, //Hitachi H8/500 289 | EM_IA_64 = 50, //Intel IA-64 processor architecture 290 | EM_MIPS_X = 51, //Stanford MIPS-X 291 | EM_COLDFIRE = 52, //Motorola ColdFire 292 | EM_68HC12 = 53, //Motorola M68HC12 293 | EM_MMA = 54, //Fujitsu MMA Multimedia Accelerator 294 | EM_PCP = 55, //Siemens PCP 295 | EM_NCPU = 56, //Sony nCPU embedded RISC processor 296 | EM_NDR1 = 57, //Denso NDR1 microprocessor 297 | EM_STARCORE = 58, //Motorola Star*Core processor 298 | EM_ME16 = 59, //Toyota ME16 processor 299 | EM_ST100 = 60, //STMicroelectronics ST100 processor 300 | EM_TINYJ = 61, //Advanced Logic Corp. TinyJ embedded processor family 301 | EM_X86_64 = 62, //AMD x86-64 architecture 302 | EM_PDSP = 63, //Sony DSP Processor 303 | EM_PDP10 = 64, //Digital Equipment Corp. PDP-10 304 | EM_PDP11 = 65, //Digital Equipment Corp. PDP-11 305 | EM_FX66 = 66, //Siemens FX66 microcontroller 306 | EM_ST9PLUS = 67, //STMicroelectronics ST9+ 8/16 bit microcontroller 307 | EM_ST7 = 68, //STMicroelectronics ST7 8-bit microcontroller 308 | EM_68HC16 = 69, //Motorola MC68HC16 Microcontroller 309 | EM_68HC11 = 70, //Motorola MC68HC11 Microcontroller 310 | EM_68HC08 = 71, //Motorola MC68HC08 Microcontroller 311 | EM_68HC05 = 72, //Motorola MC68HC05 Microcontroller 312 | EM_SVX = 73, //Silicon Graphics SVx 313 | EM_ST19 = 75, //Digital VAX 314 | EM_CRIS = 76, //Axis Communications 32-bit embedded processor 315 | EM_JAVELIN = 77, //Infineon Technologies 32-bit embedded processor 316 | EM_FIREPATH = 78, //Element 14 64-bit DSP Processor 317 | EM_ZSP = 79, //LSI Logic 16-bit DSP Processor 318 | EM_MMIX = 80, //Donald Knuth's educational 64-bit processor 319 | EM_HUANY = 81, //Harvard University machine-independent object files 320 | EM_PRISM = 82, //SiTera Prism 321 | EM_AVR = 83, //Atmel AVR 8-bit microcontroller 322 | EM_FR30 = 84, //Fujitsu FR30 323 | EM_D10V = 85, //Mitsubishi D10V 324 | EM_D30V = 86, //Mitsubishi D30V 325 | EM_V850 = 87, //NEC v850 326 | EM_M32R = 88, //Mitsubishi M32R 327 | EM_MN10300 = 89, //Matsushita MN10300 328 | EM_MN10200 = 90, //Matsushita MN10200 329 | EM_PJ = 91, //picoJava 330 | EM_OPENRISC = 92, //OpenRISC 32-bit embedded processor 331 | EM_ARC_A5 = 93, //ARC Cores Tangent-A5 332 | EM_XTENSA = 94, //Tensilica Xtensa Architecture 333 | EM_VIDEOCORE = 95, //Alphamosaic VideoCore processor 334 | EM_TMM_GPP = 96, //Thompson Multimedia General Purpose Processor 335 | EM_NS32K = 97, //National Semiconductor 32000 series 336 | EM_TPC = 98, //Tenor Network TPC processor 337 | EM_SNP1K = 99, //Trebia SNP 1000 processor 338 | EM_ST200 = 100, //STMicroelectronics (www.st.com) ST200 microcontroller 339 | EM_IP2K = 101, //Ubicom IP2xxx microcontroller family 340 | EM_MAX = 102, //MAX Processor 341 | EM_CR = 103, //National Semiconductor CompactRISC microprocessor 342 | EM_F2MC16 = 104, //Fujitsu F2MC16 343 | EM_MSP430 = 105, //Texas Instruments embedded microcontroller msp430 344 | EM_BLACKFIN = 106, //Analog Devices Blackfin (DSP) processor 345 | EM_SE_C33 = 107, //S1C33 Family of Seiko Epson processors 346 | EM_SEP = 108, //Sharp embedded microprocessor 347 | EM_ARCA = 109, //Arca RISC Microprocessor 348 | EM_UNICORE = 110 //Microprocessor series from PKU-Unity Ltd. and MPRC of Peking University 349 | } e_machine32_e; 350 | typedef e_machine32_e e_machine64_e; 351 | 352 | typedef enum { 353 | EV_NONE = 0x0, 354 | EV_CURRENT = 0x1 355 | } e_version32_e; 356 | typedef e_version32_e e_version64_e; 357 | 358 | 359 | // Program Header Types 360 | typedef enum { 361 | PT_NULL = 0x0, 362 | PT_LOAD = 0x1, 363 | PT_DYNAMIC = 0x2, 364 | PT_INERP = 0x3, 365 | PT_NOTE = 0x4, 366 | PT_SHLIB = 0x5, 367 | PT_PHDR = 0x6, 368 | PT_TLS = 0x7, 369 | PT_NUM = 0x8, 370 | PT_LOOS = 0x60000000, 371 | PT_GNU_EH_FRAME = 0x6474e550, 372 | PT_GNU_STACK = 0x6474e551, 373 | PT_GNU_RELRO = 0x6474e552, 374 | PT_LOSUNW = 0x6ffffffa, 375 | PT_SUNWBSS = 0x6ffffffa, 376 | PT_SUNWSTACK = 0x6ffffffb, 377 | PT_HISUNW = 0x6fffffff, 378 | PT_HIOS = 0x6fffffff, 379 | PT_LOPROC = 0x70000000, 380 | PT_HIPROC = 0x7fffffff, 381 | // ARM Sections 382 | PT_SHT_ARM_EXIDX = 0x70000001, 383 | PT_SHT_ARM_PREEMPTMAP = 0x70000002, 384 | PT_SHT_ARM_ATTRIBUTES = 0x70000003, 385 | PT_SHT_ARM_DEBUGOVERLAY = 0x70000004, 386 | PT_SHT_ARM_OVERLAYSECTION = 0x70000005 387 | } p_type32_e; 388 | typedef p_type32_e p_type64_e; 389 | 390 | typedef enum { 391 | PF_None = 0x0, 392 | PF_Exec = 0x1, 393 | PF_Write = 0x2, 394 | PF_Write_Exec = 0x3, 395 | PF_Read = 0x4, 396 | PF_Read_Exec = 0x5, 397 | PF_Read_Write = 0x6, 398 | PF_Read_Write_Exec = 0x7 399 | } p_flags32_e; 400 | typedef p_flags32_e p_flags64_e; 401 | 402 | typedef enum { 403 | SHN_UNDEF = 0x0, /* undefined, e.g. undefined symbol */ 404 | SHN_LORESERVE = 0xff00, /* Lower bound of reserved indices */ 405 | SHN_LOPROC = 0xff00, /* Lower bound processor-specific index */ 406 | SHN_BEFORE = 0xff00, /* Order section before all others (Solaris) */ 407 | SHN_AFTER = 0xff01, /* Order section after all others (Solaris) */ 408 | SHN_HIPROC = 0xff1f, /* Upper bound processor-specific index */ 409 | SHN_LOOS = 0xff20, /* Lower bound OS-specific index */ 410 | SHN_HIOS = 0xff3f, /* Upper bound OS-specific index */ 411 | SHN_ABS = 0xfff1, /* Absolute value, not relocated */ 412 | SHN_COMMON = 0xfff2, /* FORTRAN common or unallocated C */ 413 | SHN_XINDEX = 0xffff, /* Index is in extra table */ 414 | SHN_HIRESERVE = 0xffff /* Upper bound of reserved indices */ 415 | } s_name32_e; 416 | typedef s_name32_e s_name64_e; 417 | 418 | typedef enum { 419 | SHT_NULL = 0x0, /* Inactive section header */ 420 | SHT_PROGBITS = 0x1, /* Information defined by the program */ 421 | SHT_SYMTAB = 0x2, /* Symbol table - not DLL */ 422 | SHT_STRTAB = 0x3, /* String table */ 423 | SHT_RELA = 0x4, /* Explicit addend relocations, Elf64_Rela */ 424 | SHT_HASH = 0x5, /* Symbol hash table */ 425 | SHT_DYNAMIC = 0x6, /* Information for dynamic linking */ 426 | SHT_NOTE = 0x7, /* A Note section */ 427 | SHT_NOBITS = 0x8, /* Like SHT_PROGBITS with no data */ 428 | SHT_REL = 0x9, /* Implicit addend relocations, Elf64_Rel */ 429 | SHT_SHLIB = 0xA, /* Currently unspecified semantics */ 430 | SHT_DYNSYM = 0xD, /* Symbol table for a DLL */ 431 | SHT_INIT_ARRAY = 0xE, /* Array of constructors */ 432 | SHT_FINI_ARRAY = 0xF, /* Array of deconstructors */ 433 | SHT_PREINIT_ARRAY = 0x10, /* Array of pre-constructors */ 434 | SHT_GROUP = 0x11, /* Section group */ 435 | SHT_SYMTAB_SHNDX = 0x12, /* Extended section indeces */ 436 | SHT_NUM = 0x13, /* Number of defined types */ 437 | 438 | SHT_LOOS = 0x60000000, /* Lowest OS-specific section type */ 439 | SHT_GNU_ATTRIBUTES = 0x6ffffff5, /* Object attribuytes */ 440 | SHT_GNU_HASH = 0x6ffffff6, /* GNU-style hash table */ 441 | SHT_GNU_LIBLIST = 0x6ffffff7, /* Prelink library list */ 442 | SHT_CHECKSUM = 0x6ffffff8, /* Checksum for DSO content */ 443 | SHT_LOSUNW = 0x6ffffffa, /* Sun-specific low bound */ 444 | SHT_SUNW_move = 0x6ffffffa, // Same thing 445 | SHT_SUNW_COMDAT = 0x6ffffffb, 446 | SHT_SUNW_syminfo = 0x6ffffffc, 447 | SHT_GNU_verdef = 0x6ffffffd, /* Version definition section */ 448 | SHT_GNU_verdneed = 0x6ffffffe, /* Version needs section */ 449 | SHT_GNY_versym = 0x6fffffff, /* Version symbol table */ 450 | SHT_HISUNW = 0x6fffffff, /* Sun-specific high bound */ 451 | SHT_HIOS = 0x6fffffff, /* Highest OS-specific section type */ 452 | SHT_LOPROC = 0x70000000, /* Start of processor-specific section type */ 453 | SHT_HIPROC = 0x7fffffff, /* End of processor-specific section type */ 454 | SHT_LOUSER = 0x80000000, /* Start of application-specific */ 455 | SHT_HIUSER = 0x8fffffff /* Ennd of application-specific */ 456 | } s_type32_e; 457 | typedef s_type32_e s_type64_e; 458 | 459 | // TODO : Add new sections 460 | string ReservedSectionName(s_name32_e id) { 461 | local char buf[255]; 462 | 463 | switch(id) { 464 | case SHN_UNDEF: 465 | return "SHN_UNDEF"; 466 | case SHN_ABS: 467 | return "SHN_ABS"; 468 | case SHN_COMMON: 469 | return "SHN_COMMON"; 470 | } 471 | 472 | if(id >= SHN_LOPROC && id <= SHN_HIPROC) { 473 | SPrintf(buf, "SHN_PROC_%02X", id - SHN_LOPROC); 474 | return buf; 475 | } 476 | 477 | if(id >= SHN_LOOS && id <= SHN_HIOS) { 478 | SPrintf(buf, "SHN_OS_%02X", id - SHN_LOOS); 479 | return buf; 480 | } 481 | 482 | SPrintf(buf, "SHN_RESERVE_%02X", id - SHN_LORESERVE); 483 | return buf; 484 | } 485 | 486 | // Program Table 32/64 bit 487 | typedef struct { //32bit 488 | local quad off = FTell(); 489 | 490 | p_type32_e p_type ; 491 | 492 | if(ReadUInt(FTell()) > FileSize()) { 493 | PrintWarning("Program section offset starts after the end of the file!"); 494 | SetBackColor(cLtRed); 495 | } 496 | Elf32_Off p_offset_FROM_FILE_BEGIN ; 497 | // Ensure we reset color to not bleed 498 | SetBackColor(cWhite); 499 | 500 | Elf32_Addr p_vaddr_VIRTUAL_ADDRESS ; 501 | Elf32_Addr p_paddr_PHYSICAL_ADDRESS ; 502 | 503 | if(ReadUInt(FTell()) + p_offset_FROM_FILE_BEGIN > FileSize()) { 504 | PrintWarning("Program section data seems to be larger than file size"); 505 | SetBackColor(cLtRed); 506 | } 507 | Elf32_Word p_filesz_SEGMENT_FILE_LENGTH ; 508 | // Ensure we reset color to not bleed 509 | SetBackColor(cWhite); 510 | 511 | Elf32_Word p_memsz_SEGMENT_RAM_LENGTH ; 512 | p_flags32_e p_flags ; 513 | Elf32_Word p_align ; 514 | 515 | // Ensure we're not trying to map ourside of the file (prevent error) 516 | if(p_filesz_SEGMENT_FILE_LENGTH > 0 && p_filesz_SEGMENT_FILE_LENGTH < FileSize() && 517 | p_filesz_SEGMENT_FILE_LENGTH > 0 && p_filesz_SEGMENT_FILE_LENGTH + p_offset_FROM_FILE_BEGIN < FileSize()) { 518 | FSeek(p_offset_FROM_FILE_BEGIN); 519 | if (p_type == PT_DYNAMIC) { 520 | Elf32_Dyn p_data[p_filesz_SEGMENT_FILE_LENGTH/sizeof(Elf32_Dyn)]; 521 | } else { 522 | char p_data[p_filesz_SEGMENT_FILE_LENGTH] ; 523 | } 524 | } else { 525 | PrintWarning("Segment data appears to either overlap with header, exist after the end of the file or overlap with the end of the file!"); 526 | } 527 | 528 | FSeek(off + file.elf_header.e_phentsize_PROGRAM_HEADER_ENTRY_SIZE_IN_FILE); 529 | } program_table_entry32_t ; 530 | 531 | typedef struct { //64bit 532 | local quad off = FTell(); 533 | 534 | p_type64_e p_type ; 535 | p_flags64_e p_flags ; 536 | Elf64_Off p_offset_FROM_FILE_BEGIN ; 537 | Elf64_Addr p_vaddr_VIRTUAL_ADDRESS ; 538 | Elf64_Addr p_paddr_PHYSICAL_ADDRESS ; 539 | Elf64_Xword p_filesz_SEGMENT_FILE_LENGTH ; 540 | Elf64_Xword p_memsz_SEGMENT_RAM_LENGTH ; 541 | Elf64_Xword p_align ; 542 | 543 | if(p_filesz_SEGMENT_FILE_LENGTH > 0 && p_filesz_SEGMENT_FILE_LENGTH < (uint64) FileSize() && 544 | p_offset_FROM_FILE_BEGIN > 0 && p_offset_FROM_FILE_BEGIN + p_filesz_SEGMENT_FILE_LENGTH < (uint64) FileSize()) { 545 | FSeek(p_offset_FROM_FILE_BEGIN); 546 | char p_data[p_filesz_SEGMENT_FILE_LENGTH] ; 547 | } 548 | 549 | FSeek(off + file.elf_header.e_phentsize_PROGRAM_HEADER_ENTRY_SIZE_IN_FILE); 550 | } program_table_entry64_t ; 551 | 552 | string ProgramType( p_type64_e type ) { 553 | switch(type) { 554 | case PT_NULL: 555 | return "NULL"; 556 | case PT_LOAD: 557 | return "Loadable Segment"; 558 | case PT_DYNAMIC: 559 | return "Dynamic Segment"; 560 | case PT_INERP: 561 | return "Interpreter Path"; 562 | case PT_NOTE: 563 | return "Note"; 564 | case PT_SHLIB: 565 | return "PT_SHLIB"; 566 | case PT_PHDR: 567 | return "Program Header"; 568 | case PT_TLS: 569 | return "Thread-local Storage"; 570 | case PT_NUM: 571 | return "Number of defined sections"; 572 | case PT_LOOS: 573 | return "OS-specific start"; 574 | case PT_GNU_EH_FRAME: 575 | return "GCC .eh_frame_hdr Segment"; 576 | case PT_GNU_STACK: 577 | return "GNU Stack (executability)"; 578 | case PT_GNU_RELRO: 579 | return "GNU Read-only After Relocation"; 580 | case PT_SHT_ARM_EXIDX: 581 | return "Exception Index table"; 582 | case PT_SHT_ARM_PREEMPTMAP: 583 | return "BPABI DLL dynamic linking pre-emption map"; 584 | case PT_SHT_ARM_ATTRIBUTES: 585 | return "Object file compatibility attributes"; 586 | case PT_SHT_ARM_DEBUGOVERLAY: 587 | return "Debug Overlay (1)"; 588 | case PT_SHT_ARM_OVERLAYSECTION: 589 | return "Debug Overlay (2)"; 590 | default: 591 | return "Unknown Section"; 592 | } 593 | } 594 | 595 | string ProgramFlags(p_flags64_e flags) { 596 | local string rv = "("; 597 | 598 | rv += (flags & PF_Read) ? "R" : "_"; 599 | rv += (flags & PF_Write) ? "W" : "_"; 600 | rv += (flags & PF_Exec) ? "X" : "_"; 601 | rv += ")"; 602 | return rv; 603 | } 604 | 605 | string ProgramInfo64(program_table_entry64_t &ent) { 606 | return ProgramFlags(ent.p_flags) + " " + ProgramType(ent.p_type); 607 | } 608 | 609 | string ProgramInfo32( program_table_entry32_t &ent) { 610 | return ProgramFlags(ent.p_flags) + " " + ProgramType(ent.p_type); 611 | } 612 | 613 | // ************************************* Section Table *************************************** 614 | 615 | typedef enum { 616 | SF32_None = 0x0, 617 | SF32_Exec = 0x1, 618 | SF32_Alloc = 0x2, 619 | SF32_Alloc_Exec = 0x3, 620 | SF32_Write = 0x4, 621 | SF32_Write_Exec = 0x5, 622 | SF32_Write_Alloc = 0x6, 623 | SF32_Write_Alloc_Exec = 0x7 624 | } s_flags32_e; 625 | 626 | typedef enum { 627 | SF64_None = 0x0, 628 | SF64_Exec = 0x1, 629 | SF64_Alloc = 0x2, 630 | SF64_Alloc_Exec = 0x3, 631 | SF64_Write = 0x4, 632 | SF64_Write_Exec = 0x5, 633 | SF64_Write_Alloc = 0x6, 634 | SF64_Write_Alloc_Exec = 0x7 635 | } s_flags64_e; 636 | 637 | // Pointer to where the next name is located 638 | local quad section_name_block_off; 639 | 640 | typedef struct { 641 | s_name32_e s_name_off ; 642 | 643 | local quad off = FTell(); 644 | FSeek(section_name_block_off + s_name_off); 645 | 646 | string s_name_str; 647 | 648 | FSeek(off); 649 | } s_name32_t ; 650 | 651 | typedef s_name32_t s_name64_t; 652 | 653 | string SectionName(s_name32_t §) { 654 | if(sect.s_name_off > SHN_UNDEF && sect.s_name_off < SHN_LORESERVE) { 655 | return sect.s_name_str; 656 | } 657 | return ReservedSectionName(sect.s_name_off); 658 | } 659 | 660 | // Section Table 32/64 bit 661 | typedef struct { //64bit 662 | local quad off = FTell(); 663 | 664 | s_name64_t s_name; /* Section name */ 665 | s_type64_e s_type; /* Section type */ 666 | s_flags64_e s_flags; /* Section attributes */ 667 | Elf64_Addr s_addr; /* Virtual address in memory */ 668 | Elf64_Off s_offset ; /* Offset in file */ 669 | Elf64_Xword s_size; /* Size of section */ 670 | Elf64_Word s_link; /* Link to other section */ 671 | Elf64_Word s_info; /* Miscellaneous information */ 672 | Elf64_Xword s_addralign; /* Address alignment boundary */ 673 | Elf64_Xword s_entsize; /* Entry size, if section has table */ 674 | 675 | if(s_type != SHT_NOBITS && s_type != SHT_NULL && s_size > 0) { 676 | FSeek(s_offset); 677 | char data[s_size]; 678 | } 679 | FSeek(off + file.elf_header.e_shentsize_SECTION_HEADER_ENTRY_SIZE); 680 | } section_table_entry64_t ; 681 | 682 | typedef struct { //32bit 683 | local quad off = FTell(); 684 | 685 | s_name32_t s_name; /* Section name */ 686 | s_type32_e s_type; /* Section type */ 687 | s_flags32_e s_flags; /* Section attributes */ 688 | Elf32_Addr s_addr; /* Virtual address in memory */ 689 | Elf32_Off s_offset ; /* Offset in file */ 690 | Elf32_Xword s_size; /* Size of section */ 691 | Elf32_Word s_link; /* Link to other section */ 692 | Elf32_Word s_info; /* Miscellaneous information */ 693 | Elf32_Xword s_addralign; /* Address alignment boundary*/ 694 | Elf32_Xword s_entsize; /* Entry size, if section has table */ 695 | 696 | if(s_type != SHT_NOBITS && s_type != SHT_NULL && s_size > 0) { 697 | FSeek(s_offset); 698 | char s_data[s_size]; 699 | } 700 | FSeek(off + file.elf_header.e_shentsize_SECTION_HEADER_ENTRY_SIZE); 701 | } section_table_entry32_t ; 702 | 703 | string SectionName64(section_table_entry64_t §) { 704 | return SectionName(sect.s_name); 705 | } 706 | 707 | string SectionName32(section_table_entry32_t §) { 708 | return SectionName(sect.s_name); 709 | } 710 | 711 | // ************************************** Symbol Table *************************************** 712 | 713 | local quad symbol_name_block_off; 714 | 715 | typedef struct { 716 | Elf32_Word sym_name_off ; /* Symbol table name offset */ 717 | 718 | local quad off = FTell(); 719 | FSeek(symbol_name_block_off + sym_name_off); 720 | 721 | string sym_name_str; 722 | 723 | FSeek(off); 724 | } sym_name32_t ; 725 | typedef sym_name32_t sym_name64_t; 726 | 727 | string SymbolName(sym_name32_t &sym) { 728 | if(sym.sym_name_off > 0) { 729 | return sym.sym_name_str; 730 | } 731 | return ""; 732 | } 733 | 734 | typedef enum { 735 | STB_LOCAL = 0x0, 736 | STB_GLOBAL = 0x1, 737 | STB_WEAK = 0x2, 738 | STB_NUM = 0x3, 739 | STB_LOOS = 0xA, 740 | STB_GNU_UNIQUE = 0xA, 741 | STB_HIOS = 0xC, 742 | STB_LOPROC = 0xD, 743 | STB_HIPROC = 0xE, 744 | STB_UNKNOWN = 0xF 745 | } sym_info_bind_e; 746 | 747 | typedef enum { 748 | STT_NOTYPE = 0x0, 749 | STT_OBJECT = 0x1, 750 | STT_FUNC = 0x2, 751 | STT_SECTION = 0x3, 752 | STT_FILE = 0x4, 753 | STT_COMMON = 0x5, 754 | STT_TLS = 0x6, 755 | STT_NUM = 0x7, 756 | STT_LOOS = 0xA, 757 | STT_GNU_IFUNC = 0xA, 758 | STT_HIOS = 0xB, 759 | STT_LOPROC = 0xC, 760 | STT_HIPROC = 0xD 761 | } sym_info_type_e; 762 | 763 | typedef struct { 764 | BitfieldDisablePadding(); 765 | if(IsBigEndian()) { 766 | uchar sym_info_bind:4; 767 | uchar sym_info_type:4; 768 | } else { 769 | uchar sym_info_type:4; 770 | uchar sym_info_bind:4; 771 | } 772 | BitfieldEnablePadding(); 773 | } sym_info_t ; 774 | 775 | string SymInfoEnums(sym_info_t &info) { 776 | local sym_info_bind_e x = info.sym_info_bind; 777 | local sym_info_type_e y = info.sym_info_type; 778 | return EnumToString(x) + " | " + EnumToString(y); 779 | } 780 | 781 | typedef struct { 782 | Elf64_Word sym_name; /* Symbol name */ 783 | unsigned char sym_info; /* Type and Binding attributes */ 784 | unsigned char sym_other; /* Reserved */ 785 | Elf64_Half sym_shndx; /* Section table index */ 786 | Elf64_Addr sym_value; /* Symbol value */ 787 | Elf64_Xword sym_size; /* Size of object (e.g., common) */ 788 | } Elf64_Sym_fixed; 789 | 790 | typedef struct { 791 | Elf32_Word sym_name; /* Symbol name */ 792 | Elf32_Addr sym_value; /* Symbol value */ 793 | Elf32_Xword sym_size; /* Size of object (e.g., common) */ 794 | unsigned char sym_info; /* Type and Binding attributes */ 795 | unsigned char sym_other; /* Reserved */ 796 | Elf32_Half sym_shndx; /* Section table index */ 797 | } Elf32_Sym_fixed; 798 | 799 | typedef struct { 800 | sym_name64_t sym_name; /* Symbol name */ 801 | sym_info_t sym_info; /* Type and Binding attributes */ 802 | unsigned char sym_other; /* Reserved */ 803 | Elf64_Half sym_shndx; /* Section table index */ 804 | Elf64_Addr sym_value; /* Symbol value */ 805 | Elf64_Xword sym_size; /* Size of object (e.g., common) */ 806 | 807 | if(sym_size && SectionHasData(sym_shndx)) { 808 | local quad off = FTell(); 809 | FSeek(SectionVAddrOffset(sym_shndx, sym_value)); 810 | 811 | char sym_data[sym_size]; 812 | 813 | FSeek(off); 814 | } 815 | } Elf64_Sym ; 816 | 817 | typedef struct { 818 | sym_name32_t sym_name; /* Symbol name */ 819 | Elf32_Addr sym_value; /* Symbol value */ 820 | Elf32_Xword sym_size; /* Size of object (e.g., common) */ 821 | sym_info_t sym_info; /* Type and Binding attributes */ 822 | unsigned char sym_other; /* Reserved */ 823 | Elf32_Half sym_shndx; /* Section table index */ 824 | 825 | if(sym_size && SectionHasData(sym_shndx)) { 826 | local quad off = FTell(); 827 | FSeek( SectionVAddrOffset(sym_shndx, sym_value)); 828 | 829 | char sym_data[sym_size]; 830 | 831 | FSeek(off); 832 | } 833 | } Elf32_Sym ; 834 | 835 | string SymbolName64(Elf64_Sym &sym) { 836 | return (sym.sym_size ? "" : "[U] ") + SymbolName(sym.sym_name); 837 | } 838 | 839 | string SymbolName32(Elf32_Sym &sym) { 840 | return (sym.sym_size ? "" : "[U] ") + SymbolName(sym.sym_name); 841 | } 842 | 843 | // **************************************** ELF File ***************************************** 844 | 845 | local int iter; 846 | 847 | int FindNamedSection(string sect) { 848 | for(iter=0; iter < file.elf_header.e_shnum_NUMBER_OF_SECTION_HEADER_ENTRIES; iter++) { 849 | if(Strcmp(file.section_header_table.section_table_element[ iter ].s_name.s_name_str, sect) == 0) { 850 | return iter; 851 | } 852 | } 853 | 854 | return -1; 855 | } 856 | 857 | quad FindNamedSectionBlock(string sect) { 858 | local int off = FindNamedSection(sect); 859 | if(off != -1) 860 | return file.section_header_table.section_table_element[off].s_offset; 861 | 862 | return -1; 863 | } 864 | 865 | int SectionHasData(Elf64_Half s_index) { 866 | // This is ridiculously slow for some reason, so cache our results in an array 867 | if(sec_tbl_elem[s_index] == -1) { 868 | sec_tbl_elem[s_index] = exists(file.section_header_table.section_table_element[s_index].s_data); 869 | } 870 | return sec_tbl_elem[s_index]; 871 | } 872 | 873 | quad SectionVAddrOffset(Elf64_Half s_index, Elf64_Addr s_vaddr) { 874 | if(s_index < file.elf_header.e_shnum_NUMBER_OF_SECTION_HEADER_ENTRIES) { 875 | return file.section_header_table.section_table_element[s_index].s_offset + s_vaddr - 876 | file.section_header_table.section_table_element[s_index].s_addr; 877 | } 878 | return 0; 879 | } 880 | 881 | // Structure of elf 882 | struct { 883 | local int i; 884 | for(i=0; i<255; i++) { 885 | sec_tbl_elem[i] = -1; 886 | } 887 | 888 | struct { 889 | e_ident_t e_ident ; 890 | if(file.elf_header.e_ident.ei_class_2 == ELFCLASS32) { 891 | //32-Bit definitions of ELF Header 892 | e_type32_e e_type ; 893 | e_machine32_e e_machine ; 894 | e_version32_e e_version ; 895 | Elf32_Addr e_entry_START_ADDRESS ; 896 | Elf32_Off e_phoff_PROGRAM_HEADER_OFFSET_IN_FILE ; 897 | Elf32_Off e_shoff_SECTION_HEADER_OFFSET_IN_FILE ; 898 | Elf32_Word e_flags ; 899 | Elf32_Half e_ehsize_ELF_HEADER_SIZE ; 900 | Elf32_Half e_phentsize_PROGRAM_HEADER_ENTRY_SIZE_IN_FILE ; 901 | Elf32_Half e_phnum_NUMBER_OF_PROGRAM_HEADER_ENTRIES ; 902 | Elf32_Half e_shentsize_SECTION_HEADER_ENTRY_SIZE ; 903 | Elf32_Half e_shnum_NUMBER_OF_SECTION_HEADER_ENTRIES ; 904 | Elf32_Half e_shtrndx_STRING_TABLE_INDEX ; 905 | } else { 906 | //64-Bit definitions of ELF Header 907 | e_type64_e e_type ; 908 | e_machine64_e e_machine ; 909 | e_version64_e e_version ; 910 | Elf64_Addr e_entry_START_ADDRESS ; 911 | Elf64_Off e_phoff_PROGRAM_HEADER_OFFSET_IN_FILE ; 912 | Elf64_Off e_shoff_SECTION_HEADER_OFFSET_IN_FILE ; 913 | Elf32_Word e_flags ; 914 | Elf64_Half e_ehsize_ELF_HEADER_SIZE ; 915 | Elf64_Half e_phentsize_PROGRAM_HEADER_ENTRY_SIZE_IN_FILE ; 916 | Elf64_Half e_phnum_NUMBER_OF_PROGRAM_HEADER_ENTRIES ; 917 | Elf64_Half e_shentsize_SECTION_HEADER_ENTRY_SIZE ; 918 | Elf64_Half e_shnum_NUMBER_OF_SECTION_HEADER_ENTRIES ; 919 | Elf64_Half e_shtrndx_STRING_TABLE_INDEX ; 920 | } 921 | } elf_header ; 922 | 923 | // Find the program table 924 | if(file.elf_header.e_phnum_NUMBER_OF_PROGRAM_HEADER_ENTRIES > 0) { 925 | FSeek(file.elf_header.e_phoff_PROGRAM_HEADER_OFFSET_IN_FILE); 926 | struct { 927 | if(file.elf_header.e_ident.ei_class_2 == ELFCLASS32) { 928 | program_table_entry32_t program_table_element[file.elf_header.e_phnum_NUMBER_OF_PROGRAM_HEADER_ENTRIES]; 929 | } else { 930 | program_table_entry64_t program_table_element[file.elf_header.e_phnum_NUMBER_OF_PROGRAM_HEADER_ENTRIES]; 931 | } 932 | } program_header_table ; 933 | } 934 | 935 | // Find the header name location 936 | local quad section_name_off = 937 | file.elf_header.e_shoff_SECTION_HEADER_OFFSET_IN_FILE + 938 | (file.elf_header.e_shentsize_SECTION_HEADER_ENTRY_SIZE * 939 | file.elf_header.e_shtrndx_STRING_TABLE_INDEX); 940 | 941 | // Find the header name block 942 | if (file.elf_header.e_ident.ei_class_2 == ELFCLASS32) { 943 | if(FileSize() >= section_name_off + 2 * sizeof(Elf32_Word) + 944 | sizeof(Elf32_Xword) + sizeof(Elf32_Addr)) 945 | section_name_block_off = ReadUInt(section_name_off + 2 * sizeof(Elf32_Word) + 946 | sizeof(Elf32_Xword) + sizeof(Elf32_Addr)); 947 | else { 948 | PrintWarning("Invalid section header found, skipped and attempting to continue..."); 949 | } 950 | } else { 951 | if(FileSize() >= section_name_off + 2 * sizeof(Elf64_Word) + 952 | sizeof(Elf64_Xword) + sizeof(Elf64_Addr)) 953 | section_name_block_off = ReadUQuad( section_name_off + 2 * sizeof( Elf64_Word ) + 954 | sizeof(Elf64_Xword) + sizeof(Elf64_Addr)); 955 | else { 956 | PrintWarning("Invalid section header found, skipped and attempting to continue..."); 957 | } 958 | } 959 | 960 | local int sec_tbl_cur_elem; 961 | // Find the section headers 962 | if(file.elf_header.e_shnum_NUMBER_OF_SECTION_HEADER_ENTRIES > 0) { 963 | FSeek(file.elf_header.e_shoff_SECTION_HEADER_OFFSET_IN_FILE); 964 | struct { 965 | if(file.elf_header.e_ident.ei_class_2 == ELFCLASS32) { 966 | sec_tbl_cur_elem = 0; 967 | section_table_entry32_t section_table_element[file.elf_header.e_shnum_NUMBER_OF_SECTION_HEADER_ENTRIES]; 968 | } else { 969 | sec_tbl_cur_elem = 0; 970 | section_table_entry64_t section_table_element[file.elf_header.e_shnum_NUMBER_OF_SECTION_HEADER_ENTRIES]; 971 | } 972 | } section_header_table; 973 | } 974 | 975 | local int sym_sect; 976 | local int sym_name_sect; 977 | 978 | // Find the symbol section 979 | sym_sect = FindNamedSection(".symtab"); 980 | if(sym_sect >= 0) { 981 | sym_name_sect = file.section_header_table.section_table_element[sym_sect].s_link; 982 | symbol_name_block_off = file.section_header_table.section_table_element[sym_name_sect].s_offset; 983 | 984 | FSeek(file.section_header_table.section_table_element[sym_sect].s_offset); 985 | struct { 986 | if(file.elf_header.e_ident.ei_class_2 == ELFCLASS32) { 987 | Elf32_Sym symtab[file.section_header_table.section_table_element[sym_sect].s_size / sizeof(Elf32_Sym_fixed)]; 988 | } else { 989 | Elf64_Sym symtab[file.section_header_table.section_table_element[sym_sect].s_size / sizeof(Elf64_Sym_fixed)]; 990 | } 991 | } symbol_table; 992 | } 993 | 994 | // Find the dynamic symbol section 995 | sym_sect = FindNamedSection(".dynsym"); 996 | if(sym_sect >= 0) { 997 | sym_name_sect = file.section_header_table.section_table_element[sym_sect].s_link; 998 | symbol_name_block_off = file.section_header_table.section_table_element[sym_name_sect].s_offset; 999 | 1000 | FSeek(file.section_header_table.section_table_element[sym_sect].s_offset); 1001 | struct { 1002 | if(file.elf_header.e_ident.ei_class_2 == ELFCLASS32) { 1003 | Elf32_Sym symtab[file.section_header_table.section_table_element[sym_sect].s_size / sizeof(Elf32_Sym_fixed)]; 1004 | } else { 1005 | Elf64_Sym symtab[file.section_header_table.section_table_element[sym_sect].s_size / sizeof(Elf64_Sym_fixed)]; 1006 | } 1007 | } dynamic_symbol_table; 1008 | } 1009 | } file; 1010 | 1011 | 1012 | // It's not really useful to see just the last warning, so inform us how many warnings we should see in output 1013 | if(warnings > 1) { 1014 | Warning("%d warnings have occured and logged to the output box!", warnings); 1015 | } 1016 | 1017 | // This will make the template show "Template executed successfully." 1018 | if(warnings != 0) { 1019 | SPrintf(temp_warning, "%d warnings found, template may not have run successfully!", warnings); 1020 | return temp_warning; 1021 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 tomken 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /OATTemplate.bt: -------------------------------------------------------------------------------- 1 | //----------------------------------- 2 | //--- 010 Editor v2.0 Binary Template 3 | // 4 | // File: OATTemplate.bt 5 | // Author: tomken 6 | // Update: liumin0 7 | // Revision: 1.2 8 | // Purpose: Defines a template for 9 | // parsing OAT files. 10 | // Support: Android L, Android M, 11 | // Mutidex is supported too 12 | //----------------------------------- 13 | 14 | LittleEndian(); 15 | 16 | local char global_version[4]; 17 | 18 | #define NO_INDEX (0xFFFFFFFF) 19 | 20 | typedef uint32 Elf32_Addr; // Program address 21 | typedef uint32 Elf32_Off; // File offset 22 | typedef uint16 Elf32_Half; 23 | typedef uint32 Elf32_Word; 24 | typedef int Elf32_Sword; 25 | 26 | // Object file magic string. 27 | // static const char ElfMagic[] = { 0x7f, 'E', 'L', 'F', '\0' }; 28 | 29 | // e_ident size and indices. 30 | typedef enum { 31 | EI_MAG0 = 0, // File identification index. 32 | EI_MAG1 = 1, // File identification index. 33 | EI_MAG2 = 2, // File identification index. 34 | EI_MAG3 = 3, // File identification index. 35 | EI_CLASS = 4, // File class. 36 | EI_DATA = 5, // Data encoding. 37 | EI_VERSION = 6, // File version. 38 | EI_OSABI = 7, // OS/ABI identification. 39 | EI_ABIVERSION = 8, // ABI version. 40 | EI_PAD = 9, // Start of padding bytes. 41 | EI_NIDENT = 16 // Number of bytes in e_ident. 42 | } EI_Type; 43 | 44 | typedef struct { 45 | unsigned char e_ident[EI_NIDENT]; // ELF Identification bytes 46 | Elf32_Half e_type; // Type of file (see ET_* below) 47 | Elf32_Half e_machine; // Required architecture for this file (see EM_*) 48 | Elf32_Word e_version; // Must be equal to 1 49 | Elf32_Addr e_entry; // Address to jump to in order to start program 50 | Elf32_Off e_phoff; // Program header table's file offset, in bytes 51 | Elf32_Off e_shoff; // Section header table's file offset, in bytes 52 | Elf32_Word e_flags; // Processor-specific flags 53 | Elf32_Half e_ehsize; // Size of ELF header, in bytes 54 | Elf32_Half e_phentsize; // Size of an entry in the program header table 55 | Elf32_Half e_phnum; // Number of entries in the program header table 56 | Elf32_Half e_shentsize; // Size of an entry in the section header table 57 | Elf32_Half e_shnum; // Number of entries in the section header table 58 | Elf32_Half e_shstrndx; // Sect hdr table index of sect name string table 59 | } Elf32_Ehdr; 60 | 61 | // Segment types. 62 | enum { 63 | PT_NULL = 0, // Unused segment. 64 | PT_LOAD = 1, // Loadable segment. 65 | PT_DYNAMIC = 2, // Dynamic linking information. 66 | PT_INTERP = 3, // Interpreter pathname. 67 | PT_NOTE = 4, // Auxiliary information. 68 | PT_SHLIB = 5, // Reserved. 69 | PT_PHDR = 6, // The program header table itself. 70 | PT_TLS = 7, // The thread-local storage template. 71 | PT_LOOS = 0x60000000, // Lowest operating system-specific pt entry type. 72 | PT_HIOS = 0x6fffffff, // Highest operating system-specific pt entry type. 73 | PT_LOPROC = 0x70000000, // Lowest processor-specific program hdr entry type. 74 | PT_HIPROC = 0x7fffffff, // Highest processor-specific program hdr entry type. 75 | 76 | // x86-64 program header types. 77 | // These all contain stack unwind tables. 78 | PT_GNU_EH_FRAME = 0x6474e550, 79 | PT_SUNW_EH_FRAME = 0x6474e550, 80 | PT_SUNW_UNWIND = 0x6464e550, 81 | 82 | PT_GNU_STACK = 0x6474e551, // Indicates stack executability. 83 | PT_GNU_RELRO = 0x6474e552, // Read-only after relocation. 84 | 85 | // ARM program header types. 86 | PT_ARM_ARCHEXT = 0x70000000, // Platform architecture compatibility info 87 | // These all contain stack unwind tables. 88 | PT_ARM_EXIDX = 0x70000001, 89 | PT_ARM_UNWIND = 0x70000001 90 | }; 91 | 92 | string ReadPhdrType(Elf32_Word flag) { 93 | switch (flag) { 94 | case PT_NULL: return "null"; 95 | case PT_LOAD: return "load"; 96 | case PT_DYNAMIC: return "dynamic"; 97 | case PT_INTERP: return "interp"; 98 | case PT_NOTE: return "note"; 99 | case PT_SHLIB: return "shlib"; 100 | case PT_PHDR: return "phdr"; 101 | case PT_TLS: return "tls"; 102 | case PT_LOOS: return "loos"; 103 | case PT_HIOS: return "hios"; 104 | case PT_LOPROC: return "loproc"; 105 | case PT_HIPROC: return "hiproc"; 106 | } 107 | return "ERROR"; 108 | } 109 | 110 | // Program header for ELF32. 111 | typedef struct { 112 | Elf32_Word p_type ; // Type of segment 113 | Elf32_Off p_offset; // File offset where segment is located, in bytes 114 | Elf32_Addr p_vaddr; // Virtual address of beginning of segment 115 | Elf32_Addr p_paddr; // Physical address of beginning of segment (OS-specific) 116 | Elf32_Word p_filesz; // Num. of bytes in file image of segment (may be zero) 117 | Elf32_Word p_memsz; // Num. of bytes in mem image of segment (may be zero) 118 | Elf32_Word p_flags; // Segment flags 119 | Elf32_Word p_align; // Segment alignment constraint 120 | } Elf32_Phdr; 121 | 122 | local uint section_name_off = 0; 123 | local uint dynsym_name_off = 0; 124 | local uint oatdata_off = 0; 125 | local uint oatexec_off = 0; 126 | 127 | typedef struct { 128 | Elf32_Word off; 129 | 130 | local quad curroff = FTell(); 131 | FSeek( section_name_off + off ); 132 | string s_name_str; 133 | FSeek( curroff ); 134 | } Elf32_Shdr_Name; 135 | 136 | // Section header. 137 | typedef struct { 138 | Elf32_Word sh_name ; // Section name (index into string table) 139 | Elf32_Word sh_type; // Section type (SHT_*) 140 | Elf32_Word sh_flags; // Section flags (SHF_*) 141 | Elf32_Addr sh_addr; // Address where section is to be loaded 142 | Elf32_Off sh_offset; // File offset of section data, in bytes 143 | Elf32_Word sh_size; // Size of section, in bytes 144 | Elf32_Word sh_link; // Section type-specific header table index link 145 | Elf32_Word sh_info; // Section type-specific extra information 146 | Elf32_Word sh_addralign; // Section address alignment 147 | Elf32_Word sh_entsize; // Size of records contained within the section 148 | } Elf32_Shdr; 149 | 150 | string ReadShdrName(Elf32_Word off) { 151 | return ReadString(section_name_off + off); 152 | } 153 | 154 | string ReadDynsymName(Elf32_Word off) { 155 | return ReadString(dynsym_name_off + off); 156 | } 157 | 158 | typedef struct { 159 | Elf32_Word st_name; // Symbol name (index into string table) 160 | Elf32_Addr st_value; // Value or address associated with the symbol 161 | Elf32_Word st_size; // Size of the symbol 162 | unsigned char st_info; // Symbol's type and binding attributes 163 | unsigned char st_other; // Must be zero; reserved 164 | Elf32_Half st_shndx; // Which section (header table index) it's defined in 165 | } Elf32_Sym_Fixed; 166 | 167 | typedef struct { 168 | Elf32_Word st_name ; // Symbol name (index into string table) 169 | Elf32_Addr st_value; // Value or address associated with the symbol 170 | Elf32_Word st_size; // Size of the symbol 171 | unsigned char st_info; // Symbol's type and binding attributes 172 | unsigned char st_other; // Must be zero; reserved 173 | Elf32_Half st_shndx; // Which section (header table index) it's defined in 174 | 175 | if (st_size) { 176 | local quad off = FTell(); 177 | FSeek( SectionVAddrOffset(st_shndx, st_value) ); 178 | uchar data[st_size]; 179 | FSeek( off ); 180 | } 181 | 182 | local string name = ReadDynsymName(st_name); 183 | if (Strcmp(name, "oatdata") == 0) { 184 | oatdata_off = SectionVAddrOffset(st_shndx, st_value); 185 | } 186 | 187 | } Elf32_Sym ; 188 | 189 | quad SectionVAddrOffset( Elf32_Half s_index, Elf32_Addr s_vaddr ) { 190 | if( s_index < file.elf_header.e_shnum ) { 191 | local quad ret = file.elf_section_header[s_index].sh_offset + s_vaddr - 192 | file.elf_section_header[s_index].sh_addr; 193 | 194 | return ret; 195 | } 196 | return 0; 197 | } 198 | 199 | // local int iter; 200 | int FindNamedSection( string sect ) { 201 | local int i; 202 | local string shdr_nn; 203 | 204 | for(i=0; i; 251 | 252 | local int warnings = 0; 253 | local string temp_warning; 254 | 255 | // A hack to get warning messages to both "Warn" (show in status) and output to the "output" window 256 | void PrintWarning(string message) { 257 | Warning(temp_warning); 258 | 259 | // Ensure new-line, "Warning" statuses should not have them 260 | SPrintf(temp_warning, "%s\n", message); 261 | Printf(temp_warning); 262 | 263 | // Hack to trigger a more generic "look at warnings in output" 264 | warnings++; 265 | } 266 | 267 | string SHA1Read(SHA1 sig) { 268 | string ret; 269 | string tmp; 270 | int i; 271 | 272 | for(i = 0; i<20; i++) { 273 | SPrintf(tmp, "%.2X", sig[i]); 274 | ret += tmp; 275 | } 276 | 277 | return ret; 278 | } 279 | 280 | // utility for reading/checking the magic value 281 | typedef struct { 282 | char dex[3]; 283 | char newline; 284 | char ver[3]; 285 | char zero; 286 | 287 | // XXX not checking the version, but it should be 035 288 | if((Strcmp(dex, "dex") && Strcmp(dex, "dey")) || 289 | newline != '\n' || 290 | zero != 0) { 291 | 292 | PrintWarning("Invalid DEX file"); 293 | return -1; 294 | } 295 | } dex_magic ; 296 | 297 | string DexMagicRead(dex_magic &m) { 298 | string s; 299 | SPrintf(s, "%s %s", m.dex, m.ver); 300 | return s; 301 | } 302 | 303 | ////////////////////////////////////////////////// 304 | // LEB128 stuff 305 | ////////////////////////////////////////////////// 306 | 307 | // struct to read a uleb128 value. uleb128's are a variable-length encoding for 308 | // a 32 bit value. some of the uleb128/sleb128 code was adapted from dalvik's 309 | // libdex/Leb128.h 310 | 311 | typedef struct { 312 | ubyte val ; 313 | if(val > 0x7f) { 314 | ubyte val ; 315 | if (val > 0x7f) { 316 | ubyte val ; 317 | if(val > 0x7f) { 318 | ubyte val ; 319 | if(val > 0x7f) { 320 | ubyte val ; 321 | } 322 | } 323 | } 324 | } 325 | } uleb128 ; 326 | 327 | // get the actual uint value of the uleb128 328 | uint uleb128_value(uleb128 &u) { 329 | local uint result; 330 | local ubyte cur; 331 | 332 | result = u.val[0]; 333 | if(result > 0x7f) { 334 | cur = u.val[1]; 335 | result = (result & 0x7f) | (uint)((cur & 0x7f) << 7); 336 | if(cur > 0x7f) { 337 | cur = u.val[2]; 338 | result |= (uint)(cur & 0x7f) << 14; 339 | if(cur > 0x7f) { 340 | cur = u.val[3]; 341 | result |= (uint)(cur & 0x7f) << 21; 342 | if(cur > 0x7f) { 343 | cur = u.val[4]; 344 | result |= (uint)cur << 28; 345 | } 346 | } 347 | } 348 | } 349 | 350 | return result; 351 | } 352 | 353 | typedef struct uleb128 uleb128p1; 354 | 355 | int uleb128p1_value(uleb128 &u) { 356 | return (int)uleb128_value(u) - 1; 357 | } 358 | 359 | string ULeb128Read(uleb128 &u) { 360 | local string s; 361 | s = SPrintf(s, "0x%X", uleb128_value(u)); 362 | return s; 363 | } 364 | 365 | // sleb128 366 | typedef struct { 367 | ubyte val ; 368 | if(val > 0x7f) { 369 | ubyte val ; 370 | if (val > 0x7f) { 371 | ubyte val ; 372 | if(val > 0x7f) { 373 | ubyte val ; 374 | if(val > 0x7f) { 375 | ubyte val ; 376 | } 377 | } 378 | } 379 | } 380 | } sleb128 ; 381 | 382 | // get the actual uint value of the uleb128 383 | int sleb128_value(sleb128 &u) { 384 | local int result; 385 | local ubyte cur; 386 | 387 | result = u.val[0]; 388 | if(result <= 0x7f) { 389 | result = (result << 25) >> 25; 390 | } else { 391 | cur = u.val[1]; 392 | result = (result & 0x7f) | ((uint)(cur & 0x7f) << 7); 393 | if(cur <= 0x7f) { 394 | result = (result << 18) >> 18; 395 | } else { 396 | cur = u.val[2]; 397 | result |= (uint)(cur & 0x7f) << 14; 398 | if(cur <= 0x7f) { 399 | result = (result << 11) >> 11; 400 | } else { 401 | cur = u.val[3]; 402 | result |= (uint)(cur & 0x7f) << 21; 403 | if(cur <= 0x7f) { 404 | result = (result << 4) >> 4; 405 | } else { 406 | cur = u.val[4]; 407 | result |= (uint)cur << 28; 408 | } 409 | } 410 | } 411 | } 412 | 413 | return result; 414 | } 415 | 416 | string SLeb128Read(sleb128 &u) { 417 | local string s; 418 | s = SPrintf(s, "%i", sleb128_value(u)); 419 | return s; 420 | } 421 | 422 | ////////////////////////////////////////////////// 423 | // encoded_value type 424 | ////////////////////////////////////////////////// 425 | 426 | typedef enum { 427 | VALUE_BYTE = 0x00, 428 | VALUE_SHORT = 0x02, 429 | VALUE_CHAR = 0x03, 430 | VALUE_INT = 0x04, 431 | VALUE_LONG = 0x06, 432 | VALUE_FLOAT = 0x10, 433 | VALUE_DOUBLE = 0x11, 434 | VALUE_STRING = 0x17, 435 | VALUE_TYPE = 0x18, 436 | VALUE_FIELD = 0x19, 437 | VALUE_METHOD = 0x1a, 438 | VALUE_ENUM = 0x1b, 439 | VALUE_ARRAY = 0x1c, 440 | VALUE_ANNOTATION = 0x1d, 441 | VALUE_NULL = 0x1e, 442 | VALUE_BOOLEAN = 0x1f 443 | } VALUE; 444 | 445 | // variable-width integer used by encoded_value types 446 | typedef struct (int size, VALUE type) { 447 | local quad baseAddr = parentof(this).baseAddr; 448 | local int dexIndex = parentof(this).dexIndex; 449 | local int s = size + 1; 450 | local VALUE t = type; 451 | local int i; 452 | 453 | for(i=0; i; 455 | } 456 | } EncodedValue ; 457 | 458 | string EncodedValueRead(EncodedValue &v) { 459 | local string s = ""; 460 | 461 | switch(v.t) { 462 | case VALUE_BYTE: 463 | case VALUE_SHORT: 464 | case VALUE_INT: 465 | case VALUE_LONG: 466 | case VALUE_FLOAT: 467 | case VALUE_DOUBLE: 468 | SPrintf(s, "0x%X", EncodedValueValue(v)); 469 | break; 470 | case VALUE_STRING: 471 | s = StringIdRead(v.dexIndex, EncodedValueValue(v)); 472 | break; 473 | case VALUE_TYPE: 474 | s = LongTypeIdRead(v.dexIndex, EncodedValueValue(v)); 475 | break; 476 | case VALUE_FIELD: 477 | s = FieldIdRead(v.dexIndex, EncodedValueValue(v)); 478 | break; 479 | case VALUE_ENUM: 480 | s = FieldIdRead(v.dexIndex, EncodedValueValue(v)); 481 | break; 482 | case VALUE_ARRAY: 483 | case VALUE_ANNOTATION: 484 | case VALUE_BOOLEAN: 485 | case VALUE_NULL: 486 | s = "NULL"; 487 | break; 488 | } 489 | return s; 490 | } 491 | 492 | int64 EncodedValueValue(EncodedValue &v) { 493 | local int shift = 0; 494 | local int i; 495 | local int64 ret; 496 | 497 | if(v.s == 1) { 498 | return v.val; 499 | } 500 | 501 | for(i=0; i; 513 | ubyte value_arg:3 ; 514 | local string valstr = ""; 515 | local string typestr = ""; 516 | 517 | switch (value_type) { 518 | case VALUE_BYTE: 519 | ubyte value ; 520 | SPrintf(valstr, "0x%.2X", value); 521 | typestr = "byte"; 522 | break; 523 | case VALUE_SHORT: 524 | // value_arg has size-1, either 0 or 1 525 | EncodedValue value(value_arg, value_type) ; 526 | SPrintf(valstr, "%i", EncodedValueValue(value)); 527 | typestr = "short"; 528 | break; 529 | case VALUE_CHAR: 530 | EncodedValue value(value_arg, value_type) ; 531 | SPrintf(valstr, "'%c'", EncodedValueValue(value)); 532 | typestr = "char"; 533 | break; 534 | case VALUE_INT: 535 | EncodedValue value(value_arg, value_type) ; 536 | SPrintf(valstr, "%i", EncodedValueValue(value)); 537 | typestr = "int"; 538 | break; 539 | case VALUE_LONG: 540 | EncodedValue value(value_arg, value_type) ; 541 | SPrintf(valstr, "%li", EncodedValueValue(value)); 542 | typestr = "long"; 543 | break; 544 | case VALUE_FLOAT: // XXX this doesn't work 545 | EncodedValue value(value_arg, value_type) ; 546 | SPrintf(valstr, "%f", EncodedValueValue(value)); 547 | typestr = "float"; 548 | break; 549 | case VALUE_DOUBLE: 550 | EncodedValue value(value_arg, value_type) ; 551 | SPrintf(valstr, "%li", EncodedValueValue(value)); 552 | typestr = "double"; 553 | break; 554 | case VALUE_STRING: 555 | EncodedValue value(value_arg, value_type) ; 556 | valstr = "\"" + GetStringById(dexIndex, EncodedValueValue(value)) + "\""; 557 | typestr = "string"; 558 | break; 559 | case VALUE_TYPE: 560 | EncodedValue value(value_arg, value_type) ; 561 | valstr = GetLongTypeById(dexIndex, EncodedValueValue(value)); 562 | typestr = "type"; 563 | break; 564 | case VALUE_FIELD: 565 | EncodedValue value(value_arg, value_type) ; 566 | valstr = GetFieldById(dexIndex, EncodedValueValue(value)); 567 | typestr = "field"; 568 | break; 569 | case VALUE_METHOD: 570 | EncodedValue value(value_arg, value_type) ; 571 | valstr = GetMethodById(dexIndex, EncodedValueValue(value)); 572 | typestr = "method"; 573 | break; 574 | case VALUE_ENUM: 575 | EncodedValue value(value_arg, value_type) ; 576 | valstr = GetFieldById(dexIndex, EncodedValueValue(value)); 577 | typestr = "enum"; 578 | break; 579 | case VALUE_ARRAY: 580 | struct encoded_array array ; 581 | break; 582 | case VALUE_ANNOTATION: 583 | struct encoded_annotation annotation ; 584 | break; 585 | case VALUE_NULL: 586 | // no additional bytes used by null 587 | typestr = valstr = "NULL"; 588 | break; 589 | case VALUE_BOOLEAN: 590 | // no additional bytes used by boolean 591 | typestr = "boolean"; 592 | if(value_arg == 0) { 593 | valstr = "false"; 594 | } else { 595 | valstr = "true"; 596 | } 597 | break; 598 | default: 599 | SPrintf(temp_warning, "Unknown type for encoded value 0x%X", value_type); 600 | PrintWarning(temp_warning); 601 | break; 602 | } 603 | } encoded_value ; 604 | 605 | string EncodedValueStructRead(encoded_value &v) { 606 | return v.typestr + ": " + v.valstr; 607 | } 608 | 609 | typedef struct { 610 | local quad baseAddr = parentof(this).baseAddr; 611 | local int dexIndex = parentof(this).dexIndex; 612 | uleb128 size ; 613 | local uint valueSize = uleb128_value(size); 614 | if (valueSize != 0) { 615 | encoded_value values[uleb128_value(size)] ; 616 | } 617 | 618 | 619 | } encoded_array ; 620 | 621 | // show first 5 elements of the array 622 | string EncodedArrayRead(encoded_array &a) { 623 | local int count = 5; 624 | local int dots = 1; 625 | local int i; 626 | 627 | if(uleb128_value(a.size) < 5) { 628 | count = uleb128_value(a.size); 629 | dots = 0; 630 | } 631 | 632 | string val = "["; 633 | 634 | for(i=0; i; 653 | encoded_value value ; 654 | } annotation_element ; 655 | 656 | string AnnotationElementRead(annotation_element &e) { 657 | string name = GetStringById(e.dexIndex, uleb128_value(e.name_idx)); 658 | return name + " = " + e.value.valstr; 659 | } 660 | 661 | typedef struct { 662 | local quad baseAddr = parentof(this).baseAddr; 663 | local int dexIndex = parentof(this).dexIndex; 664 | uleb128 type_idx ; 665 | uleb128 size ; 666 | 667 | if(uleb128_value(size) > 0) { 668 | annotation_element elements[uleb128_value(size)] ; 669 | } 670 | } encoded_annotation ; 671 | 672 | string EncodedAnnotationRead(encoded_annotation &a) { 673 | string s; 674 | SPrintf(s, "%i annotations for %s", uleb128_value(a.size), GetLongTypeById(a.dexIndex, uleb128_value(a.type_idx))); 675 | return s; 676 | } 677 | 678 | ////////////////////////////////////////////////// 679 | // dex file header 680 | ////////////////////////////////////////////////// 681 | 682 | typedef struct { 683 | local int i; 684 | local quad parentAddr = startof(parentof(this)); 685 | for (i=0; i; 692 | 693 | // local uint file_start = 0; 694 | // if(odex) { 695 | // file_start = dexopt_header.dex_offset; 696 | // } 697 | // Printf("odexpad: %x", odexpad); 698 | 699 | // // Temp variable for expected file_length 700 | // local uint temp_expected_file_size = ReadUInt(odexpad + 32); 701 | // // If the size is less than the actual file - lets just set it to be filesize and let other 702 | // // things fail nicely than hit out of bound errors 703 | // if(temp_expected_file_size > FileSize()) { 704 | // temp_expected_file_size = FileSize(); 705 | // } 706 | 707 | // local uint temp_checksum = Checksum(CHECKSUM_ADLER32, odexpad + 12, temp_expected_file_size - 12, -1, -1); 708 | // if(temp_checksum != ReadUInt(FTell())) { 709 | // SetBackColor(cLtRed); 710 | // SPrintf(temp_warning, "Alder32 checksum did not match, expected %08X but got %08X", ReadUInt(FTell()), temp_checksum); 711 | // PrintWarning(temp_warning); 712 | // } 713 | uint checksum ; 714 | // Ensure we reset color to not bleed 715 | SetBackColor(cLtGreen); 716 | 717 | // // Odex files kill the sha1, but the above checksum is changed 718 | // if(!odex) { 719 | // // Preemptively read the sha1 in for comparison 720 | // local string temp_expected_sha1, temp_char; 721 | // local int i; 722 | // for(i = 0; i < 20; i++) { 723 | // SPrintf(temp_char, "%.2X", ReadUByte(FTell()+i)); 724 | // temp_expected_sha1 += temp_char; 725 | // } 726 | // local string temp_prepared_sha1 = ""; 727 | // ChecksumAlgStr(CHECKSUM_SHA1, temp_prepared_sha1, odexpad + 32, temp_expected_file_size - 32, "", -1, -1); 728 | // if(temp_expected_sha1 != temp_prepared_sha1) { 729 | // SetBackColor(cLtRed); 730 | // SPrintf(temp_warning, "Sha1 checksum did not match, expected %s but got %s", temp_expected_sha1, temp_prepared_sha1); 731 | // PrintWarning(temp_warning); 732 | // } 733 | // } 734 | SHA1 signature ; 735 | // Ensure we reset color to not bleed 736 | SetBackColor(cLtGreen); 737 | 738 | // local uint temp_file_size = ReadUInt(FTell()); 739 | // if(temp_file_size > FileSize()) { 740 | // PrintWarning("File size appears be to smaller than expected - invalid dex file"); 741 | // SetBackColor(cLtRed); 742 | // } else if(odex && temp_file_size != dexopt_header.dex_length) { 743 | // PrintWarning("File size does not match what odex header says it should be"); 744 | // SetBackColor(cLtRed); 745 | // } else if(!odex && temp_file_size < FileSize()) { 746 | // // This could still technically be a valid dex file according to code paths in the verifier 747 | // PrintWarning("File size appears be to larger than expected"); 748 | // SetBackColor(cLtRed); 749 | // } 750 | uint file_size ; 751 | // Ensure we reset color to not bleed 752 | SetBackColor(cLtGreen); 753 | 754 | if(ReadUInt(FTell()) != 0x70) { 755 | SetBackColor(cLtRed); 756 | } 757 | uint header_size ; 758 | if(header_size > 0x70) { 759 | PrintWarning("Header size appears be to larger than expected"); 760 | } 761 | // Ensure we reset color to not bleed 762 | SetBackColor(cLtGreen); 763 | 764 | uint endian_tag ; 765 | 766 | if(endian_tag != ENDIAN_CONSTANT) { 767 | // XXX we don't handle big endian files 768 | SPrintf(temp_warning, "Invalid endian_tag %.8X, should be %.8X", endian_tag, ENDIAN_CONSTANT); 769 | PrintWarning(temp_warning); 770 | } 771 | 772 | if(ReadUInt(FTell()) != 0 && ReadUInt(FTell() + 4) != 0) { 773 | SetBackColor(cLtRed); 774 | } 775 | uint link_size ; 776 | uint link_off ; 777 | if(link_size != 0 || link_off != 0) { 778 | PrintWarning("A link section appears to be set, this is not supported"); 779 | } 780 | // Ensure we reset color to not bleed 781 | SetBackColor(cLtGreen); 782 | 783 | uint map_off ; 784 | uint string_ids_size ; 785 | uint string_ids_off ; 786 | uint type_ids_size ; 787 | uint type_ids_off ; 788 | uint proto_ids_size ; 789 | uint proto_ids_off ; 790 | uint field_ids_size ; 791 | uint field_ids_off ; 792 | uint method_ids_size ; 793 | uint method_ids_off ; 794 | uint class_defs_size ; 795 | uint class_defs_off ; 796 | uint data_size ; 797 | uint data_off ; 798 | 799 | // Anything after the rest of this, but before the other sections is essentiall 800 | // just "padding", so lets create an array variable to contain it and color it 801 | // properly 802 | if(header_size > 0x70) { 803 | SetBackColor(cLtRed); 804 | char extra_padding[header_size - 0x70]; 805 | } 806 | } header_item ; 807 | 808 | int readHeaderItemSize(header_item &item) { 809 | return ReadUInt(startof(item)+36); 810 | } 811 | 812 | ////////////////////////////////////////////////// 813 | // odex file header 814 | ////////////////////////////////////////////////// 815 | 816 | // Keeping this enum, but it shouldn't ever happen that the flag 817 | // will be anything other than 0x0 or DEX_OPT_FLAG_BIG 818 | // https://android.googlesource.com/platform/dalvik.git/+/57fd399d1265ec627d28a15b3d4b98e5f239ac88%5E!/ 819 | typedef enum { 820 | DEX_FLAG_VERIFIED = 0x1, 821 | DEX_OPT_FLAG_BIG = 0x2, 822 | DEX_OPT_FLAG_FIELDS = 0x4, 823 | DEX_OPT_FLAG_INVOCATIONS = 0x8 824 | } DEX_OPT_FLAGS; 825 | 826 | typedef struct { 827 | dex_magic magic ; 828 | uint dex_offset ; 829 | uint dex_length ; 830 | uint deps_offset ; 831 | uint deps_length ; 832 | uint opt_offset ; 833 | uint opt_length ; 834 | DEX_OPT_FLAGS flags ; 835 | 836 | // This is a potentially sloppy way of getting the size of the section to be checksum'ed, 837 | // though I haven't bothered to look up how the padding is done on the end of the 838 | // deps + opt section 839 | local uint temp_checksum = Checksum(CHECKSUM_ADLER32, deps_offset,FileSize() - deps_offset, -1, -1); 840 | if(temp_checksum != ReadUInt(FTell())) { 841 | SetBackColor(cLtRed); 842 | SPrintf(temp_warning, "Alder32 checksum for optimized dependancies did not match, expected %08X but got %08X", ReadUInt(FTell()), temp_checksum); 843 | PrintWarning(temp_warning); 844 | } 845 | uint checksum ; 846 | } dexopt_header_item ; 847 | 848 | string DexOptFlagsRead(DEX_OPT_FLAGS f) { 849 | string ret = ""; 850 | string flags = ""; 851 | DEX_OPT_FLAGS i = 1; 852 | 853 | while(i <= DEX_OPT_FLAG_INVOCATIONS) { 854 | if (f & i) { 855 | flags += EnumToString(i) + " "; 856 | } 857 | i = i << 1; 858 | } 859 | 860 | SPrintf(ret, "(0x%X) %s", f, flags); 861 | return ret; 862 | } 863 | 864 | ////////////////////////////////////////////////// 865 | // strings 866 | ////////////////////////////////////////////////// 867 | 868 | typedef struct { 869 | local quad baseAddr = parentof(this).baseAddr; 870 | local int dexIndex = parentof(this).dexIndex; 871 | uleb128 utf16_size ; 872 | string data ; 873 | } string_item; 874 | 875 | typedef struct { 876 | local quad baseAddr = parentof(this).baseAddr; 877 | local int dexIndex = parentof(this).dexIndex; 878 | uint string_data_off ; 879 | 880 | local int64 pos = FTell(); 881 | FSeek(baseAddr + string_data_off); 882 | 883 | string_item string_data ; 884 | 885 | FSeek(pos); 886 | } string_id_item ; 887 | 888 | string StringDataReader(string_id_item &i) { 889 | return i.string_data.data; 890 | } 891 | 892 | typedef struct (int size) { 893 | local int i; 894 | local quad parentAddr = startof(parentof(this)); 895 | for (i=0; i; 903 | } string_id_list ; 904 | 905 | string StringIDListRead(string_id_list &l) { 906 | string s; 907 | s = SPrintf(s, "%d strings", l.s); 908 | return s; 909 | } 910 | 911 | ////////////////////////////////////////////////// 912 | // type IDs 913 | ////////////////////////////////////////////////// 914 | typedef struct { 915 | local quad baseAddr = parentof(this).baseAddr; 916 | local int dexIndex = parentof(this).dexIndex; 917 | uint idx ; 918 | } id_string ; 919 | 920 | string id_stringRead(id_string &s) { 921 | return StringIdRead(s.dexIndex, s.idx); 922 | } 923 | 924 | typedef struct { 925 | local quad baseAddr = parentof(this).baseAddr; 926 | local int dexIndex = parentof(this).dexIndex; 927 | id_string descriptor_idx ; 928 | } type_id_item ; 929 | 930 | string TypeIDItemRead(type_id_item &i) { 931 | return GetLongTypeDescriptor(GetStringById(i.dexIndex, i.descriptor_idx.idx)); 932 | } 933 | 934 | typedef struct (int size) { 935 | local int i; 936 | local quad parentAddr = startof(parentof(this)); 937 | for (i=0; i; 945 | } type_id_list ; 946 | 947 | string TypeIDListRead(type_id_list &l) { 948 | string s; 949 | s = SPrintf(s, "%d types", l.s); 950 | return s; 951 | } 952 | 953 | ////////////////////////////////////////////////// 954 | // type list 955 | ////////////////////////////////////////////////// 956 | typedef struct { 957 | local quad baseAddr = parentof(this).baseAddr; 958 | local int dexIndex = parentof(this).dexIndex; 959 | ushort type_idx ; 960 | } type_item ; 961 | 962 | typedef struct { 963 | local quad baseAddr = parentof(this).baseAddr; 964 | local int dexIndex = parentof(this).dexIndex; 965 | uint size ; 966 | 967 | if(size != 0) { 968 | type_item list[size] ; 969 | } 970 | } type_item_list ; 971 | 972 | string TypeItemRead(type_item &t) { 973 | return GetTypeById(t.dexIndex, t.type_idx); 974 | } 975 | 976 | string TypeItemListRead(type_item_list &l) { 977 | string s = ""; 978 | string tmp; 979 | int i; 980 | 981 | for(i = 0; i < l.size; i++) { 982 | s += GetTypeById(l.dexIndex, l.list[i].type_idx); 983 | if(i+1 < l.size) { 984 | s += ", "; 985 | } 986 | } 987 | return s; 988 | } 989 | 990 | string GetLongTypeDescriptor(string descriptor) { 991 | local string desc = ""; 992 | local string post = ""; 993 | local int i = 0; 994 | local int len = Strlen(descriptor); 995 | 996 | // array descriptors 997 | while(descriptor[i] == '[') { 998 | post += "[]"; 999 | i++; 1000 | 1001 | if(i >= len) return "ERROR"; 1002 | } 1003 | 1004 | if(descriptor[i] == 'L') { 1005 | // fully qualified class descriptors 1006 | i++; 1007 | while(i < len) { 1008 | if(descriptor[i] == '/') desc += "."; 1009 | else if(descriptor[i] == ';') break; 1010 | else desc += descriptor[i]; 1011 | i++; 1012 | } 1013 | } else { 1014 | // simple type descriptors 1015 | switch(descriptor[i]) { 1016 | case 'V': desc = "void"; break; 1017 | case 'Z': desc = "boolean"; break; 1018 | case 'B': desc = "byte"; break; 1019 | case 'S': desc = "short"; break; 1020 | case 'C': desc = "char"; break; 1021 | case 'I': desc = "int"; break; 1022 | case 'J': desc = "long"; break; 1023 | case 'F': desc = "float"; break; 1024 | case 'D': desc = "double"; break; 1025 | } 1026 | } 1027 | 1028 | return desc + post; 1029 | } 1030 | 1031 | ////////////////////////////////////////////////// 1032 | // protoypes 1033 | ////////////////////////////////////////////////// 1034 | typedef struct { 1035 | local quad baseAddr = parentof(this).baseAddr; 1036 | local int dexIndex = parentof(this).dexIndex; 1037 | uint idx ; 1038 | } type_string ; 1039 | 1040 | string type_stringRead(type_string &s) { 1041 | return TypeIdRead(s.dexIndex, s.idx); 1042 | } 1043 | 1044 | typedef struct { 1045 | local quad baseAddr = parentof(this).baseAddr; 1046 | local int dexIndex = parentof(this).dexIndex; 1047 | uint shorty_idx ; 1048 | type_string return_type_idx ; 1049 | uint parameters_off ; 1050 | 1051 | if(parameters_off != 0) { 1052 | local int64 pos = FTell(); 1053 | FSeek(baseAddr + parameters_off); 1054 | 1055 | type_item_list parameters ; 1056 | 1057 | FSeek(pos); 1058 | } 1059 | 1060 | } proto_id_item ; 1061 | 1062 | string ProtoIDItemRead(proto_id_item &i) { 1063 | return GetPrototypeSignature(i); 1064 | } 1065 | 1066 | typedef struct (int size) { 1067 | local int i; 1068 | local quad parentAddr = startof(parentof(this)); 1069 | for (i=0; i; 1077 | } proto_id_list ; 1078 | 1079 | string ProtoIDListRead(proto_id_list &l) { 1080 | string s; 1081 | s = SPrintf(s, "%d prototypes", l.s); 1082 | return s; 1083 | } 1084 | 1085 | string GetParameterListString(type_item_list &l) { 1086 | local string s = "("; 1087 | local string tmp; 1088 | local int i; 1089 | 1090 | for(i = 0; i < l.size; i++) { 1091 | s += GetLongTypeDescriptor(GetTypeById(l.dexIndex, l.list[i].type_idx)); 1092 | if(i+1 < l.size) { 1093 | s += ", "; 1094 | } 1095 | } 1096 | return s + ")"; 1097 | } 1098 | 1099 | string GetPrototypeSignature(proto_id_item &item) { 1100 | string ret = GetLongTypeDescriptor(GetTypeById(item.dexIndex, item.return_type_idx.idx)); 1101 | string params = "()"; 1102 | if(exists(item.parameters)) { 1103 | params = GetParameterListString(item.parameters); 1104 | } 1105 | 1106 | return ret + " " + params; 1107 | } 1108 | 1109 | ////////////////////////////////////////////////// 1110 | // fields 1111 | ////////////////////////////////////////////////// 1112 | typedef struct { 1113 | local quad baseAddr = parentof(this).baseAddr; 1114 | local int dexIndex = parentof(this).dexIndex; 1115 | ushort idx ; 1116 | } long_type_string ; 1117 | 1118 | string long_type_stringRead(long_type_string &s) { 1119 | return LongTypeIdRead(s.dexIndex, s.idx); 1120 | } 1121 | 1122 | typedef struct { 1123 | local quad baseAddr = parentof(this).baseAddr; 1124 | local int dexIndex = parentof(this).dexIndex; 1125 | long_type_string class_idx ; 1126 | long_type_string type_idx ; 1127 | id_string name_idx ; 1128 | } field_id_item ; 1129 | 1130 | string FieldIdItemRead(field_id_item &i) { 1131 | local string type = GetLongTypeDescriptor(GetTypeById(i.dexIndex, i.type_idx.idx)); 1132 | local string class = GetLongTypeDescriptor(GetTypeById(i.dexIndex, i.class_idx.idx)); 1133 | local string name = GetStringById(i.dexIndex, i.name_idx.idx); 1134 | 1135 | return type + " " + class + "." + name; 1136 | } 1137 | 1138 | typedef struct (int size) { 1139 | local int i; 1140 | local quad parentAddr = startof(parentof(this)); 1141 | for (i=0; i; 1149 | } field_id_list ; 1150 | 1151 | string FieldIDListRead(field_id_list &l) { 1152 | string s; 1153 | s = SPrintf(s, "%d fields", l.s); 1154 | return s; 1155 | } 1156 | 1157 | ////////////////////////////////////////////////// 1158 | // methods 1159 | ////////////////////////////////////////////////// 1160 | typedef struct { 1161 | local quad baseAddr = parentof(this).baseAddr; 1162 | local int dexIndex = parentof(this).dexIndex; 1163 | ushort idx ; 1164 | } proto_id_string ; 1165 | 1166 | string proto_id_stringRead(proto_id_string &s) { 1167 | return ProtoIdxRead(s.dexIndex, s.idx); 1168 | } 1169 | 1170 | typedef struct { 1171 | local quad baseAddr = parentof(this).baseAddr; 1172 | local int dexIndex = parentof(this).dexIndex; 1173 | long_type_string class_idx ; 1174 | proto_id_string proto_idx ; 1175 | id_string name_idx ; 1176 | } method_id_item ; 1177 | 1178 | string ProtoIdxRead(int dexIndex, ushort p) { 1179 | string s; 1180 | SPrintf(s, "(0x%X) %s", p, GetPrototypeSignature(file.dex_files[dexIndex].dex_proto_ids.proto_id[p])); 1181 | return s; 1182 | } 1183 | 1184 | string MethodIdItemRead(method_id_item &m) { 1185 | 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)); 1186 | local string classname = GetLongTypeDescriptor(GetStringById(m.dexIndex, file.dex_files[m.dexIndex].dex_type_ids.type_id[m.class_idx.idx].descriptor_idx.idx)); 1187 | local string methodname = GetStringById(m.dexIndex, m.name_idx.idx); 1188 | local string params = "()"; 1189 | if(exists(file.dex_files[m.dexIndex].dex_proto_ids.proto_id[m.proto_idx.idx].parameters)) { 1190 | params = GetParameterListString(file.dex_files[m.dexIndex].dex_proto_ids.proto_id[m.proto_idx.idx].parameters); 1191 | } 1192 | return retval + " " + classname + "." + methodname + params; 1193 | } 1194 | 1195 | typedef struct (int size) { 1196 | local int i; 1197 | local quad parentAddr = startof(parentof(this)); 1198 | for (i=0; i; 1206 | } method_id_list ; 1207 | 1208 | string MethodIDListRead(method_id_list &l) { 1209 | string s; 1210 | s = SPrintf(s, "%d methods", l.s); 1211 | return s; 1212 | } 1213 | 1214 | ////////////////////////////////////////////////// 1215 | // annotations 1216 | ////////////////////////////////////////////////// 1217 | typedef struct { 1218 | local quad baseAddr = parentof(this).baseAddr; 1219 | local int dexIndex = parentof(this).dexIndex; 1220 | uint idx ; 1221 | } field_uint_string ; 1222 | 1223 | string field_uint_stringRead(field_uint_string &s) { 1224 | return FieldIdRead(s.dexIndex, s.idx); 1225 | } 1226 | 1227 | typedef struct { 1228 | local quad baseAddr = parentof(this).baseAddr; 1229 | local int dexIndex = parentof(this).dexIndex; 1230 | field_uint_string field_idx; 1231 | uint annotations_off; 1232 | 1233 | if(annotations_off != 0) { 1234 | local int64 pos = FTell(); 1235 | FSeek(baseAddr + annotations_off); 1236 | 1237 | struct annotation_set_item field_annotations; 1238 | 1239 | FSeek(pos); 1240 | } 1241 | } field_annotation ; 1242 | 1243 | string FieldAnnotationRead(field_annotation &f) { 1244 | return GetFieldById(f.dexIndex, f.field_idx.idx); 1245 | } 1246 | 1247 | typedef struct { 1248 | local quad baseAddr = parentof(this).baseAddr; 1249 | local int dexIndex = parentof(this).dexIndex; 1250 | uint idx ; 1251 | } method_id_string ; 1252 | 1253 | string method_id_stringRead(method_id_string &s) { 1254 | return MethodIdRead(s.dexIndex, s.idx); 1255 | } 1256 | 1257 | typedef struct { 1258 | local quad baseAddr = parentof(this).baseAddr; 1259 | local int dexIndex = parentof(this).dexIndex; 1260 | method_id_string method_idx; 1261 | uint annotations_off; 1262 | 1263 | if(annotations_off != 0) { 1264 | local int64 pos = FTell(); 1265 | FSeek(baseAddr + annotations_off); 1266 | 1267 | struct annotation_set_item method_annotations; 1268 | 1269 | FSeek(pos); 1270 | } 1271 | } method_annotation ; 1272 | 1273 | string MethodAnnotationRead(method_annotation &m) { 1274 | return GetMethodById(m.dexIndex, m.method_idx.idx); 1275 | } 1276 | 1277 | typedef struct { 1278 | local quad baseAddr = parentof(this).baseAddr; 1279 | local int dexIndex = parentof(this).dexIndex; 1280 | method_id_string method_idx; 1281 | uint annotations_off; 1282 | 1283 | if(annotations_off != 0) { 1284 | local int64 pos = FTell(); 1285 | FSeek(baseAddr + annotations_off); 1286 | 1287 | struct annotation_set_ref_list annotations_list; 1288 | 1289 | FSeek(pos); 1290 | } 1291 | } parameter_annotation ; 1292 | 1293 | string ParameterAnnotationRead(parameter_annotation &p) { 1294 | return GetParameterListString(dex_proto_ids.proto_id[dex_method_ids.method_id[p.method_idx.idx].proto_idx.idx].parameters); 1295 | } 1296 | 1297 | typedef enum { 1298 | VISIBILITY_BUILD = 0x0, 1299 | VISIBILITY_RUNTIME = 0x1, 1300 | VISIBILITY_SYSTEM = 0x2 1301 | } VISIBILITY; 1302 | 1303 | typedef struct { 1304 | local quad baseAddr = parentof(this).baseAddr; 1305 | local int dexIndex = parentof(this).dexIndex; 1306 | VISIBILITY visibility ; 1307 | encoded_annotation annotation ; 1308 | } annotation_item ; 1309 | 1310 | string AnnotationItemRead(annotation_item &i) { 1311 | return EncodedAnnotationRead(i.annotation); 1312 | } 1313 | 1314 | typedef struct { 1315 | local quad baseAddr = parentof(this).baseAddr; 1316 | local int dexIndex = parentof(this).dexIndex; 1317 | uint annotation_off ; 1318 | 1319 | if(annotation_off != 0) { 1320 | local int64 pos = FTell(); 1321 | FSeek(baseAddr + annotation_off); 1322 | 1323 | annotation_item item ; 1324 | 1325 | FSeek(pos); 1326 | } 1327 | 1328 | } annotation_off_item ; 1329 | 1330 | string AnnotationOffItemRead(annotation_off_item &i) { 1331 | if(exists(i.item)) { 1332 | return AnnotationItemRead(i.item); 1333 | } else { 1334 | return ""; 1335 | } 1336 | } 1337 | 1338 | typedef struct { 1339 | local quad baseAddr = parentof(this).baseAddr; 1340 | local int dexIndex = parentof(this).dexIndex; 1341 | uint size ; 1342 | 1343 | if(size > 0) { 1344 | annotation_off_item entries[size] ; 1345 | } 1346 | } annotation_set_item ; 1347 | 1348 | string AnnotationSetItemRead(annotation_set_item &i) { 1349 | local string s; 1350 | SPrintf(s, "%i annotation entries", i.size); 1351 | return s; 1352 | } 1353 | 1354 | typedef struct { 1355 | local quad baseAddr = parentof(this).baseAddr; 1356 | local int dexIndex = parentof(this).dexIndex; 1357 | uint class_annotations_off ; 1358 | 1359 | if(class_annotations_off != 0) { 1360 | local int64 pos = FTell(); 1361 | FSeek(baseAddr + class_annotations_off); 1362 | 1363 | annotation_set_item class_annotations ; 1364 | 1365 | FSeek(pos); 1366 | } 1367 | uint fields_size ; 1368 | uint methods_size ; 1369 | uint parameters_size ; 1370 | 1371 | if(fields_size > 0) { 1372 | field_annotation field_annotations[fields_size] ; 1373 | } 1374 | 1375 | if(methods_size > 0) { 1376 | method_annotation method_annotations[methods_size] ; 1377 | } 1378 | 1379 | if(parameters_size > 0) { 1380 | parameter_annotation parameter_annotations[parameters_size] ; 1381 | } 1382 | } annotations_directory_item ; 1383 | 1384 | string AnnotationsDirectoryItemRead(annotations_directory_item &i) { 1385 | local string s; 1386 | local int classes = 0; 1387 | if(exists(i.class_annotations)) { 1388 | classes = i.class_annotations.size; 1389 | } 1390 | 1391 | SPrintf(s, "%i class annotations, %i field annotations, %i method annotations, %i parameter annotations", 1392 | classes, i.fields_size, i.methods_size, i.parameters_size); 1393 | return s; 1394 | } 1395 | 1396 | typedef struct { 1397 | local quad baseAddr = parentof(this).baseAddr; 1398 | local int dexIndex = parentof(this).dexIndex; 1399 | uint annotations_off ; 1400 | 1401 | if(annotations_off != 0) { 1402 | local int64 pos = FTell(); 1403 | FSeek(baseAddr + annotations_off); 1404 | 1405 | struct annotation_set_item item ; 1406 | 1407 | FSeek(pos); 1408 | } 1409 | } annotation_set_ref_item ; 1410 | 1411 | typedef struct { 1412 | local quad baseAddr = parentof(this).baseAddr; 1413 | local int dexIndex = parentof(this).dexIndex; 1414 | uint size ; 1415 | 1416 | if(size > 0) { 1417 | annotation_set_ref_item list[size] ; 1418 | } 1419 | } annotation_set_ref_list; 1420 | 1421 | ////////////////////////////////////////////////// 1422 | // classes 1423 | ////////////////////////////////////////////////// 1424 | 1425 | // access flags. some of these mean different things for different items (class/field/method) 1426 | typedef enum { 1427 | ACC_PUBLIC = 0x1, 1428 | ACC_PRIVATE = 0x2, 1429 | ACC_PROTECTED = 0x4, 1430 | ACC_STATIC = 0x8, 1431 | ACC_FINAL = 0x10, 1432 | ACC_SYNCHRONIZED = 0x20, 1433 | ACC_VOLATILE = 0x40, // field 1434 | //ACC_BRIDGE = 0x40, // method 1435 | ACC_TRANSIENT = 0x80, // field 1436 | //ACC_VARARGS = 0x80, // method 1437 | ACC_NATIVE = 0x100, 1438 | ACC_INTERFACE = 0x200, 1439 | ACC_ABSTRACT = 0x400, 1440 | ACC_STRICT = 0x800, 1441 | ACC_SYNTHETIC = 0x1000, 1442 | ACC_ANNOTATION = 0x2000, 1443 | ACC_ENUM = 0x4000, 1444 | ACC_CONSTRUCTOR = 0x10000, 1445 | ACC_DECLARED_SYNCHRONIZED = 0x20000 1446 | } ACCESS_FLAGS ; 1447 | 1448 | string AccessFlagsRead(ACCESS_FLAGS f) { 1449 | string ret = ""; 1450 | string flags = ""; 1451 | ACCESS_FLAGS i = 1; 1452 | 1453 | while(i <= ACC_DECLARED_SYNCHRONIZED) { 1454 | if (f & i) { 1455 | flags += EnumToString(i) + " "; 1456 | } 1457 | i = i << 1; 1458 | } 1459 | 1460 | SPrintf(ret, "(0x%X) %s", f, flags); 1461 | return ret; 1462 | } 1463 | 1464 | string AccessFlagsReadUleb(uleb128 &f) { 1465 | return AccessFlagsRead(uleb128_value(f)); 1466 | } 1467 | 1468 | typedef enum { 1469 | AF_CLASS, AF_FIELD, AF_METHOD 1470 | } AF_TYPE; 1471 | 1472 | string GetFriendlyAccessFlag(int flag, AF_TYPE type) { 1473 | switch (flag) { 1474 | case ACC_PUBLIC: return "public"; 1475 | case ACC_PRIVATE: return "private"; 1476 | case ACC_PROTECTED: return "protected"; 1477 | case ACC_STATIC: return "static"; 1478 | case ACC_FINAL: return "final"; 1479 | case ACC_SYNCHRONIZED: return "synchronized"; 1480 | case ACC_VOLATILE: 1481 | if(type == AF_FIELD) return "volatile"; 1482 | else return "bridge"; // 0x40 is 'bridge' for methods 1483 | case ACC_TRANSIENT: 1484 | if(type == AF_FIELD) return "transient"; 1485 | else return "varargs"; // 0x80 is 'varargs' for methods 1486 | case ACC_NATIVE: return "native"; 1487 | case ACC_INTERFACE: return "interface"; 1488 | case ACC_ABSTRACT: return "abstract"; 1489 | case ACC_STRICT: return "strict"; 1490 | case ACC_SYNTHETIC: return "synthetic"; 1491 | case ACC_ANNOTATION: return "annotation"; 1492 | case ACC_ENUM: return "enum"; 1493 | case ACC_CONSTRUCTOR: return "constructor"; 1494 | case ACC_DECLARED_SYNCHRONIZED: return "declared-synchronized"; 1495 | } 1496 | return "ERROR"; 1497 | } 1498 | 1499 | string GetFriendlyAccessFlags(ACCESS_FLAGS f, AF_TYPE type) { 1500 | string flags = ""; 1501 | ACCESS_FLAGS i = 1; 1502 | 1503 | while(i <= ACC_DECLARED_SYNCHRONIZED) { 1504 | if (f & i) { 1505 | flags += GetFriendlyAccessFlag(i, type) + " "; 1506 | } 1507 | i = i << 1; 1508 | } 1509 | 1510 | return flags; 1511 | } 1512 | 1513 | // encoded fields 1514 | typedef struct (int previd) { 1515 | local quad baseAddr = parentof(this).baseAddr; 1516 | local int dexIndex = parentof(this).dexIndex; 1517 | local int p = previd; 1518 | 1519 | uleb128 field_idx_diff ; 1520 | uleb128 access_flags ; 1521 | } encoded_field ; 1522 | 1523 | string EncodedFieldRead(encoded_field &f) { 1524 | local int realid = f.p + uleb128_value(f.field_idx_diff); 1525 | return GetFriendlyAccessFlags(uleb128_value(f.access_flags), AF_FIELD) + GetFieldById(f.dexIndex, realid); 1526 | } 1527 | 1528 | typedef struct (int size) { 1529 | local quad baseAddr = parentof(this).baseAddr; 1530 | local int dexIndex = parentof(this).dexIndex; 1531 | local int s = size; 1532 | local int i; 1533 | local int fieldid = 0; 1534 | 1535 | for(i=0; i; 1537 | fieldid = fieldid + uleb128_value(field.field_idx_diff); 1538 | } 1539 | } encoded_field_list ; 1540 | 1541 | string EncodedFieldListRead(encoded_field_list &l) { 1542 | local string s; 1543 | SPrintf(s, "%i fields", l.s); 1544 | return s; 1545 | } 1546 | 1547 | // encoded methods 1548 | typedef struct (int previd) { 1549 | local quad baseAddr = parentof(this).baseAddr; 1550 | local int dexIndex = parentof(this).dexIndex; 1551 | local int p = previd; 1552 | 1553 | uleb128 method_idx_diff ; 1554 | uleb128 access_flags ; 1555 | uleb128 code_off ; 1556 | 1557 | if(uleb128_value(code_off) != 0) { 1558 | local int64 pos = FTell(); 1559 | FSeek(baseAddr + uleb128_value(code_off)); 1560 | struct code_item code ; 1561 | FSeek(pos); 1562 | } 1563 | } encoded_method ; 1564 | 1565 | string EncodedMethodRead(encoded_method &m) { 1566 | local int realid = m.p + uleb128_value(m.method_idx_diff); 1567 | return GetFriendlyAccessFlags(uleb128_value(m.access_flags), AF_METHOD) + GetMethodById(m.dexIndex, realid); 1568 | } 1569 | 1570 | typedef struct (int size) { 1571 | local quad baseAddr = parentof(this).baseAddr; 1572 | local int dexIndex = parentof(this).dexIndex; 1573 | local int s = size; 1574 | local int i; 1575 | local int methodid = 0; 1576 | 1577 | for(i=0; i; 1579 | methodid = methodid + uleb128_value(method.method_idx_diff); 1580 | } 1581 | } encoded_method_list ; 1582 | 1583 | string EncodedMethodListRead(encoded_method_list &l) { 1584 | local string s; 1585 | SPrintf(s, "%i methods", l.s); 1586 | return s; 1587 | } 1588 | 1589 | typedef struct { 1590 | local quad baseAddr = parentof(this).baseAddr; 1591 | local int dexIndex = parentof(this).dexIndex; 1592 | uleb128 static_fields_size ; 1593 | uleb128 instance_fields_size ; 1594 | uleb128 direct_methods_size ; 1595 | uleb128 virtual_methods_size ; 1596 | 1597 | if(uleb128_value(static_fields_size) > 0) { 1598 | encoded_field_list static_fields(uleb128_value(static_fields_size)) ; 1599 | } 1600 | 1601 | if(uleb128_value(instance_fields_size) > 0) { 1602 | encoded_field_list instance_fields(uleb128_value(instance_fields_size)) ; 1603 | } 1604 | 1605 | if(uleb128_value(direct_methods_size) > 0) { 1606 | encoded_method_list direct_methods(uleb128_value(direct_methods_size)) ; 1607 | } 1608 | 1609 | if(uleb128_value(virtual_methods_size) > 0) { 1610 | encoded_method_list virtual_methods(uleb128_value(virtual_methods_size)) ; 1611 | } 1612 | } class_data_item ; 1613 | 1614 | string ClassDataItemRead(class_data_item &i) { 1615 | local string s; 1616 | SPrintf(s, "%i static fields, %i instance fields, %i direct methods, %i virtual methods", 1617 | uleb128_value(i.static_fields_size), uleb128_value(i.instance_fields_size), 1618 | uleb128_value(i.direct_methods_size), uleb128_value(i.virtual_methods_size)); 1619 | return s; 1620 | } 1621 | 1622 | typedef struct { 1623 | local quad baseAddr = parentof(this).baseAddr; 1624 | local int dexIndex = parentof(this).dexIndex; 1625 | uint idx; 1626 | } long_type_uint_string ; 1627 | 1628 | string long_type_uint_stringRead(long_type_uint_string &s) { 1629 | return LongTypeIdRead(s.dexIndex, s.idx); 1630 | } 1631 | 1632 | typedef struct { 1633 | local quad baseAddr = parentof(this).baseAddr; 1634 | local int dexIndex = parentof(this).dexIndex; 1635 | local int64 pos; 1636 | long_type_uint_string class_idx ; 1637 | // local string name = GetLongTypeDescriptor(GetTypeById(dexIndex, class_idx)); 1638 | ACCESS_FLAGS access_flags ; 1639 | long_type_uint_string superclass_idx ; 1640 | uint interfaces_off ; 1641 | if(interfaces_off != 0) { 1642 | pos = FTell(); 1643 | FSeek(baseAddr + interfaces_off); 1644 | type_item_list interfaces ; 1645 | FSeek(pos); 1646 | } 1647 | 1648 | id_string source_file_idx ; 1649 | 1650 | uint annotations_off ; 1651 | if(annotations_off != 0) { 1652 | pos = FTell(); 1653 | FSeek(baseAddr + annotations_off); 1654 | annotations_directory_item annotations ; 1655 | FSeek(pos); 1656 | } 1657 | 1658 | uint class_data_off ; 1659 | if(class_data_off != 0) { 1660 | pos = FTell(); 1661 | FSeek(baseAddr + class_data_off); 1662 | class_data_item class_data ; 1663 | FSeek(pos); 1664 | } 1665 | 1666 | uint static_values_off ; 1667 | if(static_values_off != 0) { 1668 | pos = FTell(); 1669 | FSeek(baseAddr + static_values_off); 1670 | struct encoded_array_item static_values ; 1671 | FSeek(pos); 1672 | } 1673 | } class_def_item ; 1674 | 1675 | string ClassDefItemRead(class_def_item &i) { 1676 | local string name = GetLongTypeById(i.dexIndex, i.class_idx.idx); 1677 | local string flags = GetFriendlyAccessFlags(i.access_flags, AF_CLASS); 1678 | return flags + name; 1679 | } 1680 | 1681 | string InterfacesRead(type_item_list &l) { 1682 | string s = ""; 1683 | int i; 1684 | 1685 | for(i = 0; i < l.size; i++) { 1686 | s += GetLongTypeDescriptor(GetTypeById(l.dexIndex, l.list[i].type_idx)); 1687 | if(i+1 < l.size) { 1688 | s += ", "; 1689 | } 1690 | } 1691 | return s; 1692 | } 1693 | 1694 | typedef struct (int size) { 1695 | local int i; 1696 | local quad parentAddr = startof(parentof(this)); 1697 | for (i=0; i; 1705 | } class_def_item_list ; 1706 | 1707 | string ClassDefItemListRead(class_def_item_list &l) { 1708 | string s; 1709 | s = SPrintf(s, "%d classes", l.s); 1710 | return s; 1711 | } 1712 | 1713 | typedef struct { 1714 | local quad baseAddr = parentof(this).baseAddr; 1715 | local int dexIndex = parentof(this).dexIndex; 1716 | uint start_addr ; 1717 | ushort insn_count ; 1718 | ushort handler_off ; 1719 | } try_item ; 1720 | 1721 | typedef struct { 1722 | local quad baseAddr = parentof(this).baseAddr; 1723 | local int dexIndex = parentof(this).dexIndex; 1724 | sleb128 size ; 1725 | 1726 | local int s = sleb128_value(size); 1727 | local int numhandlers = 0; 1728 | 1729 | if(s != 0) { 1730 | numhandlers = Abs(s); 1731 | struct encoded_type_addr_pair handlers[numhandlers] ; 1732 | } 1733 | 1734 | if(s <= 0) { 1735 | uleb128 catch_all_addr ; 1736 | numhandlers++; 1737 | } 1738 | } encoded_catch_handler ; 1739 | 1740 | string EncodedCatchHandlerRead(encoded_catch_handler &h) { 1741 | local string s; 1742 | SPrintf(s, "%i handlers", h.numhandlers); 1743 | return s; 1744 | } 1745 | 1746 | typedef struct { 1747 | local quad baseAddr = parentof(this).baseAddr; 1748 | local int dexIndex = parentof(this).dexIndex; 1749 | uleb128 size ; 1750 | encoded_catch_handler list[uleb128_value(size)] ; 1751 | } encoded_catch_handler_list ; 1752 | 1753 | string EncodedCatchHandlerListRead(encoded_catch_handler_list &l) { 1754 | local string s; 1755 | SPrintf(s, "%i handler lists", uleb128_value(l.size)); 1756 | return s; 1757 | } 1758 | 1759 | typedef struct { 1760 | local quad baseAddr = parentof(this).baseAddr; 1761 | local int dexIndex = parentof(this).dexIndex; 1762 | ushort registers_size ; 1763 | ushort ins_size ; 1764 | ushort outs_size ; 1765 | ushort tries_size ; 1766 | uint debug_info_off ; 1767 | 1768 | if(debug_info_off != 0) { 1769 | local int64 pos = FTell(); 1770 | FSeek(baseAddr + debug_info_off); 1771 | 1772 | struct debug_info_item debug_info ; 1773 | FSeek(pos); 1774 | } 1775 | 1776 | uint insns_size ; 1777 | if(insns_size != 0) { 1778 | ushort insns[insns_size] ; 1779 | } 1780 | 1781 | if(tries_size != 0) { 1782 | if (insns_size & 1 == 1) { 1783 | ushort padding ; 1784 | } 1785 | 1786 | try_item tries[tries_size] ; 1787 | encoded_catch_handler_list handlers ; 1788 | } 1789 | } code_item ; 1790 | 1791 | string CodeItemRead(code_item &i) { 1792 | local string s; 1793 | SPrintf(s, "%i registers, %i in arguments, %i out arguments, %i tries, %i instructions", 1794 | i.registers_size, i.ins_size, i.outs_size, i.tries_size, i.insns_size); 1795 | return s; 1796 | } 1797 | 1798 | typedef struct { 1799 | local quad baseAddr = parentof(this).baseAddr; 1800 | local int dexIndex = parentof(this).dexIndex; 1801 | uleb128 type_idx ; 1802 | uleb128 addr ; 1803 | } encoded_type_addr_pair ; 1804 | 1805 | string EncodedTypeAddrPairRead(encoded_type_addr_pair &p) { 1806 | string s; 1807 | SPrintf(s, "%s at 0x%X", GetLongTypeById(p.dexIndex, uleb128_value(p.type_idx)), uleb128_value(p.addr)); 1808 | return s; 1809 | } 1810 | 1811 | typedef struct { 1812 | local quad baseAddr = parentof(this).baseAddr; 1813 | local int dexIndex = parentof(this).dexIndex; 1814 | encoded_array value ; 1815 | } encoded_array_item ; 1816 | 1817 | string EncodedArrayItemRead(encoded_array_item &i) { 1818 | local string s; 1819 | SPrintf(s, "%i items: %s", uleb128_value(i.value.size), EncodedArrayRead(i.value)); 1820 | return s; 1821 | } 1822 | 1823 | enum TYPE_CODES { 1824 | TYPE_HEADER_ITEM = 0x0000, 1825 | TYPE_STRING_ID_ITEM = 0x0001, 1826 | TYPE_TYPE_ID_ITEM = 0x0002, 1827 | TYPE_PROTO_ID_ITEM = 0x0003, 1828 | TYPE_FIELD_ID_ITEM = 0x0004, 1829 | TYPE_METHOD_ID_ITEM = 0x0005, 1830 | TYPE_CLASS_DEF_ITEM = 0x0006, 1831 | 1832 | TYPE_MAP_LIST = 0x1000, 1833 | TYPE_TYPE_LIST = 0x1001, 1834 | TYPE_ANNOTATION_SET_REF_LIST = 0x1002, 1835 | TYPE_ANNOTATION_SET_ITEM = 0x1003, 1836 | 1837 | TYPE_CLASS_DATA_ITEM = 0x2000, 1838 | TYPE_CODE_ITEM = 0x2001, 1839 | TYPE_STRING_DATA_ITEM = 0x2002, 1840 | TYPE_DEBUG_INFO_ITEM = 0x2003, 1841 | TYPE_ANNOTATION_ITEM = 0x2004, 1842 | TYPE_ENCODED_ARRAY_ITEM = 0x2005, 1843 | TYPE_ANNOTATIONS_DIRECTORY_ITEM = 0x2006 1844 | }; 1845 | 1846 | ////////////////////////////////////////////////// 1847 | // debug info 1848 | ////////////////////////////////////////////////// 1849 | 1850 | typedef enum { 1851 | DBG_END_SEQUENCE = 0x00, 1852 | DBG_ADVANCE_PC = 0x01, 1853 | DBG_ADVANCE_LINE = 0x02, 1854 | DBG_START_LOCAL = 0x03, 1855 | DBG_START_LOCAL_EXTENDED = 0x04, 1856 | DBG_END_LOCAL = 0x05, 1857 | DBG_RESTART_LOCAL = 0x06, 1858 | DBG_SET_PROLOGUE_END = 0x07, 1859 | DBG_SET_EPILOGUE_BEGIN = 0x08, 1860 | DBG_SET_FILE = 0x09 1861 | } DBG_OPCODE; 1862 | 1863 | typedef struct { 1864 | local quad baseAddr = parentof(this).baseAddr; 1865 | local int dexIndex = parentof(this).dexIndex; 1866 | DBG_OPCODE opcode ; 1867 | local string args = ""; 1868 | 1869 | switch (opcode) { 1870 | case DBG_END_SEQUENCE: 1871 | break; 1872 | case DBG_ADVANCE_PC: 1873 | uleb128 addr_diff ; 1874 | SPrintf(args, "%i", uleb128_value(addr_diff)); 1875 | break; 1876 | case DBG_ADVANCE_LINE: 1877 | sleb128 line_diff ; 1878 | SPrintf(args, "%i", sleb128_value(line_diff)); 1879 | break; 1880 | case DBG_START_LOCAL: 1881 | uleb128 register_num ; 1882 | uleb128p1 name_idx ; 1883 | uleb128p1 type_idx ; 1884 | SPrintf(args, "%i, %s, %s", uleb128_value(register_num), StringIdReadUlebp1(name_idx), 1885 | LongTypeIdReadUlebp1(type_idx)); 1886 | break; 1887 | case DBG_START_LOCAL_EXTENDED: 1888 | uleb128 register_num ; 1889 | uleb128p1 name_idx ; 1890 | uleb128p1 type_idx ; 1891 | uleb128p1 sig_idx ; 1892 | SPrintf(args, "%i, %s, %s, %s", uleb128_value(register_num), StringIdReadUlebp1(name_idx), 1893 | LongTypeIdReadUlebp1(type_idx), StringIdReadUlebp1(sig_idx)); 1894 | break; 1895 | case DBG_END_LOCAL: 1896 | uleb128 register_num ; 1897 | SPrintf(args, "%i", uleb128_value(register_num)); 1898 | break; 1899 | case DBG_RESTART_LOCAL: 1900 | uleb128 register_num ; 1901 | SPrintf(args, "%i", uleb128_value(register_num)); 1902 | break; 1903 | case DBG_SET_PROLOGUE_END: 1904 | case DBG_SET_EPILOGUE_BEGIN: 1905 | break; 1906 | case DBG_SET_FILE: 1907 | uleb128p1 name_idx ; 1908 | SPrintf(args, "%s", StringIdReadUlebp1(name_idx)); 1909 | } 1910 | } debug_opcode ; 1911 | 1912 | #define DBG_FIRST_SPECIAL 0x0a 1913 | #define DBG_LINE_BASE -4 1914 | #define DBG_LINE_RANGE 15 1915 | 1916 | string DebugOpcodeRead(debug_opcode &opcode) { 1917 | local string s; 1918 | if(opcode.opcode >= DBG_FIRST_SPECIAL) { 1919 | local ubyte adjusted = opcode.opcode - DBG_FIRST_SPECIAL; 1920 | SPrintf(s, "Special opcode: line + %i, address + %i", DBG_LINE_BASE + (adjusted % DBG_LINE_RANGE), (adjusted / DBG_LINE_RANGE)); 1921 | } else { 1922 | s = EnumToString(opcode.opcode); 1923 | } 1924 | 1925 | if(opcode.args != "") { 1926 | s += " (" + opcode.args + ")"; 1927 | } 1928 | 1929 | return s; 1930 | } 1931 | 1932 | typedef struct { 1933 | local quad baseAddr = parentof(this).baseAddr; 1934 | local int dexIndex = parentof(this).dexIndex; 1935 | uleb128 line_start ; 1936 | uleb128 parameters_size ; 1937 | if(uleb128_value(parameters_size) > 0) { 1938 | uleb128p1 parameter_names[uleb128_value(parameters_size)] ; // actually uleb128p1 1939 | } 1940 | 1941 | do { 1942 | debug_opcode opcode ; 1943 | } while (opcode.opcode != DBG_END_SEQUENCE); 1944 | } debug_info_item; 1945 | 1946 | ////////////////////////////////////////////////// 1947 | // map list 1948 | ////////////////////////////////////////////////// 1949 | typedef struct { 1950 | local quad baseAddr = parentof(this).baseAddr; 1951 | local int dexIndex = parentof(this).dexIndex; 1952 | TYPE_CODES type; 1953 | ushort unused; 1954 | uint size; 1955 | uint offset; 1956 | } map_item ; 1957 | 1958 | string MapItemRead(map_item &m) { 1959 | string s; 1960 | SPrintf(s, "%s", EnumToString(m.type)); 1961 | return s; 1962 | } 1963 | 1964 | typedef struct { 1965 | local int i; 1966 | local quad parentAddr = startof(parentof(this)); 1967 | for (i=0; i; 1976 | 1977 | string MapListTypeRead(map_list_type &t) { 1978 | local string s; 1979 | SPrintf(s, "%i items", t.size); 1980 | return s; 1981 | } 1982 | 1983 | ////////////////////////////////////////////////// 1984 | // utility functions for reading various strings 1985 | // note: strings are stored in a format called MUTF-8, and its 1986 | // possible they won't always display correctly in the 010 UI 1987 | ////////////////////////////////////////////////// 1988 | 1989 | // read a value from the string table 1990 | string StringIdRead(int dexIndex, int id) { 1991 | if(id == NO_INDEX) { 1992 | return "NO_INDEX"; 1993 | } 1994 | local string s; 1995 | SPrintf(s, "(0x%.X) \"%s\"", id, GetStringById(dexIndex, id)); 1996 | return s; 1997 | } 1998 | 1999 | string StringIdReadUleb(uleb128 &id) { 2000 | return StringIdRead(parentof(id).dexIndex, uleb128_value(id)); 2001 | } 2002 | 2003 | string StringIdReadUlebp1(uleb128p1 &id) { 2004 | return StringIdRead(parentof(id).dexIndex, uleb128p1_value(id)); 2005 | } 2006 | 2007 | // read a value from the type table, return short form 2008 | string TypeIdRead(int dexIndex, int id) { 2009 | local string s; 2010 | return GetIdAndNameString(id, GetTypeById(dexIndex, id)); 2011 | } 2012 | 2013 | // read a value from the type table, return the long form 2014 | string LongTypeIdRead(int dexIndex, int id) { 2015 | local string s; 2016 | return GetIdAndNameString(id, GetLongTypeById(dexIndex, id)); 2017 | } 2018 | 2019 | string LongTypeIdReadUleb(uleb128 &id) { 2020 | return LongTypeIdRead(parentof(id).dexIndex, uleb128_value(id)); 2021 | } 2022 | 2023 | string LongTypeIdReadUlebp1(uleb128p1 &id) { 2024 | return LongTypeIdRead(parentof(id).dexIndex, uleb128p1_value(id)); 2025 | } 2026 | 2027 | string FieldIdRead(int dexIndex, int id) { 2028 | local string s; 2029 | return GetIdAndNameString(id, GetFieldById(dexIndex, id)); 2030 | } 2031 | 2032 | string MethodIdRead(int dexIndex, int id) { 2033 | local string s; 2034 | return GetIdAndNameString(id, GetMethodById(dexIndex, id)); 2035 | } 2036 | 2037 | string GetIdAndNameString(int id, string name) { 2038 | local string s; 2039 | SPrintf(s, "(0x%X) %s", id, name); 2040 | return s; 2041 | } 2042 | 2043 | // read a string from the string table 2044 | string GetStringById(int dexIndex, int id) { 2045 | if(id == NO_INDEX) { 2046 | return "NO_INDEX"; 2047 | } 2048 | 2049 | if(exists(file.dex_files[dexIndex].dex_string_ids.string_id[id])) { 2050 | return file.dex_files[dexIndex].dex_string_ids.string_id[id].string_data.data; 2051 | } else { 2052 | return "***### NO STRING"; 2053 | } 2054 | } 2055 | 2056 | string GetTypeById(int dexIndex, int id) { 2057 | if(id == NO_INDEX) { 2058 | return "NO_INDEX"; 2059 | } 2060 | if(exists(file.dex_files[dexIndex].dex_type_ids.type_id[id])) { 2061 | return GetStringById(dexIndex, file.dex_files[dexIndex].dex_type_ids.type_id[id].descriptor_idx.idx); 2062 | } else { 2063 | return "*** NO TYPE"; 2064 | } 2065 | } 2066 | 2067 | string GetLongTypeById(int dexIndex, int id) { 2068 | return GetLongTypeDescriptor(GetTypeById(dexIndex, id)); 2069 | } 2070 | 2071 | string GetMethodById(int dexIndex, int id) { 2072 | if(id == NO_INDEX) { 2073 | return "NO_INDEX"; 2074 | } 2075 | 2076 | if(exists(file.dex_files[dexIndex].dex_method_ids.method_id[id])) { 2077 | return MethodIdItemRead(file.dex_files[dexIndex].dex_method_ids.method_id[id]); 2078 | } else { 2079 | return "*** NO METHOD"; 2080 | } 2081 | } 2082 | 2083 | string GetFieldById(int dexIndex, int id) { 2084 | if(id == NO_INDEX) { 2085 | return "NO_INDEX"; 2086 | } 2087 | 2088 | if(exists(file.dex_files[dexIndex].dex_field_ids.field_id[id])) { 2089 | return FieldIdItemRead(file.dex_files[dexIndex].dex_field_ids.field_id[id]); 2090 | } else { 2091 | return "*** NO FIELD"; 2092 | } 2093 | } 2094 | 2095 | ////////////////////////////////////////////////// 2096 | // dexopt stuff 2097 | ////////////////////////////////////////////////// 2098 | 2099 | typedef enum { 2100 | DEX_CHUNK_CLASS_LOOKUP = 0x434c4b50, 2101 | DEX_CHUNK_REGISTER_MAPS = 0x524d4150, 2102 | DEX_CHUNK_END = 0x41454e44 2103 | } DEX_CHUNK_TYPE; 2104 | 2105 | typedef struct { 2106 | local quad baseAddr = parentof(this).baseAddr; 2107 | local int dexIndex = parentof(this).dexIndex; 2108 | DEX_CHUNK_TYPE type ; 2109 | uint size ; 2110 | local int realsize = (size + 7) & ~7; 2111 | 2112 | 2113 | if(type == DEX_CHUNK_CLASS_LOOKUP) { 2114 | struct dex_class_lookup class_lookup_table ; 2115 | } else if (type == DEX_CHUNK_REGISTER_MAPS) { 2116 | ubyte chunkbytes[realsize]; 2117 | } else if (type == DEX_CHUNK_END) { 2118 | //ubyte chunkbytes[realsize]; 2119 | } else { 2120 | SPrintf(temp_warning, "Unknown chunk type 0x%X", type); 2121 | PrintWarning(temp_warning); 2122 | return; 2123 | } 2124 | } dexopt_opt_chunk ; 2125 | 2126 | typedef struct { 2127 | local quad baseAddr = parentof(this).baseAddr; 2128 | local int dexIndex = parentof(this).dexIndex; 2129 | local int count = 0; 2130 | do { 2131 | dexopt_opt_chunk chunk; 2132 | count++; 2133 | } while(chunk.type != DEX_CHUNK_END); 2134 | } dexopt_opt_table ; 2135 | 2136 | string DexoptOptTableRead(dexopt_opt_table &t) { 2137 | local string s; 2138 | SPrintf(s, "%i items", t.count); 2139 | return s; 2140 | } 2141 | 2142 | string DexOptChunkRead(dexopt_opt_chunk &c) { 2143 | local string s; 2144 | SPrintf(s, "%s chunk: %i bytes", EnumToString(c.type), c.size); 2145 | return s; 2146 | } 2147 | 2148 | typedef struct { 2149 | local quad baseAddr = parentof(this).baseAddr; 2150 | local int dexIndex = parentof(this).dexIndex; 2151 | int offset; 2152 | } class_descriptor ; 2153 | 2154 | string readClassDescriptor(class_descriptor &item) { 2155 | if(item.offset != 0) 2156 | return ReadString(sizeof(dexopt_header) + item.offset); 2157 | return ""; 2158 | } 2159 | 2160 | typedef struct { 2161 | local quad baseAddr = parentof(this).baseAddr; 2162 | local int dexIndex = parentof(this).dexIndex; 2163 | uint class_descriptor_hash ; 2164 | class_descriptor class_descriptor_item ; 2165 | int class_definition_offset ; 2166 | } dex_class_lookup_entry ; 2167 | 2168 | string DexClassLookupEntryRead(dex_class_lookup_entry &e) { 2169 | local string s; 2170 | SPrintf(s, "0x%X: (descriptor 0x%X, definition 0x%X)", e.class_descriptor_hash, e.class_descriptor_item.offset, e.class_definition_offset); 2171 | return s; 2172 | } 2173 | 2174 | typedef struct { 2175 | local quad baseAddr = parentof(this).baseAddr; 2176 | local int dexIndex = parentof(this).dexIndex; 2177 | int size ; 2178 | int num_entries ; 2179 | 2180 | if(num_entries > 0) { 2181 | dex_class_lookup_entry table[num_entries] ; 2182 | } 2183 | } dex_class_lookup; 2184 | 2185 | ////////////////////////////////////////////////// 2186 | // main stuff 2187 | ////////////////////////////////////////////////// 2188 | 2189 | // first check file type - dex files start with 'dex', odex files start with 'dey' 2190 | 2191 | 2192 | ////////////////////////////////////////////////// 2193 | // dex file 2194 | ////////////////////////////////////////////////// 2195 | typedef struct{ 2196 | if (global_version[0] == '0' && global_version[1] == '3') { 2197 | uint32 code_offset_; 2198 | uint32 gc_map_offset_; 2199 | } else if (global_version[0] == '0' && global_version[1] == '6') { 2200 | uint32 code_offset_; 2201 | } else { 2202 | uint32 code_offset_; 2203 | uint32 frame_size_in_bytes_; 2204 | uint32 core_spill_mask_; 2205 | uint32 fp_spill_mask_; 2206 | uint32 mapping_table_offset_; 2207 | uint32 vmap_table_offset_; 2208 | uint32 gc_map_offset_; 2209 | } 2210 | 2211 | 2212 | /* 2213 | uint32 code_offset_; 2214 | uint32 frame_size_in_bytes_; 2215 | uint32 core_spill_mask_; 2216 | uint32 fp_spill_mask_; 2217 | uint32 mapping_table_offset_; 2218 | uint32 vmap_table_offset_; 2219 | uint32 gc_map_offset_; 2220 | */ 2221 | 2222 | /* 2223 | local uint32 off = code_offset_ & ~0x1; 2224 | if (off > 0) { 2225 | Printf("code_offset [%x][%x] = %x\n", code_offset_, off, off + 0x1000); 2226 | } 2227 | */ 2228 | } OatMethodOffsets; 2229 | 2230 | typedef struct (int index) { 2231 | local int dexIndex = parentof(this).dexIndex; 2232 | local int t_index = index; 2233 | if (global_version[0] == '0' && (global_version[1] == '3' || global_version[1] == '6')) { 2234 | uint16 status; 2235 | uint16 type; 2236 | if (type == 0) { 2237 | local int methodCount = getClassMethodCount(dexIndex, index); 2238 | if (methodCount > 0) { 2239 | OatMethodOffsets methodOffset[methodCount] ; 2240 | } 2241 | } else if (type == 1) { 2242 | uint32 bitsize; 2243 | ubyte arr[bitsize]; 2244 | local int i; 2245 | local int j; 2246 | local int count = 0; 2247 | for (i=0; i 0) { 2261 | OatMethodOffsets methodOffset[count] ; 2262 | } 2263 | 2264 | } 2265 | } else { 2266 | uint32 status; 2267 | local int methodCount = getClassMethodCount(dexIndex, index); 2268 | 2269 | if (methodCount > 0) { 2270 | OatMethodOffsets methodOffset[methodCount] ; 2271 | } 2272 | } 2273 | 2274 | 2275 | //Printf("%x %x %x %x \n", global_version[0], global_version[1], global_version[2], global_version[3]); 2276 | //if (methodCount > 0) { 2277 | // OatMethodOffsets methodOffset[methodCount] ; 2278 | //} 2279 | } OatClass ; 2280 | 2281 | string ReadOatClass(OatClass &c) { 2282 | local string name = getClassName(c.dexIndex, c.t_index); 2283 | return name; 2284 | } 2285 | 2286 | typedef struct (int index, int size) { 2287 | local int dexIndex = index; 2288 | local int total = size; 2289 | local int idx; 2290 | for (idx=0; idx; 2294 | 2295 | typedef struct { 2296 | 2297 | 2298 | // main dex header and structs 2299 | local quad addr = FTell(); 2300 | // local int dexIndex = dexCount; 2301 | // dexCount += 1; 2302 | SetBackColor(cLtGreen); 2303 | header_item header ; 2304 | 2305 | FSeek(header.string_ids_off + addr); 2306 | SetBackColor(cLtYellow); 2307 | string_id_list dex_string_ids(header.string_ids_size) ; 2308 | 2309 | FSeek(header.type_ids_off + addr); 2310 | SetBackColor(cLtPurple); 2311 | type_id_list dex_type_ids(header.type_ids_size) ; 2312 | 2313 | FSeek(header.proto_ids_off + addr); 2314 | SetBackColor(cLtBlue); 2315 | proto_id_list dex_proto_ids(header.proto_ids_size) ; 2316 | 2317 | FSeek(header.field_ids_off + addr); 2318 | SetBackColor(cYellow); 2319 | field_id_list dex_field_ids(header.field_ids_size) ; 2320 | 2321 | FSeek(header.method_ids_off + addr); 2322 | SetBackColor(cDkYellow); 2323 | method_id_list dex_method_ids(header.method_ids_size) ; 2324 | 2325 | FSeek(header.class_defs_off + addr); 2326 | SetBackColor(cLtGray); 2327 | class_def_item_list dex_class_defs(header.class_defs_size) ; 2328 | 2329 | // map list, we don't really do anything with it though 2330 | SetBackColor(cLtAqua); 2331 | if(header.map_off != 0) { 2332 | FSeek(addr + header.map_off); 2333 | map_list_type dex_map_list ; 2334 | } 2335 | 2336 | // It's not really useful to see just the last warning, so inform us how many warnings we should see in output 2337 | if(warnings > 1) { 2338 | Warning("%d warnings have occured and logged to the output box!", warnings); 2339 | } 2340 | 2341 | // This will make the template show "Template executed successfully." 2342 | if(warnings != 0) { 2343 | SPrintf(temp_warning, "%d warnings found, template may not have run successfully!", warnings); 2344 | return temp_warning; 2345 | } 2346 | FSeek(oatClassOffs); 2347 | OatClasses oat_classes(header.dexIndex, header.class_defs_size); 2348 | oatClassOffs = FTell(); 2349 | FSeek(addr + header.file_size); 2350 | } DexFile ; 2351 | 2352 | int readDexFileSize(DexFile &item) { 2353 | return ReadUInt(startof(item)+32); 2354 | } 2355 | 2356 | 2357 | 2358 | string ReadOatClasses(OatClasses &oc) { 2359 | local string s; 2360 | SPrintf(s, "%i classes", oc.total); 2361 | return s; 2362 | } 2363 | 2364 | string getClassName(int dexIndex, int classIdx) { 2365 | if (exists(file.dex_files[dexIndex].dex_class_defs.class_def[classIdx])) { 2366 | return GetLongTypeById(dexIndex, file.dex_files[dexIndex].dex_class_defs.class_def[classIdx].class_idx.idx); 2367 | } 2368 | return "** NO NAME **"; 2369 | } 2370 | 2371 | int getClassMethodCount(int index, int classIdx) { 2372 | if (exists(file.dex_files[dexIndex].dex_class_defs.class_def[classIdx])) { 2373 | if (exists(file.dex_files[dexIndex].dex_class_defs.class_def[classIdx].class_data)) { 2374 | local int dirNum = uleb128_value(file.dex_files[dexIndex].dex_class_defs.class_def[classIdx].class_data.direct_methods_size); 2375 | local int virNum = uleb128_value(file.dex_files[dexIndex].dex_class_defs.class_def[classIdx].class_data.virtual_methods_size); 2376 | return dirNum + virNum; 2377 | } 2378 | } 2379 | return 0; 2380 | } 2381 | 2382 | typedef struct { 2383 | uint32 dex_file_location_size; 2384 | char dex_file_location_data[dex_file_location_size]; 2385 | uint32 dex_file_checksum; 2386 | uint32 dex_file_offset; 2387 | dexOffs[dexCount] = dex_file_offset + oatdata_off; 2388 | 2389 | // local quad off = FTell(); 2390 | // FSeek(oatdata_off + dex_file_offset); 2391 | // // Printf("start dexfile\n"); 2392 | // DexFile dex_file; 2393 | // // Printf("end dexfile\n"); 2394 | // FSeek(off); 2395 | 2396 | // //local quad method_count = (oatdata_off + dex_file_offset - off) / sizeof(uint32); 2397 | // uint32 class_offs[dex_file.class_defs_size]; 2398 | 2399 | // FSeek(oatdata_off + dex_file_offset + dex_file.file_size); 2400 | // OatClasses oat_classes(dex_file.class_defs_size) ; 2401 | // FSeek(off + dex_file.class_defs_size*4); 2402 | local uint32 classDefsSize = getClassDefsSize(dex_file_offset); 2403 | defsSize[dexCount] = classDefsSize; 2404 | dexCount += 1; 2405 | uint32 class_offs[classDefsSize]; 2406 | 2407 | } OatDexFile ; 2408 | 2409 | uint32 getClassDefsSize(uint32 addr) { 2410 | // Printf("SectionVAddrOffset=%x\n", oatdata_off + addr + 0x60); 2411 | return ReadUInt(oatdata_off + addr + 0x60); 2412 | } 2413 | 2414 | typedef struct { 2415 | char magic[4]; 2416 | char version[4]; 2417 | uint32 checksum; 2418 | InstructionSet instruction_set; 2419 | if (version[0] == '0' && (version[1] == '3' || version[1] == '6')) { 2420 | uint32 instruction_set_features_; 2421 | } 2422 | global_version[0] = version[0]; 2423 | global_version[1] = version[1]; 2424 | global_version[2] = version[2]; 2425 | global_version[3] = version[3]; 2426 | uint32 dex_file_count; 2427 | uint32 executable_offset_; 2428 | uint32 interpreter_to_interpreter_bridge_offset_; 2429 | uint32 interpreter_to_compiled_code_bridge_offset_; 2430 | uint32 jni_dlsym_lookup_offset_; 2431 | 2432 | if (version[0] == '0' && version[1] == '6') { 2433 | uint32 quick_generic_jni_trampoline_offset_; 2434 | uint32 quick_imt_conflict_trampoline_offset_; 2435 | uint32 quick_resolution_trampoline_offset_; 2436 | uint32 quick_to_interpreter_bridge_offset_; 2437 | int32 image_patch_delta_; 2438 | uint32 image_file_location_oat_checksum_; 2439 | uint32 image_file_location_oat_data_begin_; 2440 | uint32 key_value_store_size_; 2441 | char key_value_store_[key_value_store_size_]; 2442 | //uint32 key_value_store_; 2443 | //uchar key_value_store_[0]; 2444 | } else { 2445 | // oat 031 begin 2446 | if (version[0] == '0' && version[1] == '3') { 2447 | uint32 portable_imt_conflict_trampoline_offset_; 2448 | } 2449 | // oat 031 end 2450 | 2451 | uint32 portable_resolution_trampoline_offset_; 2452 | uint32 portable_to_interpreter_bridge_offset_; 2453 | 2454 | // oat 031 begin 2455 | if (version[0] == '0' && version[1] == '3') { 2456 | uint32 quick_generic_jni_trampoline_offset_; 2457 | uint32 quick_imt_conflict_trampoline_offset_; 2458 | } 2459 | // oat 031 end 2460 | 2461 | uint32 quick_resolution_trampoline_offset_; 2462 | uint32 quick_to_interpreter_bridge_offset_; 2463 | 2464 | // oat 039 begin 2465 | if (version[0] == '0' && version[1] == '3' && version[2] == '9') { 2466 | uint32 image_patch_delta_; 2467 | } 2468 | // uint32 unknow_3; 2469 | // uint32 unknow_4; 2470 | // uint32 unknow_5; 2471 | // oat 039 end 2472 | 2473 | uint32 image_file_location_oat_checksum_; 2474 | uint32 image_file_location_oat_data_begin_; 2475 | uint32 image_file_location_size; 2476 | char image_file_location_data[image_file_location_size]; 2477 | } 2478 | 2479 | } OatHeader; 2480 | 2481 | struct { 2482 | local int elf = 1; 2483 | local char tmp[3]; 2484 | ReadBytes(tmp, 0, 3); 2485 | FSeek(0); 2486 | 2487 | if(!Strcmp(tmp, "oat")) { 2488 | elf = 0; 2489 | } 2490 | 2491 | if (elf) { 2492 | Elf32_Ehdr elf_header; 2493 | if (elf_header.e_phnum > 0) { 2494 | FSeek(elf_header.e_phoff); 2495 | Elf32_Phdr elf_program_header[elf_header.e_phnum]; 2496 | } 2497 | 2498 | local uint soff = elf_header.e_shoff + elf_header.e_shentsize * elf_header.e_shstrndx; 2499 | section_name_off = ReadUInt(soff + 3 * sizeof( Elf32_Word ) + sizeof( Elf32_Addr )); 2500 | // Printf("section_name_off=%x", section_name_off); 2501 | 2502 | if (elf_header.e_shnum > 0) { 2503 | FSeek(elf_header.e_shoff); 2504 | Elf32_Shdr elf_section_header[elf_header.e_shnum] ; 2505 | 2506 | local uint strindex = FindNamedSection(".dynstr"); 2507 | dynsym_name_off = elf_section_header[strindex].sh_offset; 2508 | 2509 | local uint symindex = FindNamedSection(".dynsym"); 2510 | local uint symcount = elf_section_header[symindex].sh_size / sizeof(Elf32_Sym_Fixed); 2511 | FSeek(elf_section_header[symindex].sh_offset); 2512 | 2513 | // dynsym 2514 | Elf32_Sym symtab[symcount] ; 2515 | 2516 | // dynstr 2517 | if (elf_section_header[strindex].sh_size > 0) { 2518 | local quad off = FTell(); 2519 | FSeek( dynsym_name_off ); 2520 | char dynstr[elf_section_header[strindex].sh_size]; 2521 | FSeek( off ); 2522 | } 2523 | 2524 | // hash 2525 | local uint hashindex = FindNamedSection(".hash"); 2526 | FSeek( elf_section_header[hashindex].sh_offset ); 2527 | Elf32_Word hash[elf_section_header[hashindex].sh_size]; 2528 | 2529 | // rodata 2530 | local uint rodataindex = FindNamedSection(".rodata"); 2531 | FSeek( elf_section_header[rodataindex].sh_offset ); 2532 | uchar rodata[elf_section_header[rodataindex].sh_size]; 2533 | 2534 | // text 2535 | local uint textindex = FindNamedSection(".text"); 2536 | FSeek( elf_section_header[textindex].sh_offset ); 2537 | uchar text[elf_section_header[textindex].sh_size]; 2538 | 2539 | // dynamic 2540 | local uint dynamicindex = FindNamedSection(".dynamic"); 2541 | FSeek( elf_section_header[dynamicindex].sh_offset ); 2542 | uchar dynamic[elf_section_header[dynamicindex].sh_size]; 2543 | 2544 | // shstrtab 2545 | local uint shstrtabindex = FindNamedSection(".shstrtab"); 2546 | FSeek( elf_section_header[shstrtabindex].sh_offset ); 2547 | char shstrtab[elf_section_header[shstrtabindex].sh_size]; 2548 | } 2549 | } 2550 | 2551 | 2552 | if (oatdata_off > 0) { 2553 | FSeek(oatdata_off); 2554 | } 2555 | OatHeader oat_header; 2556 | OatDexFile oat_dex_files[oat_header.dex_file_count]; 2557 | FSeek( oat_dex_files[0].dex_file_offset + oatdata_off ); 2558 | DexFile dex_files[dexCount]; 2559 | oatClassOffs = FTell(); 2560 | //local int i; 2561 | //for(i=0;i