美文网首页
HooK之hook Notification

HooK之hook Notification

作者: Lee_5566 | 来源:发表于2021-02-03 20:36 被阅读0次
    image.png

    目录

    第一章:android hook介绍
    第二章:hook之替换View.OnClickListener
    第三章:HooK之hook Notification

    HooK Notification

    发送消息到通知栏的核心代码:

    String channelId = createNotificationChannel("my_channel_ID", "my_channel_NAME", NotificationManager.IMPORTANCE_HIGH);
    NotificationCompat.Builder notification = new NotificationCompat.Builder(MainActivity.this, channelId)
                            .setContentTitle("通知")
                            .setContentText("你好,世界!")
                            .setContentIntent(pendingIntent)
                            .setSmallIcon(R.mipmap.ic_launcher)
                            .setAutoCancel(true)
                            .setWhen(System.currentTimeMillis());
    
    
    notificationManager.notify(16657, notification.build());
    

    最后是使用了notificationManager的notify方法。

    继续跟踪notify方法:

    public void notify(int id, Notification notification)
    {
        notify(null, id, notification);
    }
    
    public void notify(String tag, int id, Notification notification)
    {
        notifyAsUser(tag, id, notification, mContext.getUser());
    }
    

    notify 方法最终调用 notifyAsUser 方法:

        /**
         * @hide
         */
        @UnsupportedAppUsage
        public void notifyAsUser(String tag, int id, Notification notification, UserHandle user)
        {
            INotificationManager service = getService();
            String pkg = mContext.getPackageName();
    
            try {
                if (localLOGV) Log.v(TAG, pkg + ": notify(" + id + ", " + notification + ")");
                service.enqueueNotificationWithTag(pkg, mContext.getOpPackageName(), tag, id,
                        fixNotification(notification), user.getIdentifier());
            } catch (RemoteException e) {
                throw e.rethrowFromSystemServer();
            }
        }
    

    notifyAsUser 方法中,service 是一个单例,因此,可以想方法 hook 住这个 service。

    而且notifyAsUser 最终会调用到 service 的 enqueueNotificationWithTag 方法。

    因此 hook 住 service 的 enqueueNotificationWithTag 方法即可.

    具体思路

    Hook Notification,大概需要三步:

    • 第一步:得到 NotificationManager 的 service
    • 第二步:因为 service 是接口,所以我们可以使用动态代理,获取动态代理对象
    • 第三步:偷梁换柱,使用动态代理对象 proxyNotiMng 替换系统的 service
    代码展示

    全部源码参考:android之NotificationManager服务

    package com.exmple.hooknotify;
    
    import androidx.appcompat.app.AppCompatActivity;
    import androidx.core.app.NotificationCompat;
    
    import android.app.Notification;
    import android.app.NotificationChannel;
    import android.app.NotificationManager;
    import android.app.PendingIntent;
    import android.content.Context;
    import android.content.Intent;
    import android.graphics.BitmapFactory;
    import android.os.Bundle;
    import android.util.Log;
    import android.view.View;
    import android.widget.Button;
    import android.widget.Toast;
    
    import java.lang.reflect.Field;
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    import java.lang.reflect.Proxy;
    import java.time.format.TextStyle;
    
    public class MainActivity extends AppCompatActivity {
        public  static String TAG = "Hello Hook";
        Button button;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            try {
                hookNotificationManager(MainActivity.this);
            } catch (Exception e) {
                e.printStackTrace();
            }
    
            button = (Button)findViewById(R.id.buttonOne);
    
            button.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    NotificationManager notificationManager = (NotificationManager) MainActivity.this.getSystemService(Context.NOTIFICATION_SERVICE);
    
                    Intent intent = new Intent(MainActivity.this, MainActivity2.class);
                    intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
                    PendingIntent pendingIntent = PendingIntent.getActivity(MainActivity.this, 0, intent, 0);
    
                    String channelId = createNotificationChannel("my_channel_ID", "my_channel_NAME", NotificationManager.IMPORTANCE_HIGH);
                    NotificationCompat.Builder notification = new NotificationCompat.Builder(MainActivity.this, channelId)
                            .setContentTitle("通知")
                            .setContentText("你好,世界!")
                            .setContentIntent(pendingIntent)
                            .setSmallIcon(R.mipmap.ic_launcher)
                            .setAutoCancel(true)
                            .setWhen(System.currentTimeMillis());
    
    
                    notificationManager.notify(16657, notification.build());
                }
            });
    
    
        }
    
        private String createNotificationChannel(String channelID, String channelNAME, int level) {
            if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
                NotificationManager manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
                NotificationChannel channel = new NotificationChannel(channelID, channelNAME, level);
                manager.createNotificationChannel(channel);
                return channelID;
            } else {
                return null;
            }
        }
    
        public static void hookNotificationManager(final Context context) throws Exception {
            NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
    
            // 第一步:得到系统的 sService
            Method getService = NotificationManager.class.getDeclaredMethod("getService");
            getService.setAccessible(true);
            final Object sOriginService = getService.invoke(notificationManager);
    
            // 第二步:设置动态代理对象
            Class iNotiMngClz = Class.forName("android.app.INotificationManager");
            Object proxyNotiMng = Proxy.newProxyInstance(context.getClass().getClassLoader(), new
                    Class[]{iNotiMngClz}, new InvocationHandler() {
                @Override
                public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                    Log.d(TAG, "invoke(). method:" + method);
                    String name = method.getName();
                    Log.d(TAG, "invoke: name=" + name);
                    if (args != null && args.length > 0) {
                        for (Object arg : args) {
                            Log.d(TAG, "invoke: arg=" + arg);
                        }
                    }
                    Toast.makeText(context.getApplicationContext(), "检测到有人发通知了", Toast.LENGTH_SHORT).show();
                    // 操作交由 sOriginService 处理,不拦截通知
                    return method.invoke(sOriginService, args);
                }
            });
    
            // 第三步:偷梁换柱,使用 proxyNotiMng 替换系统的 sService
            Field sServiceField = NotificationManager.class.getDeclaredField("sService");
            sServiceField.setAccessible(true);
            sServiceField.set(notificationManager, proxyNotiMng);
        }
    
    }
    

    执行效果:

    image.png

    相关文章

      网友评论

          本文标题:HooK之hook Notification

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