├── .gitignore
├── README.md
├── build.gradle
├── libs
└── XposedBridgeApi-54.jar
├── nop.java
├── proguard-rules.pro
└── src
└── main
├── AndroidManifest.xml
├── assets
└── xposed_init
├── java
└── com
│ └── xpu01
│ ├── DialogItemAdapter.java
│ ├── Japp.java
│ ├── Main.java
│ ├── Xpu01hook.java
│ └── x64.java
└── res
├── drawable-hdpi
└── ic_launcher.png
├── drawable-mdpi
└── ic_launcher.png
├── drawable-xhdpi
└── ic_launcher.png
├── drawable-xxhdpi
└── ic_launcher.png
├── drawable
├── about.png
├── modules.png
└── settings.png
├── layout
├── drill.xml
├── elog.xml
├── hook.xml
├── item_app.xml
├── ktest_dialog.xml
├── main.xml
└── setting.xml
├── menu
└── menu.xml
├── values-v21
└── styles.xml
├── values-v23
└── styles.xml
└── values
├── color.xml
├── strings.xml
└── styles.xml
/.gitignore:
--------------------------------------------------------------------------------
1 | # Build and Release Folders
2 | bin-debug/
3 | bin-release/
4 | [Oo]bj/
5 | [Bb]in/
6 |
7 | # Other files and folders
8 | .settings/
9 |
10 | # Executables
11 | *.swf
12 | *.air
13 | *.ipa
14 | *.apk
15 |
16 | # Project files, i.e. `.project`, `.actionScriptProperties` and `.flexProperties`
17 | # should NOT be excluded as they contain compiler settings and other important
18 | # information for Eclipse / Flash Builder.
19 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # xpu01
2 | 基于Xposed框架安卓脱壳软件
3 | #### 实现与使用
4 | 通过反射调用getDex方法取得com.android.dex.Dex类(获取dex),不支持8.0系统以上版本,高系统可以配合虚拟机来使用。
5 |
6 |
7 | #### 关于类抽取(nop)填充还原代码实现
8 | 请看nop.java
9 |
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'com.android.application'
2 |
3 | android {
4 | compileSdkVersion 21
5 | buildToolsVersion "21.1.0"
6 |
7 | defaultConfig {
8 | applicationId "com.xpu01"
9 | minSdkVersion 14
10 | targetSdkVersion 21
11 | versionCode 4
12 | versionName "1.3"
13 | }
14 | buildTypes {
15 | release {
16 | minifyEnabled false
17 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
18 | }
19 | }
20 | }
21 |
22 | dependencies {
23 | compile fileTree(dir: 'libs', include: ['*.jar'])
24 | }
25 |
--------------------------------------------------------------------------------
/libs/XposedBridgeApi-54.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eksenior/xpu01/152ac26e4578e38090792f080f0f01e5a7e5c4b8/libs/XposedBridgeApi-54.jar
--------------------------------------------------------------------------------
/nop.java:
--------------------------------------------------------------------------------
1 |
2 |
3 | private String Ldex(Context mContext,String stord)throws Throwable{//脱壳 保存目录, 脱多个dex 带遍历类 nop 回填
4 | String[] strArr;
5 | Log("遍历dump 加载Dex数组...");
6 | ArrayList arrayList = new ArrayList();
7 | ClassLoader classLoader = mContext.getClassLoader();
8 | Field declaredField = classLoader.getClass().getSuperclass().getDeclaredField("pathList");
9 | declaredField.setAccessible(true);
10 | Object[] objArr2 = (Object[]) fsd(declaredField.get(classLoader), "dexElements");
11 | //publishProgress(objArr2);
12 | Method declaredMethod3 = classLoader.getClass().getSuperclass().getSuperclass().getDeclaredMethod("findClass", new Class[]{String.class});
13 | declaredMethod3.setAccessible(true);
14 | for (Object obj : objArr2) {
15 | Object d = fsd(obj, "dexFile");
16 | if (d != null) {
17 | Log("遍历类...");
18 | Method declaredMethod4 = d.getClass().getDeclaredMethod("entries", new Class[0]);
19 | if (!(declaredMethod4.invoke(d, new Object[0]) == null || (strArr = (String[]) fsd(declaredMethod4.invoke(d, new Object[0]), "mNameList")) == null || strArr.length == 0)) {
20 | Log("提取Dex");
21 | for (String str4 : strArr) {
22 | try {
23 | Class cls2 = (Class) declaredMethod3.invoke(classLoader, new Object[]{str4});
24 | Object invoke2 = cls2.getClass().getDeclaredMethod("getDex", new Class[0]).invoke(cls2, new Object[0]);
25 | if (!arrayList.contains(invoke2)) {
26 | arrayList.add(invoke2);
27 | }
28 | } catch (Throwable th2) {
29 | }
30 | }
31 | continue;
32 | }
33 | }
34 | }
35 | if (arrayList.size() == 0) {
36 | return "找不到Dex!";
37 | }
38 | File file = new File(stord);
39 | file.mkdirs();
40 | int i = 1;
41 | Iterator it = arrayList.iterator();
42 | while (true) {
43 | int i2 = i;
44 | if (it.hasNext()) {
45 | Object next = it.next();
46 | byte[] bArr2 = (byte[]) next.getClass().getDeclaredMethod("getBytes", new Class[0]).invoke(next, new Object[0]);
47 | RandomAccessFile randomAccessFile2 = new RandomAccessFile(new File(file, "Dexdump" + (i2 == 1 ? "" : Integer.valueOf(i2)) + ".dex"), "rw");
48 |
49 | randomAccessFile2.write(bArr2);
50 | randomAccessFile2.close();
51 | i = i2 + 1;
52 | } else {
53 | return "脱壳成功,共写出 " + (i2 - 1) + " 个dex,文件夹位于 "+ stord;
54 | }
55 | }
56 |
57 | }
58 |
--------------------------------------------------------------------------------
/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 C:\tools\adt-bundle-windows-x86_64-20131030\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 |
--------------------------------------------------------------------------------
/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
7 |
8 |
9 |
14 |
15 |
18 |
21 |
25 |
26 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/src/main/assets/xposed_init:
--------------------------------------------------------------------------------
1 | com.xpu01.Xpu01hook
--------------------------------------------------------------------------------
/src/main/java/com/xpu01/DialogItemAdapter.java:
--------------------------------------------------------------------------------
1 | package com.xpu01;
2 |
3 | /**
4 | * ListAdapter
5 | */
6 | import android.content.*;
7 | import android.view.*;
8 | import android.widget.*;
9 | import com.xpu01.*;
10 | import java.util.*;
11 |
12 | public class DialogItemAdapter extends BaseAdapter
13 | {
14 |
15 | //这里可以传递个对象,用来控制不同的item的效果
16 | //比如每个item的背景资源,选中样式等
17 | public List list;
18 | LayoutInflater inflater;
19 |
20 | public DialogItemAdapter(Context context, List list) { //接数据
21 | this.list = list;
22 | inflater = LayoutInflater.from(context);
23 | }
24 |
25 | @Override
26 | public int getCount() {
27 | return list.size();
28 | }
29 |
30 | @Override
31 | public String getItem(int i) {
32 | if (i == getCount() || list == null) {
33 | return null;
34 | }
35 | return list.get(i);
36 | }
37 |
38 | @Override
39 | public long getItemId(int i) {
40 | return i;
41 | }
42 |
43 | @Override
44 | public View getView(int position, View convertView, ViewGroup viewGroup) {
45 | ViewHolder holder;
46 | if (convertView == null) {
47 | holder = new ViewHolder();
48 | convertView = inflater.inflate(R.layout.item_app, null);
49 | holder.typeTextview = (TextView) convertView.findViewById(R.id.tv_app_name);
50 | holder.typeImageView = (ImageView) convertView.findViewById(R.id.iv_app);
51 | convertView.setTag(holder);
52 | } else {
53 | holder = (ViewHolder) convertView.getTag();
54 | }
55 | holder.typeTextview.setText(Japp.appname(getItem(position))); //添加文字
56 | holder.typeImageView.setImageBitmap(Japp.applcon(getItem(position))); //添加图标
57 |
58 | return convertView;
59 | }
60 |
61 |
62 | public static class ViewHolder
63 | {
64 | public TextView typeTextview;
65 |
66 | public ImageView typeImageView;
67 |
68 | }
69 |
70 |
71 |
72 |
73 |
74 |
75 | }
76 |
77 |
--------------------------------------------------------------------------------
/src/main/java/com/xpu01/Japp.java:
--------------------------------------------------------------------------------
1 | package com.xpu01;
2 |
3 | import android.content.pm.*;
4 | import android.graphics.*;
5 | import android.graphics.drawable.*;
6 | import java.io.*;
7 | import java.util.*;
8 | import android.content.pm.PackageManager.*;
9 |
10 | public class Japp
11 | {
12 |
13 | public static String[] getpacka() { //取第三方已安装应用
14 | List packageInfos = Main.getContext().getPackageManager().getInstalledPackages(0);
15 | List list = new ArrayList();
16 | for (int i = 0; i < packageInfos.size(); i++) {
17 | PackageInfo pInfo = (PackageInfo) packageInfos.get(i);
18 | if ((pInfo.applicationInfo.flags & 1) == 0) {
19 | list.add(pInfo.packageName);
20 | }
21 | }
22 | return (String[]) list.toArray(new String[list.size()]);
23 | }
24 |
25 |
26 | public static String[] sygetpacka() {//取所有应用包名
27 | List var1 = Main.getContext().getPackageManager().getInstalledPackages(0);
28 | String[] var2 = new String[var1.size()];
29 |
30 | for(int var0 = 0; var0 < var1.size(); ++var0) {
31 | var2[var0] = ((PackageInfo)var1.get(var0)).packageName;
32 | }
33 |
34 | return var2;
35 | }
36 |
37 |
38 | public static Bitmap applcon(String packagename) {//取应用图标
39 | try {
40 | PackageManager pm = Main.getContext().getPackageManager();
41 | return drawableToBitmap(pm.getApplicationInfo(packagename, 0).loadIcon(pm));
42 | } catch (PackageManager.NameNotFoundException e) {
43 | e.printStackTrace();
44 | return null;
45 | }
46 | }
47 |
48 | public static String appname(String packagename) {//取应用名称
49 | try {
50 | PackageManager pm = Main.getContext().getPackageManager();
51 | return pm.getApplicationInfo(packagename, 0).loadLabel(pm).toString();
52 | } catch (PackageManager.NameNotFoundException e) {
53 | e.printStackTrace();
54 | return "";
55 | }
56 | }
57 |
58 | public static String qversion(String packagename) {//取应用版本
59 | try {
60 | return Main.getContext().getPackageManager().getPackageInfo(packagename, 0).versionName;
61 | } catch (PackageManager.NameNotFoundException e) {
62 | e.printStackTrace();
63 | return "0";
64 | }
65 | }
66 |
67 | public static String qsign(String packagename) { //取应用签名
68 | try {
69 | return Main.getContext().getPackageManager().getPackageInfo(packagename, 64).signatures[0].toCharsString();
70 | } catch (PackageManager.NameNotFoundException e) {
71 | e.printStackTrace();
72 | return "";
73 | }
74 | }
75 |
76 |
77 | public static String qsignz(String packagename) {//获取 签名值
78 | try
79 | {
80 | PackageInfo a = Main.getContext().getPackageManager().getPackageInfo(packagename, PackageManager.GET_SIGNATURES); //packagename 包名
81 | Signature[] b = a.signatures;
82 | Signature c = b[0];
83 |
84 | return String.valueOf(c.hashCode());
85 | }
86 | catch (PackageManager.NameNotFoundException e)
87 | {
88 | return null;
89 | }
90 | }
91 |
92 | public static boolean whet_app(String packageName) { //判断手机是否安装某个应用
93 | if(packageName == null){
94 | return false;
95 | }
96 | PackageManager packageManager = Main.getContext().getPackageManager();// 获取packagemanager
97 | List pinfo = packageManager.getInstalledPackages(0);// 获取所有已安装程序的包信息
98 | if (pinfo != null) {
99 | for (int i = 0; i < pinfo.size(); i++) {
100 | String pn = pinfo.get(i).packageName;
101 | if (packageName.equals(pn)) {
102 | return true;
103 | }
104 | }
105 | }
106 | return false;
107 | }
108 |
109 |
110 |
111 | public static String qapklj(String packagename) {//获取 已知包名apk的安装路径
112 | try
113 | {
114 | return Main.getContext().getPackageManager().getApplicationInfo(packagename, 0).sourceDir;
115 | }
116 | catch (PackageManager.NameNotFoundException e)
117 | {
118 | return null;
119 | }
120 |
121 | }
122 |
123 |
124 | public static String dataDir(String packagename) {//获取应用 data数据路径
125 | try
126 | {
127 | return Main.getContext().getPackageManager().getApplicationInfo(packagename, 0).dataDir;
128 | }
129 | catch (PackageManager.NameNotFoundException e)
130 | {
131 | return null;
132 | }
133 |
134 | }
135 |
136 |
137 | private static Bitmap drawableToBitmap(Drawable paramDrawable) {
138 | int i = paramDrawable.getIntrinsicWidth();
139 | int j = paramDrawable.getIntrinsicHeight();
140 | Bitmap localBitmap = Bitmap.createBitmap(i, j, paramDrawable.getOpacity() != -1 ? Bitmap.Config.ARGB_8888 : Bitmap.Config.RGB_565);
141 | Canvas localCanvas = new Canvas(localBitmap);
142 | paramDrawable.setBounds(0, 0, i, j);
143 | paramDrawable.draw(localCanvas);
144 | return localBitmap;
145 | }
146 |
147 | public static String uid(String packagename) {//获取应用 data数据路径
148 |
149 | try {
150 | PackageManager pm = Main.getContext().getPackageManager();
151 | ApplicationInfo ai = pm.getApplicationInfo(packagename, 0);
152 | return Integer.toString(ai.uid,10);
153 | } catch (NameNotFoundException e) {
154 | }
155 | return null;
156 | }
157 |
158 | }
159 |
--------------------------------------------------------------------------------
/src/main/java/com/xpu01/Main.java:
--------------------------------------------------------------------------------
1 | package com.xpu01;
2 |
3 | import android.app.*;
4 | import android.content.*;
5 | import android.content.pm.*;
6 | import android.graphics.*;
7 | import android.net.*;
8 | import android.os.*;
9 | import android.view.*;
10 | import android.view.View.*;
11 | import android.widget.*;
12 | import android.widget.CompoundButton.*;
13 | import java.io.*;
14 | import java.util.*;
15 |
16 | import android.view.View.OnClickListener;
17 | import android.util.*;
18 |
19 | public class Main extends Activity
20 | {
21 | private static Main INSTANCE;
22 | private static String apackage = null; //包名
23 | private final static String noapp = "未选择应用"; //final 是不能被修改赋值
24 | public static String sdexsd = Environment.getExternalStorageDirectory().getPath() + "/Xpu01";
25 |
26 | Button bu,bu1,bu2,bu3;
27 | ImageView appIcon;
28 | TextView tname,tpackage,tversion,tsign,tsize,treinforce,tdatadirectory,tapkdirectory,tmd5apk,tcrc32apk,tmd5sign,tapkuid;
29 | LinearLayout logView;
30 | List apps;
31 |
32 | private SharedPreferences configs_ini;
33 |
34 |
35 | public Main() { //第一个初始化
36 | INSTANCE = this;
37 | }
38 |
39 | @Override
40 | protected void onCreate(Bundle savedInstanceState)
41 | {
42 | super.onCreate(savedInstanceState);
43 | setContentView(R.layout.main);
44 |
45 | configs_ini = getSharedPreferences("configs",MODE_WORLD_READABLE); //设置为MODE_WORLD_READABLE xp才可以读
46 |
47 | appIcon = (ImageView)findViewById(R.id.aIcon);
48 |
49 | tname = (TextView)findViewById(R.id.aname);
50 | tpackage = (TextView)findViewById(R.id.apackage);
51 | tversion = (TextView)findViewById(R.id.aversion);
52 | tsign = (TextView)findViewById(R.id.asign);
53 | tapkuid = (TextView)findViewById(R.id.apkuid);
54 | treinforce = (TextView)findViewById(R.id.areinforce);
55 | tsize = (TextView)findViewById(R.id.asize);
56 | tmd5apk = (TextView)findViewById(R.id.md5apk);
57 | tcrc32apk = (TextView)findViewById(R.id.crc32apk);
58 | tmd5sign = (TextView)findViewById(R.id.md5sign);
59 | tdatadirectory = (TextView)findViewById(R.id.datadir);
60 | tapkdirectory = (TextView)findViewById(R.id.apkdir);
61 |
62 |
63 | appIcon.setOnClickListener( new OnClickListener() {
64 | @Override
65 | public void onClick(View view) {
66 | initAppst();
67 |
68 | }});
69 |
70 | bu = (Button) findViewById( R.id.adump); //脱壳 打开另一个应用
71 | //bu.setEnabled(false);//安按钮不可用
72 | bu.setOnClickListener( new OnClickListener() {
73 | @Override
74 | public void onClick(View view) {
75 |
76 | if(Switch2bool("dump")){
77 | dk();
78 |
79 | }else if(Switch2bool("edump")){
80 |
81 | dk();
82 |
83 | }else{
84 | if(apackage != null){
85 |
86 | configs_ini.edit().putString("packagename",apackage).commit();
87 | Intent intent = getPackageManager().getLaunchIntentForPackage(apackage);
88 | startActivity(intent);
89 | }else{
90 | Toast(noapp);
91 | }
92 | }
93 |
94 | }
95 | });
96 |
97 |
98 | bu1 = (Button) findViewById( R.id.adeta); //跳转信息界面
99 | //bu1.setEnabled(false);//安按钮不可用
100 | bu1.setOnClickListener( new OnClickListener() {
101 | @Override
102 | public void onClick(View view) {
103 | if(apackage != null){
104 | //打开应用信息界面
105 | Intent mIntent = new Intent();
106 | mIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
107 | if (Build.VERSION.SDK_INT >= 9) {
108 | mIntent.setAction("android.settings.APPLICATION_DETAILS_SETTINGS");
109 | mIntent.setData(Uri.fromParts("package", apackage, null));//getPackageName() 是取当前应用 我替换成Package
110 | } else if (Build.VERSION.SDK_INT <= 8) {
111 | mIntent.setAction(Intent.ACTION_VIEW);
112 | mIntent.setClassName("com.android.settings", "com.android.setting.InstalledAppDetails");
113 | mIntent.putExtra("com.android.settings.ApplicationPkgName", apackage);
114 | }
115 | startActivity(mIntent);
116 |
117 | }else{
118 | Toast(noapp);
119 |
120 | }
121 |
122 |
123 | }
124 | });
125 |
126 |
127 | bu2 = (Button) findViewById( R.id.ahook);
128 | bu2.setOnClickListener( new OnClickListener() {
129 | @Override
130 | public void onClick(View view) {
131 | hook_dialog();
132 |
133 | }
134 | });
135 |
136 | bu3 = (Button) findViewById( R.id.aelog);
137 | bu3.setOnClickListener( new OnClickListener() {
138 | @Override
139 | public void onClick(View view) {
140 | elog_dialog();
141 |
142 | }
143 | });
144 |
145 |
146 |
147 | if(Switch2bool("dump")){
148 | bu.setText("DUMP");
149 | }else if(Switch2bool("edump")){
150 | bu.setText("DUMP");
151 | }
152 |
153 |
154 | create_sd();
155 |
156 | if(!isRunInXposed()){//不等于
157 |
158 | AlertDialog.Builder dlg = new AlertDialog.Builder(this);
159 | dlg.setTitle("温馨提示");
160 | dlg.setMessage("您尚未激活此模块、核心Hook功能将无法使用!");
161 | dlg.setPositiveButton("OK",null);
162 |
163 | dlg.setNegativeButton("模块管理",new DialogInterface.OnClickListener() {
164 | @Override
165 | public void onClick(DialogInterface dialogInterface, int i) {
166 |
167 | try {
168 | Intent intent = new Intent();
169 | intent.setComponent(new ComponentName("de.robv.android.xposed.installer", "de.robv.android.xposed.installer.WelcomeActivity"));
170 | startActivity(intent);
171 | } catch (Throwable th) {
172 | Toast("启动失败,可能未安装Xposed或者权限不足∶" + th.toString());
173 | }
174 |
175 |
176 | }});
177 |
178 | dlg.show();
179 | }
180 |
181 |
182 | }
183 |
184 |
185 |
186 | public static Main getContext() {
187 | return INSTANCE;
188 | }
189 |
190 |
191 | //创建标题菜单
192 | @Override
193 | public boolean onCreateOptionsMenu(Menu menu)
194 | {
195 | // Inflate main_menu.xml
196 | MenuInflater inflater = getMenuInflater();
197 | inflater.inflate(R.menu.menu, menu);
198 |
199 |
200 |
201 | return true;
202 | }
203 |
204 | @Override
205 | public boolean onOptionsItemSelected(MenuItem item)
206 | {
207 | switch (item.getItemId())
208 | {
209 |
210 |
211 | case R.id.setup:
212 |
213 | setup_dialog();
214 |
215 | return true;
216 |
217 | case R.id.drill:
218 | drill_dialog();
219 | return true;
220 |
221 | case R.id.about:
222 |
223 | AlertDialog.Builder dlg = new AlertDialog.Builder(this);
224 | dlg.setTitle("关于");
225 | dlg.setMessage("Xpu01(v1.2)\nby-mail:7029974@qq.com.");
226 | dlg.setIcon(R.drawable.about);
227 | dlg.setNegativeButton("关闭",null);
228 |
229 | dlg.setPositiveButton("更新",new DialogInterface.OnClickListener() {
230 | @Override
231 | public void onClick(DialogInterface dialogInterface, int i) {
232 |
233 | Uri uri = Uri.parse("https://www.lanzous.com/b0ce6cvri");
234 | Intent intent = new Intent(Intent.ACTION_VIEW, uri);
235 | startActivity(intent);
236 |
237 |
238 | }});
239 |
240 | dlg.show();
241 | return true;
242 |
243 |
244 | case R.id.exit:
245 | System.exit(0);
246 | return true;
247 |
248 | }
249 | return super.onOptionsItemSelected(item);
250 | }
251 | //菜单结束
252 |
253 | private boolean isRunInXposed(){ //判断框架有没有激活
254 | return false;
255 | }
256 |
257 | public void dk() {
258 |
259 | if(apackage != null){
260 |
261 | configs_ini.edit().putString("packagename",apackage).commit();
262 | if(Switch2bool("cdump")){
263 | configs_ini.edit().putString("exp",Environment.getExternalStorageDirectory().getPath()).commit();
264 | Toast("DUMP输出文件路径:" + Environment.getExternalStorageDirectory().getPath() +"/ 目录下");
265 | }else{
266 | configs_ini.edit().putString("exp",Japp.dataDir(apackage)).commit();
267 | Toast( "DUMP输出文件路径:" + Japp.dataDir(apackage) +"/ 目录下");
268 | }
269 |
270 |
271 | Intent intent = getPackageManager().getLaunchIntentForPackage(apackage);
272 | startActivity(intent);
273 | }else{
274 | Toast(noapp);
275 | }
276 |
277 | }
278 |
279 |
280 |
281 | private void setup_dialog() { //设置弹窗
282 |
283 | AlertDialog.Builder dlg = new AlertDialog.Builder(this);
284 | final View gview = getLayoutInflater().inflate(R.layout.setting,null);//获取自定义对话框资源
285 | //获取自定义dialog下的确定和取消按钮资源
286 | //Button okBtnInDialog=(Button)view.findViewById(R.id.register_dialog_ok_btn);
287 | //Button cancelBtnInDialog=(Button)view.findViewById(R.id.register_dialog_cancel_btn);
288 |
289 | Switch sa = (Switch)gview.findViewById( R.id.setting_sysapp); //加载系统应用
290 | sa.setChecked(Switch2bool("sysapp"));//开关状态
291 | sa.setOnCheckedChangeListener(new OnCheckedChangeListener() {
292 |
293 | @Override
294 | public void onCheckedChanged(CompoundButton buttonView,boolean isChecked) {
295 | // TODO Auto-generated method stub
296 | if (isChecked) {
297 | //打开状态
298 | configs_ini.edit().putString("sysapp","true").commit();
299 |
300 | } else {
301 | //关闭状态
302 | configs_ini.edit().putString("sysapp","false").commit();
303 |
304 | }
305 | }
306 | });
307 |
308 |
309 | Switch sb = (Switch)gview.findViewById( R.id.setting_checksh); //加载系统应用
310 | sb.setChecked(Switch2bool("checksh"));//开关状态
311 | sb.setOnCheckedChangeListener(new OnCheckedChangeListener() {
312 |
313 | @Override
314 | public void onCheckedChanged(CompoundButton buttonView,boolean isChecked) {
315 | // TODO Auto-generated method stub
316 | if (isChecked) {
317 | //打开状态
318 | configs_ini.edit().putString("checksh","true").commit();
319 |
320 | } else {
321 | //关闭状态
322 | configs_ini.edit().putString("checksh","false").commit();
323 |
324 | }
325 | }
326 | });
327 |
328 |
329 | Switch se = (Switch)gview.findViewById( R.id.setting_xlog);
330 | se.setChecked(Switch2bool("xlog"));//开关状态
331 | se.setOnCheckedChangeListener(new OnCheckedChangeListener() {
332 |
333 | @Override
334 | public void onCheckedChanged(CompoundButton buttonView,boolean isChecked) {
335 | // TODO Auto-generated method stub
336 | if (isChecked) {
337 | //打开状态
338 | configs_ini.edit().putString("xlog","true").commit();
339 |
340 | } else {
341 | //关闭状态
342 | configs_ini.edit().putString("xlog","false").commit();
343 |
344 | }
345 | }
346 | });
347 |
348 | Switch sf = (Switch)gview.findViewById( R.id.setting_cdump);
349 | sf.setChecked(Switch2bool("cdump"));//开关状态
350 | sf.setOnCheckedChangeListener(new OnCheckedChangeListener() {
351 |
352 | @Override
353 | public void onCheckedChanged(CompoundButton buttonView,boolean isChecked) {
354 | // TODO Auto-generated method stub
355 | if (isChecked) {
356 | //打开状态
357 | configs_ini.edit().putString("cdump","true").commit();
358 |
359 | } else {
360 | //关闭状态
361 | configs_ini.edit().putString("cdump","false").commit();
362 |
363 | }
364 | }
365 | });
366 |
367 | dlg.setTitle("设置");
368 | dlg.setIcon(R.drawable.settings);
369 | dlg.setView(gview);
370 | dlg.create();
371 | dlg.setPositiveButton("关闭",null);
372 | dlg.show();
373 |
374 | }
375 |
376 |
377 | public boolean Switch2bool(String key){ //key是表的key值
378 | if(configs_ini.getString(key,"").equals("true")){
379 | return true;
380 | }
381 | return false;
382 | }
383 |
384 |
385 | private void drill_dialog() { //模块弹窗
386 | AlertDialog.Builder dlg = new AlertDialog.Builder(this);
387 | final View gview = getLayoutInflater().inflate(R.layout.drill,null);//获取自定义对话框资源
388 | //获取自定义dialog下的确定和取消按钮资源
389 | //Button okBtnInDialog=(Button)view.findViewById(R.id.register_dialog_ok_btn);
390 | //Button cancelBtnInDialog=(Button)view.findViewById(R.id.register_dialog_cancel_btn);
391 |
392 | Button extractapk = (Button) gview.findViewById( R.id.extract_apk); //提取apk
393 | extractapk.setOnClickListener( new OnClickListener() {
394 | @Override
395 | public void onClick(View view) {
396 | if(Japp.whet_app(apackage)){
397 | if(x64.copy_file(Japp.qapklj(apackage),sdexsd + "/apks/" + Japp.appname(apackage) + "_" + Japp.qversion(apackage) + ".apk")){
398 | Toast("提取成功:" + sdexsd + "/apks/" + Japp.appname(apackage) + "_" + Japp.qversion(apackage) + ".apk");
399 | }else{
400 | Toast("提取失败");
401 | File file = new File(sdexsd + "/apks"); //如果文件夹不存在则创建
402 | if (!file .exists() && !file.isDirectory()){
403 | file.mkdir(); //创建文件夹
404 |
405 | }
406 | }
407 | }else{
408 | Toast(noapp);
409 | }
410 |
411 | }
412 | });
413 |
414 | Button signbase = (Button) gview.findViewById( R.id.sign_base); //复制Base64加密后的签名值
415 | signbase.setOnClickListener( new OnClickListener() {
416 | @Override
417 | public void onClick(View view) {
418 | if(Japp.whet_app(apackage)){
419 | try
420 | {
421 | String sign = new String(Base64.encode(Japp.qsign(apackage).getBytes("UTF-8"), 0));
422 | ClipboardManager manager = (ClipboardManager) getSystemService(CLIPBOARD_SERVICE);
423 | manager.setText(sign);
424 | Toast("已复制到剪切板");
425 |
426 | }
427 | catch (UnsupportedEncodingException e)
428 | {}
429 | }else{
430 | Toast(noapp);
431 | }
432 |
433 | }
434 | });
435 |
436 | Button buninstall = (Button) gview.findViewById( R.id.uninstall); //复制Base64加密后的签名值
437 | buninstall.setOnClickListener( new OnClickListener() {
438 | @Override
439 | public void onClick(View view) {
440 | if(Japp.whet_app(apackage)){
441 | //卸载应用程序
442 | Intent intent = new Intent();
443 | intent.setAction(Intent.ACTION_DELETE);
444 | intent.setData(Uri.parse("package:" + apackage));
445 | startActivity(intent);
446 |
447 | }else{
448 | Toast(noapp);
449 | }
450 |
451 | }
452 | });
453 |
454 |
455 | Button bktest = (Button) gview.findViewById( R.id.ktest); //复制Base64加密后的签名值
456 | bktest.setOnClickListener( new OnClickListener() {
457 | @Override
458 | public void onClick(View view) {
459 | if(Japp.whet_app(apackage)){
460 | ktest_dialog();
461 |
462 | }else{
463 | Toast(noapp);
464 | }
465 |
466 | }
467 | });
468 |
469 |
470 | dlg.setTitle("模块");
471 | dlg.setIcon(R.drawable.modules);
472 | dlg.setView(gview);
473 | dlg.create();
474 | dlg.setPositiveButton("关闭",null);
475 | dlg.show();
476 |
477 | }
478 |
479 | private void hook_dialog() { //hook弹窗
480 | AlertDialog.Builder dlg = new AlertDialog.Builder(this);
481 | final View gview = getLayoutInflater().inflate(R.layout.hook,null);//获取自定义对话框资源
482 | //获取自定义dialog下的确定和取消按钮资源
483 | //Button okBtnInDialog=(Button)view.findViewById(R.id.register_dialog_ok_btn);
484 | //Button cancelBtnInDialog=(Button)view.findViewById(R.id.register_dialog_cancel_btn);
485 |
486 | final Switch es = (Switch)gview.findViewById( R.id.hook_edump); //2脱壳
487 |
488 | final Switch s = (Switch)gview.findViewById( R.id.hook_dump); //脱壳
489 | s.setChecked(Switch2bool("dump"));//开关状态
490 | s.setOnCheckedChangeListener(new OnCheckedChangeListener() {
491 |
492 | @Override
493 | public void onCheckedChanged(CompoundButton buttonView,boolean isChecked) {
494 | // TODO Auto-generated method stub
495 | if (isChecked) {
496 | //打开状态
497 | if(!checkSupport()){
498 | s.setChecked(false);
499 | Toast("这台设备不支持DUMP脱壳");
500 | }else{
501 | es.setChecked(false);
502 | configs_ini.edit().putString("edump","false").commit();
503 |
504 | bu.setText("DUMP");
505 | configs_ini.edit().putString("dump","true").commit();
506 | }
507 |
508 | } else {
509 | //关闭状态
510 | bu.setText("OPEN");
511 | configs_ini.edit().putString("dump","false").commit();
512 |
513 | }
514 | }
515 | });
516 |
517 |
518 |
519 | es.setChecked(Switch2bool("edump"));//开关状态
520 | es.setOnCheckedChangeListener(new OnCheckedChangeListener() {
521 |
522 | @Override
523 | public void onCheckedChanged(CompoundButton buttonView,boolean isChecked) {
524 | // TODO Auto-generated method stub
525 | if (isChecked) {
526 | //打开状态
527 | if(!checkSupport()){
528 | es.setChecked(false);
529 | Toast("这台设备不支持DUMP脱壳");
530 | }else{
531 | s.setChecked(false);
532 | configs_ini.edit().putString("dump","false").commit();
533 |
534 | bu.setText("DUMP");
535 | configs_ini.edit().putString("edump","true").commit();
536 | }
537 |
538 | } else {
539 | //关闭状态
540 | bu.setText("OPEN");
541 | configs_ini.edit().putString("edump","false").commit();
542 |
543 | }
544 | }
545 | });
546 |
547 |
548 |
549 | Switch sa = (Switch)gview.findViewById( R.id.hook_gvpn); //屏蔽抓包检测
550 | sa.setChecked(Switch2bool("gvpu"));//开关状态
551 | sa.setOnCheckedChangeListener(new OnCheckedChangeListener() {
552 |
553 | @Override
554 | public void onCheckedChanged(CompoundButton buttonView,boolean isChecked) {
555 | // TODO Auto-generated method stub
556 | if (isChecked) {
557 | //打开状态
558 | configs_ini.edit().putString("gvpu","true").commit();
559 |
560 | } else {
561 | //关闭状态
562 | configs_ini.edit().putString("gvpu","false").commit();
563 |
564 | }
565 | }
566 | });
567 |
568 |
569 | Switch sb = (Switch)gview.findViewById( R.id.hook_dwtc); //全局定位弹窗
570 | sb.setChecked(Switch2bool("dwtc"));//开关状态
571 | sb.setOnCheckedChangeListener(new OnCheckedChangeListener() {
572 |
573 | @Override
574 | public void onCheckedChanged(CompoundButton buttonView,boolean isChecked) {
575 | // TODO Auto-generated method stub
576 | if (isChecked) {
577 | //打开状态
578 | configs_ini.edit().putString("dwtc","true").commit();
579 |
580 | } else {
581 | //关闭状态
582 | configs_ini.edit().putString("dwtc","false").commit();
583 |
584 | }
585 | }
586 | });
587 |
588 | dlg.setTitle("HookTools");
589 | dlg.setView(gview);
590 | dlg.create();
591 | //dlg.setPositiveButton("关闭",null);
592 | dlg.show();
593 |
594 | }
595 |
596 | private void elog_dialog() { //log弹窗
597 | AlertDialog.Builder dlg = new AlertDialog.Builder(this);
598 | final View gview = getLayoutInflater().inflate(R.layout.elog,null);//获取自定义对话框资源
599 | //获取自定义dialog下的确定和取消按钮资源
600 | //Button okBtnInDialog=(Button)view.findViewById(R.id.register_dialog_ok_btn);
601 | //Button cancelBtnInDialog=(Button)view.findViewById(R.id.register_dialog_cancel_btn);
602 |
603 | logView = (LinearLayout) gview.findViewById(R.id.logView);
604 | Xpu01_log();//添加日志
605 |
606 |
607 | dlg.setTitle("日志");
608 | dlg.setView(gview);
609 | dlg.create();
610 | dlg.setPositiveButton("关闭",null);
611 |
612 | dlg.setNegativeButton("删除",new DialogInterface.OnClickListener() {
613 |
614 | @Override
615 | public void onClick(DialogInterface dialogInterface, int i) {
616 |
617 | if(delete_log()){
618 | Toast("删除成功");
619 | } else {
620 | Toast("日志为空");
621 | }
622 |
623 |
624 | }});
625 |
626 | dlg.show();
627 |
628 | }
629 |
630 |
631 | public void create_sd() { //创建文件夹
632 | File file = new File(sdexsd);//如果文件夹不存在则创建
633 | if (!file .exists() && !file.isDirectory()){
634 | file.mkdir(); //创建文件夹
635 | new File(sdexsd + "/apks").mkdir(); //创建文件夹
636 | new File(sdexsd + "/.temp").mkdir(); //创建文件夹
637 | }
638 | }
639 |
640 |
641 | private void logView(String txt) { //添加标签显示ui打印日志
642 | TextView textView = new TextView(this);
643 | textView.setText(txt);
644 | textView.setTextColor(Color.parseColor("#ffffff"));
645 |
646 | textView.setTextIsSelectable(true);
647 | logView.addView(textView);
648 |
649 | }
650 |
651 |
652 | public void Xpu01_log(){ //读取日志
653 | File file = new File("/sdcard/Xpu01/Xpu01.log");
654 | try{
655 | BufferedReader br = new BufferedReader(new FileReader(file));//构造一个BufferedReader类来读取文件
656 | String s = null;
657 | while((s = br.readLine())!=null){//使用readLine方法,一次读一行
658 | logView(s);
659 | //result.append(System.lineSeparator()+s);
660 | }
661 | br.close();
662 | }catch(Exception e){
663 | e.printStackTrace();
664 | }
665 |
666 |
667 | }
668 |
669 | public boolean delete_log() { // 删除日志文件
670 | File file = new File("/sdcard/Xpu01/Xpu01.log");
671 | if (file.exists() && !file.isDirectory() && file.delete()) {
672 | return true;
673 | }
674 | return false;
675 | }
676 |
677 | private void Toast(String str) {
678 |
679 | Toast.makeText(Main.this, str, Toast.LENGTH_SHORT).show();
680 |
681 | }
682 |
683 | private boolean checkSupport() { //判断支不支持dex
684 | boolean bool = true;
685 | try {
686 | Class.forName("com.android.dex.Dex");
687 | } catch (ClassNotFoundException classNotFoundException) {
688 | bool = false;
689 | }
690 | return bool;
691 | }
692 |
693 |
694 |
695 | private void initAppst() {
696 | /*
697 | List list = new ArrayList();
698 | list.add("a1");
699 | list.add("a2");
700 | */
701 |
702 | final String[] items;
703 |
704 | if(Switch2bool("sysapp") == true){
705 | items = Japp.sygetpacka();
706 | }else{
707 | items = Japp.getpacka();
708 | }
709 |
710 | List listde = Arrays.asList(items);//数组转list
711 |
712 | DialogItemAdapter adapter = new DialogItemAdapter(this ,listde); //传数据
713 | AlertDialog alertDialog = new AlertDialog
714 | .Builder(this)
715 | .setSingleChoiceItems(adapter, 0, new DialogInterface.OnClickListener() {
716 | @Override
717 | public void onClick(DialogInterface dialog, int which) {
718 |
719 | apackage = items[which];
720 |
721 | appIcon.setImageBitmap(Japp.applcon(items[which]));
722 |
723 | tname.setText("应用名:" + Japp.appname(items[which]));
724 | tpackage.setText("包名:" +items[which]);
725 | tversion.setText("版本:" + Japp.qversion(items[which]));
726 | tsign.setText("签名值:" +Japp.qsignz(items[which]));
727 | tapkuid.setText("应用UID:" + Japp.uid(items[which]));
728 |
729 | if(Switch2bool("checksh")){
730 | treinforce.setText("加固状态:" + x64.checksh(Japp.qapklj(items[which])));
731 | } else {
732 | treinforce.setText("加固状态:没有开启识别" );
733 | }
734 | tsize.setText("安装包大小:" + x64.readableFileSize(x64.fisize(Japp.qapklj(items[which]))));
735 |
736 | tmd5apk.setText("应用MD5:" + x64.getMd5ByFile(Japp.qapklj(items[which])));
737 | tcrc32apk.setText("应用RCR:" + x64.tohex(Long.parseLong(x64.getcrc32(Japp.qapklj(items[which])))));
738 | tmd5sign.setText("MD5签名值:" + x64.strMd5(Japp.qsign(items[which])));
739 | tdatadirectory.setText("数据目录:" + Japp.dataDir(items[which]));
740 | tapkdirectory.setText("APK目录:" + Japp.qapklj(items[which]));
741 |
742 | //Toast(items[which]);
743 | //Toast(String.valueOf(which));
744 | dialog.dismiss();
745 | }
746 | }).create();
747 |
748 | alertDialog.setTitle("应用列表");
749 | alertDialog.show();
750 |
751 | }
752 |
753 | private void ktest_dialog() { //信息校验弹窗
754 | AlertDialog.Builder dlg = new AlertDialog.Builder(this);
755 | final View gview = getLayoutInflater().inflate(R.layout.ktest_dialog,null);//获取自定义对话框资源
756 | //获取自定义dialog下的确定和取消按钮资源
757 | //Button okBtnInDialog=(Button)view.findViewById(R.id.register_dialog_ok_btn);
758 | //Button cancelBtnInDialog=(Button)view.findViewById(R.id.register_dialog_cancel_btn);
759 |
760 | final EditText eewjmdu=(EditText) gview.findViewById(R.id.ewjmdu);
761 |
762 | final TextView tdbx=(TextView) gview.findViewById(R.id.dbx);
763 | final EditText eeqmmdu=(EditText) gview.findViewById(R.id.eqmmdu);
764 |
765 | tdbx.setTextColor(gview.getResources().getColor(R.color.mediumseagreen));
766 | tdbx.setText("校验对象∶" + Japp.appname(apackage));
767 |
768 | Button bwjmdu = (Button) gview.findViewById( R.id.wjmdu); //复制Base64加密后的签名值
769 | bwjmdu.setOnClickListener( new OnClickListener() {
770 | @Override
771 | public void onClick(View view) {
772 | if(Japp.whet_app(apackage)){
773 |
774 | if(eewjmdu.getText().toString().length()!=32){
775 | Toast("文件MD5值填写错误");
776 | return;//结束该方法
777 | }
778 |
779 | if(x64.getMd5ByFile(Japp.qapklj(apackage)).equals(eewjmdu.getText().toString())){
780 | tdbx.setTextColor(gview.getResources().getColor(R.color.mediumseagreen));
781 | tdbx.setText("文件MD5值匹配");
782 | }else{
783 | tdbx.setTextColor(gview.getResources().getColor(R.color.deeppink));
784 | tdbx.setText("文件MD5值不匹配");
785 | }
786 |
787 | }else{
788 | Toast(noapp);
789 | }
790 |
791 | }
792 | });
793 |
794 |
795 | Button bqmmdu = (Button) gview.findViewById( R.id.qmmdu); //复制Base64加密后的签名值
796 | bqmmdu.setOnClickListener( new OnClickListener() {
797 | @Override
798 | public void onClick(View view) {
799 | if(Japp.whet_app(apackage)){
800 |
801 | if(eeqmmdu.getText().toString().length()!=32){
802 | Toast("MD5签名值填写错误");
803 | return;//结束该方法
804 | }
805 |
806 | if(x64.strMd5(Japp.qsign((apackage))).equals(eeqmmdu.getText().toString())){
807 | tdbx.setTextColor(gview.getResources().getColor(R.color.mediumseagreen));
808 | tdbx.setText("MD5签名值匹配");
809 | }else{
810 | tdbx.setTextColor(gview.getResources().getColor(R.color.deeppink));
811 | tdbx.setText("MD5签名值不匹配");
812 | }
813 |
814 | }else{
815 | Toast(noapp);
816 | }
817 |
818 | }
819 | });
820 |
821 |
822 | dlg.setTitle("信息校验");
823 | dlg.setView(gview);
824 | dlg.create();
825 | dlg.setPositiveButton("关闭",null);
826 |
827 | dlg.show();
828 |
829 | }
830 |
831 |
832 |
833 | }
834 |
835 |
836 |
--------------------------------------------------------------------------------
/src/main/java/com/xpu01/Xpu01hook.java:
--------------------------------------------------------------------------------
1 | package com.xpu01;
2 |
3 | import android.app.*;
4 | import android.content.pm.*;
5 | import android.widget.*;
6 | import de.robv.android.xposed.*;
7 | import de.robv.android.xposed.callbacks.*;
8 | import java.io.*;
9 | import java.lang.reflect.*;
10 | import java.util.*;
11 |
12 | public class Xpu01hook implements IXposedHookLoadPackage
13 | {
14 | XSharedPreferences pini; //XSharedPreferences类去加载指定路径下得xml文件来获取返回数据
15 |
16 | Method c = null; //getDex
17 | Class p;
18 | Method o;
19 |
20 |
21 |
22 | @Override
23 | public void handleLoadPackage(final XC_LoadPackage.LoadPackageParam p1)
24 | {
25 |
26 | if(p1.packageName.equals("com.xpu01")){//判断包名是否存在
27 | XposedHelpers.findAndHookMethod("com.xpu01.Main",p1.classLoader, "isRunInXposed", new XC_MethodReplacement() {
28 |
29 | @Override
30 | protected Object replaceHookedMethod(MethodHookParam param) throws Throwable { //替换方法
31 |
32 | return new Boolean(true);
33 | }
34 | });
35 | }
36 |
37 | pini = new XSharedPreferences("com.xpu01","configs"); //包名 文件名
38 | pini.reload(); //初始化加载数据
39 |
40 | dwtc(p1.packageName);//定位弹窗
41 |
42 | if(p1.packageName.equals(pini.getString("packagename",null))){//判断包名是否存在
43 | dump(p1);//脱壳
44 | edump();//脱壳2
45 | vpn(); //屏蔽VPN
46 | //dwtc(p1.packageName);//定位弹窗
47 | }else{
48 | //XposedBridge.log("ydll_No package name");//包名不存在
49 | return;//返回
50 | }
51 |
52 |
53 |
54 | }
55 |
56 |
57 |
58 | private void vpn()//hook vpn方法
59 | {
60 | if(!pini.getString("gvpu","").equals("true")) //开关 判断是否开启 !取反 等于 就是不等于 真等于
61 | return;
62 |
63 |
64 | try {
65 | XposedHelpers.findAndHookMethod(Class.forName("java.net.NetworkInterface"), //类名
66 | "getName", // hook方法名
67 | new XC_MethodHook() {
68 |
69 | @Override
70 | protected void beforeHookedMethod(MethodHookParam param) throws Throwable { //方法前执行
71 | super.beforeHookedMethod(param);
72 |
73 | //这样设置函数的返回值
74 | param.setResult("rmnet_data1");
75 | }
76 | });
77 |
78 | } catch (Throwable e) {
79 | throw new NoClassDefFoundError(e.getMessage());
80 | }
81 |
82 | }
83 |
84 |
85 |
86 |
87 |
88 | private void dwtc(final String pack)//hook 定位弹窗方法
89 | {
90 | if(!pini.getString("dwtc","").equals("true")) //开关 判断是否开启 !取反 等于 就是不等于 真等于
91 | return;
92 |
93 |
94 | try {
95 | XposedHelpers.findAndHookMethod(Dialog.class, //类名
96 | "show", // hook方法名
97 | new XC_MethodHook() {
98 |
99 | @Override
100 | protected void beforeHookedMethod(MethodHookParam param) throws Throwable { //方法前执行
101 | printStack(pack, "Dialog");
102 | }
103 | });
104 |
105 | } catch (Throwable e) {
106 | throw new NoClassDefFoundError(e.getMessage());
107 | }
108 |
109 |
110 |
111 | try {
112 | XposedHelpers.findAndHookMethod(Toast.class, //类名
113 | "show", // hook方法名
114 | new XC_MethodHook() {
115 |
116 | @Override
117 | protected void beforeHookedMethod(MethodHookParam param) throws Throwable { //方法前执行
118 | printStack(pack, "show");
119 | }
120 | });
121 |
122 | } catch (Throwable e) {
123 | throw new NoClassDefFoundError(e.getMessage());
124 | }
125 |
126 |
127 | }
128 |
129 |
130 |
131 | private void printStack(String pack, String name)
132 | {
133 | StringBuilder localStringBuilder = new StringBuilder();
134 | localStringBuilder.append(">>>>[Xpu01弹窗定位]> ");
135 | localStringBuilder.append(pack);
136 | localStringBuilder.append(" -> ");
137 | localStringBuilder.append(name);
138 | localStringBuilder.append(".show()");
139 | Xpu01_log(localStringBuilder.toString());
140 |
141 | boolean canPrint = false;
142 | for (StackTraceElement element : new Exception().getStackTrace()) {
143 | if (!canPrint) {
144 | if (element.getMethodName().equals("show")) {
145 | canPrint = true;
146 | } else {
147 | }
148 | }
149 | StringBuilder stringBuilder = new StringBuilder();
150 | stringBuilder.append("> ");
151 | stringBuilder.append(element);
152 | Xpu01_log(stringBuilder.toString());
153 |
154 | }
155 | Xpu01_log("<<<<<<<<<[结束]<");
156 |
157 |
158 |
159 | }
160 |
161 |
162 |
163 | private void dump(final XC_LoadPackage.LoadPackageParam pa){//hook dump脱壳
164 |
165 | if(!pini.getString("dump","").equals("true")) //总开关 判断是否开启 !取反 等于 就是不等于 真等于
166 | return;
167 |
168 |
169 | dump_i();
170 |
171 | de.robv.android.xposed.XposedHelpers.findAndHookMethod( "java.lang.ClassLoader" , pa.classLoader,"loadClass" ,String.class ,boolean.class,
172 |
173 | new XC_MethodHook ()
174 | {
175 |
176 | @Override
177 | protected void afterHookedMethod(XC_MethodHook.MethodHookParam param) //执行方法后执行
178 | {
179 |
180 |
181 |
182 | //XposedBridge.log( " after hook : " ) ;
183 | boolean isSystemClass=true;
184 | Class cls =(Class)param.getResult();
185 | if(cls==null)return;
186 |
187 |
188 | try
189 | {
190 | Class.forName(cls.getName(),false,Xpu01hook.class.getClassLoader().getSystemClassLoader());
191 | //.loadClass();
192 | }
193 | catch (ClassNotFoundException e)
194 | {
195 |
196 | isSystemClass=false;}
197 |
198 | if(isSystemClass)
199 | return;
200 |
201 |
202 |
203 | try
204 | {
205 | Object dex = c.invoke(cls);
206 |
207 |
208 |
209 | byte[] data = (byte[])o.invoke(dex) ;
210 |
211 |
212 | if(data!= null )
213 | {
214 |
215 | File f=new File( pini.getString("exp","/sdcard"), "Xpu01_dump" +Integer.toHexString(data.length)+ ".dex" ); //Integer.toHexString 整数转到十六进制
216 | if(!f.exists())
217 | {
218 | dump_b( data,f.getAbsolutePath());
219 | //XposedBridge.log(dex.toString());
220 | }
221 | }
222 | }
223 | catch (Exception e)
224 | {
225 | XposedBridge.log(e.toString());
226 | }
227 | }
228 |
229 |
230 |
231 |
232 | }
233 |
234 | );
235 |
236 | }
237 |
238 | public void dump_i()//initRefect
239 | {
240 | try
241 | {
242 | p = Class.forName("com.android.dex.Dex");
243 |
244 | o = p.getDeclaredMethod("getBytes");
245 |
246 | c = Class.class.getDeclaredMethod("getDex" );
247 | }
248 | catch ( Exception e)
249 | {
250 |
251 | XposedBridge.log(e.toString());
252 |
253 | }
254 | }
255 |
256 |
257 | public void dump_b(byte [] data, String path )//写数据 Byte
258 |
259 | {
260 |
261 | try
262 | {
263 | OutputStream os = new FileOutputStream(path);
264 | os.write( data);
265 | os.close();
266 |
267 | //Xpu01hook.Toast(Xpu01hook.this,"执行DUMP脱壳成功");
268 | }
269 | catch (Exception e)
270 | {
271 | //Xpu01hook.Toast(Xpu01hook.this,"执行DUMP脱壳失败" + e.toString());
272 | }
273 |
274 | }
275 |
276 |
277 | private void edump()//第二脱壳
278 | {
279 | if(!pini.getString("edump","").equals("true")) //开关 判断是否开启 !取反 等于 就是不等于 真等于
280 | return;
281 |
282 | try
283 | {
284 | final Class> g = Class.forName("android.os.Bundle");
285 |
286 | Class> cls2 = Class.forName("android.app.Activity");
287 | XposedHelpers.findAndHookMethod(cls2, "onCreate",g, new XC_MethodHook() {
288 |
289 | @Override
290 | protected void afterHookedMethod(XC_MethodHook.MethodHookParam paramMethodHookParam) {//方法后执行
291 |
292 | hack2Dex(paramMethodHookParam.thisObject.getClass());
293 | //Xpu01hook.Toast(Xpu01hook.this,"执行成功");
294 | }
295 | });
296 |
297 | }
298 | catch (ClassNotFoundException e)
299 | {}
300 | }
301 |
302 |
303 | private void hack2Dex(Class> cls) {
304 | try {
305 | byte[] bArr = (byte[]) Class.forName("com.android.dex.Dex").getDeclaredMethod("getBytes", new Class[0]).invoke(Class.forName("java.lang.Class").getMethod("getDex", new Class[0]).invoke(cls, new Object[0]), new Object[0]);
306 | File file = new File(pini.getString("exp","/sdcard"), "Xpu01_2dump" +Integer.toHexString(bArr.length)+ ".dex" );
307 | if (!file.exists()) {
308 | file.createNewFile();
309 | }
310 | FileOutputStream fileOutputStream = new FileOutputStream(file);
311 | fileOutputStream.write(bArr);
312 | fileOutputStream.flush();
313 | fileOutputStream.close();
314 | //Xpu01hook.Toast(Xpu01hook.this,"执行2DUMP脱壳成功");
315 | } catch (Exception e) {
316 | //Toast.makeText(context, e.toString(), 0).show();
317 | //Xpu01hook.Toast(Xpu01hook.this,"执行2DUMP脱壳失败" + e.toString());
318 | }
319 | }
320 |
321 |
322 | private void Xpu01_log(String s) {
323 | if(pini.getString("xlog","").equals("true")){ //开关 判断是否开启打印到xp框架日志
324 | XposedBridge.log(s);
325 | }else{
326 |
327 | File file = new File("/sdcard/Xpu01/Xpu01.log");
328 | BufferedWriter bw = null;
329 | try {
330 | bw = new BufferedWriter(new FileWriter(file,true));
331 | bw.write("I: " +s + "\n");
332 | bw.close();
333 | } catch (IOException e) {
334 | e.printStackTrace();
335 | }
336 |
337 | }
338 | }
339 |
340 |
341 | }
342 |
343 |
--------------------------------------------------------------------------------
/src/main/java/com/xpu01/x64.java:
--------------------------------------------------------------------------------
1 | package com.xpu01;
2 |
3 | import java.io.*;
4 | import java.math.*;
5 | import java.nio.*;
6 | import java.nio.channels.*;
7 | import java.security.*;
8 | import java.text.*;
9 | import java.util.zip.*;
10 |
11 | public class x64
12 | {
13 |
14 |
15 | public static boolean copy_file(String sourcePath, String targetPath) {//复制文件 文件路径 保存后的路径文件名
16 | if (!new File(sourcePath).exists()) {
17 | return false;
18 | }
19 | int bytesum = 0;
20 | try {
21 | InputStream inStream = new FileInputStream(sourcePath);
22 | FileOutputStream fs = new FileOutputStream(targetPath);
23 | byte[] buffer = new byte[1444];
24 | while (true) {
25 | int byteread = inStream.read(buffer);
26 | if (byteread != -1) {
27 | bytesum += byteread;
28 | fs.write(buffer, 0, byteread);
29 | } else {
30 | inStream.close();
31 | fs.close();
32 | return true;
33 | }
34 | }
35 | } catch (Exception e) {
36 | e.printStackTrace();
37 | return false;
38 | }
39 | }
40 |
41 | public static String readableFileSize(long size) { //文件大小字节转换
42 | if (size <= 0) return "0";
43 | final String[] units = new String[]{"B", "KB", "MB", "GB", "TB"};
44 | int digitGroups = (int) (Math.log10(size) / Math.log10(1024));
45 | return new DecimalFormat("#,##0.#").format(size / Math.pow(1024, digitGroups)) + " " + units[digitGroups];
46 | }
47 |
48 |
49 |
50 | public static long fisize(String filePath) {//取文件大小尺寸
51 | File file = new File(filePath);
52 | try {
53 | if (file.isDirectory()) {
54 | return getFileSizes(file);
55 | }
56 | return getFileSize(file);
57 | } catch (Exception e) {
58 | e.printStackTrace();
59 | return 0;
60 | }
61 | }
62 |
63 | private static long getFileSize(File file) throws Exception {
64 | if (file.exists()) {
65 | return (long) new FileInputStream(file).available();
66 | }
67 | file.createNewFile();
68 | return 0;
69 | }
70 |
71 | private static long getFileSizes(File f) throws Exception {
72 | long fileSize;
73 | long size = 0;
74 | File[] flist = f.listFiles();
75 | for (int i = 0; i < flist.length; i++) {
76 | if (flist[i].isDirectory()) {
77 | fileSize = getFileSizes(flist[i]);
78 | } else {
79 | fileSize = getFileSize(flist[i]);
80 | }
81 | size += fileSize;
82 | }
83 | return size;
84 | }
85 |
86 |
87 |
88 | public static String checksh(String sourcePath) { //查壳 文件路径
89 | String dat= drtext(sourcePath);
90 |
91 | String nm = "360加固|腾讯加固|爱加密|百度加固|阿里加固|几维安全加固|通付盾加固|梆梆加固|";
92 | String[] identify_nm = nm.split("\\|");// 分割文本
93 | String tz = "libjiagu.so|libshell.so|libexec.so|libbaiduprotect.so|libmobisecx.so|libkwscmm.so|libegis.so|libsecexe.so|";
94 | String[] identify_tz = tz.split("\\|");// 分割文本
95 |
96 | for (int i = 0; i <= 7; i++) {
97 | if(dat.indexOf(identify_tz[i]) != -1){ //indexOf 由指定位置从前向后查找指定字符串的位置,如果查找到了则返回(第一个字母)位置索引,如果找不到返回-1.
98 | return identify_nm[i];
99 |
100 | }
101 | }
102 | return "未发现加固";
103 | }
104 |
105 |
106 | private static String drtext(String filename) { //读入文本文件 返回内容
107 | Exception e;
108 | String res = "";
109 | if (!new File(filename).exists()) {
110 | return res;
111 | }
112 | try {
113 | FileInputStream fin = new FileInputStream(filename);
114 | int length = fin.available();
115 | byte[] buffer = new byte[length];
116 | fin.read(buffer);
117 | String res2 = new String(buffer, 0, length, "utf8");
118 | try {
119 | fin.close();
120 | return res2;
121 | } catch (Exception e2) {
122 | e = e2;
123 | res = res2;
124 | e.printStackTrace();
125 | return res;
126 | }
127 | } catch (Exception e3) {
128 | e = e3;
129 | e.printStackTrace();
130 | return res;
131 | }
132 | }
133 |
134 |
135 |
136 |
137 | public static String getMd5ByFile(String filePath) { //获取文件md5值 文件路径
138 | String value = null;
139 | FileInputStream in = null;
140 | File file = new File(filePath);
141 | try {
142 | in = new FileInputStream(file);
143 | MappedByteBuffer byteBuffer = in.getChannel().map(FileChannel.MapMode.READ_ONLY, 0, file.length());
144 | MessageDigest md5 = MessageDigest.getInstance("MD5");
145 | md5.update(byteBuffer);
146 | BigInteger bi = new BigInteger(1, md5.digest());
147 | value = bi.toString(16);
148 | } catch (Exception e) {
149 | e.printStackTrace();
150 | } finally {
151 | if(null != in) {
152 | try {
153 | in.close();
154 | } catch (IOException e) {
155 | e.printStackTrace();
156 | }
157 | }
158 | }
159 | return value;
160 | }
161 |
162 | public static String getcrc32(String filename) { //获取文件crc32值
163 | File file = new File(filename);
164 | CRC32 crc32 = new CRC32();
165 | //MessageDigest.get
166 | FileInputStream fileInputStream = null;
167 | try {
168 | fileInputStream = new FileInputStream(file);
169 | byte[] buffer = new byte[8192];
170 | int length;
171 | while ((length = fileInputStream.read(buffer)) != -1) {
172 | crc32.update(buffer,0, length);
173 | }
174 | return crc32.getValue()+"";
175 |
176 |
177 | } catch (FileNotFoundException e) {
178 | e.printStackTrace();
179 | return null;
180 | } catch (IOException e) {
181 | e.printStackTrace();
182 | return null;
183 | } finally {
184 | try {
185 | if (fileInputStream != null)
186 | fileInputStream.close();
187 | } catch (IOException e) {
188 | e.printStackTrace();
189 | }
190 | }
191 | }
192 |
193 | public static String tohex(long j) { //转到十六进制
194 | try {
195 | String toHexString = Long.toHexString(j);
196 | return toHexString.length() < 2 ? "0" + toHexString : toHexString;
197 | } catch (Exception e) {
198 | return "";
199 | }
200 | }
201 |
202 | public static String strMd5(String str) { //字符串获取md5
203 | MessageDigest messageDigest = null;
204 | try {
205 | messageDigest = MessageDigest.getInstance("MD5");
206 | messageDigest.reset();
207 | messageDigest.update(str.getBytes("UTF-8"));
208 | } catch (NoSuchAlgorithmException e) {
209 | e.printStackTrace();
210 | } catch (UnsupportedEncodingException e) {
211 | e.printStackTrace();
212 | }
213 | byte[] byteArray = messageDigest.digest();
214 | StringBuffer md5StrBuff = new StringBuffer();
215 | for (int i = 0; i < byteArray.length; i++) {
216 | if (Integer.toHexString(0xFF & byteArray[i]).length() == 1)
217 |
218 | md5StrBuff.append("0").append(Integer.toHexString(0xFF & byteArray[i]));
219 | else
220 | md5StrBuff.append(Integer.toHexString(0xFF & byteArray[i]));
221 | }
222 | return md5StrBuff.toString();
223 | }
224 |
225 |
226 |
227 |
228 | }
229 |
--------------------------------------------------------------------------------
/src/main/res/drawable-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eksenior/xpu01/152ac26e4578e38090792f080f0f01e5a7e5c4b8/src/main/res/drawable-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/src/main/res/drawable-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eksenior/xpu01/152ac26e4578e38090792f080f0f01e5a7e5c4b8/src/main/res/drawable-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/src/main/res/drawable-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eksenior/xpu01/152ac26e4578e38090792f080f0f01e5a7e5c4b8/src/main/res/drawable-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/src/main/res/drawable-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eksenior/xpu01/152ac26e4578e38090792f080f0f01e5a7e5c4b8/src/main/res/drawable-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/src/main/res/drawable/about.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eksenior/xpu01/152ac26e4578e38090792f080f0f01e5a7e5c4b8/src/main/res/drawable/about.png
--------------------------------------------------------------------------------
/src/main/res/drawable/modules.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eksenior/xpu01/152ac26e4578e38090792f080f0f01e5a7e5c4b8/src/main/res/drawable/modules.png
--------------------------------------------------------------------------------
/src/main/res/drawable/settings.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/eksenior/xpu01/152ac26e4578e38090792f080f0f01e5a7e5c4b8/src/main/res/drawable/settings.png
--------------------------------------------------------------------------------
/src/main/res/layout/drill.xml:
--------------------------------------------------------------------------------
1 |
9 |
10 |
15 |
20 |
25 |
26 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/src/main/res/layout/elog.xml:
--------------------------------------------------------------------------------
1 |
10 |
15 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/src/main/res/layout/hook.xml:
--------------------------------------------------------------------------------
1 |
9 |
10 |
14 |
21 |
26 |
27 |
28 |
32 |
39 |
44 |
45 |
46 |
50 |
57 |
62 |
63 |
67 |
74 |
80 |
81 |
82 |
83 |
--------------------------------------------------------------------------------
/src/main/res/layout/item_app.xml:
--------------------------------------------------------------------------------
1 |
10 |
14 |
19 |
20 |
--------------------------------------------------------------------------------
/src/main/res/layout/ktest_dialog.xml:
--------------------------------------------------------------------------------
1 |
9 |
10 |
16 |
20 |
21 |
25 |
26 |
34 |
40 |
41 |
42 |
43 |
47 |
48 |
56 |
62 |
63 |
64 |
65 |
--------------------------------------------------------------------------------
/src/main/res/layout/main.xml:
--------------------------------------------------------------------------------
1 |
7 |
8 |
14 |
15 |
25 |
26 |
31 |
32 |
39 |
40 |
48 |
55 |
62 |
63 |
64 |
65 |
66 |
67 |
74 |
75 |
82 |
83 |
90 |
91 |
98 |
105 |
112 |
113 |
114 |
115 |
122 |
123 |
130 |
131 |
132 |
138 |
139 |
146 |
154 |
161 |
167 |
168 |
169 |
170 |
171 |
--------------------------------------------------------------------------------
/src/main/res/layout/setting.xml:
--------------------------------------------------------------------------------
1 |
9 |
10 |
11 |
15 |
22 |
27 |
28 |
32 |
39 |
45 |
46 |
47 |
51 |
58 |
63 |
64 |
65 |
69 |
76 |
81 |
82 |
83 |
84 |
--------------------------------------------------------------------------------
/src/main/res/menu/menu.xml:
--------------------------------------------------------------------------------
1 |
22 |
--------------------------------------------------------------------------------
/src/main/res/values-v21/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
12 |
13 |
--------------------------------------------------------------------------------
/src/main/res/values-v23/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
12 |
13 |
--------------------------------------------------------------------------------
/src/main/res/values/color.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | #3CB371
7 | #FF1493
8 | #151515
9 | #FFFFFF
10 | #FFFF00
11 | #111111
12 | #000000
13 |
14 |
--------------------------------------------------------------------------------
/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Xpu01
5 |
6 |
7 |
--------------------------------------------------------------------------------
/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
7 |
8 |
--------------------------------------------------------------------------------