美文网首页
Android java层的shell

Android java层的shell

作者: ESE_ | 来源:发表于2018-11-27 17:43 被阅读0次

    Android学习的第一个java层的shell,理解了不少东西,主要理解了Ref反射机制。学习路径来自F8LEFT视频。

    要求

    1、手机版本5.0以上

    代码

    MyApplication

    import android.app.Application;
    import android.content.Context;
    import android.util.Log;
    
    public class MyApplication  extends Application {
    
        public void onCreate(){
            super.onCreate();
        }
    
        protected void attachBaseContext(Context base)
        {
            super.attachBaseContext(base);
        }
    }
    
    

    MainActivity

    import android.support.v7.app.AppCompatActivity;
    import android.os.Bundle;
    import android.widget.TextView;
    
    public class MainActivity extends AppCompatActivity {
        
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            TextView tvinfo = (TextView) findViewById(R.id.tvinfo);
            TextView tvwd = (TextView) findViewById(R.id.tvwd);
    
            tvwd.setText("Shell has been loaded");
    
            if(getApplication() instanceof MyApplication)
            {
                tvinfo.setText("MyApplication has been loaded");
            }
    
            }
    
        }
    
        <TextView
            android:id="@+id/tvinfo"
            android:layout_width="wrap_content"
            android:layout_height="33dp"
            android:text="0"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintRight_toRightOf="parent"
            app:layout_constraintTop_toTopOf="parent" />
    
        <TextView
            android:id="@+id/tvwd"
            android:layout_width="wrap_content"
            android:layout_height="38dp"
            android:layout_marginStart="8dp"
            android:layout_marginTop="8dp"
            android:layout_marginEnd="8dp"
            android:layout_marginBottom="8dp"
            android:text="Application not load,Nooo"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintHorizontal_bias="0.554"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toBottomOf="@+id/tvinfo"
            app:layout_constraintVertical_bias="1.0" />
    

    AndroidManifest.xml文件中做一下声明,<application xxxx>中添加:
    android:name=".MyApplication"

    生成apk,提取dex
    java -jar ShakaApktool.jar bs classes.dex -o classes
    保留两个smali:-->MainActivity.smali MyApplication.smali
    编译成dex
    java -jar ShakaApktool.jar s classes -o encrypt.dex

    shell

    1、创建一个asset目录,将encrypt.dex复制进去。
    2、删除MainActivity.java MyApplication.java
    3、模拟系统加载的流程

    write

    首先、接管程序的Application中的两个函数[这是控制的最开始两个函数]。
    1 ---> attachBaseContext(context)
    2 ---> onCreate()

    ProxyApplication

    创建ProxyApplication继承父类android.app.Application,选择重构attachBaseContext()与onCreate()。
    ProxyApplication.java

    package esebitcoin.yshell;
    
    import android.app.Application;
    import android.app.Instrumentation;
    import android.content.Context;
    import android.content.pm.ApplicationInfo;
    import android.util.ArrayMap;
    import java.io.File;
    import java.lang.ref.WeakReference;
    import java.util.ArrayList;
    import dalvik.system.DexClassLoader;
    
    public class ProxyApplication extends Application {
        @Override
        protected void attachBaseContext(Context base) {
            super.attachBaseContext(base);
            File cache = getDir("eshell",MODE_PRIVATE);
            String sDex = cache +"/encrypt.dex";
    
            File dexFile = FileManager.releaseAssetsFile(this,"encrypt.dex",sDex,null);
    
            ClassLoader cl = new DexClassLoader(sDex,getDir("eshell_aot",MODE_PRIVATE).getAbsolutePath(), getApplicationInfo().nativeLibraryDir,getClassLoader());
            Object currentActivityThread = RefInvoke.invokeStaticMethod("android.app.ActivityThread", "currentActivityThread",new Class[]{},new Object[]{});
            ArrayMap mPackages = (ArrayMap) RefInvoke.getFieldOjbect("android.app.ActivityThread", "mPackages",currentActivityThread);
            WeakReference wr = (WeakReference) mPackages.get(getPackageName());
            RefInvoke.setFieldOjbect("android.app.LoadedApk","mClassLoader",wr.get(),cl);
    
            return;
        }
        @Override
        public void onCreate() {
            super.onCreate();
    
            Object currentActivityThread = RefInvoke.invokeStaticMethod("android.app.ActivityThread", "currentActivityThread",new Class[]{},new Object[]{});
            Object mBoundApplication = RefInvoke.getFieldOjbect("android.app.ActivityThread", "mBoundApplication",currentActivityThread);
            Object loadedApkInfo = RefInvoke.getFieldOjbect("android.app.ActivityThread$AppBindData", "info",mBoundApplication);
    
            RefInvoke.setFieldOjbect("android.app.LoadedApk","mApplication",loadedApkInfo,null);
    
            String srcAppName = "esebitcoin.yshell.MyApplication";
    
            ApplicationInfo appInfo_LoadedApke = (ApplicationInfo) RefInvoke.getFieldOjbect("android.app.LoadedApk", "mApplicationInfo",loadedApkInfo);
            appInfo_LoadedApke.className = srcAppName;
    
            ApplicationInfo appinfo_In_AppBindData = (ApplicationInfo) RefInvoke.getFieldOjbect("android.app.ActivityThread$AppBindData", "appInfo",mBoundApplication);
            appinfo_In_AppBindData.className = srcAppName;
    
            Application oldApplication = (Application) RefInvoke.getFieldOjbect("android.app.ActivityThread", "mInitialApplication",currentActivityThread);
    
    
            ArrayList<Application> mAllApplications = (ArrayList<Application>) RefInvoke.getFieldOjbect("android.app.ActivityThread", "mAllApplications",currentActivityThread);
    
            mAllApplications.remove(oldApplication);
    
            Application realApp = (Application) RefInvoke.invokeMethod("android.app.LoadedApk", "makeApplication",new Class[]{boolean.class,Instrumentation.class}, loadedApkInfo,new Object[]{false,null});
    
            realApp.onCreate();
    
            RefInvoke.setFieldOjbect("android.app.ActivityThread","mInitialApplication", currentActivityThread,realApp);
    
            return;
        }
    
    }
    

    FileManager.java

    package esebitcoin.yshell;
    
    import android.content.Context;
    import android.content.res.AssetManager;
    import java.io.ByteArrayOutputStream;
    import java.io.File;
    import java.io.FileOutputStream;
    import java.io.InputStream;
    import java.lang.reflect.Method;
    
    public class FileManager {
        public static File releaseAssetsFile(Context ctx, String assetFile, String releaseFile, Method decMethod)
        {
    
            AssetManager manager = ctx.getAssets();
            try{
                InputStream is = manager.open(assetFile);
                ByteArrayOutputStream os = new ByteArrayOutputStream();
                byte[] buf = new byte[1024];
                int iRead;
                while ((iRead = is.read(buf)) != -1) {
                    os.write(buf, 0, iRead);
                }
    
                byte[] dec = decMethod != null ? (byte[]) decMethod.invoke (null, os. toByteArray()) : os.toByteArray();
                is.close();
                os.close();
    
                FileOutputStream of = new FileOutputStream(new File(releaseFile));
                of.write(dec);
                of.close();
                return new File(releaseFile);
            } catch (Exception e) {
                e.printStackTrace();
            }
            return null;
        }
    }
    

    RefInvoke.java

    修改xml

    AndroidManifest.xml
    ---> android:name=".ProxyApplication"

    Android程序例子下载

    相关文章

      网友评论

          本文标题:Android java层的shell

          本文链接:https://www.haomeiwen.com/subject/wvknqqtx.html