美文网首页
hook AMS服务实现大型登录架构

hook AMS服务实现大型登录架构

作者: 爬行的蚂蚁2725 | 来源:发表于2019-02-20 14:15 被阅读0次

    使用场景
    例如一些商城app,在没有注册的情况下可以浏览商品但是在加入购物车或别的操作下会跳转到注册登录界面,等到注册登录后又会返回到购物车界面,对于这种需求就可以使用hook技术实现。

    技术点分析
    只需要hook两个地方,1.hook startActivity方法绕过AMS检查,将未注册的Activity伪装成注册的activity ,使用动态代理的形式创建IActiviytManager的代理类替换系统的IActvityManager 2.launchActity时会在ActivityThread的Handler处理这个消息(100),hook 这个handler,重写handlemessage方法,获取实际需要启动的intent。

    详细请看HookUtil

    public class HookUtil {
    
        private Context context;
    
        public  void hookHookMh(Context context  ) {
            try {
                Class<?> forName = Class.forName("android.app.ActivityThread");
                Field currentActivityThreadField = forName.getDeclaredField("sCurrentActivityThread");
                currentActivityThreadField.setAccessible(true);
    //            还原系统的ActivityTread   mH
                Object activityThreadObj=currentActivityThreadField.get(null);
    
                Field handlerField = forName.getDeclaredField("mH");
                handlerField.setAccessible(true);
    //            hook点找到了
                Handler mH= (Handler) handlerField.get(activityThreadObj);
                Field callbackField = Handler.class.getDeclaredField("mCallback");
    
                callbackField.setAccessible(true);
    
                callbackField.set(mH,new ActivityMH(mH));
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    
    
    
        public  void hookStartActivity(Context context) {
    //        还原 gDefault 成员变量  反射  调用一次
            this.context = context;
            try {
                Class<?> ActivityManagerNativecls=Class.forName("android.app.ActivityManagerNative");
                Field gDefault = ActivityManagerNativecls.getDeclaredField("gDefault");
                gDefault.setAccessible(true);
    //            因为是静态变量  所以获取的到的是系统值  hook   伪hook
                Object defaltValue=gDefault.get(null);
                //mInstance对象
                Class<?> SingletonClass=Class.forName("android.util.Singleton");
    
                Field mInstance = SingletonClass.getDeclaredField("mInstance");
    //        还原 IactivityManager对象  系统对象
                mInstance.setAccessible(true);
                Object iActivityManagerObject=mInstance.get(defaltValue);
                Class<?> IActivityManagerIntercept = Class.forName("android.app.IActivityManager");
                startActivty startActivtyMethod = new startActivty(iActivityManagerObject);
    //            第二参数  是即将返回的对象 需要实现那些接口
                Object oldIactivityManager = Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader()
                        , new Class[]{IActivityManagerIntercept, View.OnClickListener.class}
                        , startActivtyMethod);
    //            将系统的iActivityManager  替换成    自己通过动态代理实现的对象   oldIactivityManager对象  实现了 IActivityManager这个接口的所有方法
                mInstance.set(defaltValue, oldIactivityManager);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        class ActivityMH implements  Handler.Callback{
            private  Handler mH;
    
            public ActivityMH(Handler mH) {
                this.mH = mH;
            }
    
            @Override
            public boolean handleMessage(Message msg) {
    //LAUNCH_ACTIVITY ==100 即将要加载一个activity了
                if (msg.what == 100) {
    //加工 --完  一定丢给系统  secondActivity  -hook->proxyActivity---hook->    secondeActivtiy
                    handleLuachActivity(msg);
                }
    //做了真正的跳转
                mH.handleMessage(msg);
                return  true;
            }
    
            private void handleLuachActivity(Message msg) {
    //            还原
                Object obj = msg.obj;
                try {
                    Field intentField=obj.getClass().getDeclaredField("intent");
                    intentField.setAccessible(true);
                    //  ProxyActivity   2
                    Intent realyIntent = (Intent) intentField.get(obj);
    //                sconedActivity  1
                    Intent oldIntent = realyIntent.getParcelableExtra("oldIntent");
                    if (oldIntent != null) {
    //                    集中式登录
                        SharedPreferences share = context.getSharedPreferences("sp_info",
                                Context.MODE_PRIVATE);
                        if (share.getBoolean("login",false)||oldIntent.getComponent().getClassName().equals(SceondActivity.class.getName())) {
    
    //                      登录  还原  把原有的意图    放到realyIntent
                            realyIntent.setComponent(oldIntent.getComponent());
                        }else {
                            ComponentName componentName = new ComponentName(context,LoginActivity.class);
                            realyIntent.putExtra("extraIntent", oldIntent.getComponent()
                                    .getClassName());
                            realyIntent.setComponent(componentName);
                        }
                    }
    
    
                } catch (Exception e) {
                    e.printStackTrace();
                }
    
    
            }
        }
        class startActivty implements InvocationHandler {
            private  Object iActivityManagerObject;
    
            public startActivty(Object iActivityManagerObject) {
                this.iActivityManagerObject = iActivityManagerObject;
            }
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    
                Log.i("INFO","invoke    "+method.getName());
                if ("startActivity".equals(method.getName())) {
                    Log.i("INFO","-----------------startActivity--------------------------");
    //瞒天过海
    //                寻找传进来的intent
                    Intent intent = null;
                    int index=0;
                    for (int i=0;i<args.length;i++) {
    //                    intent
                        Object arg = args[i];
                        if (arg instanceof Intent) {
                            intent = (Intent) args[i];
                            index = i;
                        }
                    }
    //目的  ---载入acgtivity  将它还原
                    Intent newIntent = new Intent();
                    ComponentName componentName = new ComponentName(context, ProxyActivity.class);
                    newIntent.setComponent(componentName);
    //                真实的意图 被我隐藏到了  键值对
                    newIntent.putExtra("oldIntent", intent);
                    args[index] = newIntent;
                }
    
                return method.invoke(iActivityManagerObject, args);
            }
        }
    
    }
    

    清单文件中只需要生命下代理activity 其他的activity都不用申明

    <activity android:name=".ProxyActivity"/>
    

    登录成功后修改intent的意图,跳转到实际需要跳转的类

    public class LoginActivity  extends Activity {
        EditText name;
        EditText password;
        private String className;
        SharedPreferences share;
        @Override
        protected void onCreate(@Nullable Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_login);
            name = (EditText) findViewById(R.id.name);
            password = (EditText) findViewById(R.id.password);
            share = this.getSharedPreferences("sp_info", MODE_PRIVATE);//实例化
            className = getIntent().getStringExtra("extraIntent");
            if (className != null) {
                ((TextView)findViewById(R.id.text)).setText(" 跳转界面:"+className);
            }
        }
    
        public void login(View view) {
            if ((name.getText() == null || password.getText() == null)) {
                Toast.makeText(this, "请填写用户名 或密码",Toast.LENGTH_SHORT).show();
                return;
            }
            if ("david".equals(name.getText().toString()) && "123456".equals(password.getText()
                    .toString())) {
                SharedPreferences share = super.getSharedPreferences("sp_info", MODE_PRIVATE);//实例化
                SharedPreferences.Editor editor = share.edit(); //使处于可编辑状态
                editor.putString("name", name.getText().toString());
                editor.putString("sex", password.getText().toString());
                editor.putBoolean("login",true);   //设置保存的数据
                Toast.makeText(this, "登录成功",Toast.LENGTH_SHORT).show();
                editor.commit();    //提交数据保存
                if (className != null) {
    //跳转到本来要调整的activity
                    ComponentName componentName = new ComponentName(this, className);
                    Intent intent = new Intent();
                    intent.setComponent(componentName);
                    startActivity(intent);
                    finish();
                }
            }else{
                SharedPreferences.Editor editor = share.edit(); //使处于可编辑状态
                editor.putBoolean("login",false);   //设置保存的数据
                Toast.makeText(this, "登录失败",Toast.LENGTH_SHORT).show();
                editor.commit();    //提交数据保存
            }
        }
    }
    

    在application中注册hook

    public class MyApplication extends Application {
        @Override
        public void onCreate() {
            super.onCreate();
            HookUtil hookUtil = new HookUtil();
            hookUtil.hookStartActivity(this);
            hookUtil.hookHookMh(this);
        }
    }
    

    相关文章

      网友评论

          本文标题:hook AMS服务实现大型登录架构

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