├── ic_launcher-web.png ├── libs └── armeabi │ └── libdexparser.so ├── res ├── drawable-hdpi │ └── ic_launcher.png ├── drawable-mdpi │ └── ic_launcher.png ├── drawable-xhdpi │ └── ic_launcher.png ├── drawable-xxhdpi │ └── ic_launcher.png ├── values-sw600dp │ └── dimens.xml ├── values │ ├── dimens.xml │ ├── strings.xml │ └── styles.xml ├── menu │ └── main.xml ├── values-sw720dp-land │ └── dimens.xml ├── values-v11 │ └── styles.xml ├── values-v14 │ └── styles.xml └── layout │ └── activity_main.xml ├── gen └── com │ └── freshui │ └── dextamper │ ├── BuildConfig.java │ └── R.java ├── .gitattributes ├── project.properties ├── proguard-project.txt ├── src └── com │ └── freshui │ └── dextamper │ ├── GameControl.java │ └── MainActivity.java ├── jni ├── Android.mk ├── dexFile.h └── dexFileParser.cpp ├── AndroidManifest.xml └── .gitignore /ic_launcher-web.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/freshui/dexBytecodeTamper/HEAD/ic_launcher-web.png -------------------------------------------------------------------------------- /libs/armeabi/libdexparser.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/freshui/dexBytecodeTamper/HEAD/libs/armeabi/libdexparser.so -------------------------------------------------------------------------------- /res/drawable-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/freshui/dexBytecodeTamper/HEAD/res/drawable-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /res/drawable-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/freshui/dexBytecodeTamper/HEAD/res/drawable-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /res/drawable-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/freshui/dexBytecodeTamper/HEAD/res/drawable-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /res/drawable-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/freshui/dexBytecodeTamper/HEAD/res/drawable-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /gen/com/freshui/dextamper/BuildConfig.java: -------------------------------------------------------------------------------- 1 | /** Automatically generated file. DO NOT MODIFY */ 2 | package com.freshui.dextamper; 3 | 4 | public final class BuildConfig { 5 | public final static boolean DEBUG = true; 6 | } -------------------------------------------------------------------------------- /res/values-sw600dp/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /res/values/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 16dp 5 | 16dp 6 | 7 | 8 | -------------------------------------------------------------------------------- /res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | dexTemper 5 | Settings 6 | Hello world! 7 | 8 | 9 | -------------------------------------------------------------------------------- /res/menu/main.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /res/values-sw720dp-land/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 128dp 8 | 9 | 10 | -------------------------------------------------------------------------------- /res/values-v11/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /res/values-v14/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Custom for Visual Studio 5 | *.cs diff=csharp 6 | *.sln merge=union 7 | *.csproj merge=union 8 | *.vbproj merge=union 9 | *.fsproj merge=union 10 | *.dbproj merge=union 11 | 12 | # Standard to msysgit 13 | *.doc diff=astextplain 14 | *.DOC diff=astextplain 15 | *.docx diff=astextplain 16 | *.DOCX diff=astextplain 17 | *.dot diff=astextplain 18 | *.DOT diff=astextplain 19 | *.pdf diff=astextplain 20 | *.PDF diff=astextplain 21 | *.rtf diff=astextplain 22 | *.RTF diff=astextplain 23 | -------------------------------------------------------------------------------- /project.properties: -------------------------------------------------------------------------------- 1 | # This file is automatically generated by Android Tools. 2 | # Do not modify this file -- YOUR CHANGES WILL BE ERASED! 3 | # 4 | # This file must be checked in Version Control Systems. 5 | # 6 | # To customize properties used by the Ant build system edit 7 | # "ant.properties", and override values to adapt the script to your 8 | # project structure. 9 | # 10 | # To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home): 11 | #proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt 12 | 13 | # Project target. 14 | target=android-18 15 | -------------------------------------------------------------------------------- /res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 10 | 11 | 16 | 17 | -------------------------------------------------------------------------------- /res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 14 | 15 | 16 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /proguard-project.txt: -------------------------------------------------------------------------------- 1 | # To enable ProGuard in your project, edit project.properties 2 | # to define the proguard.config property as described in that file. 3 | # 4 | # Add project specific ProGuard rules here. 5 | # By default, the flags in this file are appended to flags specified 6 | # in ${sdk.dir}/tools/proguard/proguard-android.txt 7 | # You can edit the include path and order by changing the ProGuard 8 | # include property in project.properties. 9 | # 10 | # For more details, see 11 | # http://developer.android.com/guide/developing/tools/proguard.html 12 | 13 | # Add any project specific keep options here: 14 | 15 | # If your project uses WebView with JS, uncomment the following 16 | # and specify the fully qualified class name to the JavaScript interface 17 | # class: 18 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 19 | # public *; 20 | #} 21 | -------------------------------------------------------------------------------- /src/com/freshui/dextamper/GameControl.java: -------------------------------------------------------------------------------- 1 | package com.freshui.dextamper; 2 | 3 | import android.util.Log; 4 | 5 | class GameControl{ 6 | 7 | private Double mScore; 8 | private double mDuration; 9 | 10 | public GameControl(){ 11 | mScore = null; 12 | } 13 | 14 | public void setScoreHidden(double result) 15 | { 16 | this.mScore = Double.valueOf(result*1.8); 17 | } 18 | 19 | public void setScore(double result) 20 | { 21 | if(mScore == null) 22 | MainActivity.LOG("setScore: multiple sets"); 23 | this.mScore = Double.valueOf(result); 24 | } 25 | 26 | public Double getScore() 27 | { 28 | return mScore; 29 | } 30 | 31 | public void setDuration(double paramDouble) 32 | { 33 | this.mDuration = Math.max(0.0D, paramDouble); 34 | } 35 | 36 | public void setDuration2(double paramDouble) 37 | { 38 | this.mDuration *= 1.8; 39 | } 40 | } 41 | 42 | 43 | -------------------------------------------------------------------------------- /jni/Android.mk: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2009 The Android Open Source Project 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | # 15 | LOCAL_PATH:= $(call my-dir) 16 | 17 | include $(CLEAR_VARS) 18 | 19 | LOCAL_MODULE := libdexparser 20 | LOCAL_CFLAGS := -Werror 21 | 22 | LOCAL_SRC_FILES := dexFileParser.cpp 23 | 24 | LOCAL_LDLIBS := -llog -ldl 25 | 26 | include $(BUILD_SHARED_LIBRARY) 27 | -------------------------------------------------------------------------------- /AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 10 | 11 | 16 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /src/com/freshui/dextamper/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.freshui.dextamper; 2 | 3 | import com.freshui.dextamper.R; 4 | 5 | import android.os.Bundle; 6 | import android.app.Activity; 7 | import android.util.Log; 8 | import android.view.Menu; 9 | import android.widget.Button; 10 | import android.widget.TextView; 11 | 12 | public class MainActivity extends Activity { 13 | 14 | static { 15 | System.loadLibrary("dexparser"); 16 | } 17 | 18 | private TextView mTextView = null; 19 | 20 | @Override 21 | protected void onCreate(Bundle savedInstanceState) { 22 | super.onCreate(savedInstanceState); 23 | setContentView(R.layout.activity_main); 24 | 25 | mTextView = (TextView) findViewById(R.id.textView1); 26 | GameControl res = new GameControl(); 27 | 28 | res.setScore(1.0); 29 | 30 | String text= String.format("setScore(1.0), but getScore is %f", res.getScore()); 31 | 32 | mTextView.setText(text); 33 | Log.d("dexer", "result="+res.getScore()); 34 | } 35 | 36 | @Override 37 | public boolean onCreateOptionsMenu(Menu menu) { 38 | // Inflate the menu; this adds items to the action bar if it is present. 39 | getMenuInflater().inflate(R.menu.main, menu); 40 | return true; 41 | } 42 | 43 | static void LOG(String s){ 44 | 45 | Log.d("test", "test"+s); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /gen/com/freshui/dextamper/R.java: -------------------------------------------------------------------------------- 1 | /* AUTO-GENERATED FILE. DO NOT MODIFY. 2 | * 3 | * This class was automatically generated by the 4 | * aapt tool from the resource data it found. It 5 | * should not be modified by hand. 6 | */ 7 | 8 | package com.freshui.dextamper; 9 | 10 | public final class R { 11 | public static final class attr { 12 | } 13 | public static final class dimen { 14 | /** Default screen margins, per the Android Design guidelines. 15 | 16 | Customize dimensions originally defined in res/values/dimens.xml (such as 17 | screen margins) for sw720dp devices (e.g. 10" tablets) in landscape here. 18 | 19 | */ 20 | public static final int activity_horizontal_margin=0x7f040000; 21 | public static final int activity_vertical_margin=0x7f040001; 22 | } 23 | public static final class drawable { 24 | public static final int ic_launcher=0x7f020000; 25 | } 26 | public static final class id { 27 | public static final int action_settings=0x7f080001; 28 | public static final int textView1=0x7f080000; 29 | } 30 | public static final class layout { 31 | public static final int activity_main=0x7f030000; 32 | } 33 | public static final class menu { 34 | public static final int main=0x7f070000; 35 | } 36 | public static final class string { 37 | public static final int action_settings=0x7f050001; 38 | public static final int app_name=0x7f050000; 39 | public static final int hello_world=0x7f050002; 40 | } 41 | public static final class style { 42 | /** 43 | Base application theme, dependent on API level. This theme is replaced 44 | by AppBaseTheme from res/values-vXX/styles.xml on newer devices. 45 | 46 | 47 | Theme customizations available in newer API levels can go in 48 | res/values-vXX/styles.xml, while customizations related to 49 | backward-compatibility can go here. 50 | 51 | 52 | Base application theme for API 11+. This theme completely replaces 53 | AppBaseTheme from res/values/styles.xml on API 11+ devices. 54 | 55 | API 11 theme customizations can go here. 56 | 57 | Base application theme for API 14+. This theme completely replaces 58 | AppBaseTheme from BOTH res/values/styles.xml and 59 | res/values-v11/styles.xml on API 14+ devices. 60 | 61 | API 14 theme customizations can go here. 62 | */ 63 | public static final int AppBaseTheme=0x7f060000; 64 | /** Application theme. 65 | All customizations that are NOT specific to a particular API-level can go here. 66 | */ 67 | public static final int AppTheme=0x7f060001; 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ################# 2 | ## Eclipse 3 | ################# 4 | 5 | *.pydevproject 6 | .project 7 | .metadata 8 | bin/ 9 | tmp/ 10 | *.tmp 11 | *.bak 12 | *.swp 13 | *~.nib 14 | local.properties 15 | .classpath 16 | .settings/ 17 | .loadpath 18 | 19 | # External tool builders 20 | .externalToolBuilders/ 21 | 22 | # Locally stored "Eclipse launch configurations" 23 | *.launch 24 | 25 | # CDT-specific 26 | .cproject 27 | 28 | # PDT-specific 29 | .buildpath 30 | 31 | 32 | ################# 33 | ## Visual Studio 34 | ################# 35 | 36 | ## Ignore Visual Studio temporary files, build results, and 37 | ## files generated by popular Visual Studio add-ons. 38 | 39 | # User-specific files 40 | *.suo 41 | *.user 42 | *.sln.docstates 43 | 44 | # Build results 45 | 46 | [Dd]ebug/ 47 | [Rr]elease/ 48 | x64/ 49 | build/ 50 | [Bb]in/ 51 | [Oo]bj/ 52 | 53 | # MSTest test Results 54 | [Tt]est[Rr]esult*/ 55 | [Bb]uild[Ll]og.* 56 | 57 | *_i.c 58 | *_p.c 59 | *.ilk 60 | *.meta 61 | *.obj 62 | *.pch 63 | *.pdb 64 | *.pgc 65 | *.pgd 66 | *.rsp 67 | *.sbr 68 | *.tlb 69 | *.tli 70 | *.tlh 71 | *.tmp 72 | *.tmp_proj 73 | *.log 74 | *.vspscc 75 | *.vssscc 76 | .builds 77 | *.pidb 78 | *.log 79 | *.scc 80 | 81 | # Visual C++ cache files 82 | ipch/ 83 | *.aps 84 | *.ncb 85 | *.opensdf 86 | *.sdf 87 | *.cachefile 88 | 89 | # Visual Studio profiler 90 | *.psess 91 | *.vsp 92 | *.vspx 93 | 94 | # Guidance Automation Toolkit 95 | *.gpState 96 | 97 | # ReSharper is a .NET coding add-in 98 | _ReSharper*/ 99 | *.[Rr]e[Ss]harper 100 | 101 | # TeamCity is a build add-in 102 | _TeamCity* 103 | 104 | # DotCover is a Code Coverage Tool 105 | *.dotCover 106 | 107 | # NCrunch 108 | *.ncrunch* 109 | .*crunch*.local.xml 110 | 111 | # Installshield output folder 112 | [Ee]xpress/ 113 | 114 | # DocProject is a documentation generator add-in 115 | DocProject/buildhelp/ 116 | DocProject/Help/*.HxT 117 | DocProject/Help/*.HxC 118 | DocProject/Help/*.hhc 119 | DocProject/Help/*.hhk 120 | DocProject/Help/*.hhp 121 | DocProject/Help/Html2 122 | DocProject/Help/html 123 | 124 | # Click-Once directory 125 | publish/ 126 | 127 | # Publish Web Output 128 | *.Publish.xml 129 | *.pubxml 130 | 131 | # NuGet Packages Directory 132 | ## TODO: If you have NuGet Package Restore enabled, uncomment the next line 133 | #packages/ 134 | 135 | # Windows Azure Build Output 136 | csx 137 | *.build.csdef 138 | 139 | # Windows Store app package directory 140 | AppPackages/ 141 | 142 | # Others 143 | sql/ 144 | *.Cache 145 | ClientBin/ 146 | [Ss]tyle[Cc]op.* 147 | ~$* 148 | *~ 149 | *.dbmdl 150 | *.[Pp]ublish.xml 151 | *.pfx 152 | *.publishsettings 153 | 154 | # RIA/Silverlight projects 155 | Generated_Code/ 156 | 157 | # Backup & report files from converting an old project file to a newer 158 | # Visual Studio version. Backup files are not needed, because we have git ;-) 159 | _UpgradeReport_Files/ 160 | Backup*/ 161 | UpgradeLog*.XML 162 | UpgradeLog*.htm 163 | 164 | # SQL Server files 165 | App_Data/*.mdf 166 | App_Data/*.ldf 167 | 168 | ############# 169 | ## Windows detritus 170 | ############# 171 | 172 | # Windows image file caches 173 | Thumbs.db 174 | ehthumbs.db 175 | 176 | # Folder config file 177 | Desktop.ini 178 | 179 | # Recycle Bin used on file shares 180 | $RECYCLE.BIN/ 181 | 182 | # Mac crap 183 | .DS_Store 184 | 185 | 186 | ############# 187 | ## Python 188 | ############# 189 | 190 | *.py[co] 191 | 192 | # Packages 193 | *.egg 194 | *.egg-info 195 | dist/ 196 | build/ 197 | eggs/ 198 | parts/ 199 | var/ 200 | sdist/ 201 | develop-eggs/ 202 | .installed.cfg 203 | 204 | # Installer logs 205 | pip-log.txt 206 | 207 | # Unit test / coverage reports 208 | .coverage 209 | .tox 210 | 211 | #Translations 212 | *.mo 213 | 214 | #Mr Developer 215 | .mr.developer.cfg 216 | -------------------------------------------------------------------------------- /jni/dexFile.h: -------------------------------------------------------------------------------- 1 | #ifndef LIBDEX_DEXFILE_H_ 2 | #define LIBDEX_DEXFILE_H_ 3 | 4 | typedef unsigned long u4; 5 | typedef unsigned short u2; 6 | typedef unsigned char u1; 7 | 8 | 9 | 10 | /* DEX file magic number */ 11 | #define DEX_MAGIC "dex\n" 12 | 13 | /* current version, encoded in 4 bytes of ASCII */ 14 | #define DEX_MAGIC_VERS "036\0" 15 | 16 | /* 17 | * older but still-recognized version (corresponding to Android API 18 | * levels 13 and earlier 19 | */ 20 | #define DEX_MAGIC_VERS_API_13 "035\0" 21 | 22 | /* same, but for optimized DEX header */ 23 | #define DEX_OPT_MAGIC "dey\n" 24 | #define DEX_OPT_MAGIC_VERS "036\0" 25 | 26 | #define DEX_DEP_MAGIC "deps" 27 | 28 | /* 29 | * 160-bit SHA-1 digest. 30 | */ 31 | enum { kSHA1DigestLen = 20, 32 | kSHA1DigestOutputLen = kSHA1DigestLen*2 +1 }; 33 | 34 | /* general constants */ 35 | enum { 36 | kDexEndianConstant = 0x12345678, /* the endianness indicator */ 37 | kDexNoIndex = 0xffffffff, /* not a valid index value */ 38 | }; 39 | 40 | /* 41 | * Enumeration of all the primitive types. 42 | */ 43 | enum PrimitiveType { 44 | PRIM_NOT = 0, /* value is a reference type, not a primitive type */ 45 | PRIM_VOID = 1, 46 | PRIM_BOOLEAN = 2, 47 | PRIM_BYTE = 3, 48 | PRIM_SHORT = 4, 49 | PRIM_CHAR = 5, 50 | PRIM_INT = 6, 51 | PRIM_LONG = 7, 52 | PRIM_FLOAT = 8, 53 | PRIM_DOUBLE = 9, 54 | }; 55 | 56 | /* 57 | * access flags and masks; the "standard" ones are all <= 0x4000 58 | * 59 | * Note: There are related declarations in vm/oo/Object.h in the ClassFlags 60 | * enum. 61 | */ 62 | enum { 63 | ACC_PUBLIC = 0x00000001, // class, field, method, ic 64 | ACC_PRIVATE = 0x00000002, // field, method, ic 65 | ACC_PROTECTED = 0x00000004, // field, method, ic 66 | ACC_STATIC = 0x00000008, // field, method, ic 67 | ACC_FINAL = 0x00000010, // class, field, method, ic 68 | ACC_SYNCHRONIZED = 0x00000020, // method (only allowed on natives) 69 | ACC_SUPER = 0x00000020, // class (not used in Dalvik) 70 | ACC_VOLATILE = 0x00000040, // field 71 | ACC_BRIDGE = 0x00000040, // method (1.5) 72 | ACC_TRANSIENT = 0x00000080, // field 73 | ACC_VARARGS = 0x00000080, // method (1.5) 74 | ACC_NATIVE = 0x00000100, // method 75 | ACC_INTERFACE = 0x00000200, // class, ic 76 | ACC_ABSTRACT = 0x00000400, // class, method, ic 77 | ACC_STRICT = 0x00000800, // method 78 | ACC_SYNTHETIC = 0x00001000, // field, method, ic 79 | ACC_ANNOTATION = 0x00002000, // class, ic (1.5) 80 | ACC_ENUM = 0x00004000, // class, field, ic (1.5) 81 | ACC_CONSTRUCTOR = 0x00010000, // method (Dalvik only) 82 | ACC_DECLARED_SYNCHRONIZED = 83 | 0x00020000, // method (Dalvik only) 84 | ACC_CLASS_MASK = 85 | (ACC_PUBLIC | ACC_FINAL | ACC_INTERFACE | ACC_ABSTRACT 86 | | ACC_SYNTHETIC | ACC_ANNOTATION | ACC_ENUM), 87 | ACC_INNER_CLASS_MASK = 88 | (ACC_CLASS_MASK | ACC_PRIVATE | ACC_PROTECTED | ACC_STATIC), 89 | ACC_FIELD_MASK = 90 | (ACC_PUBLIC | ACC_PRIVATE | ACC_PROTECTED | ACC_STATIC | ACC_FINAL 91 | | ACC_VOLATILE | ACC_TRANSIENT | ACC_SYNTHETIC | ACC_ENUM), 92 | ACC_METHOD_MASK = 93 | (ACC_PUBLIC | ACC_PRIVATE | ACC_PROTECTED | ACC_STATIC | ACC_FINAL 94 | | ACC_SYNCHRONIZED | ACC_BRIDGE | ACC_VARARGS | ACC_NATIVE 95 | | ACC_ABSTRACT | ACC_STRICT | ACC_SYNTHETIC | ACC_CONSTRUCTOR 96 | | ACC_DECLARED_SYNCHRONIZED), 97 | }; 98 | 99 | /* annotation constants */ 100 | enum { 101 | kDexVisibilityBuild = 0x00, /* annotation visibility */ 102 | kDexVisibilityRuntime = 0x01, 103 | kDexVisibilitySystem = 0x02, 104 | 105 | kDexAnnotationByte = 0x00, 106 | kDexAnnotationShort = 0x02, 107 | kDexAnnotationChar = 0x03, 108 | kDexAnnotationInt = 0x04, 109 | kDexAnnotationLong = 0x06, 110 | kDexAnnotationFloat = 0x10, 111 | kDexAnnotationDouble = 0x11, 112 | kDexAnnotationString = 0x17, 113 | kDexAnnotationType = 0x18, 114 | kDexAnnotationField = 0x19, 115 | kDexAnnotationMethod = 0x1a, 116 | kDexAnnotationEnum = 0x1b, 117 | kDexAnnotationArray = 0x1c, 118 | kDexAnnotationAnnotation = 0x1d, 119 | kDexAnnotationNull = 0x1e, 120 | kDexAnnotationBoolean = 0x1f, 121 | 122 | kDexAnnotationValueTypeMask = 0x1f, /* low 5 bits */ 123 | kDexAnnotationValueArgShift = 5, 124 | }; 125 | 126 | /* map item type codes */ 127 | enum { 128 | kDexTypeHeaderItem = 0x0000, 129 | kDexTypeStringIdItem = 0x0001, 130 | kDexTypeTypeIdItem = 0x0002, 131 | kDexTypeProtoIdItem = 0x0003, 132 | kDexTypeFieldIdItem = 0x0004, 133 | kDexTypeMethodIdItem = 0x0005, 134 | kDexTypeClassDefItem = 0x0006, 135 | kDexTypeMapList = 0x1000, 136 | kDexTypeTypeList = 0x1001, 137 | kDexTypeAnnotationSetRefList = 0x1002, 138 | kDexTypeAnnotationSetItem = 0x1003, 139 | kDexTypeClassDataItem = 0x2000, 140 | kDexTypeCodeItem = 0x2001, 141 | kDexTypeStringDataItem = 0x2002, 142 | kDexTypeDebugInfoItem = 0x2003, 143 | kDexTypeAnnotationItem = 0x2004, 144 | kDexTypeEncodedArrayItem = 0x2005, 145 | kDexTypeAnnotationsDirectoryItem = 0x2006, 146 | }; 147 | 148 | /* auxillary data section chunk codes */ 149 | enum { 150 | kDexChunkClassLookup = 0x434c4b50, /* CLKP */ 151 | kDexChunkRegisterMaps = 0x524d4150, /* RMAP */ 152 | 153 | kDexChunkEnd = 0x41454e44, /* AEND */ 154 | }; 155 | 156 | /* debug info opcodes and constants */ 157 | enum { 158 | DBG_END_SEQUENCE = 0x00, 159 | DBG_ADVANCE_PC = 0x01, 160 | DBG_ADVANCE_LINE = 0x02, 161 | DBG_START_LOCAL = 0x03, 162 | DBG_START_LOCAL_EXTENDED = 0x04, 163 | DBG_END_LOCAL = 0x05, 164 | DBG_RESTART_LOCAL = 0x06, 165 | DBG_SET_PROLOGUE_END = 0x07, 166 | DBG_SET_EPILOGUE_BEGIN = 0x08, 167 | DBG_SET_FILE = 0x09, 168 | DBG_FIRST_SPECIAL = 0x0a, 169 | DBG_LINE_BASE = -4, 170 | DBG_LINE_RANGE = 15, 171 | }; 172 | 173 | /* 174 | * Direct-mapped "header_item" struct. 175 | */ 176 | struct DexHeader { 177 | u1 magic[8]; /* includes version number */ 178 | u4 checksum; /* adler32 checksum */ 179 | u1 signature[kSHA1DigestLen]; /* SHA-1 hash */ 180 | u4 fileSize; /* length of entire file */ 181 | u4 headerSize; /* offset to start of next section */ 182 | u4 endianTag; 183 | u4 linkSize; 184 | u4 linkOff; 185 | u4 mapOff; 186 | u4 stringIdsSize; 187 | u4 stringIdsOff; 188 | u4 typeIdsSize; 189 | u4 typeIdsOff; 190 | u4 protoIdsSize; 191 | u4 protoIdsOff; 192 | u4 fieldIdsSize; 193 | u4 fieldIdsOff; 194 | u4 methodIdsSize; 195 | u4 methodIdsOff; 196 | u4 classDefsSize; 197 | u4 classDefsOff; 198 | u4 dataSize; 199 | u4 dataOff; 200 | }; 201 | 202 | /* 203 | * Direct-mapped "map_item". 204 | */ 205 | struct DexMapItem { 206 | u2 type; /* type code (see kDexType* above) */ 207 | u2 unused; 208 | u4 size; /* count of items of the indicated type */ 209 | u4 offset; /* file offset to the start of data */ 210 | }; 211 | 212 | /* 213 | * Direct-mapped "map_list". 214 | */ 215 | struct DexMapList { 216 | u4 size; /* #of entries in list */ 217 | DexMapItem list[1]; /* entries */ 218 | }; 219 | 220 | /* 221 | * Direct-mapped "string_id_item". 222 | */ 223 | struct DexStringId { 224 | u4 stringDataOff; /* file offset to string_data_item */ 225 | }; 226 | 227 | /* 228 | * Direct-mapped "type_id_item". 229 | */ 230 | struct DexTypeId { 231 | u4 descriptorIdx; /* index into stringIds list for type descriptor */ 232 | }; 233 | 234 | /* 235 | * Direct-mapped "field_id_item". 236 | */ 237 | struct DexFieldId { 238 | u2 classIdx; /* index into typeIds list for defining class */ 239 | u2 typeIdx; /* index into typeIds for field type */ 240 | u4 nameIdx; /* index into stringIds for field name */ 241 | }; 242 | 243 | /* 244 | * Direct-mapped "method_id_item". 245 | */ 246 | struct DexMethodId { 247 | u2 classIdx; /* index into typeIds list for defining class */ 248 | u2 protoIdx; /* index into protoIds for method prototype */ 249 | u4 nameIdx; /* index into stringIds for method name */ 250 | }; 251 | 252 | /* 253 | * Direct-mapped "proto_id_item". 254 | */ 255 | struct DexProtoId { 256 | u4 shortyIdx; /* index into stringIds for shorty descriptor */ 257 | u4 returnTypeIdx; /* index into typeIds list for return type */ 258 | u4 parametersOff; /* file offset to type_list for parameter types */ 259 | }; 260 | 261 | /* 262 | * Direct-mapped "class_def_item". 263 | */ 264 | struct DexClassDef { 265 | u4 classIdx; /* index into typeIds for this class */ 266 | u4 accessFlags; 267 | u4 superclassIdx; /* index into typeIds for superclass */ 268 | u4 interfacesOff; /* file offset to DexTypeList */ 269 | u4 sourceFileIdx; /* index into stringIds for source file name */ 270 | u4 annotationsOff; /* file offset to annotations_directory_item */ 271 | u4 classDataOff; /* file offset to class_data_item */ 272 | u4 staticValuesOff; /* file offset to DexEncodedArray */ 273 | }; 274 | 275 | /* 276 | * Direct-mapped "type_item". 277 | */ 278 | struct DexTypeItem { 279 | u2 typeIdx; /* index into typeIds */ 280 | }; 281 | 282 | /* 283 | * Direct-mapped "type_list". 284 | */ 285 | struct DexTypeList { 286 | u4 size; /* #of entries in list */ 287 | DexTypeItem list[1]; /* entries */ 288 | }; 289 | 290 | /* 291 | * Direct-mapped "code_item". 292 | * 293 | * The "catches" table is used when throwing an exception, 294 | * "debugInfo" is used when displaying an exception stack trace or 295 | * debugging. An offset of zero indicates that there are no entries. 296 | */ 297 | struct DexCode { 298 | u2 registersSize; 299 | u2 insSize; 300 | u2 outsSize; 301 | u2 triesSize; 302 | u4 debugInfoOff; /* file offset to debug info stream */ 303 | u4 insnsSize; /* size of the insns array, in u2 units */ 304 | u2 insns[1]; 305 | /* followed by optional u2 padding */ 306 | /* followed by try_item[triesSize] */ 307 | /* followed by uleb128 handlersSize */ 308 | /* followed by catch_handler_item[handlersSize] */ 309 | }; 310 | 311 | /* 312 | * Direct-mapped "try_item". 313 | */ 314 | struct DexTry { 315 | u4 startAddr; /* start address, in 16-bit code units */ 316 | u2 insnCount; /* instruction count, in 16-bit code units */ 317 | u2 handlerOff; /* offset in encoded handler data to handlers */ 318 | }; 319 | 320 | /* 321 | * Link table. Currently undefined. 322 | */ 323 | struct DexLink { 324 | u1 bleargh; 325 | }; 326 | 327 | 328 | /* 329 | * Direct-mapped "annotations_directory_item". 330 | */ 331 | struct DexAnnotationsDirectoryItem { 332 | u4 classAnnotationsOff; /* offset to DexAnnotationSetItem */ 333 | u4 fieldsSize; /* count of DexFieldAnnotationsItem */ 334 | u4 methodsSize; /* count of DexMethodAnnotationsItem */ 335 | u4 parametersSize; /* count of DexParameterAnnotationsItem */ 336 | /* followed by DexFieldAnnotationsItem[fieldsSize] */ 337 | /* followed by DexMethodAnnotationsItem[methodsSize] */ 338 | /* followed by DexParameterAnnotationsItem[parametersSize] */ 339 | }; 340 | 341 | /* 342 | * Direct-mapped "field_annotations_item". 343 | */ 344 | struct DexFieldAnnotationsItem { 345 | u4 fieldIdx; 346 | u4 annotationsOff; /* offset to DexAnnotationSetItem */ 347 | }; 348 | 349 | /* 350 | * Direct-mapped "method_annotations_item". 351 | */ 352 | struct DexMethodAnnotationsItem { 353 | u4 methodIdx; 354 | u4 annotationsOff; /* offset to DexAnnotationSetItem */ 355 | }; 356 | 357 | /* 358 | * Direct-mapped "parameter_annotations_item". 359 | */ 360 | struct DexParameterAnnotationsItem { 361 | u4 methodIdx; 362 | u4 annotationsOff; /* offset to DexAnotationSetRefList */ 363 | }; 364 | 365 | /* 366 | * Direct-mapped "annotation_set_ref_item". 367 | */ 368 | struct DexAnnotationSetRefItem { 369 | u4 annotationsOff; /* offset to DexAnnotationSetItem */ 370 | }; 371 | 372 | /* 373 | * Direct-mapped "annotation_set_ref_list". 374 | */ 375 | struct DexAnnotationSetRefList { 376 | u4 size; 377 | DexAnnotationSetRefItem list[1]; 378 | }; 379 | 380 | /* 381 | * Direct-mapped "annotation_set_item". 382 | */ 383 | struct DexAnnotationSetItem { 384 | u4 size; 385 | u4 entries[1]; /* offset to DexAnnotationItem */ 386 | }; 387 | 388 | /* 389 | * Direct-mapped "annotation_item". 390 | * 391 | * NOTE: this structure is byte-aligned. 392 | */ 393 | struct DexAnnotationItem { 394 | u1 visibility; 395 | u1 annotation[1]; /* data in encoded_annotation format */ 396 | }; 397 | 398 | /* 399 | * Direct-mapped "encoded_array". 400 | * 401 | * NOTE: this structure is byte-aligned. 402 | */ 403 | struct DexEncodedArray { 404 | u1 array[1]; /* data in encoded_array format */ 405 | }; 406 | 407 | /* 408 | * Lookup table for classes. It provides a mapping from class name to 409 | * class definition. Used by dexFindClass(). 410 | * 411 | * We calculate this at DEX optimization time and embed it in the file so we 412 | * don't need the same hash table in every VM. This is slightly slower than 413 | * a hash table with direct pointers to the items, but because it's shared 414 | * there's less of a penalty for using a fairly sparse table. 415 | */ 416 | struct DexClassLookup { 417 | int size; // total size, including "size" 418 | int numEntries; // size of table[]; always power of 2 419 | struct { 420 | u4 classDescriptorHash; // class descriptor hash code 421 | int classDescriptorOffset; // in bytes, from start of DEX 422 | int classDefOffset; // in bytes, from start of DEX 423 | } table[1]; 424 | }; 425 | 426 | /* 427 | * Header added by DEX optimization pass. Values are always written in 428 | * local byte and structure padding. The first field (magic + version) 429 | * is guaranteed to be present and directly readable for all expected 430 | * compiler configurations; the rest is version-dependent. 431 | * 432 | * Try to keep this simple and fixed-size. 433 | */ 434 | struct DexOptHeader { 435 | u1 magic[8]; /* includes version number */ 436 | 437 | u4 dexOffset; /* file offset of DEX header */ 438 | u4 dexLength; 439 | u4 depsOffset; /* offset of optimized DEX dependency table */ 440 | u4 depsLength; 441 | u4 optOffset; /* file offset of optimized data tables */ 442 | u4 optLength; 443 | 444 | u4 flags; /* some info flags */ 445 | u4 checksum; /* adler32 checksum covering deps/opt */ 446 | 447 | /* pad for 64-bit alignment if necessary */ 448 | }; 449 | 450 | #define DEX_OPT_FLAG_BIG (1<<1) /* swapped to big-endian */ 451 | 452 | #define DEX_INTERFACE_CACHE_SIZE 128 /* must be power of 2 */ 453 | 454 | /* 455 | * Structure representing a DEX file. 456 | * 457 | * Code should regard DexFile as opaque, using the API calls provided here 458 | * to access specific structures. 459 | */ 460 | struct DexFile { 461 | /* directly-mapped "opt" header */ 462 | const DexOptHeader* pOptHeader; 463 | 464 | /* pointers to directly-mapped structs and arrays in base DEX */ 465 | const DexHeader* pHeader; 466 | const DexStringId* pStringIds; 467 | const DexTypeId* pTypeIds; 468 | const DexFieldId* pFieldIds; 469 | const DexMethodId* pMethodIds; 470 | const DexProtoId* pProtoIds; 471 | const DexClassDef* pClassDefs; 472 | const DexLink* pLinkData; 473 | 474 | /* 475 | * These are mapped out of the "auxillary" section, and may not be 476 | * included in the file. 477 | */ 478 | const DexClassLookup* pClassLookup; 479 | const void* pRegisterMapPool; // RegisterMapClassPool 480 | 481 | /* points to start of DEX file data */ 482 | const u1* baseAddr; 483 | 484 | /* track memory overhead for auxillary structures */ 485 | int overhead; 486 | 487 | /* additional app-specific data structures associated with the DEX */ 488 | //void* auxData; 489 | }; 490 | 491 | 492 | /* expanded form of a class_data_item header */ 493 | struct DexClassDataHeader { 494 | u4 staticFieldsSize; 495 | u4 instanceFieldsSize; 496 | u4 directMethodsSize; 497 | u4 virtualMethodsSize; 498 | }; 499 | 500 | /* expanded form of encoded_field */ 501 | struct DexField { 502 | u4 fieldIdx; /* index to a field_id_item */ 503 | u4 accessFlags; 504 | }; 505 | 506 | /* expanded form of encoded_method */ 507 | struct DexMethod { 508 | u4 methodIdx; /* index to a method_id_item */ 509 | u4 accessFlags; 510 | u4 codeOff; /* file offset to a code_item */ 511 | }; 512 | 513 | /* expanded form of class_data_item. Note: If a particular item is 514 | * absent (e.g., no static fields), then the corresponding pointer 515 | * is set to NULL. */ 516 | struct DexClassData { 517 | DexClassDataHeader header; 518 | DexField* staticFields; 519 | DexField* instanceFields; 520 | DexMethod* directMethods; 521 | DexMethod* virtualMethods; 522 | }; 523 | #endif 524 | -------------------------------------------------------------------------------- /jni/dexFileParser.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2009 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | // OpenGL ES 2.0 code 18 | 19 | #define LOG_TAG "dexer" 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include "dexFile.h" 30 | 31 | #define ALOGD(...) ((void)__android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)) 32 | #define ALOGE(...) ((void)__android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)) 33 | 34 | 35 | static void* get_module_base( pid_t pid, const char* module_name) 36 | { 37 | FILE *fp; 38 | long addr = 0; 39 | char *pch; 40 | char filename[32]; 41 | char line[1024]; 42 | 43 | if ( pid < 0 ){ 44 | /* self process */ 45 | strcpy(filename, "/proc/self/maps"); 46 | }else{ 47 | snprintf( filename, sizeof(filename), "/proc/%d/maps", pid); 48 | } 49 | 50 | fp = fopen( filename, "r" ); 51 | 52 | if ( fp != NULL ){ 53 | while ( fgets( line, sizeof(line), fp ) ){ 54 | 55 | if ( strstr( line, module_name) ){ 56 | pch = strtok( line, "-" ); 57 | addr = strtoul( pch, NULL, 16 ); 58 | if ( addr == 0x8000 ) addr = 0; 59 | 60 | break; 61 | } 62 | } 63 | 64 | fclose( fp ) ; 65 | } 66 | 67 | return (void *)addr; 68 | } 69 | 70 | static size_t get_module_size( pid_t pid, const char* module_name) 71 | { 72 | FILE *fp; 73 | long size = 0; 74 | char *pch; 75 | char *first; 76 | char *last; 77 | char filename[32]; 78 | char line[1024]; 79 | 80 | if ( pid < 0 ){ 81 | /* self process */ 82 | strcpy(filename, "/proc/self/maps"); 83 | }else{ 84 | snprintf( filename, sizeof(filename), "/proc/%d/maps", pid); 85 | } 86 | 87 | fp = fopen( filename, "r" ); 88 | 89 | if ( fp != NULL ){ 90 | while ( fgets( line, sizeof(line), fp ) ){ 91 | if ( strstr( line, module_name ) ){ 92 | pch = strtok( line, " " ); 93 | //BEN_LOG("pch=%s", pch); 94 | 95 | first = strtok(pch, "-"); 96 | last = strtok(NULL, "-"); 97 | 98 | //BEN_LOG("%s - %s",first, last); 99 | size = strtoul( last, NULL, 16 ) - strtoul( first, NULL, 16 ); 100 | 101 | break; 102 | } 103 | } 104 | fclose( fp) ; 105 | } 106 | 107 | return size; 108 | } 109 | 110 | 111 | static void getAccessFlags(char *buf, int flags) 112 | { 113 | if((flags & ACC_PUBLIC) != 0) strcat(buf, "public "); 114 | if((flags & ACC_PRIVATE) != 0) strcat(buf, "private "); 115 | if((flags & ACC_PROTECTED) != 0) strcat(buf, "protected "); 116 | if((flags & ACC_STATIC) != 0) strcat(buf, "static "); 117 | if((flags & ACC_FINAL) != 0) strcat(buf, "final "); 118 | if((flags & ACC_SYNCHRONIZED) != 0) strcat(buf, "synchronized "); 119 | if((flags & ACC_SUPER) != 0) strcat(buf, "super "); 120 | if((flags & ACC_VOLATILE) != 0) strcat(buf, "volatile "); 121 | if((flags & ACC_BRIDGE) != 0) strcat(buf, "bridge "); 122 | if((flags & ACC_TRANSIENT) != 0) strcat(buf, "transient "); 123 | if((flags & ACC_VARARGS) != 0) strcat(buf, "varargs "); 124 | if((flags & ACC_NATIVE) != 0) strcat(buf, "native "); 125 | if((flags & ACC_INTERFACE) != 0) strcat(buf, "interface "); 126 | if((flags & ACC_ABSTRACT) != 0) strcat(buf, "abstract "); 127 | if((flags & ACC_STRICT) != 0) strcat(buf, "strict "); 128 | if((flags & ACC_SYNTHETIC) != 0) strcat(buf, "synthetic "); 129 | if((flags & ACC_ANNOTATION) != 0) strcat(buf, "annotation "); 130 | if((flags & ACC_ENUM) != 0) strcat(buf, "enum "); 131 | if((flags & ACC_CONSTRUCTOR) != 0) strcat(buf, "constructor "); 132 | if((flags & ACC_DECLARED_SYNCHRONIZED) != 0) strcat(buf, "synchronize "); 133 | } 134 | 135 | static int readUnsignedLeb128(const u1** pStream) { 136 | const u1* ptr = *pStream; 137 | int result = *(ptr++); 138 | 139 | if (result > 0x7f) { 140 | int cur = *(ptr++); 141 | result = (result & 0x7f) | ((cur & 0x7f) << 7); 142 | if (cur > 0x7f) { 143 | cur = *(ptr++); 144 | result |= (cur & 0x7f) << 14; 145 | if (cur > 0x7f) { 146 | cur = *(ptr++); 147 | result |= (cur & 0x7f) << 21; 148 | if (cur > 0x7f) { 149 | /* 150 | * Note: We don't check to see if cur is out of 151 | * range here, meaning we tolerate garbage in the 152 | * high four-order bits. 153 | */ 154 | cur = *(ptr++); 155 | result |= cur << 28; 156 | } 157 | } 158 | } 159 | } 160 | 161 | *pStream = ptr; 162 | return result; 163 | } 164 | 165 | 166 | static const DexCode* dexGetCode(const DexFile* pDexFile, 167 | const DexMethod* pDexMethod) 168 | { 169 | if (pDexMethod->codeOff == 0) 170 | return NULL; 171 | return (const DexCode*) (pDexFile->baseAddr + pDexMethod->codeOff); 172 | } 173 | 174 | /* return the ClassDef with the specified index */ 175 | static const DexClassDef* dexGetClassDef(const DexFile* pDexFile, u4 idx) { 176 | assert(idx < pDexFile->pHeader->classDefsSize); 177 | return &pDexFile->pClassDefs[idx]; 178 | } 179 | 180 | 181 | /* Read the header of a class_data_item without verification. This 182 | * updates the given data pointer to point past the end of the read 183 | * data. */ 184 | static void dexReadClassDataHeader(const u1** pData, 185 | DexClassDataHeader *pHeader) { 186 | pHeader->staticFieldsSize = readUnsignedLeb128(pData); 187 | pHeader->instanceFieldsSize = readUnsignedLeb128(pData); 188 | pHeader->directMethodsSize = readUnsignedLeb128(pData); 189 | pHeader->virtualMethodsSize = readUnsignedLeb128(pData); 190 | } 191 | 192 | /* Read an encoded_field without verification. This updates the 193 | * given data pointer to point past the end of the read data. 194 | * 195 | * The lastIndex value should be set to 0 before the first field in 196 | * a list is read. It is updated as fields are read and used in the 197 | * decode process. 198 | */ 199 | static void dexReadClassDataField(const u1** pData, DexField* pField, 200 | u4* lastIndex) { 201 | u4 index = *lastIndex + readUnsignedLeb128(pData); 202 | 203 | pField->accessFlags = readUnsignedLeb128(pData); 204 | pField->fieldIdx = index; 205 | *lastIndex = index; 206 | } 207 | 208 | /* Read an encoded_method without verification. This updates the 209 | * given data pointer to point past the end of the read data. 210 | * 211 | * The lastIndex value should be set to 0 before the first method in 212 | * a list is read. It is updated as fields are read and used in the 213 | * decode process. 214 | */ 215 | static void dexReadClassDataMethod(const u1** pData, DexMethod* pMethod, 216 | u4* lastIndex) { 217 | u4 index = *lastIndex + readUnsignedLeb128(pData); 218 | 219 | pMethod->accessFlags = readUnsignedLeb128(pData); 220 | pMethod->codeOff = readUnsignedLeb128(pData); 221 | pMethod->methodIdx = index; 222 | *lastIndex = index; 223 | } 224 | 225 | 226 | 227 | static char *getString(const DexFile *dexFile, int id) 228 | { 229 | return (char *)(dexFile->baseAddr + dexFile->pStringIds[id].stringDataOff+1); 230 | } 231 | 232 | static int getTypeIdStringId(const DexFile *dexFile, int id) 233 | { 234 | const DexTypeId *typeId = dexFile->pTypeIds; 235 | return typeId[id].descriptorIdx; 236 | } 237 | #define getTpyeIdString(dexFile, id) getString((dexFile), getTypeIdStringId((dexFile),(id))) 238 | 239 | static u1 *getClassDataPtr(const DexFile *dexFile, int idx) 240 | { 241 | return (u1 *)(dexFile->baseAddr + dexFile->pClassDefs[idx].classDataOff); 242 | } 243 | 244 | static void dumpDexHeader(DexHeader *header) 245 | { 246 | ALOGD("[Dex Header] headerSize:0x%08lx fileSize:0x%08lx", header->headerSize, header->fileSize); 247 | ALOGD("[Dex Header] linkSize:0x%08lx linkOff:0x%08lx mapOff:0x%08lx", header->linkSize, header->linkOff, header->mapOff); 248 | ALOGD("[Dex Header] StringIds size:0x%08lx offset:0x%08lx", header->stringIdsSize, header->stringIdsOff); 249 | ALOGD("[Dex Header] TypeIds size:0x%08lx offset:0x%08lx", header->typeIdsSize, header->typeIdsOff); 250 | ALOGD("[Dex Header] ProtoIds size:0x%08lx offset:0x%08lx", header->protoIdsSize, header->protoIdsOff); 251 | ALOGD("[Dex Header] FieldIds size:0x%08lx offset:0x%08lx", header->fieldIdsSize, header->fieldIdsOff); 252 | ALOGD("[Dex Header] MethodIds size:0x%08lx offset:0x%08lx", header->methodIdsSize, header->methodIdsOff); 253 | ALOGD("[Dex Header] ClassDefs size:0x%08lx offset:0x%08lx", header->classDefsSize, header->classDefsOff); 254 | ALOGD("[Dex Header] Data size:0x%08lx offset:0x%08lx", header->dataSize, header->dataOff); 255 | } 256 | 257 | static void dumpDexStrings(const DexFile *dexFile) 258 | { 259 | int i =0; 260 | char *str; 261 | int count = dexFile->pHeader->stringIdsSize; 262 | 263 | for(i=0; ibaseAddr + dexFile->pStringIds[i].stringDataOff); 265 | ALOGD("[Strings] id=%d [%d]:%s", i, str[0], str+1); 266 | } 267 | } 268 | 269 | 270 | static void dumpDexTypeIds(const DexFile *dexFile) 271 | { 272 | const DexTypeId *typeId = dexFile->pTypeIds; 273 | int count = dexFile->pHeader->typeIdsSize; 274 | 275 | for(int i=0; ipFieldIds; 283 | int count = dexFile->pHeader->fieldIdsSize; 284 | 285 | for(int i=0; i %s %s", 287 | getTpyeIdString(dexFile, pfield[i].classIdx), 288 | getString(dexFile, pfield[i].nameIdx), 289 | getTpyeIdString(dexFile, pfield[i].typeIdx)); 290 | } 291 | } 292 | 293 | static void dumpDexProtos(const DexFile *dexFile) 294 | { 295 | char buffer[1024]; 296 | const DexProtoId *proto = dexFile->pProtoIds; 297 | int count = dexFile->pHeader->protoIdsSize; 298 | DexTypeList *plist; 299 | 300 | for(int i=0; ibaseAddr + proto[i].parametersOff); 312 | for(u4 j=0; jsize; j++){ 313 | strcat(buffer, getTpyeIdString(dexFile, plist->list[j].typeIdx)); 314 | } 315 | ALOGD("%s", buffer); 316 | } 317 | } 318 | 319 | static void dumpClassDefines(const DexFile *dexFile) 320 | { 321 | char buffer[1024]; 322 | const DexClassDef* classdef = dexFile->pClassDefs; 323 | int count = dexFile->pHeader->classDefsSize; 324 | 325 | buffer[0] = 0; 326 | for(int i=0; ipMethodIds; 345 | } 346 | 347 | 348 | static int readAndVerifyUnsignedLeb128(const u1** pStream, const u1* limit, 349 | bool* okay) { 350 | const u1* ptr = *pStream; 351 | int result = readUnsignedLeb128(pStream); 352 | 353 | if (((limit != NULL) && (*pStream > limit)) 354 | || (((*pStream - ptr) == 5) && (ptr[4] > 0x0f))) { 355 | *okay = false; 356 | } 357 | 358 | return result; 359 | } 360 | 361 | /* Helper for verification which reads and verifies a given number 362 | * of uleb128 values. */ 363 | static bool verifyUlebs(const u1* pData, const u1* pLimit, u4 count) { 364 | bool okay = true; 365 | u4 i; 366 | 367 | while (okay && (count-- != 0)) { 368 | readAndVerifyUnsignedLeb128(&pData, pLimit, &okay); 369 | } 370 | 371 | return okay; 372 | } 373 | 374 | /* Read and verify the header of a class_data_item. This updates the 375 | * given data pointer to point past the end of the read data and 376 | * returns an "okay" flag (that is, false == failure). */ 377 | static bool dexReadAndVerifyClassDataHeader(const u1** pData, const u1* pLimit, 378 | DexClassDataHeader *pHeader) { 379 | if (! verifyUlebs(*pData, pLimit, 4)) { 380 | return false; 381 | } 382 | 383 | dexReadClassDataHeader(pData, pHeader); 384 | ALOGD("ClassHeader: field: s-%ld i-%ld method: d-%ld v-%ld", 385 | pHeader->staticFieldsSize, pHeader->instanceFieldsSize, 386 | pHeader->directMethodsSize, pHeader->staticFieldsSize); 387 | return true; 388 | } 389 | 390 | /* Read and verify an encoded_field. This updates the 391 | * given data pointer to point past the end of the read data and 392 | * returns an "okay" flag (that is, false == failure). 393 | * 394 | * The lastIndex value should be set to 0 before the first field in 395 | * a list is read. It is updated as fields are read and used in the 396 | * decode process. 397 | * 398 | * The verification done by this function is of the raw data format 399 | * only; it does not verify that access flags or indices 400 | * are valid. */ 401 | static bool dexReadAndVerifyClassDataField(const u1** pData, const u1* pLimit, 402 | DexField* pField, u4* lastIndex) { 403 | if (! verifyUlebs(*pData, pLimit, 2)) { 404 | return false; 405 | } 406 | 407 | dexReadClassDataField(pData, pField, lastIndex); 408 | return true; 409 | } 410 | 411 | /* Read and verify an encoded_method. This updates the 412 | * given data pointer to point past the end of the read data and 413 | * returns an "okay" flag (that is, false == failure). 414 | * 415 | * The lastIndex value should be set to 0 before the first method in 416 | * a list is read. It is updated as fields are read and used in the 417 | * decode process. 418 | * 419 | * The verification done by this function is of the raw data format 420 | * only; it does not verify that access flags, indices, or offsets 421 | * are valid. */ 422 | static bool dexReadAndVerifyClassDataMethod(const u1** pData, const u1* pLimit, 423 | DexMethod* pMethod, u4* lastIndex) { 424 | if (! verifyUlebs(*pData, pLimit, 3)) { 425 | return false; 426 | } 427 | 428 | dexReadClassDataMethod(pData, pMethod, lastIndex); 429 | return true; 430 | } 431 | 432 | /* Read, verify, and return an entire class_data_item. This updates 433 | * the given data pointer to point past the end of the read data. This 434 | * function allocates a single chunk of memory for the result, which 435 | * must subsequently be free()d. This function returns NULL if there 436 | * was trouble parsing the data. If this function is passed NULL, it 437 | * returns an initialized empty DexClassData structure. 438 | * 439 | * The verification done by this function is of the raw data format 440 | * only; it does not verify that access flags, indices, or offsets 441 | * are valid. */ 442 | static DexClassData* dexReadAndVerifyClassData(const u1** pData, const u1* pLimit) { 443 | DexClassDataHeader header; 444 | u4 lastIndex; 445 | 446 | if (*pData == NULL) { 447 | DexClassData* result = (DexClassData*) malloc(sizeof(DexClassData)); 448 | memset(result, 0, sizeof(*result)); 449 | return result; 450 | } 451 | 452 | if (! dexReadAndVerifyClassDataHeader(pData, pLimit, &header)) { 453 | return NULL; 454 | } 455 | 456 | size_t resultSize = sizeof(DexClassData) + 457 | (header.staticFieldsSize * sizeof(DexField)) + 458 | (header.instanceFieldsSize * sizeof(DexField)) + 459 | (header.directMethodsSize * sizeof(DexMethod)) + 460 | (header.virtualMethodsSize * sizeof(DexMethod)); 461 | 462 | DexClassData* result = (DexClassData*) malloc(resultSize); 463 | u1* ptr = ((u1*) result) + sizeof(DexClassData); 464 | bool okay = true; 465 | u4 i; 466 | 467 | if (result == NULL) { 468 | return NULL; 469 | } 470 | 471 | result->header = header; 472 | 473 | if (header.staticFieldsSize != 0) { 474 | result->staticFields = (DexField*) ptr; 475 | ptr += header.staticFieldsSize * sizeof(DexField); 476 | } else { 477 | result->staticFields = NULL; 478 | } 479 | 480 | if (header.instanceFieldsSize != 0) { 481 | result->instanceFields = (DexField*) ptr; 482 | ptr += header.instanceFieldsSize * sizeof(DexField); 483 | } else { 484 | result->instanceFields = NULL; 485 | } 486 | 487 | if (header.directMethodsSize != 0) { 488 | result->directMethods = (DexMethod*) ptr; 489 | ptr += header.directMethodsSize * sizeof(DexMethod); 490 | } else { 491 | result->directMethods = NULL; 492 | } 493 | 494 | if (header.virtualMethodsSize != 0) { 495 | result->virtualMethods = (DexMethod*) ptr; 496 | } else { 497 | result->virtualMethods = NULL; 498 | } 499 | 500 | lastIndex = 0; 501 | for (i = 0; okay && (i < header.staticFieldsSize); i++) { 502 | okay = dexReadAndVerifyClassDataField(pData, pLimit, 503 | &result->staticFields[i], &lastIndex); 504 | } 505 | 506 | lastIndex = 0; 507 | for (i = 0; okay && (i < header.instanceFieldsSize); i++) { 508 | okay = dexReadAndVerifyClassDataField(pData, pLimit, 509 | &result->instanceFields[i], &lastIndex); 510 | } 511 | 512 | lastIndex = 0; 513 | for (i = 0; okay && (i < header.directMethodsSize); i++) { 514 | okay = dexReadAndVerifyClassDataMethod(pData, pLimit, 515 | &result->directMethods[i], &lastIndex); 516 | } 517 | 518 | lastIndex = 0; 519 | for (i = 0; okay && (i < header.virtualMethodsSize); i++) { 520 | okay = dexReadAndVerifyClassDataMethod(pData, pLimit, 521 | &result->virtualMethods[i], &lastIndex); 522 | } 523 | 524 | if (! okay) { 525 | free(result); 526 | return NULL; 527 | } 528 | 529 | return result; 530 | } 531 | 532 | static void dumpDexClassDataMethod(const DexFile *dexFile, DexClassData* classData) 533 | { 534 | int idx = 0; 535 | DexMethod *method = NULL; 536 | const DexMethodId* methodId = NULL; 537 | 538 | method = classData->directMethods; 539 | methodId = dexFile->pMethodIds; 540 | 541 | for (int i = 0; i < (int) classData->header.directMethodsSize; i++) { 542 | idx = classData->directMethods[i].methodIdx; 543 | ALOGD(":idx-%d [%06x]: %s->%s", idx, classData->directMethods[i].codeOff, 544 | getTpyeIdString(dexFile, methodId[idx].classIdx), getString(dexFile, methodId[idx].nameIdx)); 545 | 546 | const DexCode* pCode = dexGetCode(dexFile, &classData->directMethods[i]); 547 | if(pCode == NULL) continue; 548 | ALOGD(" registers : %d", pCode->registersSize); 549 | ALOGD(" ins : %d", pCode->insSize); 550 | ALOGD(" outs : %d", pCode->outsSize); 551 | ALOGD(" insns size : %d 16-bit code units", pCode->insnsSize); 552 | 553 | int a = 0; 554 | char buffer[256] = {0, 0}; 555 | char tmp[32]; 556 | for(u4 k=0; kinsnsSize; k++){ 557 | sprintf(tmp, "%04x ", pCode->insns[k]); 558 | strcat(buffer, tmp); 559 | if(k%8 == 7){ 560 | ALOGD("%s", buffer); 561 | buffer[0] = 0; 562 | } 563 | } 564 | ALOGD("%s", buffer); 565 | } 566 | 567 | for (int i = 0; i < (int) classData->header.virtualMethodsSize; i++) { 568 | idx = classData->virtualMethods[i].methodIdx; 569 | ALOGD("idx-%d [%06lx]: %s->%s", idx, classData->virtualMethods[i].codeOff, 570 | getTpyeIdString(dexFile, methodId[idx].classIdx), getString(dexFile, methodId[idx].nameIdx)); 571 | 572 | const DexCode* pCode = dexGetCode(dexFile, &classData->virtualMethods[i]); 573 | if(pCode == NULL) continue; 574 | ALOGD(" registers : %d", pCode->registersSize); 575 | ALOGD(" ins : %d", pCode->insSize); 576 | ALOGD(" outs : %d", pCode->outsSize); 577 | ALOGD(" insns size : %ld 16-bit code units", pCode->insnsSize); 578 | ALOGD(" insns at : %x ", (int)(pCode->insns) - (int)dexFile->baseAddr); 579 | 580 | ALOGD("%x %x %x %x", pCode->insns[0], pCode->insns[1], pCode->insns[2], pCode->insns[3]); 581 | 582 | int a = 0; 583 | char buffer[256] = {0, 0}; 584 | char tmp[32]; 585 | for(u4 k=0; kinsnsSize; k++){ 586 | sprintf(tmp, "%04x ", pCode->insns[k]); 587 | strcat(buffer, tmp); 588 | if(k%8 == 7){ 589 | ALOGD("%s", buffer); 590 | buffer[0] = 0; 591 | } 592 | } 593 | ALOGD("%s", buffer); 594 | 595 | } 596 | } 597 | 598 | static DexClassData* dexFindClassData(const DexFile *dexFile, const char* clazz) 599 | { 600 | const DexClassDef* classdef; 601 | u4 count = dexFile->pHeader->classDefsSize; 602 | 603 | const u1* pEncodedData = NULL; 604 | DexClassData* pClassData = NULL; 605 | const char *descriptor = NULL; 606 | 607 | ALOGD("total count: %ld search:%s", count, clazz); 608 | 609 | for(u4 i=0; iclassIdx); 613 | ALOGD("%s", descriptor); 614 | 615 | pEncodedData = dexFile->baseAddr + classdef->classDataOff; 616 | pClassData = dexReadAndVerifyClassData(&pEncodedData, NULL); 617 | ALOGD("[%p] [%p]", pEncodedData, pClassData); 618 | 619 | if(strcmp(descriptor, clazz) == 0){ 620 | ALOGD("found %s", clazz); 621 | return pClassData; 622 | } 623 | 624 | if (pClassData == NULL) { 625 | ALOGE("Trouble reading class data (#%ld) for %s\n", i, descriptor); 626 | continue; 627 | } 628 | 629 | free(pClassData); 630 | } 631 | 632 | return NULL; 633 | } 634 | 635 | static void dumpDexCode(const DexCode *pCode) 636 | { 637 | ALOGD(" registers : %d", pCode->registersSize); 638 | ALOGD(" ins : %d", pCode->insSize); 639 | ALOGD(" outs : %d", pCode->outsSize); 640 | ALOGD(" insns size : %ld 16-bit code units", pCode->insnsSize); 641 | 642 | int a = 0; 643 | char buffer[256] = {0, 0}; 644 | char tmp[32]; 645 | 646 | for(u4 k=0; kinsnsSize; k++){ 647 | sprintf(tmp, "%04x ", pCode->insns[k]); 648 | strcat(buffer, tmp); 649 | if(k%8 == 7){ 650 | ALOGD("%s", buffer); 651 | buffer[0] = 0; 652 | } 653 | } 654 | ALOGD("%s", buffer); 655 | } 656 | 657 | static const DexCode* dexFindMethodInsns(const DexFile *dexFile, const DexClassData*classData, const char* methodName) 658 | { 659 | int idx = 0; 660 | DexMethod *method = NULL; 661 | const DexMethodId* methodId = NULL; 662 | DexCode* code = NULL; 663 | 664 | method = classData->directMethods; 665 | methodId = dexFile->pMethodIds; 666 | 667 | for (int i = 0; i < (int) classData->header.directMethodsSize; i++) { 668 | idx = classData->directMethods[i].methodIdx; 669 | //ALOGD(":idx-%d [%06lx]: %s->%s", idx, classData->directMethods[i].codeOff, 670 | // getTpyeIdString(dexFile, methodId[idx].classIdx), getString(dexFile, methodId[idx].nameIdx)); 671 | 672 | 673 | const DexCode* pCode = dexGetCode(dexFile, &classData->directMethods[i]); 674 | 675 | if(strcmp(getString(dexFile, methodId[idx].nameIdx), methodName) == 0){ 676 | return pCode; 677 | } 678 | } 679 | 680 | for (int i = 0; i < (int) classData->header.virtualMethodsSize; i++) { 681 | idx = classData->virtualMethods[i].methodIdx; 682 | //ALOGD("idx-%d [%06lx]: %s->%s", idx, classData->virtualMethods[i].codeOff, 683 | // getTpyeIdString(dexFile, methodId[idx].classIdx), getString(dexFile, methodId[idx].nameIdx)); 684 | 685 | const DexCode* pCode = dexGetCode(dexFile, &classData->virtualMethods[i]); 686 | 687 | if(strcmp(getString(dexFile, methodId[idx].nameIdx), methodName) == 0){ 688 | return pCode; 689 | } 690 | } 691 | 692 | return code; 693 | } 694 | 695 | static void handleDexMethod(DexClassData* classData, const char*method) 696 | { 697 | // TODO 698 | } 699 | 700 | void* searchDexStart(const void *base) 701 | { 702 | DexOptHeader *optHeader = (DexOptHeader*)base; 703 | ALOGD("Magic: %s flag:0x%08x checksum:0x%08x", optHeader->magic, optHeader->flags, optHeader->checksum); 704 | ALOGD("Dex File: offset-0x%08x size-0x%08x", optHeader->dexOffset, optHeader->dexLength); 705 | ALOGD("Deps opt: offset-0x%08x size-0x%08x", optHeader->depsOffset, optHeader->depsLength); 706 | ALOGD("Opt info: offset-0x%08x size-0x%08x", optHeader->optOffset, optHeader->optLength); 707 | 708 | return (void*)((u4)base + optHeader->dexOffset); 709 | } 710 | 711 | static bool checkDexMagic(const void *dexBase) 712 | { 713 | const char *pattern = "dex\n035"; 714 | const char *dexer = (const char *)dexBase; 715 | 716 | if(strcmp(dexer, pattern) == 0){ 717 | return true; 718 | } 719 | 720 | return false; 721 | } 722 | 723 | 724 | 725 | static const DexCode *dexFindClassMethod(DexFile *dexFile, const char *clazz, const char *method) 726 | { 727 | ALOGD("finding: %s->%s", clazz, method); 728 | DexClassData* classData = dexFindClassData(dexFile, clazz); 729 | if(classData == NULL) return NULL; 730 | 731 | const DexCode* code = dexFindMethodInsns(dexFile, classData, method); 732 | 733 | if(code != NULL) { 734 | dumpDexCode(code); 735 | } 736 | dumpDexClassDataMethod(dexFile, classData); 737 | 738 | ALOGD("found[%p]: %s->%s", code, clazz, method); 739 | return code; 740 | } 741 | 742 | 743 | static DexFile gDexFile; 744 | static void nativeParserDex() 745 | { 746 | void *base = NULL; 747 | int module_size = 0; 748 | char filename[512]; 749 | 750 | // simple test code here! 751 | for(int i=0; i<2; i++){ 752 | sprintf(filename, "/data/dalvik-cache/data@app@%s-%d.apk@classes.d", "com.freshui.dextamper", i+1); 753 | 754 | base = get_module_base(-1, filename); 755 | if(base != NULL){ 756 | break; 757 | } 758 | } 759 | 760 | if(base == NULL){ 761 | ALOGE("Can not found module: %s", filename); 762 | return; 763 | } 764 | 765 | module_size = get_module_size(-1, filename); 766 | 767 | // search dex from odex 768 | void *dexBase = searchDexStart(base); 769 | if(checkDexMagic(dexBase) == false){ 770 | ALOGE("Error! invalid dex format at: %p", dexBase); 771 | return; 772 | } 773 | 774 | DexHeader *dexHeader = (DexHeader *)dexBase; 775 | 776 | gDexFile.baseAddr = (u1*)dexBase; 777 | gDexFile.pHeader = dexHeader; 778 | gDexFile.pStringIds = (DexStringId*)((u4)dexBase+dexHeader->stringIdsOff); 779 | gDexFile.pTypeIds = (DexTypeId*)((u4)dexBase+dexHeader->typeIdsOff); 780 | gDexFile.pMethodIds = (DexMethodId*)((u4)dexBase+dexHeader->methodIdsOff); 781 | gDexFile.pFieldIds = (DexFieldId*)((u4)dexBase+dexHeader->fieldIdsOff); 782 | gDexFile.pClassDefs = (DexClassDef*)((u4)dexBase+dexHeader->classDefsOff); 783 | gDexFile.pProtoIds = (DexProtoId*)((u4)dexBase+dexHeader->protoIdsOff); 784 | 785 | 786 | //dumpDexHeader(dexHeader); 787 | //dumpDexStrings(&gDexFile); 788 | //dumpDexTypeIds(&gDexFile); 789 | //dumpDexProtos(&gDexFile); 790 | //dumpFieldIds(&gDexFile); 791 | //dumpClassDefines(&gDexFile); 792 | 793 | 794 | // 2. found Dex Class! 795 | const DexCode *code = 796 | dexFindClassMethod(&gDexFile, "Lcom/freshui/dextamper/GameControl;", "setScoreHidden"); 797 | if(code == NULL){ 798 | ALOGE("Error can not found setScoreHidden"); 799 | return; 800 | } 801 | 802 | const DexCode *code2 = dexFindClassMethod(&gDexFile, "Lcom/freshui/dextamper/GameControl;", "setScore"); 803 | if(code2 == NULL){ 804 | ALOGE("Error can not found setScore"); 805 | return; 806 | } 807 | // remap!!!! 808 | if(mprotect(base, module_size, PROT_READ | PROT_WRITE | PROT_EXEC) == 0){ 809 | ALOGD("Found the odex module at: %p [%x]", base, module_size); 810 | DexCode *pCode = (DexCode *)code2; 811 | 812 | // Modify! to simple the case, just replace the method. 813 | pCode->registersSize = code->registersSize; 814 | for(u4 k=0; kinsnsSize; k++){ 815 | pCode->insns[k] = code->insns[k]; 816 | } 817 | 818 | // cleanup write PROT 819 | mprotect(base, module_size, PROT_READ | PROT_EXEC); 820 | } 821 | } 822 | 823 | 824 | 825 | // JNI_onLoad, must be extern C 826 | extern "C" jint JNI_OnLoad(JavaVM* vm, void* reserved) { 827 | JNIEnv* env = NULL; 828 | jint result = -1; 829 | 830 | if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) { 831 | ALOGE("ERROR: GetEnv failed\n"); 832 | goto bail; 833 | } 834 | assert(env != NULL); 835 | 836 | // TODO registerMethods if any!! 837 | 838 | nativeParserDex(); 839 | 840 | /* success -- return valid version number */ 841 | result = JNI_VERSION_1_4; 842 | 843 | bail: 844 | return result; 845 | } 846 | --------------------------------------------------------------------------------