├── common ├── .gitignore ├── build.gradle └── src │ └── main │ └── java │ └── com │ └── common │ ├── Project.java │ ├── FileUtil.java │ ├── LogUtil.java │ ├── PrintUtil.java │ └── stream │ └── RandomAccessStreamer.java ├── parser_arsc ├── .gitignore ├── res │ └── resources.arsc ├── build.gradle └── src │ └── main │ └── java │ └── com │ └── arsc │ ├── stream │ ├── ArscStreamer.java │ └── LittleEndianStreamer.java │ ├── data │ ├── BaseTypeChunk.java │ ├── ResTableRef.java │ ├── ResStringPoolRef.java │ ├── ResFileHeaderChunk.java │ ├── ResTableMap.java │ ├── ChunkHeader.java │ ├── ResTableValueEntry.java │ ├── ResTableEntry.java │ ├── ResTableTypeSpecChunk.java │ ├── ResTableMapEntry.java │ ├── ArscFile.java │ ├── ResStringPoolChunk.java │ ├── ResTableConfig.java │ ├── ResTableTypeInfoChunk.java │ ├── ResTablePackageChunk.java │ └── ResValue.java │ └── ArscParser.java ├── parser_dex ├── .gitignore ├── res │ ├── IGreet.java │ ├── ISay.java │ ├── classes.dex │ ├── Hello.java │ └── makedex.sh ├── build.gradle └── src │ └── main │ └── java │ └── com │ └── dex │ ├── stream │ ├── DexStreamer.java │ └── LittleEndianStreamer.java │ ├── data │ ├── MethodDataItem.java │ ├── FieldDataItem.java │ ├── StringDataItem.java │ ├── MethodPool.java │ ├── FieldPool.java │ ├── ClassPool.java │ ├── EncodedField.java │ ├── ProtoPool.java │ ├── TypePool.java │ ├── StringPool.java │ ├── ClassInterfaceItem.java │ ├── DexFile.java │ ├── EncodedMethod.java │ ├── CodeItem.java │ ├── ProtoDataItem.java │ ├── ClassDefItem.java │ ├── ClassDataItem.java │ ├── DexHeader.java │ └── AccessFlags.java │ └── DexParser.java ├── parser_elfso ├── .gitignore ├── res │ ├── libjiagu.so │ └── libhello-jni.so ├── src │ └── main │ │ └── java │ │ └── com │ │ ├── elfso │ │ ├── data │ │ │ ├── Section.java │ │ │ ├── Segment.java │ │ │ ├── StringTable.java │ │ │ ├── Eident.java │ │ │ ├── ProgramHeader.java │ │ │ ├── SectionHeader.java │ │ │ ├── ElfFile.java │ │ │ └── ElfHeader.java │ │ ├── stream │ │ │ ├── ElfStreamer.java │ │ │ ├── BigEndianStreamer.java │ │ │ └── LittleEndianStreamer.java │ │ └── ElfParser.java │ │ └── elf │ │ └── excep │ │ └── FormatException.java └── build.gradle ├── parser_manifest ├── .gitignore ├── res │ ├── compiled_manifest.xml │ ├── origin_manifest.xml │ └── apktool_manifest.xml ├── build.gradle └── src │ └── main │ └── java │ └── com │ └── manifest │ ├── data │ ├── TagChunk.java │ ├── MfHeader.java │ ├── EndTagChunk.java │ ├── ResourceIdChunk.java │ ├── ChunkInfo.java │ ├── EndNamespaceChunk.java │ ├── AttributeEntry.java │ ├── StartNamespaceChunk.java │ ├── StartTagChunk.java │ ├── StringChunk.java │ ├── AttributeType.java │ └── MfFile.java │ ├── stream │ ├── MfStreamer.java │ └── LittleEndianStreamer.java │ └── ManifestParser.java ├── doc ├── ELF.pdf ├── ELF.png └── ascii.jpg ├── settings.gradle ├── gradle └── wrapper │ └── gradle-wrapper.properties ├── src └── main │ └── java │ └── com │ └── codesky │ └── ApkParser.java ├── .gitignore ├── local.properties ├── README.md ├── gradlew.bat └── gradlew /common/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /parser_arsc/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /parser_dex/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | .class -------------------------------------------------------------------------------- /parser_elfso/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /parser_manifest/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /doc/ELF.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dutlxq2014/ApkParser/HEAD/doc/ELF.pdf -------------------------------------------------------------------------------- /doc/ELF.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dutlxq2014/ApkParser/HEAD/doc/ELF.png -------------------------------------------------------------------------------- /doc/ascii.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dutlxq2014/ApkParser/HEAD/doc/ascii.jpg -------------------------------------------------------------------------------- /parser_dex/res/IGreet.java: -------------------------------------------------------------------------------- 1 | 2 | public interface IGreet { 3 | public void greet(); 4 | } -------------------------------------------------------------------------------- /parser_dex/res/ISay.java: -------------------------------------------------------------------------------- 1 | 2 | public interface ISay { 3 | 4 | public void sayHello(); 5 | } -------------------------------------------------------------------------------- /parser_dex/res/classes.dex: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dutlxq2014/ApkParser/HEAD/parser_dex/res/classes.dex -------------------------------------------------------------------------------- /parser_elfso/res/libjiagu.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dutlxq2014/ApkParser/HEAD/parser_elfso/res/libjiagu.so -------------------------------------------------------------------------------- /parser_arsc/res/resources.arsc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dutlxq2014/ApkParser/HEAD/parser_arsc/res/resources.arsc -------------------------------------------------------------------------------- /parser_elfso/res/libhello-jni.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dutlxq2014/ApkParser/HEAD/parser_elfso/res/libhello-jni.so -------------------------------------------------------------------------------- /parser_manifest/res/compiled_manifest.xml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dutlxq2014/ApkParser/HEAD/parser_manifest/res/compiled_manifest.xml -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | include ':common', ':parser_elfso', ':parser_arsc', ':parser_manifest', ':parser_dex' 2 | include ':elfso_parser' 3 | rootProject.name = 'ApkParser' 4 | -------------------------------------------------------------------------------- /common/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'java' 2 | 3 | dependencies { 4 | compile fileTree(dir: 'libs', include: ['*.jar']) 5 | } 6 | 7 | sourceCompatibility = "1.6" 8 | targetCompatibility = "1.6" 9 | -------------------------------------------------------------------------------- /parser_elfso/src/main/java/com/elfso/data/Section.java: -------------------------------------------------------------------------------- 1 | package com.elfso.data; 2 | 3 | /** 4 | * Body of section indexed by SectionHeader 5 | * Created by xueqiulxq on 11/07/2017. 6 | */ 7 | 8 | public class Section { 9 | 10 | } 11 | -------------------------------------------------------------------------------- /parser_elfso/src/main/java/com/elfso/data/Segment.java: -------------------------------------------------------------------------------- 1 | package com.elfso.data; 2 | 3 | /** 4 | * Body of section indexed by ProgramHeader 5 | * Created by xueqiulxq on 11/07/2017. 6 | */ 7 | 8 | public class Segment { 9 | 10 | } 11 | -------------------------------------------------------------------------------- /parser_arsc/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'java' 2 | 3 | dependencies { 4 | compile fileTree(dir: 'libs', include: ['*.jar']) 5 | compile project(':common') 6 | } 7 | 8 | sourceCompatibility = "1.6" 9 | targetCompatibility = "1.6" 10 | -------------------------------------------------------------------------------- /parser_dex/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'java' 2 | 3 | dependencies { 4 | compile fileTree(dir: 'libs', include: ['*.jar']) 5 | compile project(':common') 6 | } 7 | 8 | sourceCompatibility = "1.6" 9 | targetCompatibility = "1.6" 10 | -------------------------------------------------------------------------------- /parser_elfso/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'java' 2 | 3 | dependencies { 4 | compile fileTree(dir: 'libs', include: ['*.jar']) 5 | compile project(':common') 6 | } 7 | 8 | sourceCompatibility = "1.6" 9 | targetCompatibility = "1.6" 10 | -------------------------------------------------------------------------------- /parser_manifest/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'java' 2 | 3 | dependencies { 4 | compile fileTree(dir: 'libs', include: ['*.jar']) 5 | compile project(':common') 6 | } 7 | 8 | sourceCompatibility = "1.6" 9 | targetCompatibility = "1.6" 10 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Mon Dec 28 10:00:20 PST 2015 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-2.14.1-all.zip 7 | -------------------------------------------------------------------------------- /common/src/main/java/com/common/Project.java: -------------------------------------------------------------------------------- 1 | package com.common; 2 | 3 | import java.io.File; 4 | 5 | /** 6 | * 7 | * Created by xueqiulxq on 06/07/2017. 8 | */ 9 | 10 | public class Project { 11 | 12 | public static File getApk() { 13 | return new File("xx"); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /parser_elfso/src/main/java/com/elf/excep/FormatException.java: -------------------------------------------------------------------------------- 1 | package com.elf.excep; 2 | 3 | /** 4 | * Created by xueqiulxq on 07/07/2017. 5 | */ 6 | 7 | public class FormatException extends Exception { 8 | 9 | public FormatException(String detail) { 10 | super(detail); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/main/java/com/codesky/ApkParser.java: -------------------------------------------------------------------------------- 1 | package com.codesky; 2 | 3 | import com.common.FileUtil; 4 | 5 | /** 6 | * 7 | * Created by xueqiulxq on 06/07/2017. 8 | */ 9 | 10 | public class ApkParser { 11 | 12 | public static void main(String[] args) { 13 | FileUtil.load(); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Created by .ignore support plugin (hsz.mobi) 2 | ### Java template 3 | *.class 4 | 5 | # BlueJ files 6 | *.ctxt 7 | 8 | # Mobile Tools for Java (J2ME) 9 | .mtj.tmp/ 10 | 11 | # Package Files # 12 | *.jar 13 | *.war 14 | *.ear 15 | 16 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 17 | hs_err_pid* 18 | 19 | # IntelliJ project files 20 | .idea 21 | *.iml 22 | out 23 | gen 24 | *.swp 25 | -------------------------------------------------------------------------------- /parser_manifest/src/main/java/com/manifest/data/TagChunk.java: -------------------------------------------------------------------------------- 1 | package com.manifest.data; 2 | 3 | /** 4 | * 5 | * Created by xueqiulxq on 23/07/2017. 6 | */ 7 | 8 | public class TagChunk { 9 | 10 | public long chunkType; 11 | public long chunkSize; 12 | public long lineNumber; 13 | public long unknown; 14 | public long nameSpaceUri; 15 | public long name; // Tag name index 16 | 17 | // Assistant 18 | public String nameSpaceUriStr; 19 | public String nameStr; 20 | } 21 | -------------------------------------------------------------------------------- /parser_dex/res/Hello.java: -------------------------------------------------------------------------------- 1 | 2 | public class Hello implements ISay, IGreet { 3 | 4 | private static final String TAG = "Hello"; 5 | public String vStr; 6 | 7 | public void doSay() { 8 | System.out.println("Hello dex."); 9 | } 10 | 11 | @Override 12 | public void greet() { 13 | 14 | } 15 | 16 | @Override 17 | public void sayHello() { 18 | doSay(); 19 | } 20 | 21 | public static void main(String[] args) { 22 | Hello hello = new Hello(); 23 | hello.sayHello(); 24 | } 25 | } -------------------------------------------------------------------------------- /parser_dex/src/main/java/com/dex/stream/DexStreamer.java: -------------------------------------------------------------------------------- 1 | package com.dex.stream; 2 | 3 | import com.common.stream.RandomAccessStreamer; 4 | 5 | 6 | /** 7 | * 8 | * Created by xueqiulxq on 07/08/2017. 9 | */ 10 | 11 | public abstract class DexStreamer extends RandomAccessStreamer { 12 | 13 | public abstract int readU1(); 14 | 15 | public abstract int readU2(); 16 | 17 | public abstract long readU4(); 18 | 19 | public abstract long parseUleb4(byte[] bytes); 20 | 21 | public abstract String readString(int len); 22 | } 23 | -------------------------------------------------------------------------------- /parser_dex/res/makedex.sh: -------------------------------------------------------------------------------- 1 | #=============================================== 2 | # Copyright (C) 2017 All rights reserved. 3 | #=============================================== 4 | # Filename: makedex.sh 5 | # Author: codesky.club 6 | # Date: 2017-09-24 7 | # Description: 8 | # 9 | # Modification: 10 | # 11 | #=============================================== 12 | #!/bin/bash 13 | 14 | javac Hello.java 15 | 16 | # make sure dx version >= javac, or something like 'bad class file magic (cafebabe) or version(0034.000)...' will be thrown. 17 | dx --dex --output=classes.dex *.class 18 | 19 | -------------------------------------------------------------------------------- /local.properties: -------------------------------------------------------------------------------- 1 | ## This file is automatically generated by Android Studio. 2 | # Do not modify this file -- YOUR CHANGES WILL BE ERASED! 3 | # 4 | # This file must *NOT* be checked into Version Control Systems, 5 | # as it contains information specific to your local configuration. 6 | # 7 | # Location of the SDK. This is only used by Gradle. 8 | # For customization when using a Version Control System, please read the 9 | # header note. 10 | #Thu Jul 06 22:46:03 CST 2017 11 | ndk.dir=/Users/xuqiulxq/Applications/android-sdk-macosx/ndk-bundle 12 | sdk.dir=/Users/xuqiulxq/Applications/android-sdk-macosx 13 | -------------------------------------------------------------------------------- /parser_manifest/src/main/java/com/manifest/stream/MfStreamer.java: -------------------------------------------------------------------------------- 1 | package com.manifest.stream; 2 | 3 | import com.common.stream.RandomAccessStreamer; 4 | 5 | /** 6 | * 7 | * Created by xueqiulxq on 16/07/2017. 8 | */ 9 | 10 | public abstract class MfStreamer extends RandomAccessStreamer { 11 | 12 | public MfStreamer() { 13 | super(); 14 | } 15 | 16 | public abstract long readUInt(); 17 | 18 | public abstract int readUShort(); 19 | 20 | // utf-8 char 21 | public abstract char readChar8(); 22 | 23 | // utf-16 char 24 | public abstract char readChar16(); 25 | } 26 | -------------------------------------------------------------------------------- /parser_arsc/src/main/java/com/arsc/stream/ArscStreamer.java: -------------------------------------------------------------------------------- 1 | package com.arsc.stream; 2 | 3 | import com.common.stream.RandomAccessStreamer; 4 | 5 | /** 6 | * 7 | * Created by xueqiulxq on 25/07/2017. 8 | */ 9 | 10 | public abstract class ArscStreamer extends RandomAccessStreamer { 11 | 12 | public abstract long readUInt(); 13 | 14 | public abstract int readUShort(); 15 | 16 | public abstract char readChar16(); 17 | 18 | public abstract char readChar8(); 19 | 20 | public abstract String readNullEndString(int lenInclEnd); 21 | 22 | public abstract String readNullEndString16(int lenInclEnd); 23 | } 24 | -------------------------------------------------------------------------------- /parser_arsc/src/main/java/com/arsc/data/BaseTypeChunk.java: -------------------------------------------------------------------------------- 1 | package com.arsc.data; 2 | 3 | /** 4 | * 5 | * Created by xueqiulxq on 30/07/2017. 6 | */ 7 | 8 | public abstract class BaseTypeChunk { 9 | 10 | public abstract String getChunkName(); 11 | 12 | public abstract long getEntryCount(); 13 | 14 | public abstract String getType(); 15 | 16 | public abstract int getTypeId(); 17 | 18 | public abstract void translateValues(ResStringPoolChunk globalStringPool, 19 | ResStringPoolChunk typeStringPool, 20 | ResStringPoolChunk keyStringPool); 21 | } 22 | -------------------------------------------------------------------------------- /parser_arsc/src/main/java/com/arsc/data/ResTableRef.java: -------------------------------------------------------------------------------- 1 | package com.arsc.data; 2 | 3 | import com.arsc.stream.ArscStreamer; 4 | import com.common.PrintUtil; 5 | 6 | /** 7 | * 8 | * Created by xueqiulxq on 29/07/2017. 9 | */ 10 | 11 | public class ResTableRef { 12 | 13 | public long ident; 14 | 15 | public static ResTableRef parseFrom(ArscStreamer s) { 16 | ResTableRef ref = new ResTableRef(); 17 | ref.ident = s.readUInt(); 18 | return ref; 19 | } 20 | 21 | @Override 22 | public String toString() { 23 | return String.format("%s: 0x%s", "ident", PrintUtil.hex4(ident)); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /parser_arsc/src/main/java/com/arsc/data/ResStringPoolRef.java: -------------------------------------------------------------------------------- 1 | package com.arsc.data; 2 | 3 | import com.arsc.stream.ArscStreamer; 4 | import com.common.PrintUtil; 5 | 6 | /** 7 | * 8 | * Created by xueqiulxq on 29/07/2017. 9 | */ 10 | 11 | public class ResStringPoolRef { 12 | 13 | public long index; 14 | 15 | public static ResStringPoolRef parseFrom(ArscStreamer s) { 16 | ResStringPoolRef ref = new ResStringPoolRef(); 17 | ref.index = s.readUInt(); 18 | return ref; 19 | } 20 | 21 | @Override 22 | public String toString() { 23 | String form = "%s: 0x%s"; 24 | return String.format(form, "index", PrintUtil.hex4(index)); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /common/src/main/java/com/common/FileUtil.java: -------------------------------------------------------------------------------- 1 | package com.common; 2 | 3 | import java.io.Closeable; 4 | import java.io.File; 5 | import java.io.FileNotFoundException; 6 | import java.io.IOException; 7 | import java.io.RandomAccessFile; 8 | 9 | public class FileUtil { 10 | 11 | public static RandomAccessFile loadAsRAF(String pathname) throws FileNotFoundException { 12 | if (!new File(pathname).exists()) { 13 | return null; 14 | } 15 | return new RandomAccessFile(pathname, "r"); 16 | } 17 | 18 | public static void closeQuietly(Closeable io) { 19 | if (io != null) { 20 | try { 21 | io.close(); 22 | } catch (IOException e) { 23 | e.printStackTrace(); 24 | } 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /parser_manifest/src/main/java/com/manifest/stream/LittleEndianStreamer.java: -------------------------------------------------------------------------------- 1 | package com.manifest.stream; 2 | 3 | /** 4 | * 5 | * Created by xueqiulxq on 16/07/2017. 6 | */ 7 | 8 | public class LittleEndianStreamer extends MfStreamer { 9 | 10 | public LittleEndianStreamer() { 11 | super(); 12 | } 13 | 14 | @Override 15 | public long readUInt() { 16 | return super.readUnsignedInt(Endian.Little); 17 | } 18 | 19 | @Override 20 | public int readUShort() { 21 | return super.readUnsignedShort(Endian.Little); 22 | } 23 | 24 | @Override 25 | public char readChar8() { 26 | return super.readChar8(Endian.Little); 27 | } 28 | 29 | @Override 30 | public char readChar16() { 31 | return super.readChar16(Endian.Little); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /parser_elfso/src/main/java/com/elfso/stream/ElfStreamer.java: -------------------------------------------------------------------------------- 1 | package com.elfso.stream; 2 | 3 | 4 | import com.common.stream.RandomAccessStreamer; 5 | 6 | /** 7 | * 8 | * Created by xueqiulxq on 07/07/2017. 9 | */ 10 | 11 | public abstract class ElfStreamer extends RandomAccessStreamer { 12 | 13 | public ElfStreamer() { 14 | super(); 15 | } 16 | 17 | // unsigned int addr 4byte 18 | public abstract long readElf32Addr(); 19 | 20 | // unsigned short half 2byte 21 | public abstract int readElf32Half(); 22 | 23 | // unsinged int off 4byte 24 | public abstract long readElf32Off(); 25 | 26 | // signed int 4byte 27 | public abstract int readElf32Sword(); 28 | 29 | // unsigned int 4byte 30 | public abstract long readElf32Word(); 31 | 32 | // unsinged char 1byte 33 | public abstract char readUChar(); 34 | } 35 | -------------------------------------------------------------------------------- /common/src/main/java/com/common/LogUtil.java: -------------------------------------------------------------------------------- 1 | package com.common; 2 | 3 | /** 4 | * 5 | * Created by xueqiulxq on 07/07/2017. 6 | */ 7 | 8 | public class LogUtil { 9 | 10 | 11 | public static void e(String tag, String... detail) { 12 | System.err.println(tag + ": " + format(detail)); 13 | } 14 | 15 | public static void i(String tag, String... detail) { 16 | System.out.println(tag + ": " + format(detail)); 17 | } 18 | 19 | private static String format(String... detail) { 20 | if (detail == null || detail.length == 0) { 21 | return ""; 22 | } else if (detail.length == 1) { 23 | return detail[0]; 24 | } 25 | StringBuilder builder = new StringBuilder(); 26 | for (int i=0; i 2 | 6 | 7 | 8 | 9 | 15 | 16 | 17 | 18 | 19 | 20 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /parser_manifest/res/apktool_manifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /parser_arsc/src/main/java/com/arsc/data/ResTableMap.java: -------------------------------------------------------------------------------- 1 | package com.arsc.data; 2 | 3 | import com.arsc.stream.ArscStreamer; 4 | 5 | /** 6 | * 7 | * Created by xueqiulxq on 29/07/2017. 8 | */ 9 | 10 | public class ResTableMap { 11 | 12 | // Bag resource ID 13 | public ResTableRef name; 14 | 15 | // Bag resource item value 16 | public ResValue value; 17 | 18 | public static ResTableMap parseFrom(ArscStreamer s) { 19 | ResTableMap tableMap = new ResTableMap(); 20 | tableMap.name = ResTableRef.parseFrom(s); 21 | tableMap.value = ResValue.parseFrom(s); 22 | return tableMap; 23 | } 24 | 25 | @Override 26 | public String toString() { 27 | StringBuilder builder = new StringBuilder(); 28 | builder.append(String.format("%-10s {%s}\n", "name", name.toString())); 29 | builder.append("value:\n" + value.toString()); 30 | return builder.toString(); 31 | } 32 | 33 | public void translateValues(ResStringPoolChunk globalStringPool, 34 | ResStringPoolChunk typeStringPool, 35 | ResStringPoolChunk keyStringPool) { 36 | value.translateValues(globalStringPool, typeStringPool, keyStringPool); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /parser_dex/src/main/java/com/dex/data/MethodDataItem.java: -------------------------------------------------------------------------------- 1 | package com.dex.data; 2 | 3 | import com.dex.stream.DexStreamer; 4 | 5 | /** 6 | * 7 | * Created by xueqiulxq on 17/09/2017. 8 | */ 9 | 10 | public class MethodDataItem { 11 | 12 | public static final int LENGTH = 8; 13 | 14 | public int classIdx; // 2B 15 | public int protoIdx; // 2B 16 | public long nameIdx; // 4B 17 | 18 | // Assistant 19 | public String classStr; 20 | public ProtoDataItem protoItem; 21 | public String nameStr; 22 | 23 | public static MethodDataItem parseFrom(DexStreamer s, StringPool stringPool, TypePool typePool, ProtoPool protoPool) { 24 | MethodDataItem item = new MethodDataItem(); 25 | item.classIdx = s.readU2(); 26 | item.protoIdx = s.readU2(); 27 | item.nameIdx = s.readU4(); 28 | 29 | item.classStr = typePool.getType(item.classIdx); 30 | item.nameStr = stringPool.getString(item.nameIdx); 31 | item.protoItem = protoPool.getProto(item.protoIdx); 32 | 33 | return item; 34 | } 35 | 36 | @Override 37 | public String toString() { 38 | StringBuilder builder = new StringBuilder(); 39 | builder.append(classStr).append(" -> ").append(nameStr).append(protoItem); 40 | return builder.toString(); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /parser_dex/src/main/java/com/dex/data/FieldDataItem.java: -------------------------------------------------------------------------------- 1 | package com.dex.data; 2 | 3 | import com.dex.stream.DexStreamer; 4 | 5 | /** 6 | * 7 | * Created by xueqiulxq on 17/09/2017. 8 | */ 9 | 10 | public class FieldDataItem { 11 | 12 | public static final int LENGTH = 8; 13 | 14 | public int classIdx; // 2B The class index this field belongs to in type_ids 15 | public int typeIdx; // 2B Field type index in type_ids 16 | public long nameIdx; // 4B The name index in string_ids 17 | 18 | // Assistant 19 | public String classStr; 20 | public String typeStr; 21 | public String nameStr; 22 | 23 | public static FieldDataItem parseFrom(DexStreamer s, StringPool stringPool, TypePool typePool) { 24 | FieldDataItem item = new FieldDataItem(); 25 | item.classIdx = s.readU2(); 26 | item.typeIdx = s.readU2(); 27 | item.nameIdx = s.readU4(); 28 | 29 | item.classStr = typePool.getType(item.classIdx); 30 | item.typeStr = typePool.getType(item.typeIdx); 31 | item.nameStr = stringPool.getString(item.nameIdx); 32 | return item; 33 | } 34 | 35 | @Override 36 | public String toString() { 37 | StringBuilder builder = new StringBuilder(); 38 | builder.append(classStr).append(" -> ").append(typeStr).append(" ").append(nameStr); 39 | return builder.toString(); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /parser_dex/src/main/java/com/dex/data/StringDataItem.java: -------------------------------------------------------------------------------- 1 | package com.dex.data; 2 | 3 | import com.common.PrintUtil; 4 | import com.dex.stream.DexStreamer; 5 | 6 | import java.io.IOException; 7 | import java.io.RandomAccessFile; 8 | 9 | /** 10 | * 11 | * Created by xueqiulxq on 17/09/2017. 12 | */ 13 | 14 | public class StringDataItem { 15 | 16 | public long size; 17 | public String data; 18 | // Assistant 19 | public int ulebLen; 20 | 21 | public static StringDataItem parseFrom(RandomAccessFile racFile, DexStreamer s, long offset) throws IOException { 22 | StringDataItem data = new StringDataItem(); 23 | // Test the length of uleb 24 | racFile.seek(offset); 25 | byte[] leb128 = new byte[5]; 26 | racFile.read(leb128, 0, leb128.length); 27 | s.use(leb128); 28 | leb128 = s.readUleb128Bytes(); 29 | 30 | // Parse data item 31 | data.size = s.parseUleb4(leb128); 32 | racFile.seek(offset + leb128.length); // Move cursor to the start position of string 33 | byte[] strBytes = new byte[(int) data.size]; 34 | racFile.read(strBytes, 0, strBytes.length); 35 | data.data = new String(strBytes); 36 | return data; 37 | } 38 | 39 | @Override 40 | public String toString() { 41 | return String.format("size=%s\t \"%s\"", PrintUtil.hex4(size), data); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /parser_dex/src/main/java/com/dex/data/MethodPool.java: -------------------------------------------------------------------------------- 1 | package com.dex.data; 2 | 3 | import com.dex.stream.DexStreamer; 4 | 5 | import java.io.IOException; 6 | import java.io.RandomAccessFile; 7 | 8 | /** 9 | * 10 | * Created by xueqiulxq on 17/09/2017. 11 | */ 12 | 13 | public class MethodPool { 14 | 15 | public MethodDataItem[] methods; 16 | 17 | public static MethodPool parseFrom(RandomAccessFile racFile, DexStreamer s, DexHeader dexHeader, 18 | StringPool stringPool, TypePool typePool, ProtoPool protoPool) throws IOException { 19 | MethodPool pool = new MethodPool(); 20 | MethodDataItem[] methods = pool.methods = new MethodDataItem[(int) dexHeader.methodIdsSize]; 21 | byte[] itemBytes = new byte[MethodDataItem.LENGTH]; 22 | for (int i=0; i= 0 && (c = readChar16()) != 0) { 52 | builder.append(c); 53 | } 54 | if (lenInclEnd > 0) { 55 | read(lenInclEnd); // Skip remained nulls. 56 | } 57 | return builder.toString(); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /parser_manifest/src/main/java/com/manifest/data/EndTagChunk.java: -------------------------------------------------------------------------------- 1 | package com.manifest.data; 2 | 3 | import com.common.PrintUtil; 4 | import com.manifest.stream.MfStreamer; 5 | 6 | /** 7 | * 8 | * Created by xueqiulxq on 19/07/2017. 9 | */ 10 | 11 | public class EndTagChunk extends TagChunk { 12 | 13 | public static EndTagChunk parseFrom(MfStreamer s, StringChunk stringChunk) { 14 | EndTagChunk chunk = new EndTagChunk(); 15 | chunk.chunkType = s.readUInt(); 16 | chunk.chunkSize = s.readUInt(); 17 | chunk.lineNumber = s.readUInt(); 18 | chunk.unknown = s.readUInt(); 19 | chunk.nameSpaceUri = s.readUInt(); 20 | chunk.name = s.readUInt(); 21 | 22 | // Fill data 23 | chunk.nameSpaceUriStr = stringChunk.getString((int) chunk.nameSpaceUri); 24 | chunk.nameStr = stringChunk.getString((int) chunk.name); 25 | return chunk; 26 | } 27 | 28 | @Override 29 | public String toString() { 30 | StringBuilder builder = new StringBuilder(512); 31 | String form2 = "%-16s %s\n"; 32 | String form3 = "%-16s %-16s %s\n"; 33 | 34 | builder.append(String.format(form2, "chunkType", PrintUtil.hex4(chunkType))); 35 | builder.append(String.format(form2, "chunkSize", PrintUtil.hex4(chunkSize))); 36 | builder.append(String.format(form2, "lineNumber", PrintUtil.hex4(lineNumber))); 37 | builder.append(String.format(form2, "unknown", PrintUtil.hex4(unknown))); 38 | builder.append(String.format(form3, "nameSpaceUri", PrintUtil.hex4(nameSpaceUri), nameSpaceUriStr)); 39 | builder.append(String.format(form3, "name", PrintUtil.hex4(name), nameStr)); 40 | return builder.toString(); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /parser_manifest/src/main/java/com/manifest/data/ResourceIdChunk.java: -------------------------------------------------------------------------------- 1 | package com.manifest.data; 2 | 3 | import com.common.PrintUtil; 4 | import com.manifest.stream.MfStreamer; 5 | 6 | /** 7 | * 8 | * Created by xueqiulxq on 16/07/2017. 9 | */ 10 | 11 | public class ResourceIdChunk { 12 | 13 | public long chunkType; 14 | public long chunkSize; 15 | public long[] resourceIds; 16 | // Assistant 17 | public int numIds = 0; 18 | 19 | public static ResourceIdChunk parseFrom(MfStreamer s) { 20 | ResourceIdChunk chunk = new ResourceIdChunk(); 21 | chunk.chunkType = s.readUInt(); 22 | chunk.chunkSize = s.readUInt(); 23 | chunk.numIds = (int)((chunk.chunkSize - 8) / 4); 24 | chunk.resourceIds = new long[chunk.numIds]; 25 | for (int i=0; i\n"); 40 | return builder.toString(); 41 | } 42 | 43 | @Override 44 | public void translateValues(ResStringPoolChunk globalStringPool, 45 | ResStringPoolChunk typeStringPool, 46 | ResStringPoolChunk keyStringPool) { 47 | super.translateValues(globalStringPool, typeStringPool, keyStringPool); 48 | resValue.translateValues(globalStringPool, typeStringPool, keyStringPool); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /parser_elfso/src/main/java/com/elfso/data/StringTable.java: -------------------------------------------------------------------------------- 1 | package com.elfso.data; 2 | 3 | import com.elfso.stream.ElfStreamer; 4 | 5 | import java.util.ArrayList; 6 | import java.util.List; 7 | 8 | /** 9 | * 10 | * Created by xueqiulxq on 07/07/2017. 11 | */ 12 | 13 | public class StringTable { 14 | 15 | public String[] strs; 16 | public byte[] strBytes; 17 | 18 | public static StringTable parseFrom(ElfStreamer s) { 19 | int len = s.length(); 20 | StringTable strTab = new StringTable(); 21 | strTab.strBytes = new byte[len]; 22 | List tmp = new ArrayList(); 23 | StringBuilder builder = new StringBuilder(); 24 | for (int i=0; i> 24; 32 | entry.data = s.readUInt(); 33 | // Fill data 34 | entry.namespaceUriStr = stringChunk.getString((int) entry.namespaceUri); 35 | entry.nameStr = stringChunk.getString((int) entry.name); 36 | entry.valueStringStr = stringChunk.getString((int) entry.valueString); 37 | entry.typeStr = AttributeType.getAttributeType(entry); 38 | entry.dataStr = AttributeType.getAttributeData(entry, stringChunk); 39 | return entry; 40 | } 41 | 42 | @Override 43 | public String toString() { 44 | StringBuilder builder = new StringBuilder(128); 45 | String form3 = "%-16s %-16s %s\n"; 46 | builder.append(String.format(form3, "namespaceUri", PrintUtil.hex4(namespaceUri), namespaceUriStr)); 47 | builder.append(String.format(form3, "name", PrintUtil.hex4(name), nameStr)); 48 | builder.append(String.format(form3, "valueString", PrintUtil.hex4(valueString), valueStringStr)); 49 | builder.append(String.format(form3, "type", PrintUtil.hex4(type), typeStr)); 50 | builder.append(String.format(form3, "data", PrintUtil.hex4(data), dataStr)); 51 | return builder.toString(); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /parser_dex/src/main/java/com/dex/data/DexFile.java: -------------------------------------------------------------------------------- 1 | package com.dex.data; 2 | 3 | import com.dex.stream.DexStreamer; 4 | import com.dex.stream.LittleEndianStreamer; 5 | 6 | import java.io.IOException; 7 | import java.io.RandomAccessFile; 8 | 9 | /** 10 | * 11 | * Created by xueqiulxq on 07/08/2017. 12 | */ 13 | 14 | public class DexFile { 15 | 16 | private DexStreamer mStreamer; 17 | public DexHeader dexHeader; 18 | public StringPool stringPool; 19 | public TypePool typePool; 20 | public ProtoPool protoPool; 21 | public FieldPool fieldPool; 22 | public MethodPool methodPool; 23 | public ClassPool classPool; 24 | 25 | public void parse(RandomAccessFile racFile) throws IOException { 26 | racFile.seek(0); 27 | mStreamer = new LittleEndianStreamer(); 28 | 29 | byte[] headerBytes; 30 | 31 | headerBytes = new byte[DexHeader.LENGTH]; 32 | racFile.read(headerBytes, 0, headerBytes.length); 33 | mStreamer.use(headerBytes); 34 | dexHeader = DexHeader.parseFrom(mStreamer); 35 | 36 | stringPool = StringPool.parseFrom(racFile, mStreamer, dexHeader); 37 | typePool = TypePool.parseFrom(racFile, mStreamer, dexHeader, stringPool); 38 | protoPool = ProtoPool.parseFrom(racFile, mStreamer, dexHeader, stringPool, typePool); 39 | fieldPool = FieldPool.parseFrom(racFile, mStreamer, dexHeader, stringPool, typePool); 40 | methodPool = MethodPool.parseFrom(racFile, mStreamer, dexHeader, stringPool, typePool, protoPool); 41 | classPool = ClassPool.parseFrom(racFile, mStreamer, dexHeader, stringPool, typePool, protoPool); 42 | } 43 | 44 | @Override 45 | public String toString() { 46 | StringBuilder builder = new StringBuilder(); 47 | builder.append(dexHeader); 48 | builder.append('\n'); 49 | builder.append(stringPool); 50 | builder.append('\n'); 51 | builder.append(typePool); 52 | builder.append('\n'); 53 | builder.append(protoPool); 54 | builder.append('\n'); 55 | builder.append(fieldPool); 56 | builder.append('\n'); 57 | builder.append(methodPool); 58 | builder.append('\n'); 59 | builder.append(classPool); 60 | return builder.toString(); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /parser_arsc/src/main/java/com/arsc/data/ResTableEntry.java: -------------------------------------------------------------------------------- 1 | package com.arsc.data; 2 | 3 | import com.arsc.stream.ArscStreamer; 4 | import com.common.PrintUtil; 5 | 6 | /** 7 | * 8 | * Created by xueqiulxq on 29/07/2017. 9 | */ 10 | 11 | public class ResTableEntry { 12 | 13 | // If set, this is a complex entry, holding a set of name/value. It is followed by an array of ResTableMap structures. 14 | public static final int FLAG_COMPLEX = 0x0001; 15 | // If set, this resource has been declared public, so libraries are allowed to reference it. 16 | public static final int FLAG_PUBLIC = 0x0002; 17 | 18 | public int size; // short 19 | public int flags; // short 20 | public ResStringPoolRef key; // Reference into ResTablePackage::keyStrings identifying this entry. 21 | 22 | public int entryId; // 16bit 0x7f01nnnn 23 | public String keyStr; 24 | 25 | public static ResTableEntry parseFrom(ArscStreamer s) { 26 | ResTableEntry entry = new ResTableEntry(); 27 | parseFrom(s, entry); 28 | return entry; 29 | } 30 | 31 | public static void parseFrom(ArscStreamer s, ResTableEntry entry) { 32 | entry.size = s.readUShort(); 33 | entry.flags = s.readUShort(); 34 | entry.key = ResStringPoolRef.parseFrom(s); 35 | } 36 | 37 | @Override 38 | public String toString() { 39 | StringBuilder builder = new StringBuilder(); 40 | String form = "%-10s 0x%s\n"; 41 | builder.append(String.format(form, "size", PrintUtil.hex2(size))); 42 | builder.append(String.format(form, "flags", PrintUtil.hex2(flags))); 43 | builder.append(String.format("%-10s {%s} \t%s\n", "key", key, "/* Reference into ResTablePackage::keyStrings */")); 44 | builder.append(String.format("%-10s %s\n", "keyStr", keyStr)); 45 | return builder.toString(); 46 | } 47 | 48 | public String buildEntry2String(int packageId, int typeId, String typeStr, ResStringPoolChunk keyStringPool) { 49 | return "Not implemented."; 50 | } 51 | 52 | public void translateValues(ResStringPoolChunk globalStringPool, 53 | ResStringPoolChunk typeStringPool, 54 | ResStringPoolChunk keyStringPool) { 55 | keyStr = keyStringPool.getString((int) key.index); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /parser_dex/src/main/java/com/dex/data/EncodedMethod.java: -------------------------------------------------------------------------------- 1 | package com.dex.data; 2 | 3 | import com.common.PrintUtil; 4 | import com.dex.stream.DexStreamer; 5 | 6 | import java.io.IOException; 7 | import java.io.RandomAccessFile; 8 | 9 | /** 10 | * 11 | * Created by xueqiulxq on 19/09/2017. 12 | */ 13 | 14 | public class EncodedMethod { 15 | 16 | public byte[] methodIdxDiff; // uleb128 17 | public byte[] accessFlags; // uleb128 18 | public byte[] codeOff; // uleb128 -> code_item {@link CodeItem} 19 | 20 | public CodeItem codeItem; 21 | // Assistant 22 | public long methodIdxDiffInt; 23 | public long accessFlagsInt; 24 | public long codeOffInt; 25 | 26 | public static EncodedMethod parseFrom(RandomAccessFile racFile, DexStreamer s, 27 | StringPool stringPool, TypePool typePool, ProtoPool protoPool) throws IOException { 28 | EncodedMethod method = new EncodedMethod(); 29 | method.methodIdxDiff = s.readUleb128BytesFrom(racFile); 30 | method.accessFlags = s.readUleb128BytesFrom(racFile); 31 | method.codeOff = s.readUleb128BytesFrom(racFile); 32 | 33 | method.methodIdxDiffInt = s.parseUleb4(method.methodIdxDiff); 34 | method.accessFlagsInt = s.parseUleb4(method.accessFlags); 35 | method.codeOffInt = s.parseUleb4(method.codeOff); 36 | 37 | if (method.codeOffInt != 0) { 38 | long cursor = racFile.getFilePointer(); 39 | racFile.seek(method.codeOffInt); 40 | method.codeItem = CodeItem.parseFrom(racFile, s, stringPool, typePool, protoPool); 41 | racFile.seek(cursor); 42 | } 43 | return method; 44 | } 45 | 46 | public int getLength() { 47 | return methodIdxDiff.length + accessFlags.length + codeOff.length; 48 | } 49 | 50 | @Override 51 | public String toString() { 52 | StringBuilder builder = new StringBuilder(); 53 | String form2 = "%-20s0x%s\n"; 54 | String form3 = "%-20s0x%s \t%s\n"; 55 | builder.append(String.format(form2, "methodIdxDiff", PrintUtil.hex(methodIdxDiff))); 56 | builder.append(String.format(form3, "accessFlags", PrintUtil.hex(accessFlags), AccessFlags.accMethodStr(accessFlagsInt))); 57 | builder.append(String.format(form3, "codeOff", PrintUtil.hex(codeOff), "-> CodeItem")); 58 | if (codeItem != null) { 59 | String codeItemStr = codeItem.toString(); 60 | builder.append("\t").append(codeItemStr.trim().replace("\n", "\n\t")).append('\n'); 61 | } else { 62 | builder.append("\tCodeItem: ").append("Not implemented.").append('\n'); 63 | } 64 | return builder.toString(); 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 12 | set DEFAULT_JVM_OPTS= 13 | 14 | set DIRNAME=%~dp0 15 | if "%DIRNAME%" == "" set DIRNAME=. 16 | set APP_BASE_NAME=%~n0 17 | set APP_HOME=%DIRNAME% 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windowz variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | if "%@eval[2+2]" == "4" goto 4NT_args 53 | 54 | :win9xME_args 55 | @rem Slurp the command line arguments. 56 | set CMD_LINE_ARGS= 57 | set _SKIP=2 58 | 59 | :win9xME_args_slurp 60 | if "x%~1" == "x" goto execute 61 | 62 | set CMD_LINE_ARGS=%* 63 | goto execute 64 | 65 | :4NT_args 66 | @rem Get arguments from the 4NT Shell from JP Software 67 | set CMD_LINE_ARGS=%$ 68 | 69 | :execute 70 | @rem Setup the command line 71 | 72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if "%ERRORLEVEL%"=="0" goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 85 | exit /b 1 86 | 87 | :mainEnd 88 | if "%OS%"=="Windows_NT" endlocal 89 | 90 | :omega 91 | -------------------------------------------------------------------------------- /parser_manifest/src/main/java/com/manifest/data/StartNamespaceChunk.java: -------------------------------------------------------------------------------- 1 | package com.manifest.data; 2 | 3 | import com.common.PrintUtil; 4 | import com.manifest.stream.MfStreamer; 5 | 6 | import java.util.HashMap; 7 | import java.util.Map; 8 | 9 | /** 10 | * 11 | * Created by xueqiulxq on 16/07/2017. 12 | */ 13 | 14 | public class StartNamespaceChunk { 15 | 16 | public long chunkType; 17 | public long chunkSize; 18 | public long lineNumber; 19 | public long unknown; 20 | public long prefixIdx; 21 | public long uriIdx; 22 | 23 | public String prefixStr; 24 | public String uriStr; 25 | public Map uri2prefixMap; 26 | public Map prefix2UriMap; 27 | 28 | public static StartNamespaceChunk parseFrom(MfStreamer s, StringChunk stringChunk) { 29 | StartNamespaceChunk chunk = new StartNamespaceChunk(); 30 | // Meta data 31 | chunk.chunkType = s.readUInt(); 32 | chunk.chunkSize = s.readUInt(); 33 | chunk.lineNumber = s.readUInt(); 34 | chunk.unknown = s.readUInt(); 35 | chunk.prefixIdx = s.readUInt(); 36 | chunk.uriIdx = s.readUInt(); 37 | // Fill data 38 | chunk.prefixStr = stringChunk.getString((int) chunk.prefixIdx); 39 | chunk.uriStr = stringChunk.getString((int) chunk.uriIdx); 40 | chunk.uri2prefixMap = new HashMap(); 41 | chunk.prefix2UriMap = new HashMap(); 42 | chunk.uri2prefixMap.put(chunk.uriStr, chunk.prefixStr); 43 | chunk.prefix2UriMap.put(chunk.prefixStr, chunk.uriStr); 44 | return chunk; 45 | } 46 | 47 | @Override 48 | public String toString() { 49 | StringBuilder builder = new StringBuilder(256); 50 | String form2 = "%-16s %s\n"; 51 | String form3 = "%-16s %s %s\n"; 52 | 53 | builder.append("-- StartNamespace Chunk --").append('\n'); 54 | builder.append(String.format(form2, "chunkType", PrintUtil.hex4(chunkType))); 55 | builder.append(String.format(form2, "chunkSize", PrintUtil.hex4(chunkSize))); 56 | builder.append(String.format(form2, "lineNumber", PrintUtil.hex4(lineNumber))); 57 | builder.append(String.format(form2, "unknown", PrintUtil.hex4(unknown))); 58 | builder.append(String.format(form3, "prefixIdx", PrintUtil.hex4(prefixIdx), prefixStr)); 59 | builder.append(String.format(form3, "uriIdx", PrintUtil.hex4(uriIdx), uriStr)); 60 | 61 | builder.append("--------------------------\n"); 62 | for (Map.Entry entry : prefix2UriMap.entrySet()) { 63 | builder.append("xmlns:").append(entry.getKey()).append("=").append(entry.getValue()).append('\n'); 64 | } 65 | return builder.toString(); 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /parser_arsc/src/main/java/com/arsc/data/ResTableTypeSpecChunk.java: -------------------------------------------------------------------------------- 1 | package com.arsc.data; 2 | 3 | import com.arsc.stream.ArscStreamer; 4 | import com.common.PrintUtil; 5 | 6 | /** 7 | * 8 | * Created by xueqiulxq on 26/07/2017. 9 | */ 10 | 11 | public class ResTableTypeSpecChunk extends BaseTypeChunk { 12 | 13 | public ChunkHeader header; 14 | public int typeId; // 1byte 15 | public int res0; // 1byte 16 | public int res1; // 2byte 17 | public long entryCount; 18 | public long[] entryConfig; 19 | 20 | public static ResTableTypeSpecChunk parseFrom(ArscStreamer s, ResStringPoolChunk stringChunk) { 21 | ResTableTypeSpecChunk chunk = new ResTableTypeSpecChunk(); 22 | chunk.header = ChunkHeader.parseFrom(s); 23 | chunk.typeId = s.readUInt8(); 24 | chunk.res0 = s.readUInt8(); 25 | chunk.res1 = s.readUShort(); 26 | chunk.entryCount = s.readUInt(); 27 | chunk.entryConfig = new long[(int) chunk.entryCount]; 28 | 29 | for (int i=0; i\n"); 55 | return builder.toString(); 56 | } 57 | 58 | @Override 59 | public void translateValues(ResStringPoolChunk globalStringPool, 60 | ResStringPoolChunk typeStringPool, 61 | ResStringPoolChunk keyStringPool) { 62 | super.translateValues(globalStringPool, typeStringPool, keyStringPool); 63 | for (int i=0; i attributes; 20 | 21 | public static StartTagChunk parseFrom(MfStreamer s, StringChunk stringChunk) { 22 | StartTagChunk chunk = new StartTagChunk(); 23 | chunk.chunkType = s.readUInt(); 24 | chunk.chunkSize = s.readUInt(); 25 | chunk.lineNumber = s.readUInt(); 26 | chunk.unknown = s.readUInt(); 27 | chunk.nameSpaceUri = s.readUInt(); 28 | chunk.name = s.readUInt(); 29 | chunk.flags = s.readUInt(); 30 | chunk.attributeCount = s.readUInt(); 31 | chunk.classAttribute = s.readUInt(); 32 | 33 | chunk.attributes = new ArrayList((int) chunk.attributeCount); 34 | for (int i=0; i").append('\n'); 61 | builder.append(attributes.get(i)); 62 | } 63 | return builder.toString(); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /parser_dex/src/main/java/com/dex/data/CodeItem.java: -------------------------------------------------------------------------------- 1 | package com.dex.data; 2 | 3 | import com.common.PrintUtil; 4 | import com.dex.stream.DexStreamer; 5 | 6 | import java.io.IOException; 7 | import java.io.RandomAccessFile; 8 | 9 | /** 10 | * 11 | * Created by xueqiulxq on 19/09/2017. 12 | */ 13 | 14 | public class CodeItem { 15 | 16 | public int registersSize; // 2B number of register need for current code segment 17 | public int insSize; // 2B number of input parameters 18 | public int outsSize; // 2B number of parameters for other method 19 | public int triesSize; // 2B number of try_item 20 | public long debugInfoOff; // 4B offset to debug_info_item in current code segment 21 | public long insnsSize; // 4B size of instructions list. insns is short for instructions 22 | public int[] insns; // 2B*n 23 | // public int padding; // optional 24 | // public try_item tries[triesSize]; // optional 25 | // public encoded_catch_handler_list handlers // optional 26 | 27 | public static CodeItem parseFrom(RandomAccessFile racFile, DexStreamer s, 28 | StringPool stringPool, TypePool typePool, ProtoPool protoPool) throws IOException { 29 | CodeItem item = new CodeItem(); 30 | byte[] sizeBytes = new byte[2*4 + 4*2]; 31 | racFile.read(sizeBytes, 0, sizeBytes.length); 32 | s.use(sizeBytes); 33 | item.registersSize = s.readU2(); 34 | item.insSize = s.readU2(); 35 | item.outsSize = s.readU2(); 36 | item.triesSize = s.readU2(); 37 | item.debugInfoOff = s.readU4(); 38 | item.insnsSize = s.readU4(); 39 | item.insns = new int[0]; 40 | int[] insns = item.insns = new int[(int) item.insnsSize]; 41 | 42 | byte[] insnsBytes = new byte[insns.length * 2]; 43 | racFile.read(insnsBytes, 0, insnsBytes.length); 44 | s.use(insnsBytes); 45 | for (int i=0; i 0) { 75 | for (int i=0; i ClassInterfaceItem")); 73 | builder.append(String.format(form3, "sourceFileIdx", PrintUtil.hex4(sourceFileIdx), sourceFileStr)); 74 | builder.append(String.format(form3, "annotationsOff", PrintUtil.hex4(annotationsOff), "->")); 75 | builder.append(String.format(form3, "classDataOff", PrintUtil.hex4(classDataOff), "-> ClassDataItem")); 76 | builder.append(String.format(form3, "staticValueOff", PrintUtil.hex4(staticValueOff), "->")); 77 | 78 | String itfStr = interfaceItem.toString(); 79 | builder.append(PrintUtil.indent(itfStr)); 80 | String dataItemStr = dataItem.toString(); 81 | builder.append(PrintUtil.indent(dataItemStr)); 82 | 83 | return builder.toString(); 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /parser_elfso/src/main/java/com/elfso/data/Eident.java: -------------------------------------------------------------------------------- 1 | package com.elfso.data; 2 | 3 | import com.common.PrintUtil; 4 | 5 | import java.io.IOException; 6 | import java.io.RandomAccessFile; 7 | 8 | /** 9 | * 10 | * Created by xueqiulxq on 07/07/2017. 11 | */ 12 | 13 | public class Eident { 14 | 15 | public static final int EI_NIDENT = 16; 16 | public static final int EI_MAG0 = 0; 17 | public static final int EI_MAG1 = 1; 18 | public static final int EI_MAG2 = 2; 19 | public static final int EI_MAG3 = 3; 20 | public static final int EI_CLASS = 4; 21 | public static final int EI_DATA = 5; 22 | public static final int EI_VERSION = 6; 23 | public static final int EI_PAD = 7; 24 | 25 | public static final int ELFCLASSNONE = 0; 26 | public static final int ELFCLASS32 = 1; 27 | public static final int ELFCLASS64 = 2; 28 | public static final int ELFDATANONE = 0; 29 | public static final int ELFDATA2LSB = 1; 30 | public static final int ELFDATA2MSB = 2; 31 | public static final int EV_NONE = 0; 32 | public static final int EV_CURRENT = 1; 33 | 34 | public byte[] e_ident = new byte[EI_NIDENT]; 35 | public byte ei_mag0; // 0x7f 36 | public byte ei_mag1; // 'E' 37 | public byte ei_mag2; // 'L' 38 | public byte ei_mag3; // 'F' 39 | public byte ei_class; 40 | public byte ei_data; 41 | public byte ei_version; 42 | public byte ei_pad; 43 | public byte[] ext; 44 | 45 | public Eident(byte[] eIdent) { 46 | e_ident = eIdent; 47 | 48 | ei_mag0 = eIdent[0]; 49 | ei_mag1 = eIdent[1]; 50 | ei_mag2 = eIdent[2]; 51 | ei_mag3 = eIdent[3]; 52 | ei_class = eIdent[4]; 53 | ei_data = eIdent[5]; 54 | ei_version = eIdent[6]; 55 | ei_pad = eIdent[7]; 56 | ext = new byte[eIdent.length - 8]; 57 | System.arraycopy(eIdent, 8, ext, 0, ext.length); 58 | } 59 | 60 | @Override 61 | public String toString() { 62 | StringBuilder builder = new StringBuilder(); 63 | builder.append(PrintUtil.hex1(ei_mag0)) 64 | .append(PrintUtil.bChar(ei_mag1)) 65 | .append(PrintUtil.bChar(ei_mag2)) 66 | .append(PrintUtil.bChar(ei_mag3)); 67 | builder.append('\t'); 68 | 69 | if (ei_class == ELFCLASSNONE) { 70 | builder.append("ELFCLASSNONE"); 71 | } else if (ei_class == ELFCLASS32) { 72 | builder.append("ELFCLASS32"); 73 | } else if (ei_class == ELFCLASS64) { 74 | builder.append("ELFCLASS64"); 75 | } 76 | builder.append('\t'); 77 | 78 | if (ei_data == ELFDATANONE) { 79 | builder.append("ELFDATANONE"); 80 | } else if (ei_data == ELFDATA2LSB) { 81 | builder.append("ELFDATA2LSB"); 82 | } else if (ei_data == ELFDATA2MSB) { 83 | builder.append("ELFDATA2MSB"); 84 | } 85 | builder.append('\t'); 86 | 87 | if (ei_version == EV_NONE) { 88 | builder.append("EV_NONE"); 89 | } else if (ei_version == EV_CURRENT){ 90 | builder.append("EV_CURRENT"); 91 | } 92 | builder.append('\t'); 93 | 94 | builder.append(PrintUtil.hex1(ei_pad)).append('\t'); 95 | for (int i=0; i> 24; 107 | if (resTablePackageChunk.pkgId == pkgId) { 108 | return resTablePackageChunk.getResource(resId); 109 | } else { 110 | return null; 111 | } 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /parser_dex/src/main/java/com/dex/data/ClassDataItem.java: -------------------------------------------------------------------------------- 1 | package com.dex.data; 2 | 3 | import com.common.PrintUtil; 4 | import com.dex.stream.DexStreamer; 5 | 6 | import java.io.IOException; 7 | import java.io.RandomAccessFile; 8 | 9 | /** 10 | * 11 | * Created by xueqiulxq on 19/09/2017. 12 | */ 13 | 14 | public class ClassDataItem { 15 | 16 | public long staticFieldsSize; // uleb128 17 | public long instanceFieldsSize; // uleb128 18 | public long directMethodsSize; // uleb128 19 | public long virtualMethodSize; // uleb128 20 | 21 | public EncodedField[] staticFields; 22 | public EncodedField[] instanceFields; 23 | public EncodedMethod[] directMethods; 24 | public EncodedMethod[] virtualMethods; 25 | 26 | public static ClassDataItem parseFrom(RandomAccessFile racFile, DexStreamer s, 27 | StringPool stringPool, TypePool typePool, ProtoPool protoPool) throws IOException { 28 | long start = racFile.getFilePointer(); 29 | 30 | // Read uleb128 based data 31 | long len = 0; 32 | long[] values = new long[4]; 33 | for (int i=0; i= 0 && index < strings.length ? strings[index] : null; 76 | } 77 | 78 | public String getString(long index) { 79 | return index >=0 && index < strings.length ? strings[(int) index] : null; 80 | } 81 | 82 | public String getStyle(int index) { 83 | return index >= 0 && index < styles.length ? styles[index] : null; 84 | } 85 | 86 | @Override 87 | public String toString() { 88 | StringBuilder builder = new StringBuilder(1024); 89 | String formH = "%-16s %s\n"; 90 | 91 | builder.append("-- String Chunk --").append('\n'); 92 | builder.append(String.format(formH, "chunkType", PrintUtil.hex4(chunkType))); 93 | builder.append(String.format(formH, "chunkSize", PrintUtil.hex4(chunkSize))); 94 | builder.append(String.format(formH, "stringCount", PrintUtil.hex4(stringCount))); 95 | builder.append(String.format(formH, "styleCount", PrintUtil.hex4(styleCount))); 96 | builder.append(String.format(formH, "unknown", PrintUtil.hex4(unknown))); 97 | builder.append(String.format(formH, "stringPoolOffset", PrintUtil.hex4(stringPoolOffset))); 98 | builder.append(String.format(formH, "stylePoolOffset", PrintUtil.hex4(stylePoolOffset))); 99 | 100 | builder.append("|----|----------|-----|---------").append('\n'); 101 | builder.append("| Id | Offset | Len | Content").append('\n'); 102 | builder.append("|----|----------|-----|---------").append('\n'); 103 | String formC = "|%-4d| %-8s | %-3d | %s\n"; 104 | for (int i=0; i strings; 30 | public List styles; 31 | 32 | public static ResStringPoolChunk parseFrom(ArscStreamer s) { 33 | 34 | long baseCursor = s.getCursor(); 35 | 36 | ResStringPoolChunk chunk = new ResStringPoolChunk(); 37 | chunk.header = ChunkHeader.parseFrom(s); 38 | chunk.stringCount = s.readUInt(); 39 | chunk.styleCount = s.readUInt(); 40 | chunk.flags = s.readUInt(); 41 | chunk.stringsStart = s.readUInt(); 42 | chunk.stylesStart = s.readUInt(); 43 | 44 | long[] strOffsets = chunk.stringOffsetArray = new long[(int) chunk.stringCount]; 45 | long[] styleOffsets = chunk.styleOffsetArray = new long[(int) chunk.styleCount]; 46 | List strings = chunk.strings = new ArrayList((int) chunk.stringCount); 47 | List styles = chunk.styles = new ArrayList((int) chunk.styleCount); 48 | 49 | for (int i=0; i> 8; 59 | String str = s.readNullEndString(len + 1); // The last byte is 0x00 60 | strings.add(str); 61 | } 62 | for (int i=0; i> 8; 66 | String str = s.readNullEndString(len + 1); // The last byte is 0x00 67 | styles.add(str); 68 | } 69 | 70 | return chunk; 71 | } 72 | 73 | public String getString(int idx) { 74 | return strings != null && idx < strings.size() ? strings.get(idx) : null; 75 | } 76 | 77 | public String getStyle(int idx) { 78 | return styles != null && idx < styles.size() ? styles.get(idx) : null; 79 | } 80 | 81 | @Override 82 | public String toString() { 83 | StringBuilder builder = new StringBuilder(64); 84 | String form = "%-16s %s\n"; 85 | 86 | builder.append("-- ResStringPool Chunk --").append('\n'); 87 | builder.append(header); 88 | builder.append(String.format(form, "stringCount", PrintUtil.hex4(stringCount))); 89 | builder.append(String.format(form, "styleCount", PrintUtil.hex4(styleCount))); 90 | builder.append(String.format("%-16s %s", "flags", PrintUtil.hex4(flags))); 91 | builder.append("\tutf8=").append((flags & UTF8_FLAG) != 0 ? "Y" : "N") 92 | .append(" ").append("sorted=").append((flags & SORTED_FLAG) != 0 ? "Y" : "N").append('\n'); 93 | builder.append(String.format(form, "stringsStart", PrintUtil.hex4(stringsStart))); 94 | builder.append(String.format(form, "stylesStart", PrintUtil.hex4(stylesStart))); 95 | 96 | builder.append(String.format("\nString offset array: length=%d\n", stringOffsetArray.length)); 97 | for (int i=0; i classStrs = new LinkedHashMap() { 36 | { 37 | put(ACC_PUBLIC, "ACC_PUBLIC"); 38 | put(ACC_FINAL, "ACC_FINAL"); 39 | put(ACC_INTERFACE, "ACC_INTERFACE"); 40 | put(ACC_ABSTRACT, "ACC_ABSTRACT"); 41 | put(ACC_SYNTHETIC, "ACC_SYNTHETIC"); 42 | put(ACC_ANNOTATION, "ACC_ANNOTATION"); 43 | put(ACC_ENUM, "ACC_ENUM"); 44 | // Inner class 45 | put(ACC_PRIVATE, "ACC_PRIVATE"); 46 | put(ACC_PROTECTED, "ACC_PROTECTED"); 47 | put(ACC_STATIC, "ACC_STATIC"); 48 | } 49 | }; 50 | public static final Map fieldStrs = new LinkedHashMap() { 51 | { 52 | put(ACC_PUBLIC, "ACC_PUBLIC"); 53 | put(ACC_PRIVATE, "ACC_PRIVATE"); 54 | put(ACC_PROTECTED, "ACC_PROTECTED"); 55 | put(ACC_STATIC, "ACC_STATIC"); 56 | put(ACC_FINAL, "ACC_FINAL"); 57 | put(ACC_VOLATILE, "ACC_VOLATILE"); 58 | put(ACC_TRANSIENT, "ACC_TRANSIENT"); 59 | put(ACC_SYNTHETIC, "ACC_SYNTHETIC"); 60 | put(ACC_ENUM, "ACC_ENUM"); 61 | } 62 | }; 63 | public static final Map methodStrs = new LinkedHashMap() { 64 | { 65 | put(ACC_PUBLIC, "ACC_PUBLIC"); 66 | put(ACC_PRIVATE, "ACC_PRIVATE"); 67 | put(ACC_PROTECTED, "ACC_PROTECTED"); 68 | put(ACC_STATIC, "ACC_STATIC"); 69 | put(ACC_FINAL, "ACC_FINAL"); 70 | put(ACC_SYNCHRONIZED, "ACC_SYNCHRONIZED"); 71 | put(ACC_BRIDGE, "ACC_BRIDGE"); 72 | put(ACC_VARARGS, "ACC_VARARGS"); 73 | put(ACC_NATIVE, "ACC_NATIVE"); 74 | put(ACC_ABSTRACT, "ACC_ABSTRACT"); 75 | put(ACC_STRICT, "ACC_STRICT"); 76 | put(ACC_SYNTHETIC, "ACC_SYNTHETIC"); 77 | put(ACC_CONSTRUCTOR, "ACC_CONSTRUCTOR"); 78 | put(ACC_DECLARED_SYNCHRONIZED, "ACC_DECLARED_SYNCHRONIZED"); 79 | } 80 | }; 81 | 82 | public static final int 83 | ACC_CLASS_MASK = ACC_PUBLIC | ACC_FINAL | ACC_INTERFACE | ACC_ABSTRACT 84 | | ACC_SYNTHETIC | ACC_ANNOTATION | ACC_ENUM, 85 | 86 | ACC_INNER_CLASS_MASK = ACC_CLASS_MASK | ACC_PRIVATE | ACC_PROTECTED | ACC_STATIC, 87 | 88 | ACC_FIELD_MASK = ACC_PUBLIC | ACC_PRIVATE | ACC_PROTECTED | ACC_STATIC | ACC_FINAL 89 | | ACC_VOLATILE | ACC_TRANSIENT | ACC_SYNTHETIC | ACC_ENUM, 90 | 91 | ACC_METHOD_MASK = ACC_PUBLIC | ACC_PRIVATE | ACC_PROTECTED | ACC_STATIC | ACC_FINAL 92 | | ACC_SYNCHRONIZED | ACC_BRIDGE | ACC_VARARGS | ACC_NATIVE 93 | | ACC_ABSTRACT | ACC_STRICT | ACC_SYNTHETIC | ACC_CONSTRUCTOR 94 | | ACC_DECLARED_SYNCHRONIZED; 95 | 96 | private static String accStr(Map map, long flags) { 97 | StringBuilder builder = new StringBuilder(); 98 | for (Integer flag : map.keySet()) { 99 | if ((flag & flags) != 0) { 100 | builder.append(map.get(flag)).append(" | "); 101 | } 102 | } 103 | if (builder.length() > 0) { 104 | builder.setLength(builder.length() - 3); 105 | } 106 | return builder.toString(); 107 | } 108 | 109 | public static String accClassStr(long flags) { 110 | return accStr(classStrs, flags); 111 | } 112 | 113 | public static String accFieldStr(long flags) { 114 | return accStr(fieldStrs, flags); 115 | } 116 | 117 | public static String accMethodStr(long flags) { 118 | return accStr(methodStrs, flags); 119 | } 120 | 121 | } 122 | -------------------------------------------------------------------------------- /parser_elfso/src/main/java/com/elfso/data/SectionHeader.java: -------------------------------------------------------------------------------- 1 | package com.elfso.data; 2 | 3 | import com.common.PrintUtil; 4 | import com.elfso.stream.ElfStreamer; 5 | 6 | /** 7 | * 8 | * Created by xueqiulxq on 07/07/2017. 9 | */ 10 | 11 | public class SectionHeader { 12 | 13 | public static final int SHN_UNDEF = 0; 14 | public static final int SHN_LORESERVE = 0xFF00; 15 | public static final int SHN_LOPROC = 0xFF00; 16 | public static final int SHN_HIPROC = 0XFF1F; 17 | public static final int SHN_ABS = 0xFFF1; 18 | public static final int SHN_COMMON = 0xFFF2; 19 | public static final int SHN_HIRESERVE = 0xFFFF; 20 | 21 | // sh_type 22 | public static final int SHT_NULL = 0; 23 | public static final int SHT_PROGBITS = 1; 24 | public static final int SHT_SYMTAB = 2; 25 | public static final int SHT_STRTAB = 3; 26 | public static final int SHT_RELA = 4; 27 | public static final int SHT_HASH = 5; 28 | public static final int SHT_DYNAMIC = 6; 29 | public static final int SHT_NOTE = 7; 30 | public static final int SHT_NOBITS = 8; 31 | public static final int SHT_REL = 9; 32 | public static final int SHT_SHLIB = 10; 33 | public static final int SHT_DYNSYM = 11; 34 | public static final int SH_NUM = 12; 35 | public static final int SHT_LOPROC = 0x70000000; 36 | public static final int SHT_HIPROC = 0x7FFFFFFF; 37 | public static final int SHT_LOUSER = 0x80000000; 38 | public static final int SHT_HIUSER = 0X8FFFFFFF; 39 | public static final int SHT_INTERP = 0x1b; // add 40 | 41 | // sh_flags 42 | public static final int SHF_WRITE = 0x1; // mask 43 | public static final int SHF_ALLOC = 0x2; 44 | public static final int SHF_EXECINSTR = 0x4; 45 | public static final int SHF_MASKPROC = 0xF0000000; 46 | 47 | // sh_link sh_info 48 | 49 | public long sh_name; // Elf32_Word 50 | public long sh_type; // Elf32_Word 51 | public long sh_flags; // Elf32_Word 52 | public long sh_addr; // Elf32_Addr 53 | public long sh_offset; // Elf32_Off 54 | public long sh_size; // Elf32_Word 55 | public long sh_link; // Elf32_Word 56 | public long sh_info; // Elf32_Word 57 | public long sh_addralign; // Elf32_Word 58 | public long sh_entsize; // Elf32_Word 59 | 60 | // detail 61 | public String _sh_name; 62 | 63 | public static SectionHeader parseFrom(ElfStreamer s) { 64 | SectionHeader h = new SectionHeader(); 65 | h.sh_name = s.readElf32Word(); 66 | h.sh_type = s.readElf32Word(); 67 | h.sh_flags = s.readElf32Word(); 68 | h.sh_addr = s.readElf32Addr(); 69 | h.sh_offset = s.readElf32Off(); 70 | h.sh_size = s.readElf32Word(); 71 | h.sh_link = s.readElf32Word(); 72 | h.sh_info = s.readElf32Word(); 73 | h.sh_addralign = s.readElf32Word(); 74 | h.sh_entsize = s.readElf32Word(); 75 | return h; 76 | } 77 | 78 | @Override 79 | public String toString() { 80 | StringBuilder builder = new StringBuilder(); 81 | String form = "%-12s\t%s\n"; 82 | builder.append(String.format(form, "_sh_name", _sh_name)); 83 | builder.append(String.format(form, "sh_name", PrintUtil.hex4(sh_name))); 84 | String type; 85 | switch ((int)sh_type) { 86 | case SHT_NULL: type = "SHT_NULL"; break; 87 | case SHT_PROGBITS: type = "SHT_PROGBITS .comment .data .data1 .debug .fini .got .init .interp .line .plt .rodata .rodata1 .text"; break; 88 | case SHT_SYMTAB: type = "SHT_SYMTAB .symtab"; break; 89 | case SHT_STRTAB: type = "SHT_STRTAB .dynstr .shstrtab .strtab"; break; 90 | case SHT_RELA: type = "SHT_RELA .relaname"; break; 91 | case SHT_HASH: type = "SHT_HASH .hash"; break; 92 | case SHT_DYNAMIC: type = "SHT_DYNAMIC .dynamic"; break; 93 | case SHT_NOTE: type = "SHT_NOTE .note"; break; 94 | case SHT_NOBITS: type = "SHT_NOBITS .bss"; break; 95 | case SHT_REL: type = "SHT_REL relname"; break; 96 | case SHT_SHLIB: type = "SHT_SHLIB"; break; 97 | case SHT_DYNSYM: type = "SHT_DYNSYM .dynsym"; break; 98 | case SH_NUM: type = "SH_NUM"; break; 99 | case SHT_LOPROC: type = "SHT_LOPROC"; break; 100 | case SHT_HIPROC: type = "SHT_HIPROC"; break; 101 | case SHT_LOUSER: type = "SHT_LOUSER"; break; 102 | case SHT_HIUSER: type = "SHT_HIUSER"; break; 103 | case SHT_INTERP: type = "SHT_INTERP"; break; 104 | default: type = "unknown"; 105 | } 106 | builder.append(String.format(form, "sh_type", PrintUtil.hex4(sh_type) + "\t" + type)); 107 | builder.append(String.format(form, "sh_flags", PrintUtil.hex4(sh_flags))); 108 | builder.append(String.format(form, "sh_addr", PrintUtil.hex4(sh_addr))); 109 | builder.append(String.format(form, "sh_offset", PrintUtil.hex4(sh_offset))); 110 | builder.append(String.format(form, "sh_size", PrintUtil.hex4(sh_size))); 111 | builder.append(String.format(form, "sh_link", PrintUtil.hex4(sh_link))); 112 | builder.append(String.format(form, "sh_info", PrintUtil.hex4(sh_info))); 113 | builder.append(String.format(form, "sh_addralign", PrintUtil.hex4(sh_addralign))); 114 | builder.append(String.format(form, "sh_entsize", PrintUtil.hex4(sh_entsize))); 115 | 116 | builder.append('\n'); 117 | return builder.toString(); 118 | } 119 | 120 | public void fillDetail(StringTable table) { 121 | _sh_name = table.get((int)sh_name); 122 | } 123 | } 124 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 10 | DEFAULT_JVM_OPTS="" 11 | 12 | APP_NAME="Gradle" 13 | APP_BASE_NAME=`basename "$0"` 14 | 15 | # Use the maximum available, or set MAX_FD != -1 to use that value. 16 | MAX_FD="maximum" 17 | 18 | warn ( ) { 19 | echo "$*" 20 | } 21 | 22 | die ( ) { 23 | echo 24 | echo "$*" 25 | echo 26 | exit 1 27 | } 28 | 29 | # OS specific support (must be 'true' or 'false'). 30 | cygwin=false 31 | msys=false 32 | darwin=false 33 | case "`uname`" in 34 | CYGWIN* ) 35 | cygwin=true 36 | ;; 37 | Darwin* ) 38 | darwin=true 39 | ;; 40 | MINGW* ) 41 | msys=true 42 | ;; 43 | esac 44 | 45 | # Attempt to set APP_HOME 46 | # Resolve links: $0 may be a link 47 | PRG="$0" 48 | # Need this for relative symlinks. 49 | while [ -h "$PRG" ] ; do 50 | ls=`ls -ld "$PRG"` 51 | link=`expr "$ls" : '.*-> \(.*\)$'` 52 | if expr "$link" : '/.*' > /dev/null; then 53 | PRG="$link" 54 | else 55 | PRG=`dirname "$PRG"`"/$link" 56 | fi 57 | done 58 | SAVED="`pwd`" 59 | cd "`dirname \"$PRG\"`/" >/dev/null 60 | APP_HOME="`pwd -P`" 61 | cd "$SAVED" >/dev/null 62 | 63 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 64 | 65 | # Determine the Java command to use to start the JVM. 66 | if [ -n "$JAVA_HOME" ] ; then 67 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 68 | # IBM's JDK on AIX uses strange locations for the executables 69 | JAVACMD="$JAVA_HOME/jre/sh/java" 70 | else 71 | JAVACMD="$JAVA_HOME/bin/java" 72 | fi 73 | if [ ! -x "$JAVACMD" ] ; then 74 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 75 | 76 | Please set the JAVA_HOME variable in your environment to match the 77 | location of your Java installation." 78 | fi 79 | else 80 | JAVACMD="java" 81 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 82 | 83 | Please set the JAVA_HOME variable in your environment to match the 84 | location of your Java installation." 85 | fi 86 | 87 | # Increase the maximum file descriptors if we can. 88 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then 89 | MAX_FD_LIMIT=`ulimit -H -n` 90 | if [ $? -eq 0 ] ; then 91 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 92 | MAX_FD="$MAX_FD_LIMIT" 93 | fi 94 | ulimit -n $MAX_FD 95 | if [ $? -ne 0 ] ; then 96 | warn "Could not set maximum file descriptor limit: $MAX_FD" 97 | fi 98 | else 99 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 100 | fi 101 | fi 102 | 103 | # For Darwin, add options to specify how the application appears in the dock 104 | if $darwin; then 105 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 106 | fi 107 | 108 | # For Cygwin, switch paths to Windows format before running java 109 | if $cygwin ; then 110 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 111 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 112 | JAVACMD=`cygpath --unix "$JAVACMD"` 113 | 114 | # We build the pattern for arguments to be converted via cygpath 115 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 116 | SEP="" 117 | for dir in $ROOTDIRSRAW ; do 118 | ROOTDIRS="$ROOTDIRS$SEP$dir" 119 | SEP="|" 120 | done 121 | OURCYGPATTERN="(^($ROOTDIRS))" 122 | # Add a user-defined pattern to the cygpath arguments 123 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 124 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 125 | fi 126 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 127 | i=0 128 | for arg in "$@" ; do 129 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 130 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 131 | 132 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 133 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 134 | else 135 | eval `echo args$i`="\"$arg\"" 136 | fi 137 | i=$((i+1)) 138 | done 139 | case $i in 140 | (0) set -- ;; 141 | (1) set -- "$args0" ;; 142 | (2) set -- "$args0" "$args1" ;; 143 | (3) set -- "$args0" "$args1" "$args2" ;; 144 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 145 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 146 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 147 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 148 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 149 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 150 | esac 151 | fi 152 | 153 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules 154 | function splitJvmOpts() { 155 | JVM_OPTS=("$@") 156 | } 157 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS 158 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" 159 | 160 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" 161 | -------------------------------------------------------------------------------- /parser_elfso/src/main/java/com/elfso/data/ElfFile.java: -------------------------------------------------------------------------------- 1 | package com.elfso.data; 2 | 3 | import com.common.LogUtil; 4 | import com.elf.excep.FormatException; 5 | import com.elfso.stream.BigEndianStreamer; 6 | import com.elfso.stream.LittleEndianStreamer; 7 | import com.elfso.stream.ElfStreamer; 8 | 9 | import java.io.IOException; 10 | import java.io.RandomAccessFile; 11 | 12 | /** 13 | * 14 | * Created by xueqiulxq on 07/07/2017. 15 | */ 16 | 17 | public class ElfFile { 18 | 19 | private static final String TAG = ElfFile.class.getSimpleName(); 20 | 21 | // Tools 22 | private ElfStreamer mStreamer; 23 | // Sections 24 | public Eident eident; 25 | public ElfHeader elfHeader; 26 | public ProgramHeader[] programHeaders; 27 | public SectionHeader[] sectionHeaders; 28 | public StringTable shStringTable; 29 | 30 | public ElfFile() { 31 | 32 | } 33 | 34 | public void parse(RandomAccessFile racFile) throws IOException, FormatException { 35 | 36 | racFile.seek(0); 37 | 38 | // Determine endian 39 | eident = parseIdent(racFile); 40 | if (eident.ei_data == Eident.ELFDATA2MSB) { 41 | mStreamer = new BigEndianStreamer(); 42 | } else if (eident.ei_data == Eident.ELFDATA2LSB) { 43 | mStreamer = new LittleEndianStreamer(); 44 | } else { 45 | throw new FormatException("Illegal data format"); 46 | } 47 | 48 | // Elf header 49 | elfHeader = parseHeader(racFile); 50 | 51 | // Program headers 52 | programHeaders = parseProgramHeader(racFile); 53 | 54 | // Section headers 55 | sectionHeaders = parseSectionHeaders(racFile); 56 | 57 | // String table 58 | shStringTable = parseShStringTable(racFile); 59 | 60 | completeElfDetails(racFile); 61 | 62 | LogUtil.i(TAG, "Parse end!\n"); 63 | } 64 | 65 | @Override 66 | public String toString() { 67 | 68 | StringBuilder builder = new StringBuilder(4096); 69 | 70 | builder.append(elfHeader).append('\n'); 71 | 72 | for (int i=0; i\n"); 126 | builder.append(String.format(form2, "size", size)); 127 | builder.append(String.format(union2, "mcc", PrintUtil.hex2(mcc), "mnc", PrintUtil.hex2(mnc), "imsi", PrintUtil.hex4(imsi))); 128 | builder.append(String.format(union2, "language", PrintUtil.hex2(language), "country", PrintUtil.hex2(country), "locale", PrintUtil.hex4(locale))); 129 | builder.append(String.format(union3, "orientation", PrintUtil.hex1(orientation), "touchScreen", PrintUtil.hex1(touchScreen), "density", PrintUtil.hex2(density), "screenType", PrintUtil.hex4(screenType))); 130 | builder.append(String.format(union4, "keyboard", PrintUtil.hex1(keyboard), "navigation", PrintUtil.hex1(navigation), "inputFlags", PrintUtil.hex2(inputFlags), "inputPad0", PrintUtil.hex2(inputPad0), "input", PrintUtil.hex4(input))); 131 | builder.append(String.format(union2, "screenWidth", PrintUtil.hex2(screenWidth), "screenHeight", PrintUtil.hex2(screenHeight), "screenSize", PrintUtil.hex4(screenSize))); 132 | builder.append(String.format(union2, "sdkVersion", PrintUtil.hex2(sdkVersion), "minorVersion", PrintUtil.hex2(minorVersion), "version", PrintUtil.hex4(version))); 133 | builder.append(String.format(union3, "screenLayout", PrintUtil.hex1(screenLayout), "uiModeByte", PrintUtil.hex1(uiModeByte), "smallestScreenWidthDp", PrintUtil.hex2(smallestScreenWidthDp), "screenConfig", PrintUtil.hex4(screenConfig))); 134 | builder.append(String.format(union2, "screenWidthDp", PrintUtil.hex2(screenWidthDp), "screenHeightDp", PrintUtil.hex2(screenHeightDp), "screenSizeDp", PrintUtil.hex4(screenSizeDp))); 135 | builder.append("localeScript: "); 136 | for (int i=0; i\n"); 146 | return builder.toString(); 147 | } 148 | } 149 | -------------------------------------------------------------------------------- /common/src/main/java/com/common/stream/RandomAccessStreamer.java: -------------------------------------------------------------------------------- 1 | package com.common.stream; 2 | 3 | import com.common.LogUtil; 4 | 5 | import java.io.IOException; 6 | import java.io.RandomAccessFile; 7 | 8 | /** 9 | * 10 | * Created by xueqiulxq on 16/07/2017. 11 | */ 12 | 13 | public class RandomAccessStreamer { 14 | 15 | public enum Endian { 16 | Little, Big 17 | } 18 | 19 | private byte[] mData = new byte[8]; 20 | private int cursor = 0; 21 | 22 | public RandomAccessStreamer() { 23 | } 24 | 25 | public void use(byte[] data) { 26 | mData = data; 27 | cursor = 0; 28 | } 29 | 30 | public int length() { 31 | return mData != null ? mData.length : 0; 32 | } 33 | 34 | public int skipBytes(int len) { 35 | int newCursor = cursor + len; 36 | if (newCursor > mData.length) { 37 | newCursor = mData.length; 38 | } 39 | int skipNum = newCursor - cursor; 40 | cursor = newCursor; 41 | return skipNum; 42 | } 43 | 44 | public int getCursor() { 45 | return cursor; 46 | } 47 | 48 | public void seek(long pos) { 49 | if (pos < 0) { 50 | cursor = 0; 51 | } else if (pos > mData.length) { 52 | cursor = mData.length; 53 | } else { 54 | cursor = (int) pos; 55 | } 56 | } 57 | 58 | /** 59 | * If len > 0 read len bytes else if len < 0 read to the end. 60 | * @param len length of bytes to read 61 | * @return byte array 62 | */ 63 | public byte[] read(int len) { 64 | if (cursor >= mData.length) { 65 | LogUtil.e("Stream has finished!!"); 66 | return null; 67 | } 68 | if (cursor + len > mData.length) { 69 | LogUtil.e(String.format("Cannot read %d bytes with only %d remains. Return %bytes!", 70 | len, mData.length - cursor, mData.length - cursor)); 71 | len = mData.length - cursor; 72 | } else if (len < 0) { 73 | len = mData.length - cursor; 74 | } 75 | byte[] ret = new byte[len]; 76 | System.arraycopy(mData, cursor, ret, 0, len); 77 | cursor += len; 78 | return ret; 79 | } 80 | 81 | protected long readUnsignedInt(Endian endian) { 82 | byte[] buf = read(4); 83 | long ret = 0; 84 | if (endian == Endian.Little) { 85 | for (int i=3; i>=0; --i) { 86 | ret <<= 8; 87 | ret |= (buf[i] & 0xff); 88 | } 89 | } else { 90 | for (int i=0; i<=3; ++i) { 91 | ret <<= 8; 92 | ret |= (buf[i] & 0xff); 93 | } 94 | } 95 | return ret; 96 | } 97 | 98 | protected int readSignedInt(Endian endian) { 99 | byte[] buf = read(4); 100 | int ret = 0; 101 | if (endian == Endian.Little) { 102 | for (int i=3; i>=0; --i) { 103 | ret <<= 8; 104 | ret |= (buf[i] & 0xff); 105 | } 106 | } else { 107 | for (int i=0; i<=3; ++i) { 108 | ret <<= 8; 109 | ret |= (buf[i] & 0xff); 110 | } 111 | } 112 | return ret; 113 | } 114 | 115 | public byte[] readUleb128BytesFrom(RandomAccessFile racFile) throws IOException { 116 | 117 | byte[] buf = new byte[1]; 118 | long len = 0; 119 | long remain = racFile.length() - racFile.getFilePointer(); 120 | for (int i=0; i", entry.data, entry.type); 105 | } 106 | 107 | return attrData; 108 | } 109 | 110 | public static final int COMPLEX_UNIT_SHIFT = 0; 111 | public static final int COMPLEX_UNIT_MASK = 0xf; 112 | public static final int COMPLEX_UNIT_PX = 0; 113 | public static final int COMPLEX_UNIT_DIP = 1; 114 | public static final int COMPLEX_UNIT_SP = 2; 115 | public static final int COMPLEX_UNIT_PT = 3; 116 | public static final int COMPLEX_UNIT_IN = 4; 117 | public static final int COMPLEX_UNIT_MM = 5; 118 | public static final int COMPLEX_UNIT_FRACTION = 6; 119 | public static final int COMPLEX_UNIT_FRACTION_PARENT = 7; 120 | 121 | private static String getDimenUnit(long data) { 122 | //noinspection PointlessBitwiseExpression 123 | switch ((int) (data >> COMPLEX_UNIT_SHIFT & COMPLEX_UNIT_MASK)) { 124 | case COMPLEX_UNIT_PX: return "px"; 125 | case COMPLEX_UNIT_DIP: return "dp"; 126 | case COMPLEX_UNIT_SP: return "sp"; 127 | case COMPLEX_UNIT_PT: return "pt"; 128 | case COMPLEX_UNIT_IN: return "in"; 129 | case COMPLEX_UNIT_MM: return "mm"; 130 | default: return " (unknown unit)"; 131 | } 132 | } 133 | 134 | private static String getFractionUnit(long data) { 135 | //noinspection PointlessBitwiseExpression 136 | switch ((int) (data >> COMPLEX_UNIT_SHIFT & COMPLEX_UNIT_MASK)) { 137 | case COMPLEX_UNIT_FRACTION: return "%%"; 138 | case COMPLEX_UNIT_FRACTION_PARENT: return "%%p"; 139 | default: return " (unknown unit)"; 140 | } 141 | } 142 | 143 | private static String getPackage(long data) { 144 | return "ref"; 145 | } 146 | } 147 | -------------------------------------------------------------------------------- /parser_elfso/src/main/java/com/elfso/data/ElfHeader.java: -------------------------------------------------------------------------------- 1 | package com.elfso.data; 2 | 3 | import com.common.PrintUtil; 4 | import com.elfso.stream.ElfStreamer; 5 | 6 | /** 7 | * 8 | * Created by xueqiulxq on 07/07/2017. 9 | */ 10 | 11 | public class ElfHeader { 12 | 13 | public static final int LENGTH = 0x34; 14 | 15 | // e_type 16 | public static final int ET_NONE = 0; 17 | public static final int ET_REL = 1; 18 | public static final int ET_EXEC = 2; 19 | public static final int ET_DYN = 3; 20 | public static final int ET_CORE = 4; 21 | public static final int ET_LOPROC = 0Xff00; 22 | public static final int ET_HIPROC = 0xffff; 23 | // e_machine 24 | public static final int EM_NONE = 0; 25 | public static final int EM_M32 = 1; 26 | public static final int EM_SPARC = 2; 27 | public static final int EM_386 = 3; 28 | public static final int EM_68K = 4; 29 | public static final int EM_88 = 5; 30 | public static final int EM_860 = 7; 31 | public static final int EM_MIPS = 8; 32 | public static final int EM_MIPS_RS4_BE = 10; 33 | public static final int EM_SPARC64 = 11; 34 | public static final int EM_PARISC = 15; 35 | public static final int EM_SPARC32PLUS = 18; 36 | public static final int EM_PPC = 20; 37 | public static final int EM_ARM = 40; 38 | public static final int EM_ALPHA = 41; 39 | public static final int EM_SPARCV9 = 43; 40 | public static final int EM_ALPHA_EXP = 0x9026; 41 | public static final int EM_AMD64 = 62; 42 | public static final int EM_VAX = 75; 43 | public static final int EM_NUM = 15; 44 | // e_version 45 | public static final int EV_NONE = 0; 46 | public static final int EV_CURRENT = 1; 47 | 48 | public Eident e_indent; // ELF Identification 49 | public int e_type; // 10h Elf32_Half object file type 50 | public int e_machine; // 12h Elf32_Half machine 51 | public long e_version; // 14h Elf32_Word object file version 52 | public long e_entry; // 18h Elf32_Addr virtual entry point 53 | public long e_phoff; // 1ch Elf32_Off program header table offset 54 | public long e_shoff; // 20h Elf32_Off section header table offset 55 | public long e_flags; // 24h Elf32_Word processor-specific flags 56 | public int e_ehsize; // 28h Elf32_Half ELF header size 57 | public int e_phentsize; // 2ah Elf32_Half program header entry size 58 | public int e_phnum; // 2ch Elf32_Half number of program header entries 59 | public int e_shentsize; // 2eh Elf32_Half section header entry size 60 | public int e_shnum; // 30h Elf32_Half number of section header entries 61 | public int e_shstrndx; // 32h Elf32_Half section header table's section header string table entry offset 62 | 63 | public static ElfHeader parseFrom(ElfStreamer s) { 64 | ElfHeader header = new ElfHeader(); 65 | header.e_indent = Eident.parseFrom(s.read(Eident.EI_NIDENT)); 66 | header.e_type = s.readElf32Half(); 67 | header.e_machine = s.readElf32Half(); 68 | header.e_version = s.readElf32Word(); 69 | header.e_entry = s.readElf32Addr(); 70 | header.e_phoff = s.readElf32Off(); 71 | header.e_shoff = s.readElf32Off(); 72 | header.e_flags = s.readElf32Word(); 73 | header.e_ehsize = s.readElf32Half(); 74 | header.e_phentsize = s.readElf32Half(); 75 | header.e_phnum = s.readElf32Half(); 76 | header.e_shentsize = s.readElf32Half(); 77 | header.e_shnum = s.readElf32Half(); 78 | header.e_shstrndx = s.readElf32Half(); 79 | return header; 80 | } 81 | 82 | @Override 83 | public String toString() { 84 | StringBuilder builder = new StringBuilder(); 85 | builder.append("Elf header:\n"); 86 | builder.append(this.e_indent); 87 | 88 | String form1 = "%-12s\t"; 89 | builder.append(String.format(form1, "e_type")); 90 | switch (e_type) { 91 | case ET_NONE: builder.append("ET_NONE"); break; 92 | case ET_REL: builder.append("ET_REL"); break; 93 | case ET_EXEC: builder.append("ET_EXEC"); break; 94 | case ET_DYN: builder.append("ET_DYN"); break; 95 | case ET_CORE: builder.append("ET_CORE"); break; 96 | case ET_LOPROC: builder.append("ET_LOPROC"); break; 97 | case ET_HIPROC: builder.append("ET_HIPROC"); break; 98 | default: builder.append(PrintUtil.hex2(e_type)); 99 | } 100 | builder.append('\n'); 101 | 102 | builder.append(String.format(form1, "e_machine")); 103 | switch (e_machine) { 104 | case EM_NONE: builder.append("EM_NONE"); break; 105 | case EM_M32: builder.append("EM_M32"); break; 106 | case EM_SPARC: builder.append("EM_SPARC"); break; 107 | case EM_386: builder.append("EM_386"); break; 108 | case EM_68K: builder.append("EM_68K"); break; 109 | case EM_88: builder.append("EM_88"); break; 110 | case EM_860: builder.append("EM_860"); break; 111 | case EM_MIPS: builder.append("EM_MIPS"); break; 112 | case EM_MIPS_RS4_BE: builder.append("EM_MIPS_RS4_BE"); break; 113 | case EM_SPARC64: builder.append("EM_SPARC64"); break; 114 | case EM_PARISC: builder.append("EM_PARISC"); break; 115 | case EM_SPARC32PLUS: builder.append("EM_SPARC32PLUS"); break; 116 | case EM_PPC: builder.append("EM_PPC"); break; 117 | case EM_ARM: builder.append("EM_ARM"); break; 118 | case EM_ALPHA: builder.append("EM_ALPHA"); break; 119 | case EM_SPARCV9: builder.append("EM_SPARCV9"); break; 120 | case EM_ALPHA_EXP: builder.append("EM_ALPHA_EXP"); break; 121 | case EM_AMD64: builder.append("EM_AMD64"); break; 122 | case EM_VAX: builder.append("EM_VAX"); break; 123 | default: builder.append(PrintUtil.hex2(e_machine)); 124 | } 125 | 126 | builder.append('\n'); 127 | 128 | String form2 = "%-12s\t%s\n"; 129 | builder.append(String.format(form2, "e_version", PrintUtil.hex4(e_version))); 130 | builder.append(String.format(form2, "e_entry", PrintUtil.hex4(e_entry))); 131 | builder.append(String.format(form2, "e_phoff", PrintUtil.hex4(e_phoff))); 132 | builder.append(String.format(form2, "e_shoff", PrintUtil.hex4(e_shoff))); 133 | builder.append(String.format(form2, "e_flags", PrintUtil.hex4(e_flags))); 134 | 135 | builder.append(String.format(form2, "e_ehsize", PrintUtil.hex2(e_ehsize))); 136 | builder.append(String.format(form2, "e_phentsize", PrintUtil.hex2(e_phentsize))); 137 | builder.append(String.format(form2, "e_phnum", PrintUtil.hex2(e_phnum))); 138 | builder.append(String.format(form2, "e_shentsize", PrintUtil.hex2(e_shentsize))); 139 | builder.append(String.format(form2, "e_shnum", PrintUtil.hex2(e_shnum))); 140 | builder.append(String.format(form2, "e_shstrndx", PrintUtil.hex2(e_shstrndx))); 141 | return builder.toString(); 142 | } 143 | } 144 | -------------------------------------------------------------------------------- /parser_arsc/src/main/java/com/arsc/data/ResTableTypeInfoChunk.java: -------------------------------------------------------------------------------- 1 | package com.arsc.data; 2 | 3 | import com.arsc.stream.ArscStreamer; 4 | import com.common.PrintUtil; 5 | 6 | import java.util.List; 7 | 8 | /** 9 | * 10 | * Created by xueqiulxq on 26/07/2017. 11 | */ 12 | 13 | public class ResTableTypeInfoChunk extends BaseTypeChunk { 14 | 15 | public static final long NO_ENTRY = 0xffffffffL; 16 | 17 | public ChunkHeader header; 18 | public int typeId; // 1byte resource type 0x00ff0000 19 | public int res0; // 1byte 20 | public int res1; // 2byte 21 | public long entryCount; 22 | public long entriesStart; // start of table entries. 23 | public ResTableConfig resConfig; 24 | 25 | // Data Block 26 | public long[] entryOffsets; // offset of table entries. 27 | public ResTableEntry[] tableEntries; 28 | 29 | public static ResTableTypeInfoChunk parseFrom(ArscStreamer s, ResStringPoolChunk stringChunk) { 30 | ResTableTypeInfoChunk chunk = new ResTableTypeInfoChunk(); 31 | int start = s.getCursor(); 32 | chunk.header = ChunkHeader.parseFrom(s); 33 | chunk.typeId = s.readUInt8(); 34 | chunk.res0 = s.readUInt8(); 35 | chunk.res1 = s.readUShort(); 36 | chunk.entryCount = s.readUInt(); 37 | chunk.entriesStart = s.readUInt(); 38 | chunk.resConfig = ResTableConfig.parseFrom(s); 39 | 40 | chunk.entryOffsets = new long[(int) chunk.entryCount]; 41 | for (int i=0; i typeInfos) { 131 | StringBuilder builder = new StringBuilder(); 132 | 133 | int configCount = typeInfos.size(); 134 | int entryCount = (int) typeInfos.get(0).entryCount; 135 | 136 | for (int i=0; i 0) { 140 | builder.append(entryStr); 141 | break; // This entryId has done. 142 | } 143 | } 144 | } 145 | return builder.toString(); 146 | } 147 | 148 | @Override 149 | public String getChunkName() { 150 | return "ResTableTypeInfoChunk"; 151 | } 152 | 153 | @Override 154 | public long getEntryCount() { 155 | return entryCount; 156 | } 157 | 158 | @Override 159 | public String getType() { 160 | return String.format("0x%s", PrintUtil.hex1(typeId)); 161 | } 162 | 163 | public int getTypeId() { 164 | return typeId; 165 | } 166 | 167 | @Override 168 | public void translateValues(ResStringPoolChunk globalStringPool, ResStringPoolChunk typeStringPool, ResStringPoolChunk keyStringPool) { 169 | for (ResTableEntry entry : tableEntries) { 170 | if (entry != null) { 171 | entry.translateValues(globalStringPool, typeStringPool, keyStringPool); 172 | } 173 | } 174 | } 175 | 176 | public ResTableEntry getResource(int resId) { 177 | int entryId = resId & 0x0000ffff; 178 | return entryId < tableEntries.length ? tableEntries[entryId] : null; 179 | } 180 | } 181 | -------------------------------------------------------------------------------- /parser_arsc/src/main/java/com/arsc/data/ResTablePackageChunk.java: -------------------------------------------------------------------------------- 1 | package com.arsc.data; 2 | 3 | import com.arsc.stream.ArscStreamer; 4 | import com.common.LogUtil; 5 | import com.common.PrintUtil; 6 | 7 | import java.util.ArrayList; 8 | import java.util.HashMap; 9 | import java.util.List; 10 | import java.util.Map; 11 | 12 | /** 13 | * 14 | * Created by xueqiulxq on 26/07/2017. 15 | */ 16 | 17 | public class ResTablePackageChunk { 18 | 19 | public static final String TAG = ResTablePackageChunk.class.getSimpleName(); 20 | 21 | public static final int RES_TABLE_TYPE_SPEC_TYPE = 0x0202; 22 | public static final int RES_TABLE_TYPE_TYPE = 0x0201; 23 | 24 | // Header Block 0x0120 25 | public ChunkHeader header; 26 | public long pkgId; // 0x0000007f->UserResources 0x00000001->SystemResources 27 | public String packageName; 28 | public long typeStringOffset; // Offset in this chunk 29 | public long lastPublicType; // Num of type string 30 | public long keyStringOffset; // Offset in chunk 31 | public long lastPublicKey; // Num of key string 32 | 33 | // DataBlock 34 | public ResStringPoolChunk typeStringPool; 35 | public ResStringPoolChunk keyStringPool; 36 | public List typeChunks; 37 | 38 | // Create Index 39 | public Map> typeInfoIndexer; 40 | 41 | public static ResTablePackageChunk parseFrom(ArscStreamer s, ResStringPoolChunk stringChunk) { 42 | ResTablePackageChunk chunk = new ResTablePackageChunk(); 43 | chunk.header = ChunkHeader.parseFrom(s); 44 | chunk.pkgId = s.readUInt(); 45 | chunk.packageName = s.readNullEndString16(128 * 2); 46 | chunk.typeStringOffset = s.readUInt(); 47 | chunk.lastPublicType = s.readUInt(); 48 | chunk.keyStringOffset = s.readUInt(); 49 | chunk.lastPublicKey = s.readUInt(); 50 | 51 | // Data Block 52 | s.seek(chunk.typeStringOffset); 53 | chunk.typeStringPool = ResStringPoolChunk.parseFrom(s); 54 | s.seek(chunk.keyStringOffset); 55 | chunk.keyStringPool = ResStringPoolChunk.parseFrom(s); 56 | 57 | // TableTypeSpecType TableTypeType 58 | s.seek(chunk.keyStringOffset + chunk.keyStringPool.header.chunkSize); 59 | chunk.typeChunks = new ArrayList(); 60 | int resCount = 0; 61 | StringBuilder logInfo = new StringBuilder(); 62 | while (s.getCursor() < s.length()) { 63 | 64 | logInfo.setLength(0); 65 | resCount++; 66 | ChunkHeader header = ChunkHeader.parseFrom(s); 67 | s.seek(s.getCursor() - ChunkHeader.LENGTH); 68 | 69 | BaseTypeChunk typeChunk = null; 70 | if (header.type == RES_TABLE_TYPE_SPEC_TYPE) { 71 | typeChunk = ResTableTypeSpecChunk.parseFrom(s, stringChunk); 72 | } else if (header.type == RES_TABLE_TYPE_TYPE){ 73 | typeChunk = ResTableTypeInfoChunk.parseFrom(s, stringChunk); 74 | } 75 | if (typeChunk != null) { 76 | logInfo.append(typeChunk.getChunkName()).append(" ") 77 | .append(String.format("type=%s ", typeChunk.getType())) 78 | .append(String.format("count=%s ", typeChunk.getEntryCount())); 79 | } else { 80 | logInfo.append("None TableTypeSpecType or TableTypeType!!"); 81 | } 82 | LogUtil.i(TAG, logInfo.toString()); 83 | chunk.typeChunks.add(typeChunk); 84 | } 85 | 86 | chunk.createResourceIndex(); 87 | for (int i=0; i\n"); 129 | builder.append("\n\t"); 130 | 131 | for (int i = 0; i typeInfos = new ArrayList(); 136 | for (int j = i + 1; j"); 152 | return builder.toString(); 153 | } 154 | 155 | private void createResourceIndex() { 156 | typeInfoIndexer = new HashMap>(); 157 | for (BaseTypeChunk typeChunk : typeChunks) { 158 | // The first chunk in typeList should be ResTableTypeSpecChunk 159 | List typeList = typeInfoIndexer.get(typeChunk.getTypeId()); 160 | if (typeList == null) { 161 | typeList = new ArrayList(); 162 | typeInfoIndexer.put(typeChunk.getTypeId(), typeList); 163 | } 164 | typeList.add(typeChunk); 165 | } 166 | } 167 | 168 | public ResTableEntry getResource(int resId) { 169 | int typeId = (resId & 0x00ff0000) >> 16; 170 | List typeList = typeInfoIndexer.get(typeId); // The first chunk in typeList should be ResTableTypeSpecChunk 171 | for (int i=1; i\n"); 79 | builder.append(String.format(form, "size", PrintUtil.hex2(size))); 80 | builder.append(String.format(form, "res0", PrintUtil.hex1(res0))); 81 | builder.append(String.format(form3, "dataType", PrintUtil.hex1(dataType), getTypeStr())); 82 | builder.append(String.format(form, "data", PrintUtil.hex4(data))); 83 | builder.append(String.format(form, "dataStr", dataStr)); 84 | builder.append("\n"); 85 | return builder.toString(); 86 | } 87 | 88 | public String getTypeStr(){ 89 | switch(dataType){ 90 | case TYPE_NULL: 91 | return "TYPE_NULL"; 92 | case TYPE_REFERENCE: 93 | return "TYPE_REFERENCE"; 94 | case TYPE_ATTRIBUTE: 95 | return "TYPE_ATTRIBUTE"; 96 | case TYPE_STRING: 97 | return "TYPE_STRING"; 98 | case TYPE_FLOAT: 99 | return "TYPE_FLOAT"; 100 | case TYPE_DIMENSION: 101 | return "TYPE_DIMENSION"; 102 | case TYPE_FRACTION: 103 | return "TYPE_FRACTION"; 104 | case TYPE_FIRST_INT: 105 | return "TYPE_FIRST_INT"; 106 | case TYPE_INT_HEX: 107 | return "TYPE_INT_HEX"; 108 | case TYPE_INT_BOOLEAN: 109 | return "TYPE_INT_BOOLEAN"; 110 | case TYPE_FIRST_COLOR_INT: 111 | return "TYPE_FIRST_COLOR_INT"; 112 | case TYPE_INT_COLOR_RGB8: 113 | return "TYPE_INT_COLOR_RGB8"; 114 | case TYPE_INT_COLOR_ARGB4: 115 | return "TYPE_INT_COLOR_ARGB4"; 116 | case TYPE_INT_COLOR_RGB4: 117 | return "TYPE_INT_COLOR_RGB4"; 118 | } 119 | return "Unknown"; 120 | } 121 | 122 | public String getDataStr(ResStringPoolChunk stringPool) { 123 | String dataStr; 124 | if (dataType == TYPE_REFERENCE) { 125 | dataStr = String.format("@%s/0x%08x", getPackage(data), data); 126 | } else if (dataType == TYPE_ATTRIBUTE) { 127 | dataStr = String.format("?%s/0x%08x", getPackage(data), data); 128 | } else if (dataType == TYPE_STRING) { 129 | dataStr = stringPool.getString((int) data); 130 | } else if (dataType == TYPE_FLOAT) { 131 | dataStr = String.valueOf(Float.intBitsToFloat((int) data)); 132 | } else if (dataType == TYPE_DIMENSION) { 133 | dataStr = Float.toString(complexToFloat((int) data)) + getDimenUnit(data); 134 | } else if (dataType == TYPE_FRACTION) { 135 | dataStr = Float.toString(complexToFloat((int) data)) + getFractionUnit(data); 136 | } else if (dataType == TYPE_DYNAMIC_REFERENCE) { 137 | dataStr = "TYPE_DYNAMIC_REFERENCE"; 138 | } else if (dataType == TYPE_INT_DEC) { 139 | dataStr = String.format("%d", data); 140 | } else if (dataType == TYPE_INT_HEX) { 141 | dataStr = String.format("0x%08x", data); 142 | } else if (dataType == TYPE_INT_BOOLEAN) { 143 | dataStr = data == 0 ? "false" : "true"; 144 | } else if (dataType == TYPE_INT_COLOR_ARGB8) { 145 | dataStr = String.format("#%08x", data); 146 | } else if (dataType == TYPE_INT_COLOR_RGB8) { 147 | dataStr = String.format("#ff%06x", 0xffffff & data); 148 | } else if (dataType == TYPE_INT_COLOR_ARGB4) { 149 | dataStr = String.format("#%04x", 0xffff & data); 150 | } else if (dataType == TYPE_INT_COLOR_RGB4) { 151 | dataStr = String.format("#f%03x", 0x0fff & data); 152 | } else { 153 | dataStr = String.format("<0x%08x, type 0x%08x>", data, dataType); 154 | } 155 | return dataStr; 156 | } 157 | 158 | private static String getPackage(long id) { 159 | if (id >>> 24 == 1) { 160 | return "android:"; 161 | } 162 | return ""; 163 | } 164 | 165 | public static float complexToFloat(int complex) { 166 | return (float) (complex & 0xFFFFFF00) * RADIX_MULTS[(complex>>4) & 3]; 167 | } 168 | 169 | private static final float RADIX_MULTS[]={ 170 | 0.00390625F,3.051758E-005F,1.192093E-007F,4.656613E-010F 171 | }; 172 | 173 | private static final String DIMENSION_UNITS[]={ 174 | "px","dip","sp","pt","in","mm","","" 175 | }; 176 | 177 | private static final String FRACTION_UNITS[]={ 178 | "%","%p","","","","","","" 179 | }; 180 | 181 | private static String getDimenUnit(long data) { 182 | //noinspection PointlessBitwiseExpression 183 | switch ((int) (data >> COMPLEX_UNIT_SHIFT & COMPLEX_UNIT_MASK)) { 184 | case COMPLEX_UNIT_PX: return "px"; 185 | case COMPLEX_UNIT_DIP: return "dp"; 186 | case COMPLEX_UNIT_SP: return "sp"; 187 | case COMPLEX_UNIT_PT: return "pt"; 188 | case COMPLEX_UNIT_IN: return "in"; 189 | case COMPLEX_UNIT_MM: return "mm"; 190 | default: return " (unknown unit)"; 191 | } 192 | } 193 | 194 | private static String getFractionUnit(long data) { 195 | //noinspection PointlessBitwiseExpression 196 | switch ((int) (data >> COMPLEX_UNIT_SHIFT & COMPLEX_UNIT_MASK)) { 197 | case COMPLEX_UNIT_FRACTION: return "%"; 198 | case COMPLEX_UNIT_FRACTION_PARENT: return "%p"; 199 | default: return " (unknown unit)"; 200 | } 201 | } 202 | } 203 | -------------------------------------------------------------------------------- /parser_manifest/src/main/java/com/manifest/data/MfFile.java: -------------------------------------------------------------------------------- 1 | package com.manifest.data; 2 | 3 | import com.common.LogUtil; 4 | import com.manifest.stream.LittleEndianStreamer; 5 | import com.manifest.stream.MfStreamer; 6 | 7 | import java.io.IOException; 8 | import java.io.RandomAccessFile; 9 | import java.util.ArrayList; 10 | import java.util.List; 11 | import java.util.Map; 12 | 13 | /** 14 | * 15 | * Created by xueqiulxq on 16/07/2017. 16 | */ 17 | 18 | public class MfFile { 19 | 20 | private static final String TAG = MfFile.class.getSimpleName(); 21 | 22 | private MfStreamer mStreamer; 23 | public MfHeader header; 24 | public StringChunk stringChunk; 25 | public ResourceIdChunk resourceIdChunk; 26 | public StartNamespaceChunk startNamespaceChunk; 27 | public List startTagChunks; 28 | public List endTagChunks; 29 | public List tagChunks; 30 | public EndNamespaceChunk endNamespaceChunk; 31 | 32 | public MfFile() { 33 | startTagChunks = new ArrayList(); 34 | endTagChunks = new ArrayList(); 35 | tagChunks = new ArrayList(); 36 | } 37 | 38 | public void parse(RandomAccessFile racFile) throws IOException { 39 | racFile.seek(0); 40 | mStreamer = new LittleEndianStreamer(); 41 | 42 | byte[] headerBytes = new byte[MfHeader.LENGTH]; 43 | racFile.read(headerBytes, 0, headerBytes.length); 44 | header = parseHeader(headerBytes); 45 | 46 | int chunkIdx = 0; 47 | int cursor = MfHeader.LENGTH; 48 | do { 49 | byte[] infoBytes = new byte[ChunkInfo.LENGTH]; 50 | cursor += racFile.read(infoBytes, 0, infoBytes.length); 51 | mStreamer.use(infoBytes); 52 | ChunkInfo info = ChunkInfo.parseFrom(mStreamer); 53 | info.chunkIndex = chunkIdx++; 54 | 55 | // Chunk size = ChunkInfo + BodySize 56 | byte[] chunkBytes = new byte[(int)info.chunkSize]; 57 | System.arraycopy(infoBytes, 0, chunkBytes, 0, ChunkInfo.LENGTH); 58 | cursor += racFile.read(chunkBytes, ChunkInfo.LENGTH, (int)info.chunkSize - ChunkInfo.LENGTH); 59 | StartTagChunk startTagChunk; 60 | EndTagChunk endTagChunk; 61 | switch ((int)info.chunkType) { 62 | case ChunkInfo.STRING_CHUNK_ID: 63 | stringChunk = parseStringChunk(chunkBytes); 64 | break; 65 | case ChunkInfo.RESOURCE_ID_CHUNK_ID: 66 | resourceIdChunk = parseResourceIdChunk(chunkBytes); 67 | break; 68 | case ChunkInfo.START_NAMESPACE_CHUNK_ID: 69 | startNamespaceChunk = parseStartNamespaceChunk(chunkBytes); 70 | break; 71 | case ChunkInfo.START_TAG_CHUNK_ID: 72 | startTagChunk = parseStartTagChunk(chunkBytes); 73 | startTagChunks.add(startTagChunk); 74 | tagChunks.add(startTagChunk); 75 | break; 76 | case ChunkInfo.EDN_TAG_CHUNK_ID: 77 | endTagChunk = parseEndTagChunk(chunkBytes); 78 | endTagChunks.add(endTagChunk); 79 | tagChunks.add(endTagChunk); 80 | break; 81 | case ChunkInfo.CHUNK_ENDNS_CHUNK_ID: 82 | endNamespaceChunk = parseEndNamespaceChunk(chunkBytes); 83 | break; 84 | default: 85 | break; 86 | } 87 | LogUtil.i(TAG, info.toString()); 88 | } while (cursor < header.fileLength); 89 | } 90 | 91 | @Override 92 | public String toString() { 93 | StringBuilder builder = new StringBuilder(4096); 94 | builder.append('\n'); 95 | builder.append(header).append('\n'); 96 | builder.append(stringChunk).append('\n'); 97 | builder.append(resourceIdChunk).append('\n'); 98 | builder.append(startNamespaceChunk).append('\n'); 99 | 100 | builder.append("-- StartTag Chunks --").append('\n'); 101 | for (int i=0; i\n"); 122 | for (TagChunk tagChunk : tagChunks) { 123 | if (tagChunk instanceof StartTagChunk) { 124 | builder.append(createStartTagXml((StartTagChunk) tagChunk, depth)); 125 | ++depth; 126 | } else if (tagChunk instanceof EndTagChunk) { 127 | --depth; 128 | builder.append(createEndTagXml((EndTagChunk) tagChunk, depth)); 129 | } 130 | } 131 | return builder.toString(); 132 | } 133 | 134 | 135 | private String createStartTagXml(StartTagChunk chunk, int depth) { 136 | StringBuilder builder = new StringBuilder(256); 137 | String lineIndent = makeLineIndent(depth, 4); 138 | if ("manifest".equals(chunk.nameStr)) { 139 | builder.append(" entry : startNamespaceChunk.prefix2UriMap.entrySet()) { 141 | builder.append(" ").append("xmlns:").append(entry.getKey()).append("=") 142 | .append("\"").append(entry.getValue()).append("\""); 143 | } 144 | } else { 145 | builder.append(lineIndent); 146 | builder.append("<").append(chunk.nameStr); 147 | } 148 | List attrEntries = chunk.attributes; 149 | if (attrEntries.size() > 0) { 150 | for (AttributeEntry entry : attrEntries) { 151 | 152 | builder.append("\n"); 153 | builder.append(lineIndent).append(" "); 154 | String prefixName = startNamespaceChunk.uri2prefixMap.get(entry.namespaceUriStr); 155 | if (prefixName != null) { 156 | builder.append(prefixName).append(':'); 157 | } 158 | builder.append(entry.nameStr).append('=') 159 | .append("\"").append(entry.dataStr).append("\""); 160 | } 161 | } 162 | builder.append(" >\n"); 163 | return builder.toString(); 164 | } 165 | 166 | private String createEndTagXml(EndTagChunk chunk, int depth) { 167 | StringBuilder builder = new StringBuilder(256); 168 | String lineIndent = makeLineIndent(depth, 4); 169 | builder.append(lineIndent); 170 | builder.append("").append('\n'); 171 | return builder.toString(); 172 | } 173 | 174 | private String makeLineIndent(int depth, int indent) { 175 | StringBuilder builder = new StringBuilder(depth * indent); 176 | for (int i=0; i