├── 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 |
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 |
--------------------------------------------------------------------------------