├── .gitignore
├── .idea
├── compiler.xml
├── copyright
│ └── profiles_settings.xml
├── gradle.xml
├── misc.xml
├── modules.xml
├── runConfigurations.xml
└── vcs.xml
├── README.md
├── app
├── .gitignore
├── build.gradle
├── lib
│ └── XposedBridgeApi-54.jar
├── proguard-rules.pro
└── src
│ ├── androidTest
│ └── java
│ │ └── com
│ │ └── smartdone
│ │ └── dexdump
│ │ └── ExampleInstrumentedTest.java
│ ├── main
│ ├── AndroidManifest.xml
│ ├── assets
│ │ └── xposed_init
│ ├── java
│ │ └── com
│ │ │ └── smartdone
│ │ │ └── dexdump
│ │ │ ├── Appinfo.java
│ │ │ ├── Config.java
│ │ │ ├── DensityUtil.java
│ │ │ ├── Dumpper.java
│ │ │ ├── Main.java
│ │ │ ├── MainActivity.java
│ │ │ └── PermisionUtils.java
│ ├── jni
│ │ ├── Android.mk
│ │ ├── Application.mk
│ │ ├── dlopen.c
│ │ ├── dlopen.h
│ │ ├── dump.cpp
│ │ ├── dump.h
│ │ ├── include
│ │ │ └── inlineHook.h
│ │ ├── inlineHook.c
│ │ ├── relocate.c
│ │ └── relocate.h
│ └── res
│ │ ├── layout
│ │ ├── activity_main.xml
│ │ └── item.xml
│ │ ├── mipmap-hdpi
│ │ ├── ic_launcher.png
│ │ └── ic_launcher_round.png
│ │ ├── mipmap-mdpi
│ │ ├── ic_launcher.png
│ │ └── ic_launcher_round.png
│ │ ├── mipmap-xhdpi
│ │ ├── ic_launcher.png
│ │ └── ic_launcher_round.png
│ │ ├── mipmap-xxhdpi
│ │ ├── ic_launcher.png
│ │ └── ic_launcher_round.png
│ │ ├── mipmap-xxxhdpi
│ │ ├── ic_launcher.png
│ │ └── ic_launcher_round.png
│ │ └── values
│ │ ├── colors.xml
│ │ ├── strings.xml
│ │ └── styles.xml
│ └── test
│ └── java
│ └── com
│ └── smartdone
│ └── dexdump
│ └── ExampleUnitTest.java
├── build.gradle
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
└── settings.gradle
/.gitignore:
--------------------------------------------------------------------------------
1 | *.iml
2 | .gradle
3 | /local.properties
4 | /.idea/workspace.xml
5 | /.idea/libraries
6 | .DS_Store
7 | /build
8 | /captures
9 | .externalNativeBuild
10 |
--------------------------------------------------------------------------------
/.idea/compiler.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/.idea/copyright/profiles_settings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
--------------------------------------------------------------------------------
/.idea/gradle.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
17 |
18 |
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/.idea/runConfigurations.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # dexdump
2 |
3 | # 已经用纯frida实现了,frida版本的会去遍历所有的类,并且加载,对于抽类的,能够修复那种执行的时候把代码填充回dex的
4 | [https://github.com/smartdone/Frida-Scripts/tree/master/unpack](https://github.com/smartdone/Frida-Scripts/tree/master/unpack)
5 | > 还是frida方便,环境配置简单,喜欢请点star哦
6 |
7 | ## 感谢
8 | - `ele7enxxh`大佬的[Android-Inline-Hook](https://github.com/ele7enxxh/Android-Inline-Hook)
9 | - `rrrfff`大佬的[ndk_dlopen](https://github.com/rrrfff/ndk_dlopen)
10 |
11 | # Usage
12 |
13 | 1. 把libhook.so复制到/data/local/tmp下面,并且更改权限为777 (`chmod 777 /data/local/tmp/libhook.so`)
14 | 2. 安装xposed插件
15 | 3. 激活插件并且重启手机
16 | 4. 在xposed插件的界面里面勾选你需要脱壳的应用
17 | 5. 干掉你需要脱壳的应用的进程,然后重新启动应用 (`kill -9 {pid}`)
18 | 6. 如果脱壳成功的话,就会在应用的`/data/data/{packagename}`下面写入dex文件
19 | 7. `grep {activity name} -r *` 筛选出dex
20 |
21 | # Notice
22 |
23 | > 在5.x,6.0目前正常。
24 |
25 | - 根据[@jwchen119](https://github.com/jwchen119)大佬的建议,写的6.0
26 |
27 | - 7.x应该有问题,刚弄了一个7.x的设备,最近跟新一下
28 |
29 | - 4.4及以下的也的Dalvik也没有试,可以正常使用了会在这个地方声明
30 |
31 | - 感谢大家
32 |
--------------------------------------------------------------------------------
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 |
--------------------------------------------------------------------------------
/app/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | android {
4 | compileSdkVersion 26
5 | buildToolsVersion '26.0.2'
6 | defaultConfig {
7 | applicationId "com.smartdone.dexdump"
8 | minSdkVersion 15
9 | targetSdkVersion 26
10 | versionCode 1
11 | versionName "1.0"
12 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
13 |
14 | externalNativeBuild {
15 | ndkBuild {
16 | abiFilters "armeabi", "armeabi-v7a"
17 | }
18 | }
19 |
20 |
21 | }
22 | sourceSets.main {
23 | jni.srcDirs 'src/main/jni'
24 | }
25 | buildTypes {
26 | release {
27 | minifyEnabled false
28 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
29 | }
30 | }
31 | externalNativeBuild {
32 | ndkBuild {
33 | path 'src/main/jni/Android.mk'
34 | }
35 | }
36 | }
37 |
38 | dependencies {
39 | compile fileTree(include: ['*.jar'], dir: 'libs')
40 | androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
41 | exclude group: 'com.android.support', module: 'support-annotations'
42 | })
43 | compile 'com.android.support:appcompat-v7:26.+'
44 | compile 'com.android.support.constraint:constraint-layout:1.0.2'
45 | testCompile 'junit:junit:4.12'
46 | provided files('lib/XposedBridgeApi-54.jar')
47 | }
48 |
--------------------------------------------------------------------------------
/app/lib/XposedBridgeApi-54.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/smartdone/dexdump/7cc4a427b0e9377829de020ecf037942eb74f0c6/app/lib/XposedBridgeApi-54.jar
--------------------------------------------------------------------------------
/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | # Add project specific ProGuard rules here.
2 | # By default, the flags in this file are appended to flags specified
3 | # in /Users/smartdone/Library/Android/sdk/tools/proguard/proguard-android.txt
4 | # You can edit the include path and order by changing the proguardFiles
5 | # directive in build.gradle.
6 | #
7 | # For more details, see
8 | # http://developer.android.com/guide/developing/tools/proguard.html
9 |
10 | # Add any project specific keep options here:
11 |
12 | # If your project uses WebView with JS, uncomment the following
13 | # and specify the fully qualified class name to the JavaScript interface
14 | # class:
15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
16 | # public *;
17 | #}
18 |
19 | # Uncomment this to preserve the line number information for
20 | # debugging stack traces.
21 | #-keepattributes SourceFile,LineNumberTable
22 |
23 | # If you keep the line number information, uncomment this to
24 | # hide the original source file name.
25 | #-renamesourcefileattribute SourceFile
26 |
--------------------------------------------------------------------------------
/app/src/androidTest/java/com/smartdone/dexdump/ExampleInstrumentedTest.java:
--------------------------------------------------------------------------------
1 | package com.smartdone.dexdump;
2 |
3 | import android.content.Context;
4 | import android.support.test.InstrumentationRegistry;
5 | import android.support.test.runner.AndroidJUnit4;
6 |
7 | import org.junit.Test;
8 | import org.junit.runner.RunWith;
9 |
10 | import static org.junit.Assert.*;
11 |
12 | /**
13 | * Instrumentation test, which will execute on an Android device.
14 | *
15 | * @see Testing documentation
16 | */
17 | @RunWith(AndroidJUnit4.class)
18 | public class ExampleInstrumentedTest {
19 | @Test
20 | public void useAppContext() throws Exception {
21 | // Context of the app under test.
22 | Context appContext = InstrumentationRegistry.getTargetContext();
23 |
24 | assertEquals("com.smartdone.dexdump", appContext.getPackageName());
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/app/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
8 |
9 |
16 |
19 |
22 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
--------------------------------------------------------------------------------
/app/src/main/assets/xposed_init:
--------------------------------------------------------------------------------
1 | com.smartdone.dexdump.Main
--------------------------------------------------------------------------------
/app/src/main/java/com/smartdone/dexdump/Appinfo.java:
--------------------------------------------------------------------------------
1 | package com.smartdone.dexdump;
2 |
3 | import android.graphics.drawable.Drawable;
4 |
5 | /**
6 | * Created by smartdone on 2017/7/2.
7 | */
8 |
9 | public class Appinfo {
10 | private String appName;
11 | private String appPackage;
12 | private boolean isChecked;
13 | private Drawable icon;
14 |
15 | public Drawable getIcon() {
16 | return icon;
17 | }
18 |
19 | public void setIcon(Drawable icon) {
20 | this.icon = icon;
21 | }
22 |
23 | public Appinfo() {
24 |
25 | }
26 |
27 | public Appinfo(String appName, String appPackage) {
28 | this.appName = appName;
29 | this.appPackage = appPackage;
30 | }
31 |
32 | public String getAppName() {
33 | return appName;
34 | }
35 |
36 | public void setAppName(String appName) {
37 | this.appName = appName;
38 | }
39 |
40 | public String getAppPackage() {
41 | return appPackage;
42 | }
43 |
44 | public void setAppPackage(String appPackage) {
45 | this.appPackage = appPackage;
46 | }
47 |
48 | public boolean isChecked() {
49 | return isChecked;
50 | }
51 |
52 | public void setChecked(boolean checked) {
53 | this.isChecked = checked;
54 | }
55 |
56 | }
57 |
--------------------------------------------------------------------------------
/app/src/main/java/com/smartdone/dexdump/Config.java:
--------------------------------------------------------------------------------
1 | package com.smartdone.dexdump;
2 |
3 | import android.os.Environment;
4 | import android.util.Log;
5 |
6 | import org.json.JSONArray;
7 |
8 | import java.io.BufferedReader;
9 | import java.io.File;
10 | import java.io.FileInputStream;
11 | import java.io.FileOutputStream;
12 | import java.io.InputStreamReader;
13 | import java.util.ArrayList;
14 | import java.util.List;
15 |
16 | /**
17 | * Created by smartdone on 2017/7/2.
18 | */
19 |
20 | public class Config {
21 | private static final String TAG = "DEX_DUMP";
22 | private static final String FILENAME = Environment.getExternalStorageDirectory().getPath() + File.separator + "dumdex.js";
23 |
24 | private static void writeConfig(String s) {
25 | try {
26 | FileOutputStream fout = new FileOutputStream(FILENAME);
27 | fout.write(s.getBytes("utf-8"));
28 | fout.flush();
29 | fout.close();
30 | Log.e("DEX_DUMP", "write file");
31 | } catch (Exception e) {
32 | e.printStackTrace();
33 | }
34 | }
35 |
36 | public static void addOne(String name) {
37 | List ori = getConfig();
38 | if(ori == null) {
39 | JSONArray jsonArray = new JSONArray();
40 | jsonArray.put(name);
41 | writeConfig(jsonArray.toString());
42 | }else {
43 | ori.add(name);
44 | JSONArray jsonArray = new JSONArray();
45 | for(String o : ori) {
46 | jsonArray.put(o);
47 | }
48 | writeConfig(jsonArray.toString());
49 | }
50 | }
51 |
52 | public static void removeOne(String name) {
53 | List ori = getConfig();
54 | if(ori != null) {
55 | for(int i = 0; i < ori.size(); i++) {
56 | if(ori.get(i).equals(name)) {
57 | ori.remove(i);
58 | }
59 | }
60 | JSONArray jsonArray = new JSONArray();
61 | for(String s : ori) {
62 | jsonArray.put(s);
63 | }
64 | writeConfig(jsonArray.toString());
65 | }
66 | }
67 |
68 | public static List getConfig() {
69 | File file = new File(FILENAME);
70 | if (file.exists() && file.canRead()) {
71 | try {
72 | BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(file)));
73 | String line = br.readLine();
74 | JSONArray jsonArray = new JSONArray(line);
75 | List apps = new ArrayList<>();
76 | for(int i = 0; i < jsonArray.length(); i++) {
77 | apps.add(jsonArray.getString(i));
78 | }
79 | br.close();
80 | // Log.e("DEX_DUMP", "需要hook的列表: " + line);
81 | return apps;
82 | } catch (Exception e) {
83 | e.printStackTrace();
84 | }
85 | } else {
86 | try {
87 | if (!file.exists())
88 | file.createNewFile();
89 | if(!file.canRead())
90 | Log.e(TAG, "文件没有读取权限");
91 | } catch (Exception e) {
92 | e.printStackTrace();
93 | }
94 | }
95 | return null;
96 | }
97 |
98 | public static boolean contains(List lists, String name) {
99 | if(lists == null) {
100 | return false;
101 | }
102 | for(String l : lists) {
103 | if(l.equals(name)) {
104 | return true;
105 | }
106 | }
107 | return false;
108 | }
109 |
110 | }
111 |
--------------------------------------------------------------------------------
/app/src/main/java/com/smartdone/dexdump/DensityUtil.java:
--------------------------------------------------------------------------------
1 | package com.smartdone.dexdump;
2 |
3 | import android.content.Context;
4 |
5 | /**
6 | * Created by root on 2017/7/5.
7 | */
8 |
9 | public class DensityUtil {
10 | /**
11 | * 根据手机的分辨率从 dp 的单位 转成为 px(像素)
12 | */
13 | public static int dip2px(Context context, float dpValue) {
14 | final float scale = context.getResources().getDisplayMetrics().density;
15 | return (int) (dpValue * scale + 0.5f);
16 | }
17 |
18 | /**
19 | * 根据手机的分辨率从 px(像素) 的单位 转成为 dp
20 | */
21 | public static int px2dip(Context context, float pxValue) {
22 | final float scale = context.getResources().getDisplayMetrics().density;
23 | return (int) (pxValue / scale + 0.5f);
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/app/src/main/java/com/smartdone/dexdump/Dumpper.java:
--------------------------------------------------------------------------------
1 | package com.smartdone.dexdump;
2 |
3 | /**
4 | * Created by smartdone on 2017/7/1.
5 | */
6 |
7 | public class Dumpper {
8 | public static native void dump();
9 | }
10 |
--------------------------------------------------------------------------------
/app/src/main/java/com/smartdone/dexdump/Main.java:
--------------------------------------------------------------------------------
1 | package com.smartdone.dexdump;
2 |
3 | import android.content.Context;
4 | import android.util.Log;
5 |
6 | import java.util.List;
7 |
8 | import de.robv.android.xposed.IXposedHookLoadPackage;
9 | import de.robv.android.xposed.XC_MethodHook;
10 | import de.robv.android.xposed.XposedBridge;
11 | import de.robv.android.xposed.XposedHelpers;
12 | import de.robv.android.xposed.callbacks.XC_LoadPackage;
13 |
14 | /**
15 | * Created by smartdone on 2017/7/1.
16 | */
17 |
18 | public class Main implements IXposedHookLoadPackage {
19 | private static final String TAG = "DEX_DUMP";
20 | @Override
21 | public void handleLoadPackage(final XC_LoadPackage.LoadPackageParam loadPackageParam) throws Throwable {
22 |
23 | List hooklist = Config.getConfig();
24 |
25 | if(!Config.contains(hooklist, loadPackageParam.packageName))
26 | return;
27 |
28 | XposedBridge.log("对" + loadPackageParam.packageName + "进行处理");
29 | Log.e(TAG, "开始处理: " + loadPackageParam.packageName);
30 |
31 | try{
32 | System.load("/data/local/tmp/libhook.so");
33 | }catch (Exception e) {
34 | Log.e(TAG, "加载动态库失败:" + e.getMessage());
35 | }
36 | Log.e(TAG, "加载动态库成功");
37 | XposedHelpers.findAndHookMethod("android.app.Application", loadPackageParam.classLoader, "attach", Context.class, new XC_MethodHook() {
38 | private Context context;
39 | @Override
40 | protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
41 | super.beforeHookedMethod(param);
42 | Dumpper.dump();
43 | }
44 |
45 | @Override
46 | protected void afterHookedMethod(MethodHookParam param) throws Throwable {
47 | super.afterHookedMethod(param);
48 | }
49 | });
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/app/src/main/java/com/smartdone/dexdump/MainActivity.java:
--------------------------------------------------------------------------------
1 | package com.smartdone.dexdump;
2 |
3 | import android.content.Intent;
4 | import android.content.pm.ApplicationInfo;
5 | import android.content.pm.PackageInfo;
6 | import android.content.pm.PackageManager;
7 | import android.content.pm.ResolveInfo;
8 | import android.graphics.PixelFormat;
9 | import android.graphics.drawable.BitmapDrawable;
10 | import android.graphics.drawable.Drawable;
11 | import android.support.v7.app.AppCompatActivity;
12 | import android.os.Bundle;
13 | import android.view.LayoutInflater;
14 | import android.view.View;
15 | import android.view.ViewGroup;
16 | import android.widget.BaseAdapter;
17 | import android.widget.CheckBox;
18 | import android.widget.CompoundButton;
19 | import android.widget.ImageView;
20 | import android.widget.ListView;
21 | import android.widget.TextView;
22 | import android.graphics.Bitmap;
23 | import android.graphics.Canvas;
24 | import android.graphics.Matrix;
25 |
26 |
27 | import java.util.ArrayList;
28 | import java.util.List;
29 |
30 | public class MainActivity extends AppCompatActivity {
31 |
32 | static {
33 | System.loadLibrary("hook");
34 | }
35 |
36 | private ListView listView;
37 | private AppAdapter adapter;
38 | private List appinfos;
39 | private List selected;
40 |
41 | @Override
42 | protected void onCreate(Bundle savedInstanceState) {
43 | super.onCreate(savedInstanceState);
44 | setContentView(R.layout.activity_main);
45 | PermisionUtils.verifyStoragePermissions(this);
46 | Dumpper.dump();
47 | selected = Config.getConfig();
48 | appinfos = new ArrayList<>();
49 |
50 | listView = findViewById(R.id.applist);
51 | adapter = new AppAdapter(appinfos);
52 | listView.setAdapter(adapter);
53 | getInstallAppList();
54 | adapter.notifyDataSetChanged();
55 |
56 | }
57 |
58 |
59 | private void getInstallAppList() {
60 | try {
61 | if(getApiLevel() <= 23) {
62 | List packageInfos = getPackageManager().getInstalledPackages(0);
63 | for (PackageInfo packageInfo : packageInfos) {
64 | if ((packageInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0) {
65 | Appinfo info = new Appinfo();
66 | info.setIcon(zoomDrawable(packageInfo.applicationInfo.loadIcon(getPackageManager()), DensityUtil.dip2px(this, 128), DensityUtil.dip2px(this, 128)));
67 | info.setAppName(packageInfo.applicationInfo.loadLabel(getPackageManager()).toString());
68 | info.setAppPackage(packageInfo.packageName);
69 | if (Config.contains(selected, info.getAppPackage())) {
70 | info.setChecked(true);
71 | } else {
72 | info.setChecked(false);
73 | }
74 | appinfos.add(info);
75 | }
76 | }
77 | } else {
78 | Intent startupIntent = new Intent(Intent.ACTION_MAIN);
79 | startupIntent.addCategory(Intent.CATEGORY_LAUNCHER);
80 | final PackageManager pm = getPackageManager();
81 | List activities = pm.queryIntentActivities(startupIntent, 0);
82 | for(ResolveInfo resolveInfo : activities) {
83 | Appinfo appinfo = new Appinfo();
84 | appinfo.setIcon(zoomDrawable(resolveInfo.loadIcon(pm), DensityUtil.dip2px(this, 128), DensityUtil.dip2px(this, 128)));
85 | appinfo.setAppName(resolveInfo.loadLabel(pm).toString());
86 | appinfo.setAppPackage(resolveInfo.activityInfo.packageName);
87 |
88 | if (Config.contains(selected, appinfo.getAppPackage())) {
89 | appinfo.setChecked(true);
90 | } else {
91 | appinfo.setChecked(false);
92 | }
93 | appinfos.add(appinfo);
94 | }
95 | }
96 | // adapter.notifyDataSetChanged();
97 | } catch (Exception e) {
98 | e.printStackTrace();
99 | }
100 | }
101 |
102 | private int getApiLevel() {
103 | return Integer.parseInt(android.os.Build.VERSION.SDK);
104 | }
105 |
106 | class AppAdapter extends BaseAdapter {
107 |
108 | private List appinfos;
109 |
110 | private AppAdapter(List appinfos) {
111 | this.appinfos = appinfos;
112 | }
113 |
114 | @Override
115 | public int getCount() {
116 | return appinfos.size();
117 | }
118 |
119 | @Override
120 | public Object getItem(int i) {
121 | return appinfos.get(i);
122 | }
123 |
124 | @Override
125 | public long getItemId(int i) {
126 | return i;
127 | }
128 |
129 | @Override
130 | public View getView(int i, View view, ViewGroup viewGroup) {
131 | View v = LayoutInflater.from(MainActivity.this).inflate(R.layout.item, null);
132 | final int posi = i;
133 | final TextView appname = v.findViewById(R.id.tv_appname);
134 | appname.setText(appinfos.get(i).getAppName());
135 | TextView appPackage = v.findViewById(R.id.tv_apppackage);
136 | appPackage.setText(appinfos.get(i).getAppPackage());
137 | CheckBox checkBox = v.findViewById(R.id.cb_select);
138 | ImageView icon = v.findViewById(R.id.iv_icon);
139 | icon.setImageDrawable(appinfos.get(i).getIcon());
140 | if (appinfos.get(i).isChecked()) {
141 | checkBox.setChecked(true);
142 | } else {
143 | checkBox.setChecked(false);
144 | }
145 | checkBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
146 | @Override
147 | public void onCheckedChanged(CompoundButton compoundButton, boolean b) {
148 | if (b) {
149 | Config.addOne(appinfos.get(posi).getAppPackage());
150 | } else {
151 | Config.removeOne(appinfos.get(posi).getAppPackage());
152 | }
153 | }
154 | });
155 | return v;
156 | }
157 | }
158 |
159 | private Drawable zoomDrawable(Drawable drawable, int w, int h) {
160 | int width = drawable.getIntrinsicWidth();
161 | int height = drawable.getIntrinsicHeight();
162 | Bitmap oldbmp = drawableToBitmap(drawable);
163 | Matrix matrix = new Matrix();
164 | float scaleWidth = ((float) w / width);
165 | float scaleHeight = ((float) h / height);
166 | matrix.postScale(scaleWidth, scaleHeight);
167 | Bitmap newbmp = Bitmap.createBitmap(oldbmp, 0, 0, width, height,
168 | matrix, true);
169 | return new BitmapDrawable(null, newbmp);
170 | }
171 |
172 | private Bitmap drawableToBitmap(Drawable drawable) {
173 | int width = drawable.getIntrinsicWidth();
174 | int height = drawable.getIntrinsicHeight();
175 | Bitmap.Config config = drawable.getOpacity() != PixelFormat.OPAQUE ? Bitmap.Config.ARGB_8888
176 | : Bitmap.Config.RGB_565;
177 | Bitmap bitmap = Bitmap.createBitmap(width, height, config);
178 | Canvas canvas = new Canvas(bitmap);
179 | drawable.setBounds(0, 0, width, height);
180 | drawable.draw(canvas);
181 | return bitmap;
182 | }
183 | }
184 |
--------------------------------------------------------------------------------
/app/src/main/java/com/smartdone/dexdump/PermisionUtils.java:
--------------------------------------------------------------------------------
1 | package com.smartdone.dexdump;
2 |
3 | /**
4 | * 来源 http://blog.csdn.net/wi2rfl78/article/details/78314286
5 | */
6 |
7 | import android.Manifest;
8 | import android.app.Activity;
9 | import android.content.pm.PackageManager;
10 | import android.support.v4.app.ActivityCompat;
11 |
12 | public class PermisionUtils {
13 |
14 | // Storage Permissions
15 | private static final int REQUEST_EXTERNAL_STORAGE = 1;
16 | private static String[] PERMISSIONS_STORAGE = {
17 | Manifest.permission.READ_EXTERNAL_STORAGE,
18 | Manifest.permission.WRITE_EXTERNAL_STORAGE};
19 |
20 | /**
21 | * Checks if the app has permission to write to device storage
22 | * If the app does not has permission then the user will be prompted to
23 | * grant permissions
24 | *
25 | * @param activity
26 | */
27 | public static void verifyStoragePermissions(Activity activity) {
28 | // Check if we have write permission
29 | int permission = ActivityCompat.checkSelfPermission(activity,
30 | Manifest.permission.WRITE_EXTERNAL_STORAGE);
31 |
32 | if (permission != PackageManager.PERMISSION_GRANTED) {
33 | // We don't have permission so prompt the user
34 | ActivityCompat.requestPermissions(activity, PERMISSIONS_STORAGE,
35 | REQUEST_EXTERNAL_STORAGE);
36 | }
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/app/src/main/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 | #
16 | #
17 | LOCAL_PATH := $(call my-dir)
18 |
19 | include $(CLEAR_VARS)
20 | LOCAL_MODULE := hook
21 | LOCAL_SRC_FILES := inlineHook.c relocate.c dlopen.c dump.cpp
22 | LOCAL_LDLIBS := -llog
23 | include $(BUILD_SHARED_LIBRARY)
24 |
--------------------------------------------------------------------------------
/app/src/main/jni/Application.mk:
--------------------------------------------------------------------------------
1 | APP_ABI := armeabi armeabi-v7a
2 | APP_PIE:= true
3 | APP_STL := stlport_static
--------------------------------------------------------------------------------
/app/src/main/jni/dlopen.c:
--------------------------------------------------------------------------------
1 | /*
2 | *
3 | * @author : rrrfff@foxmail.com
4 | * https://github.com/rrrfff/ndk_dlopen
5 | *
6 | */
7 | #include "dlopen.h"
8 | #include
9 | #include
10 | #include
11 | #include
12 | #include
13 | #include
14 | #include
15 |
16 | #define LOG_TAG "ndk_dlopen"
17 | #define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)
18 |
19 | static volatile int SDK_INT = 0;
20 | static void *quick_on_stack_back;
21 | static union
22 | {
23 | void *generic_stub;
24 | void *(*quick_on_stack_replace)(const void *param1, const void *param2,
25 | const void *fake_trampoline, const void *called);
26 | } STUBS;
27 |
28 | void JNIEXPORT ndk_init(JNIEnv *env)
29 | {
30 | if (SDK_INT <= 0) {
31 | char sdk[PROP_VALUE_MAX];
32 | __system_property_get("ro.build.version.sdk", sdk);
33 | SDK_INT = atoi(sdk);
34 | LOGI("SDK_INT = %d", SDK_INT);
35 | if (SDK_INT >= 24) {
36 | static __attribute__((__aligned__(PAGE_SIZE))) uint8_t __insns[PAGE_SIZE];
37 | STUBS.generic_stub = __insns;
38 | mprotect(__insns, sizeof(__insns), PROT_READ | PROT_WRITE | PROT_EXEC);
39 |
40 | // we are currently hijacking "FatalError" as a fake system-call trampoline
41 | uintptr_t pv = (uintptr_t)(*env)->FatalError;
42 | uintptr_t pu = (pv | (PAGE_SIZE - 1)) + 1u;
43 | uintptr_t pd = (pv & ~(PAGE_SIZE - 1));
44 | mprotect((void *)pd, pv + 8u >= pu ? PAGE_SIZE * 2u : PAGE_SIZE, PROT_READ | PROT_WRITE | PROT_EXEC);
45 | quick_on_stack_back = (void *)pv;
46 |
47 | #if defined(__i386__)
48 | /*
49 | DEFINE_FUNCTION art_quick_on_stack_replace
50 | movl 12(REG_VAR(esp)), REG_VAR(eax)
51 | movl (REG_VAR(esp)), REG_VAR(edx)
52 | movl REG_VAR(eax), (REG_VAR(esp))
53 | movl REG_VAR(edx), 12(REG_VAR(esp))
54 | pushl 16(REG_VAR(esp))
55 | ret
56 | END_FUNCTION art_quick_on_stack_replace
57 | */
58 | memcpy(__insns, "\x8B\x44\x24\x0C\x8B\x14\x24\x89\x04\x24\x89\x54\x24\x0C\xFF\x74\x24\x10\xC3", 19);
59 | /*
60 | DEFINE_FUNCTION art_quick_on_stack_back
61 | push 8(REG_VAR(esp))
62 | ret
63 | END_FUNCTION art_quick_on_stack_back
64 | */
65 | memcpy(quick_on_stack_back, "\xC3\xFF\x74\x24\x08\xC3", 6);
66 | quick_on_stack_back = (void *)(pv + 1); // inserts `ret` at first
67 | #elif defined(__x86_64__)
68 | // rdi, rsi, rdx, rcx, r8, r9
69 | /*
70 | 0x0000000000000000: 52 push rdx
71 | 0x0000000000000001: FF E1 jmp rcx
72 | */
73 | memcpy(__insns, "\x52\xFF\xE1", 3);
74 | /*
75 | 0x0000000000000000: C3 ret
76 | */
77 | memcpy(quick_on_stack_back, "\xC3", 1);
78 | #elif defined(__aarch64__)
79 | // x0~x7
80 | /*
81 | 0x0000000000000000: FD 7B BF A9 stp x29, x30, [sp, #-0x10]!
82 | 0x0000000000000004: FD 03 00 91 mov x29, sp
83 | 0x0000000000000008: FE 03 02 AA mov x30, x2
84 | 0x000000000000000C: 60 00 1F D6 br x3
85 | */
86 | memcpy(__insns, "\xFD\x7B\xBF\xA9\xFD\x03\x00\x91\xFE\x03\x02\xAA\x60\x00\x1F\xD6", 16);
87 | /*
88 | 0x0000000000000000: FD 7B C1 A8 ldp x29, x30, [sp], #0x10
89 | 0x0000000000000004: C0 03 5F D6 ret
90 | */
91 | memcpy(quick_on_stack_back, "\xFD\x7B\xC1\xA8\xC0\x03\x5F\xD6", 8);
92 | #elif defined(__arm__)
93 | // r0~r3
94 | /*
95 | 0x0000000000000000: 04 E0 2D E5 str lr, [sp, #-4]!
96 | 0x0000000000000004: 02 E0 A0 E1 mov lr, r2
97 | 0x0000000000000008: 13 FF 2F E1 bx r3
98 | */
99 | memcpy(__insns, "\x04\xE0\x2D\xE5\x02\xE0\xA0\xE1\x13\xFF\x2F\xE1", 12);
100 | if ((pv & 1u) != 0u) { // Thumb
101 | /*
102 | 0x0000000000000000: 08 BC pop {r3}
103 | 0x0000000000000002: 18 47 bx r3
104 | */
105 | memcpy((void *)(pv - 1), "\x08\xBC\x18\x47", 4);
106 | } else {
107 | /*
108 | 0x0000000000000000: 04 30 9D E4 pop {r3}
109 | 0x0000000000000004: 13 FF 2F E1 bx r3
110 | */
111 | memcpy(quick_on_stack_back, "\x04\x30\x9D\xE4\x13\xFF\x2F\xE1", 8);
112 | } //if
113 | #else
114 | # error "not supported"
115 | #endif
116 | LOGI("init done! quick_on_stack_replace = %p, quick_on_stack_back = %p",
117 | STUBS.generic_stub, quick_on_stack_back);
118 | } //if
119 | } //if
120 | }
121 |
122 | void *JNIEXPORT ndk_dlopen(const char *filename, int flag)
123 | {
124 | if (SDK_INT >= 24) {
125 | #if defined(__i386__) || defined(__x86_64__) || defined(__aarch64__) || defined(__arm__)
126 | return STUBS.quick_on_stack_replace(filename, (void *)flag,
127 | quick_on_stack_back, dlopen);
128 | #else
129 | # error "not supported"
130 | #endif
131 | } //if
132 |
133 | return dlopen(filename, flag);
134 | }
135 |
136 | int JNIEXPORT ndk_dlclose(void *handle)
137 | {
138 | if (SDK_INT >= 24) {
139 | #if defined(__i386__) || defined(__x86_64__) || defined(__aarch64__) || defined(__arm__)
140 | return (int)STUBS.quick_on_stack_replace(handle, NULL,
141 | quick_on_stack_back, dlclose);
142 | #else
143 | # error "not supported"
144 | #endif
145 | } //if
146 |
147 | return dlclose(handle);
148 | }
149 |
150 | const char *JNIEXPORT ndk_dlerror(void)
151 | {
152 | if (SDK_INT >= 24) {
153 | #if defined(__i386__) || defined(__x86_64__) || defined(__aarch64__) || defined(__arm__)
154 | return STUBS.quick_on_stack_replace(NULL, NULL,
155 | quick_on_stack_back, dlerror);
156 | #else
157 | # error "not supported"
158 | #endif
159 | } //if
160 |
161 | return dlerror();
162 | }
163 |
164 | void *JNIEXPORT ndk_dlsym(void *handle, const char *symbol)
165 | {
166 | if (SDK_INT >= 24) {
167 | #if defined(__i386__) || defined(__x86_64__) || defined(__aarch64__) || defined(__arm__)
168 | return STUBS.quick_on_stack_replace(handle, symbol,
169 | quick_on_stack_back, dlsym);
170 |
171 | #else
172 | # error "not supported"
173 | #endif
174 | } //if
175 |
176 | return dlsym(handle, symbol);
177 | }
178 |
179 | int JNIEXPORT ndk_dladdr(const void *ddr, Dl_info *info)
180 | {
181 | if (SDK_INT >= 24) {
182 | #if defined(__i386__) || defined(__x86_64__) || defined(__aarch64__) || defined(__arm__)
183 | return (int)STUBS.quick_on_stack_replace(ddr, info,
184 | quick_on_stack_back, dladdr);
185 | #else
186 | # error "not supported"
187 | #endif
188 | } //if
189 |
190 | return dladdr(ddr, info);
191 | }
192 |
--------------------------------------------------------------------------------
/app/src/main/jni/dlopen.h:
--------------------------------------------------------------------------------
1 | /*
2 | *
3 | * @author : rrrfff@foxmail.com
4 | * https://github.com/rrrfff/ndk_dlopen
5 | *
6 | */
7 | #pragma once
8 | #include
9 | #include
10 |
11 | #ifdef __cplusplus
12 | extern "C" {
13 | #endif
14 |
15 | void ndk_init(JNIEnv *env);
16 | void *ndk_dlopen(const char *filename, int flag);
17 | int ndk_dlclose(void *handle);
18 | const char *ndk_dlerror(void);
19 | void *ndk_dlsym(void *handle, const char *symbol);
20 | int ndk_dladdr(const void *ddr, Dl_info *info);
21 |
22 | #ifdef __cplusplus
23 | }
24 | #endif
25 |
--------------------------------------------------------------------------------
/app/src/main/jni/dump.cpp:
--------------------------------------------------------------------------------
1 | //
2 | // Created by 袁东明 on 2017/7/1.
3 | //
4 |
5 | extern "C" {
6 | #include "include/inlineHook.h"
7 | #include "dlopen.h"
8 | }
9 |
10 | #include "dump.h"
11 | #include
12 | #include
13 | #include
14 | #include
15 | #include
16 | #include
17 | #include
18 | #include
19 |
20 |
21 | #define TAG "DEX_DUMP"
22 |
23 | int apiLevel();
24 |
25 | void getProcessName(int pid, char *name, int len);
26 |
27 | void dumpFileName(char *name, int len, const char *pname, int dexlen);
28 |
29 | static char pname[256];
30 |
31 | int apiLevel() {
32 | char version[10];
33 | __system_property_get("ro.build.version.sdk", version);
34 | __android_log_print(ANDROID_LOG_INFO, TAG, "api level %s", version);
35 | int sdk = atoi(version);
36 | return sdk;
37 | }
38 |
39 | void getProcessName(int pid, char *name, int len) {
40 | int fp = open("/proc/self/cmdline", O_RDONLY);
41 | memset(name, 0, len);
42 | read(fp, name, len);
43 | close(fp);
44 | }
45 |
46 | void dumpFileName(char *name, int len, const char *pname, int dexlen) {
47 | time_t now;
48 | struct tm *timenow;
49 | time(&now);
50 | timenow = localtime(&now);
51 | memset(name, 0, len);
52 | sprintf(name, "/data/data/%s/dump_size_%u_time_%d_%d_%d_%d_%d_%d.dex", pname, dexlen,
53 | timenow->tm_year + 1900,
54 | timenow->tm_mon + 1,
55 | timenow->tm_mday,
56 | timenow->tm_hour,
57 | timenow->tm_min,
58 | timenow->tm_sec);
59 | }
60 |
61 | void writeToFile(const char *pname, u_int8_t *data, size_t length) {
62 | char dname[1024];
63 | dumpFileName(dname, sizeof(dname), pname, length);
64 | __android_log_print(ANDROID_LOG_ERROR, TAG, "dump dex file name is : %s", dname);
65 | __android_log_print(ANDROID_LOG_ERROR, TAG, "start dump");
66 | int dex = open(dname, O_CREAT | O_WRONLY, 0644);
67 | if (dex < 0) {
68 | __android_log_print(ANDROID_LOG_ERROR, TAG, "open or create file error");
69 | return;
70 | }
71 | int ret = write(dex, data, length);
72 | if (ret < 0) {
73 | __android_log_print(ANDROID_LOG_ERROR, TAG, "write file error");
74 | } else {
75 | __android_log_print(ANDROID_LOG_ERROR, TAG, "dump dex file success `%s`", dname);
76 | }
77 | close(dex);
78 | }
79 |
80 | art::DexFile *(*old_openmemory)(const byte *base, size_t size, const std::string &location,
81 | uint32_t location_checksum, art::MemMap *mem_map,
82 | const art::OatDexFile *oat_dex_file, std::string *error_msg) = NULL;
83 |
84 | art::DexFile *new_openmemory(const byte *base, size_t size, const std::string &location,
85 | uint32_t location_checksum, art::MemMap *mem_map,
86 | const art::OatDexFile *oat_dex_file, std::string *error_msg) {
87 | __android_log_print(ANDROID_LOG_ERROR, TAG, "art::DexFile::OpenMemory is called");
88 | writeToFile(pname, (uint8_t *) base, size);
89 | return (*old_openmemory)(base, size, location, location_checksum, mem_map, oat_dex_file,
90 | error_msg);
91 | }
92 |
93 |
94 | art::DexFile *(*old_openmemory_23)(void* DexFile_thiz,char* base,int size,void* location,
95 | void* location_checksum,void* mem_map,void* oat_dex_file,void* error_meessage) = NULL;
96 |
97 | art::DexFile *new_openmemory_23(void* DexFile_thiz,char* base,int size,void* location,
98 | void* location_checksum,void* mem_map,void* oat_dex_file,void* error_meessage) {
99 | writeToFile(pname, (u_int8_t *)base, size);
100 | return (*old_openmemory_23)(DexFile_thiz, base, size, location, location_checksum, mem_map,
101 | oat_dex_file, error_meessage);
102 | }
103 |
104 | DexFile* (*old_dexFileParse)(const u1 *data, size_t length, int flags) = NULL;
105 |
106 | DexFile* new_dexFileParse(const u1 *data, size_t length, int flags) {
107 | writeToFile(pname, (u_int8_t *)data, length);
108 | return (*old_dexFileParse)(data, length, flags);
109 | }
110 |
111 | DvmDex* (*old_dvmDexFileOpenPartial)(const void* addr, int len, DvmDex** ppDvmDex) = NULL;
112 |
113 | DvmDex* new_dvmDexFileOpenPartial(const void* addr, int len, DvmDex** ppDvmDex) {
114 | writeToFile(pname, (u_int8_t *)addr, len);
115 | return (*old_dvmDexFileOpenPartial)(addr, len, ppDvmDex);
116 | }
117 |
118 | void hook_dvm() {
119 | void *handle = dlopen("libdvm.so", RTLD_GLOBAL | RTLD_LAZY);
120 | if(handle == NULL) {
121 | __android_log_print(ANDROID_LOG_ERROR, TAG, "Error: unable to find the SO : libdvm.so");
122 | return;
123 | }
124 | void *addr = dlsym(handle, "_Z12dexFileParsePKhji");
125 | if(addr == NULL) {
126 | __android_log_print(ANDROID_LOG_ERROR, TAG, "Unable find symbol _Z12dexFileParsePKhji");
127 | return;
128 | }
129 | if (registerInlineHook((uint32_t) addr, (uint32_t) new_dexFileParse,
130 | (uint32_t **) &old_dexFileParse) != ELE7EN_OK) {
131 | __android_log_print(ANDROID_LOG_ERROR, TAG, "register hook failed");
132 | return;
133 | }
134 |
135 | if (inlineHook((uint32_t) addr) != ELE7EN_OK) {
136 | __android_log_print(ANDROID_LOG_ERROR, TAG, "register hook failed");
137 | return;
138 | }
139 |
140 | addr = dlsym(handle, "_Z21dvmDexFileOpenPartialPKviPP6DvmDex");
141 | if(addr == NULL) {
142 | __android_log_print(ANDROID_LOG_ERROR, TAG, "Unable find symbol _Z21dvmDexFileOpenPartialPKviPP6DvmDex");
143 | return;
144 | }
145 | if (registerInlineHook((uint32_t) addr, (uint32_t) new_dvmDexFileOpenPartial,
146 | (uint32_t **) &old_dvmDexFileOpenPartial) != ELE7EN_OK) {
147 | __android_log_print(ANDROID_LOG_ERROR, TAG, "register hook failed");
148 | return;
149 | }
150 |
151 | if (inlineHook((uint32_t) addr) != ELE7EN_OK) {
152 | __android_log_print(ANDROID_LOG_ERROR, TAG, "register hook failed");
153 | return;
154 | }
155 |
156 | }
157 |
158 | void hook_21_22() {
159 | void *handle = dlopen("libart.so", RTLD_GLOBAL | RTLD_LAZY);
160 | if (handle == NULL) {
161 | __android_log_print(ANDROID_LOG_ERROR, TAG, "Error: unable to find the SO : libart.so");
162 | return;
163 | }
164 | void *addr = dlsym(handle,
165 | "_ZN3art7DexFile10OpenMemoryEPKhjRKNSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEEjPNS_6MemMapEPKNS_10OatDexFileEPS9_");
166 | if (addr == NULL) {
167 | __android_log_print(ANDROID_LOG_ERROR, TAG,
168 | "Error: unable to find the Symbol : _ZN3art7DexFile10OpenMemoryEPKhjRKNSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEEjPNS_6MemMapEPKNS_10OatDexFileEPS9_");
169 | return;
170 | }
171 |
172 | if (registerInlineHook((uint32_t) addr, (uint32_t) new_openmemory,
173 | (uint32_t **) &old_openmemory) != ELE7EN_OK) {
174 | __android_log_print(ANDROID_LOG_ERROR, TAG, "register hook failed");
175 | return;
176 | }
177 |
178 | if (inlineHook((uint32_t) addr) != ELE7EN_OK) {
179 | __android_log_print(ANDROID_LOG_ERROR, TAG, "register hook failed");
180 | return;
181 | }
182 |
183 | __android_log_print(ANDROID_LOG_INFO, TAG, "register hook success");
184 | }
185 |
186 | void hook_23_plus() {
187 | void *handle = ndk_dlopen("libart.so", RTLD_NOW);
188 | if (handle == NULL) {
189 | __android_log_print(ANDROID_LOG_ERROR, TAG, "Error: unable to find the SO : libart.so");
190 | return;
191 | }
192 | void *addr = ndk_dlsym(handle,
193 | "_ZN3art7DexFile10OpenMemoryEPKhjRKNSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEEjPNS_6MemMapEPKNS_10OatDexFileEPS9_");
194 | if (addr == NULL) {
195 | __android_log_print(ANDROID_LOG_ERROR, TAG,
196 | "Error: unable to find the Symbol : _ZN3art7DexFile10OpenMemoryEPKhjRKNSt3__112basic_stringIcNS3_11char_traitsIcEENS3_9allocatorIcEEEEjPNS_6MemMapEPKNS_10OatDexFileEPS9_");
197 | return;
198 | }
199 |
200 | if (registerInlineHook((uint32_t) addr, (uint32_t) new_openmemory_23,
201 | (uint32_t **) &old_openmemory_23) != ELE7EN_OK) {
202 | __android_log_print(ANDROID_LOG_ERROR, TAG, "register hook failed");
203 | return;
204 | }
205 |
206 | if (inlineHook((uint32_t) addr) != ELE7EN_OK) {
207 | __android_log_print(ANDROID_LOG_ERROR, TAG, "register hook failed");
208 | return;
209 | }
210 |
211 | __android_log_print(ANDROID_LOG_INFO, TAG, "register hook success");
212 | }
213 |
214 |
215 | JNIEXPORT void JNICALL Java_com_smartdone_dexdump_Dumpper_dump(JNIEnv *env, jclass clazz) {
216 | getProcessName(getpid(), pname, sizeof(pname));
217 | int api = apiLevel();
218 | if(api < 21){
219 | hook_dvm();
220 | } else if(api < 23) {
221 | hook_21_22();
222 | } else {
223 | ndk_init(env);
224 | hook_23_plus();
225 | }
226 | }
227 |
--------------------------------------------------------------------------------
/app/src/main/jni/dump.h:
--------------------------------------------------------------------------------
1 | //
2 | // Created by 袁东明 on 2017/7/1.
3 | //
4 |
5 | #include
6 | #include
7 | #include
8 |
9 | #ifndef DEXDUMP_DUMP_H
10 | #define DEXDUMP_DUMP_H
11 |
12 | #ifdef __cplusplus
13 | extern "C" {
14 | #endif
15 |
16 | JNIEXPORT void JNICALL Java_com_smartdone_dexdump_Dumpper_dump(JNIEnv *, jclass);
17 | typedef uint8_t byte;
18 | namespace art {
19 |
20 | class OatFile;
21 |
22 | class DexFile;
23 |
24 | class OatDexFile;
25 |
26 | class MemMap;
27 | }
28 |
29 | typedef uint8_t u1;
30 | typedef uint16_t u2;
31 | typedef uint32_t u4;
32 | typedef uint64_t u8;
33 | typedef int8_t s1;
34 | typedef int16_t s2;
35 | typedef int32_t s4;
36 | typedef int64_t s8;
37 |
38 | enum { kSHA1DigestLen = 20,
39 | kSHA1DigestOutputLen = kSHA1DigestLen*2 +1 };
40 |
41 | struct DexHeader {
42 | u1 magic[8]; /* includes version number */
43 | u4 checksum; /* adler32 checksum */
44 | u1 signature[kSHA1DigestLen]; /* SHA-1 hash */
45 | u4 fileSize; /* length of entire file */
46 | u4 headerSize; /* offset to start of next section */
47 | u4 endianTag;
48 | u4 linkSize;
49 | u4 linkOff;
50 | u4 mapOff;
51 | u4 stringIdsSize;
52 | u4 stringIdsOff;
53 | u4 typeIdsSize;
54 | u4 typeIdsOff;
55 | u4 protoIdsSize;
56 | u4 protoIdsOff;
57 | u4 fieldIdsSize;
58 | u4 fieldIdsOff;
59 | u4 methodIdsSize;
60 | u4 methodIdsOff;
61 | u4 classDefsSize;
62 | u4 classDefsOff;
63 | u4 dataSize;
64 | u4 dataOff;
65 | };
66 |
67 | struct DexOptHeader {
68 | u1 magic[8]; /* includes version number */
69 |
70 | u4 dexOffset; /* file offset of DEX header */
71 | u4 dexLength;
72 | u4 depsOffset; /* offset of optimized DEX dependency table */
73 | u4 depsLength;
74 | u4 optOffset; /* file offset of optimized data tables */
75 | u4 optLength;
76 |
77 | u4 flags; /* some info flags */
78 | u4 checksum; /* adler32 checksum covering deps/opt */
79 |
80 | /* pad for 64-bit alignment if necessary */
81 | };
82 |
83 |
84 | struct DexStringId {
85 | u4 stringDataOff; /* file offset to string_data_item */
86 | };
87 |
88 | struct DexTypeId {
89 | u4 descriptorIdx; /* index into stringIds list for type descriptor */
90 | };
91 |
92 | struct DexFieldId {
93 | u2 classIdx; /* index into typeIds list for defining class */
94 | u2 typeIdx; /* index into typeIds for field type */
95 | u4 nameIdx; /* index into stringIds for field name */
96 | };
97 |
98 | struct DexMethodId {
99 | u2 classIdx; /* index into typeIds list for defining class */
100 | u2 protoIdx; /* index into protoIds for method prototype */
101 | u4 nameIdx; /* index into stringIds for method name */
102 | };
103 |
104 | struct DexProtoId {
105 | u4 shortyIdx; /* index into stringIds for shorty descriptor */
106 | u4 returnTypeIdx; /* index into typeIds list for return type */
107 | u4 parametersOff; /* file offset to type_list for parameter types */
108 | };
109 |
110 | struct DexClassDef {
111 | u4 classIdx; /* index into typeIds for this class */
112 | u4 accessFlags;
113 | u4 superclassIdx; /* index into typeIds for superclass */
114 | u4 interfacesOff; /* file offset to DexTypeList */
115 | u4 sourceFileIdx; /* index into stringIds for source file name */
116 | u4 annotationsOff; /* file offset to annotations_directory_item */
117 | u4 classDataOff; /* file offset to class_data_item */
118 | u4 staticValuesOff; /* file offset to DexEncodedArray */
119 | };
120 |
121 | struct DexLink {
122 | u1 bleargh;
123 | };
124 |
125 | struct DexClassLookup {
126 | int size; // total size, including "size"
127 | int numEntries; // size of table[]; always power of 2
128 | struct {
129 | u4 classDescriptorHash; // class descriptor hash code
130 | int classDescriptorOffset; // in bytes, from start of DEX
131 | int classDefOffset; // in bytes, from start of DEX
132 | } table[1];
133 | };
134 |
135 | struct DexFile {
136 | /* directly-mapped "opt" header */
137 | const DexOptHeader* pOptHeader;
138 |
139 | /* pointers to directly-mapped structs and arrays in base DEX */
140 | const DexHeader* pHeader;
141 | const DexStringId* pStringIds;
142 | const DexTypeId* pTypeIds;
143 | const DexFieldId* pFieldIds;
144 | const DexMethodId* pMethodIds;
145 | const DexProtoId* pProtoIds;
146 | const DexClassDef* pClassDefs;
147 | const DexLink* pLinkData;
148 |
149 | /*
150 | * These are mapped out of the "auxillary" section, and may not be
151 | * included in the file.
152 | */
153 | const DexClassLookup* pClassLookup;
154 | const void* pRegisterMapPool; // RegisterMapClassPool
155 |
156 | /* points to start of DEX file data */
157 | const u1* baseAddr;
158 |
159 | /* track memory overhead for auxillary structures */
160 | int overhead;
161 |
162 | /* additional app-specific data structures associated with the DEX */
163 | //void* auxData;
164 | };
165 |
166 | struct MemMapping {
167 | void* addr; /* start of data */
168 | size_t length; /* length of data */
169 |
170 | void* baseAddr; /* page-aligned base address */
171 | size_t baseLength; /* length of mapping */
172 | };
173 |
174 | struct DvmDex {
175 | /* pointer to the DexFile we're associated with */
176 | DexFile* pDexFile;
177 |
178 | /* clone of pDexFile->pHeader (it's used frequently enough) */
179 | const DexHeader* pHeader;
180 |
181 | /* interned strings; parallel to "stringIds" */
182 | struct StringObject** pResStrings;
183 |
184 | /* resolved classes; parallel to "typeIds" */
185 | struct ClassObject** pResClasses;
186 |
187 | /* resolved methods; parallel to "methodIds" */
188 | struct Method** pResMethods;
189 |
190 | /* resolved instance fields; parallel to "fieldIds" */
191 | /* (this holds both InstField and StaticField) */
192 | struct Field** pResFields;
193 |
194 | /* interface method lookup cache */
195 | struct AtomicCache* pInterfaceCache;
196 |
197 | /* shared memory region with file contents */
198 | bool isMappedReadOnly;
199 | MemMapping memMap;
200 |
201 | jobject dex_object;
202 |
203 | /* lock ensuring mutual exclusion during updates */
204 | pthread_mutex_t modLock;
205 | };
206 |
207 | struct RawDexFile {
208 | char* cacheFileName;
209 | DvmDex* pDvmDex;
210 | };
211 |
212 |
213 | #ifdef __cplusplus
214 | }
215 | #endif
216 |
217 | #endif //DEXDUMP_DUMP_H
218 |
--------------------------------------------------------------------------------
/app/src/main/jni/include/inlineHook.h:
--------------------------------------------------------------------------------
1 | #ifndef _INLINEHOOK_H
2 | #define _INLINEHOOK_H
3 |
4 | #include
5 |
6 | enum ele7en_status {
7 | ELE7EN_ERROR_UNKNOWN = -1,
8 | ELE7EN_OK = 0,
9 | ELE7EN_ERROR_NOT_INITIALIZED,
10 | ELE7EN_ERROR_NOT_EXECUTABLE,
11 | ELE7EN_ERROR_NOT_REGISTERED,
12 | ELE7EN_ERROR_NOT_HOOKED,
13 | ELE7EN_ERROR_ALREADY_REGISTERED,
14 | ELE7EN_ERROR_ALREADY_HOOKED,
15 | ELE7EN_ERROR_SO_NOT_FOUND,
16 | ELE7EN_ERROR_FUNCTION_NOT_FOUND
17 | };
18 |
19 | enum ele7en_status registerInlineHook(uint32_t target_addr, uint32_t new_addr, uint32_t **proto_addr);
20 | enum ele7en_status inlineUnHook(uint32_t target_addr);
21 | void inlineUnHookAll();
22 | enum ele7en_status inlineHook(uint32_t target_addr);
23 | void inlineHookAll();
24 |
25 |
26 |
27 | #endif
28 |
--------------------------------------------------------------------------------
/app/src/main/jni/inlineHook.c:
--------------------------------------------------------------------------------
1 | /*
2 | thumb16 thumb32 arm32 inlineHook
3 | author: ele7enxxh
4 | mail: ele7enxxh@qq.com
5 | website: ele7enxxh.com
6 | modified time: 2015-01-23
7 | created time: 2015-11-30
8 | */
9 |
10 | #include
11 | #include
12 | #include
13 | #include
14 | #include
15 | #include
16 | // #include
17 | #include
18 | #include
19 |
20 | #include "relocate.h"
21 | #include "include/inlineHook.h"
22 |
23 | #ifndef PAGE_SIZE
24 | #define PAGE_SIZE 4096
25 | #endif
26 |
27 | #define PAGE_START(addr) (~(PAGE_SIZE - 1) & (addr))
28 | #define SET_BIT0(addr) (addr | 1)
29 | #define CLEAR_BIT0(addr) (addr & 0xFFFFFFFE)
30 | #define TEST_BIT0(addr) (addr & 1)
31 |
32 | #define ACTION_ENABLE 0
33 | #define ACTION_DISABLE 1
34 |
35 | enum hook_status {
36 | REGISTERED,
37 | HOOKED,
38 | };
39 |
40 | struct inlineHookItem {
41 | uint32_t target_addr;
42 | uint32_t new_addr;
43 | uint32_t **proto_addr;
44 | void *orig_instructions;
45 | int orig_boundaries[4];
46 | int trampoline_boundaries[20];
47 | int count;
48 | void *trampoline_instructions;
49 | int length;
50 | int status;
51 | int mode;
52 | };
53 |
54 | struct inlineHookInfo {
55 | struct inlineHookItem item[1024];
56 | int size;
57 | };
58 |
59 | static struct inlineHookInfo info = {0};
60 |
61 | static int getAllTids(pid_t pid, pid_t *tids)
62 | {
63 | char dir_path[32];
64 | DIR *dir;
65 | int i;
66 | struct dirent *entry;
67 | pid_t tid;
68 |
69 | if (pid < 0) {
70 | snprintf(dir_path, sizeof(dir_path), "/proc/self/task");
71 | }
72 | else {
73 | snprintf(dir_path, sizeof(dir_path), "/proc/%d/task", pid);
74 | }
75 |
76 | dir = opendir(dir_path);
77 | if (dir == NULL) {
78 | return 0;
79 | }
80 |
81 | i = 0;
82 | while((entry = readdir(dir)) != NULL) {
83 | tid = atoi(entry->d_name);
84 | if (tid != 0 && tid != getpid()) {
85 | tids[i++] = tid;
86 | }
87 | }
88 | closedir(dir);
89 | return i;
90 | }
91 |
92 | static bool doProcessThreadPC(struct inlineHookItem *item, struct pt_regs *regs, int action)
93 | {
94 | int offset;
95 | int i;
96 |
97 | switch (action)
98 | {
99 | case ACTION_ENABLE:
100 | offset = regs->ARM_pc - CLEAR_BIT0(item->target_addr);
101 | for (i = 0; i < item->count; ++i) {
102 | if (offset == item->orig_boundaries[i]) {
103 | regs->ARM_pc = (uint32_t) item->trampoline_instructions + item->trampoline_boundaries[i];
104 | return true;
105 | }
106 | }
107 | break;
108 | case ACTION_DISABLE:
109 | offset = regs->ARM_pc - (int) item->trampoline_instructions;
110 | for (i = 0; i < item->count; ++i) {
111 | if (offset == item->trampoline_boundaries[i]) {
112 | regs->ARM_pc = CLEAR_BIT0(item->target_addr) + item->orig_boundaries[i];
113 | return true;
114 | }
115 | }
116 | break;
117 | }
118 |
119 | return false;
120 | }
121 |
122 | static void processThreadPC(pid_t tid, struct inlineHookItem *item, int action)
123 | {
124 | struct pt_regs regs;
125 |
126 | if (ptrace(PTRACE_GETREGS, tid, NULL, ®s) == 0) {
127 | if (item == NULL) {
128 | int pos;
129 |
130 | for (pos = 0; pos < info.size; ++pos) {
131 | if (doProcessThreadPC(&info.item[pos], ®s, action) == true) {
132 | break;
133 | }
134 | }
135 | }
136 | else {
137 | doProcessThreadPC(item, ®s, action);
138 | }
139 |
140 | ptrace(PTRACE_SETREGS, tid, NULL, ®s);
141 | }
142 | }
143 |
144 | static pid_t freeze(struct inlineHookItem *item, int action)
145 | {
146 | int count;
147 | pid_t tids[1024];
148 | pid_t pid;
149 |
150 | pid = -1;
151 | count = getAllTids(getpid(), tids);
152 | if (count > 0) {
153 | pid = fork();
154 |
155 | if (pid == 0) {
156 | int i;
157 |
158 | for (i = 0; i < count; ++i) {
159 | if (ptrace(PTRACE_ATTACH, tids[i], NULL, NULL) == 0) {
160 | waitpid(tids[i], NULL, WUNTRACED);
161 | processThreadPC(tids[i], item, action);
162 | }
163 | }
164 |
165 | raise(SIGSTOP);
166 |
167 | for (i = 0; i < count; ++i) {
168 | ptrace(PTRACE_DETACH, tids[i], NULL, NULL);
169 | }
170 |
171 | raise(SIGKILL);
172 | }
173 |
174 | else if (pid > 0) {
175 | waitpid(pid, NULL, WUNTRACED);
176 | }
177 | }
178 |
179 | return pid;
180 | }
181 |
182 | static void unFreeze(pid_t pid)
183 | {
184 | if (pid < 0) {
185 | return;
186 | }
187 |
188 | kill(pid, SIGCONT);
189 | wait(NULL);
190 | }
191 |
192 | static bool isExecutableAddr(uint32_t addr)
193 | {
194 | FILE *fp;
195 | char line[1024];
196 | uint32_t start;
197 | uint32_t end;
198 |
199 | fp = fopen("/proc/self/maps", "r");
200 | if (fp == NULL) {
201 | return false;
202 | }
203 |
204 | while (fgets(line, sizeof(line), fp)) {
205 | if (strstr(line, "r-xp")) {
206 | start = strtoul(strtok(line, "-"), NULL, 16);
207 | end = strtoul(strtok(NULL, " "), NULL, 16);
208 | if (addr >= start && addr <= end) {
209 | fclose(fp);
210 | return true;
211 | }
212 | }
213 | }
214 |
215 | fclose(fp);
216 |
217 | return false;
218 | }
219 |
220 | static struct inlineHookItem *findInlineHookItem(uint32_t target_addr)
221 | {
222 | int i;
223 |
224 | for (i = 0; i < info.size; ++i) {
225 | if (info.item[i].target_addr == target_addr) {
226 | return &info.item[i];
227 | }
228 | }
229 |
230 | return NULL;
231 | }
232 |
233 | static struct inlineHookItem *addInlineHookItem() {
234 | struct inlineHookItem *item;
235 |
236 | if (info.size >= 1024) {
237 | return NULL;
238 | }
239 |
240 | item = &info.item[info.size];
241 | ++info.size;
242 |
243 | return item;
244 | }
245 |
246 | static void deleteInlineHookItem(int pos)
247 | {
248 | info.item[pos] = info.item[info.size - 1];
249 | --info.size;
250 | }
251 |
252 | enum ele7en_status registerInlineHook(uint32_t target_addr, uint32_t new_addr, uint32_t **proto_addr)
253 | {
254 | struct inlineHookItem *item;
255 |
256 | if (!isExecutableAddr(target_addr) || !isExecutableAddr(new_addr)) {
257 | return ELE7EN_ERROR_NOT_EXECUTABLE;
258 | }
259 |
260 | item = findInlineHookItem(target_addr);
261 | if (item != NULL) {
262 | if (item->status == REGISTERED) {
263 | return ELE7EN_ERROR_ALREADY_REGISTERED;
264 | }
265 | else if (item->status == HOOKED) {
266 | return ELE7EN_ERROR_ALREADY_HOOKED;
267 | }
268 | else {
269 | return ELE7EN_ERROR_UNKNOWN;
270 | }
271 | }
272 |
273 | item = addInlineHookItem();
274 |
275 | item->target_addr = target_addr;
276 | item->new_addr = new_addr;
277 | item->proto_addr = proto_addr;
278 |
279 | item->length = TEST_BIT0(item->target_addr) ? 12 : 8;
280 | item->orig_instructions = malloc(item->length);
281 | memcpy(item->orig_instructions, (void *) CLEAR_BIT0(item->target_addr), item->length);
282 |
283 | item->trampoline_instructions = mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_ANONYMOUS | MAP_PRIVATE, 0, 0);
284 | relocateInstruction(item->target_addr, item->orig_instructions, item->length, item->trampoline_instructions, item->orig_boundaries, item->trampoline_boundaries, &item->count);
285 |
286 | item->status = REGISTERED;
287 |
288 | return ELE7EN_OK;
289 | }
290 |
291 | static void doInlineUnHook(struct inlineHookItem *item, int pos)
292 | {
293 | mprotect((void *) PAGE_START(CLEAR_BIT0(item->target_addr)), PAGE_SIZE * 2, PROT_READ | PROT_WRITE | PROT_EXEC);
294 | memcpy((void *) CLEAR_BIT0(item->target_addr), item->orig_instructions, item->length);
295 | mprotect((void *) PAGE_START(CLEAR_BIT0(item->target_addr)), PAGE_SIZE * 2, PROT_READ | PROT_EXEC);
296 | munmap(item->trampoline_instructions, PAGE_SIZE);
297 | free(item->orig_instructions);
298 |
299 | deleteInlineHookItem(pos);
300 |
301 | cacheflush(CLEAR_BIT0(item->target_addr), CLEAR_BIT0(item->target_addr) + item->length, 0);
302 | }
303 |
304 | enum ele7en_status inlineUnHook(uint32_t target_addr)
305 | {
306 | int i;
307 |
308 | for (i = 0; i < info.size; ++i) {
309 | if (info.item[i].target_addr == target_addr && info.item[i].status == HOOKED) {
310 | pid_t pid;
311 |
312 | pid = freeze(&info.item[i], ACTION_DISABLE);
313 |
314 | doInlineUnHook(&info.item[i], i);
315 |
316 | unFreeze(pid);
317 |
318 | return ELE7EN_OK;
319 | }
320 | }
321 |
322 | return ELE7EN_ERROR_NOT_HOOKED;
323 | }
324 |
325 | void inlineUnHookAll()
326 | {
327 | pid_t pid;
328 | int i;
329 |
330 | pid = freeze(NULL, ACTION_DISABLE);
331 |
332 | for (i = 0; i < info.size; ++i) {
333 | if (info.item[i].status == HOOKED) {
334 | doInlineUnHook(&info.item[i], i);
335 | --i;
336 | }
337 | }
338 |
339 | unFreeze(pid);
340 | }
341 |
342 | static void doInlineHook(struct inlineHookItem *item)
343 | {
344 | mprotect((void *) PAGE_START(CLEAR_BIT0(item->target_addr)), PAGE_SIZE * 2, PROT_READ | PROT_WRITE | PROT_EXEC);
345 |
346 | if (item->proto_addr != NULL) {
347 | *(item->proto_addr) = TEST_BIT0(item->target_addr) ? (uint32_t *) SET_BIT0((uint32_t) item->trampoline_instructions) : item->trampoline_instructions;
348 | }
349 |
350 | if (TEST_BIT0(item->target_addr)) {
351 | int i;
352 |
353 | i = 0;
354 | if (CLEAR_BIT0(item->target_addr) % 4 != 0) {
355 | ((uint16_t *) CLEAR_BIT0(item->target_addr))[i++] = 0xBF00; // NOP
356 | }
357 | ((uint16_t *) CLEAR_BIT0(item->target_addr))[i++] = 0xF8DF;
358 | ((uint16_t *) CLEAR_BIT0(item->target_addr))[i++] = 0xF000; // LDR.W PC, [PC]
359 | ((uint16_t *) CLEAR_BIT0(item->target_addr))[i++] = item->new_addr & 0xFFFF;
360 | ((uint16_t *) CLEAR_BIT0(item->target_addr))[i++] = item->new_addr >> 16;
361 | }
362 | else {
363 | ((uint32_t *) (item->target_addr))[0] = 0xe51ff004; // LDR PC, [PC, #-4]
364 | ((uint32_t *) (item->target_addr))[1] = item->new_addr;
365 | }
366 |
367 | mprotect((void *) PAGE_START(CLEAR_BIT0(item->target_addr)), PAGE_SIZE * 2, PROT_READ | PROT_EXEC);
368 |
369 | item->status = HOOKED;
370 |
371 | cacheflush(CLEAR_BIT0(item->target_addr), CLEAR_BIT0(item->target_addr) + item->length, 0);
372 | }
373 |
374 | enum ele7en_status inlineHook(uint32_t target_addr)
375 | {
376 | int i;
377 | struct inlineHookItem *item;
378 |
379 | item = NULL;
380 | for (i = 0; i < info.size; ++i) {
381 | if (info.item[i].target_addr == target_addr) {
382 | item = &info.item[i];
383 | break;
384 | }
385 | }
386 |
387 | if (item == NULL) {
388 | return ELE7EN_ERROR_NOT_REGISTERED;
389 | }
390 |
391 | if (item->status == REGISTERED) {
392 | pid_t pid;
393 |
394 | pid = freeze(item, ACTION_ENABLE);
395 |
396 | doInlineHook(item);
397 |
398 | unFreeze(pid);
399 |
400 | return ELE7EN_OK;
401 | }
402 | else if (item->status == HOOKED) {
403 | return ELE7EN_ERROR_ALREADY_HOOKED;
404 | }
405 | else {
406 | return ELE7EN_ERROR_UNKNOWN;
407 | }
408 | }
409 |
410 | void inlineHookAll()
411 | {
412 | pid_t pid;
413 | int i;
414 |
415 | pid = freeze(NULL, ACTION_ENABLE);
416 |
417 | for (i = 0; i < info.size; ++i) {
418 | if (info.item[i].status == REGISTERED) {
419 | doInlineHook(&info.item[i]);
420 | }
421 | }
422 |
423 | unFreeze(pid);
424 | }
425 |
--------------------------------------------------------------------------------
/app/src/main/jni/relocate.c:
--------------------------------------------------------------------------------
1 | /*
2 | relocate instruction
3 | author: ele7enxxh
4 | mail: ele7enxxh@qq.com
5 | website: ele7enxxh.com
6 | modified time: 2016-10-17
7 | created time: 2015-01-17
8 | */
9 |
10 | #include "relocate.h"
11 |
12 | #define ALIGN_PC(pc) (pc & 0xFFFFFFFC)
13 |
14 | enum INSTRUCTION_TYPE {
15 | // B