[Android Framework Series] Chapter 10 PMS Hook Realizes Broadcast Call

1 Introduction

In the previous chapters, we learned [Android Framework series] Chapter 4 PMS principle We learned about the PMS principle, [Android Framework series] Chapter 9 AMS Hook to realize the login page jump We know that AMS can be intercepted by Hook to realize the unregistered Activity page Jump, let's try it in this chapter HookPMS实现广播的发送.

Here we only briefly introduce the ideas and key codes of HookPMS. If you need to know more, please go to the project address at the end of the article to download and view.

Do students encounter the need to dynamically deliver components? By what means?
In the previous chapters, we analyzed PMSthe relevant principles, and briefly reviewed PMS:
PMSit is the package management system service, which is used to manage all package information, including application installation, uninstallation, update and analysis AndroidManifest.xml. After the mobile phone is turned on, it will traverse all the files on the device /data/app/and /system/app/under the directory , and cache all the data ( , , etc.) information in the memory apkby parsing all installed applications , and then provide them to other services.AndroidManifest.xmlxml应用信息权限四大组件AMS

Whether HookPMSit is possible to realize apkthe distribution of dynamic components, in this chapter, we realize the call dynamic distribution by HookPMSgetting the ones in the PMS . **receivers(BroadcastReceiver)apkBroadcastReceiver

2 achieve

The four major components are managed in the PMS, and all the apks will be parsed and the information corresponding to the four major components will be saved to the corresponding collections Activity, receivers, probiders, respectively services.

/frameworks/base/core/java/android/content/pm/PackageParser.java

6460          @UnsupportedAppUsage
6461          public final ArrayList<Activity> activities = new ArrayList<Activity>(0);
6462          @UnsupportedAppUsage
6463          public final ArrayList<Activity> receivers = new ArrayList<Activity>(0);
6464          @UnsupportedAppUsage
6465          public final ArrayList<Provider> providers = new ArrayList<Provider>(0);
6466          @UnsupportedAppUsage
6467          public final ArrayList<Service> services = new ArrayList<Service>(0);

BroadcastReceiverIn this chapter, we have to get the collection of HookPMS receivers.

2.1 Implementation ideas

  1. Download the one to be delivered first apk(we directly add it to the storage of the device here)
  2. Decompress and parse the passed apkmethod into theHookPMSPMS
  3. Then by HookPMSgetting the collection with BroadcastReceiverthe informationreceivers
  4. apkUse the name in the dynamic distribution BroadcastReceiveras a parameter, HookPMSand call it through the method, so as to achieve the purpose of this chapter.

2.2 Project structure

insert image description here
As we can see in the picture above, there are two modules, namely app and pmsbr.
app module:
HookPMSThe main logic is in PMSPackageParserthe class, which is used for apkparsing and receiving broadcasts, and for operating .PMSHookClientActivityHookPMS

pmsbr module:
This moduleis actually just for packaging into a dynamic apk, the internal one BroadcastReceiveris used to verify HookPMSwhether the dynamic delivery can be apkcalledBroadcastReceiver

2.3 ClientActivity

package com.yvan.hookpms;

import android.Manifest;
import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Bundle;
import android.view.View;
import android.widget.Toast;

import androidx.appcompat.app.AppCompatActivity;

import java.io.File;

/**
 * @author yvan
 * @date 2023/8/7
 * @description
 */
public class ClientActivity extends AppCompatActivity {
    
    

    @Override
    protected void onCreate(Bundle savedInstanceState) {
    
    
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_client);
        checkPermission(this);
        IntentFilter filter = new IntentFilter();
        filter.addAction("com.yvan.client");
        registerReceiver(new FinishBroadcastReceiver(), filter);
    }
    
    public static boolean checkPermission(
            Activity activity) {
    
    
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && activity.checkSelfPermission(
                Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
    
    
            activity.requestPermissions(new String[]{
    
    
                    Manifest.permission.READ_EXTERNAL_STORAGE,
                    Manifest.permission.WRITE_EXTERNAL_STORAGE
            }, 1);
        }
        return false;
    }

    public void registerBroaderCast(View view) {
    
    
        PMSPackageParser pmsPackageParser = new PMSPackageParser();
        try {
    
    
            pmsPackageParser.parserReceivers(this,
                    new File(getFilesDir(), "input.apk"));
        } catch (Exception e) {
    
    
            e.printStackTrace();
        }
    }

    public void sendBroaderCast(View view) {
    
    
        Toast.makeText(this, "1.发送消息给server", Toast.LENGTH_SHORT).show();
        view.postDelayed(() -> {
    
    
            Intent intent = new Intent();
            intent.setAction("com.yvan.server");
            sendBroadcast(intent);
        }, 3000);
    }

    static class FinishBroadcastReceiver extends BroadcastReceiver {
    
    
        @Override
        public void onReceive(Context context, Intent intent) {
    
    
            Toast.makeText(context, "3.收到server回复消息", Toast.LENGTH_SHORT).show();
        }
    }

}

activity_client.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".ClientActivity">

    <Button
        android:layout_width="match_parent"
        android:layout_height="50dp"
        android:gravity="center"
        android:onClick="registerBroaderCast"
        android:text="注册广播" />

    <Button
        android:layout_width="match_parent"
        android:layout_height="50dp"
        android:gravity="center"
        android:onClick="sendBroaderCast"
        android:text="发送广播" />

</LinearLayout>
  1. After the page is opened, create a message BroadcastReceiverto receive the reply from , and the two buttons are "Register Broadcast" and "Send Broadcast".server
  2. Click "Register Broadcast": Parse the delivered apk (here it is packaged with the pmsbr module and placed input.pakin the private directory of data/data/com.yvan.hookpms/files of the device) through PMS, and then deliver the HookPMSapk through implementation broadcast registration in .
  3. Click "Send Broadcast": Send a message to the broadcast registered in 1 above

We mainly look at step 2 to register the broadcast, here is本章的重点HookPMS

2.4 PMSPackageParser

package com.yvan.hookpms;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.IntentFilter;
import android.content.pm.PackageManager;

import java.io.File;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.List;

import dalvik.system.DexClassLoader;

/**
 * @author yvan
 * @date 2023/8/7
 * @description
 */
public class PMSPackageParser {
    
    

    public void parserReceivers(Context context, File apkFile) throws Exception {
    
    
        Class<?> packageParserClass = Class.forName("android.content.pm.PackageParser");
        Method parsePackageMethod = packageParserClass.getDeclaredMethod("parsePackage",
                File.class, int.class);
        parsePackageMethod.setAccessible(true);
        Object packageParser = packageParserClass.newInstance();

        Object packageObj = parsePackageMethod.invoke(packageParser, apkFile,
                PackageManager.GET_RECEIVERS);
        packageObj.hashCode();

        Field receiversField = packageObj.getClass().getDeclaredField("receivers");

        List receivers = (List) receiversField.get(packageObj);

        // AndroidManifest---> Package对象   描述信息
        DexClassLoader dexClassLoader = new DexClassLoader(apkFile.getAbsolutePath(),
                context.getDir("plugin", Context.MODE_PRIVATE).getAbsolutePath(),
                null, context.getClassLoader());
        // 动态注册
        Class<?> componentClass = Class.forName("android.content.pm.PackageParser$Component");
        Field intentsField = componentClass.getDeclaredField("intents");
        for (Object receiverObject : receivers) {
    
    
            String name = (String) receiverObject.getClass().getField("className")
                    .get(receiverObject);
            // class  --->对象
            try {
    
    
                BroadcastReceiver broadcastReceiver = (BroadcastReceiver) dexClassLoader.loadClass(name).newInstance();
                List<? extends IntentFilter> filters = (List<? extends IntentFilter>)
                        intentsField.get(receiverObject);
                for (IntentFilter filter : filters) {
    
    
                    context.registerReceiver(broadcastReceiver, filter);
                }
            } catch (Exception e) {
    
    
                e.printStackTrace();
            }
        }
    }
}

We see HookPMSthe following operations done:

  1. HookWhat is the method of PMSparsing the class to get the objectandroid.content.pm.PackageParserparsePackage()Package
  2. Then get the collection stored Packagein the objectBroadcastReceiverreceivers
  3. Load the dynamically delivered apk through the class loader
  4. Then traverse the collection of PMS receiversto find the broadcast registered in the delivered apk
  5. Finally sign up for this broadcast.

The broadcast registered here is a dynamic delivery component input.apk, PMSBroadcastReceiverlet's continue to look down

2.5 PMSBroadcastReceiver

package com.yvan.pmsbr;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.Handler;
import android.os.Looper;
import android.widget.Toast;

/**
 * @author yvan
 * @date 2023/8/7
 * @description
 */
public class PMSBroadcastReceiver extends BroadcastReceiver {
    
    

    @Override
    public void onReceive(Context context, Intent intent) {
    
    
        // 收到你的信息了
        Toast.makeText(context, "2.接收到client的消息", Toast.LENGTH_SHORT).show();
        new Handler(Looper.getMainLooper()).postDelayed(() -> {
    
    
            Intent intent1 = new Intent();
            intent1.setAction("com.yvan.client");
            context.sendBroadcast(intent1);
        }, 3000);
    }
}

PMSBroadcastReceiverThe main thing is to receive clientthe broadcast from, and then clientreply a broadcast. After we FinishBroadcastReceiverreceived serverthe reply above, a Toast display pops up to indicate completion, sending and receiving input.apkmessages of dynamic delivery components.
insert image description here

3 summary

At this point we have completed the calling and calling of the entire dynamically delivered apk. Here we summarize a little bit: mainly
through HookPMSthe implementation of parsing the dynamically delivered apk apk, storing the information PMSin it , and then fetching the collection PMScontaining BroadcastReceiverthe information receiversTo, the program (Client) sends a broadcast to the broadcast (Server) defined in the dynamically delivered apk, the broadcast (Server) responds to the program (Client), and then the program (Client) receives the response (similar three-way handshake logic TCP) . PMSSo as to achieve the purpose of this chapter Hook.
The article only HookPMSanalyzes the core code ideas. Here is the project address . Friends can download and view it by themselves. Don’t forget to click Star, thank you! !

Guess you like

Origin blog.csdn.net/u010687761/article/details/132148944