[Android combat notes] get the pid, uid, packageName and process name of the application

Posted by Mesden on Fri, 31 Dec 2021 22:12:01 +0100

catalogue

pid

1. Obtain through api call: [need to be called in the application]

uid 

1. Obtain through api call: [need to be called in the application]

2. Call process through reflection getUidForPid(int pid);

Process name (/ package name)

1. Obtain: application. Through api call getProcessName(); [need to be called in the application]

2. Call activitythread through reflection currentProcessName(); [need to be called in the application]

3. Obtained through AMS

4. Call: process. By reflection according to pid readProcLines(String path, String[] reqFields, long[] outSizes)

5. Obtain through the proc node according to the pid [can be used in the native layer]

pid

1. Obtain through api call: [need to be called in the application]

int pid = android.os.Process.myPid();

uid 

1. Obtain through api call: [need to be called in the application]

int pid = android.os.Process.myUid();

2. Call process through reflection getUidForPid(int pid);

/** @hide */

public static final int getUidForPid(int pid);

Process name (/ package name)

*Note: Generally speaking, the unspecified process name and package name are consistent. For some multi process applications, multiple process names under the application are generally: Package Name: specify the process suffix.  

1. Obtain: application. Through api call getProcessName(); [need to be called in the application]

public static String getProcessName();

Disadvantages: SDK28 adds this api, which can only be used on systems above Android 9

public static String getCurrentProcessNameByApplication() {
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
        return Application.getProcessName();
    }
    return null;
}

2. Call activitythread through reflection currentProcessName(); [need to be called in the application]

/** @hide */

public static String currentProcessName();

Disadvantages: the ActivityThread class is @ hide, and app cannot call it directly. But it can be achieved by reflection.

public static String getCurrentProcessNameByActivityThread() {
    String processName = null;
    try {
        final Method declaredMethod = Class.forName("android.app.ActivityThread", false, Application.class.getClassLoader()).getDeclaredMethod("currentProcessName", (Class<?>[]) new Class[0]);
        declaredMethod.setAccessible(true);
        final Object invoke = declaredMethod.invoke(null, new Object[0]);
        if (invoke instanceof String) {
            processName = (String) invoke;
        }
    } catch (Throwable e) {
    }
    return processName;
}

3. Obtained through AMS

public static String getCurrentProcessNameByActivityManager(@NonNull Context context) {
    int pid = Process.myPid();
    ActivityManager am = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
    if (am != null) {
        List<ActivityManager.RunningAppProcessInfo> runningAppList = am.getRunningAppProcesses();
        if (runningAppList != null) {
            for (ActivityManager.RunningAppProcessInfo processInfo : runningAppList) {
                if (processInfo.pid == pid) {
                    return processInfo.processName;
                }
            }
        }
    }
    return null;
}

*There are also pid, uid and other information in RunningAppProcessInfo, which can also be used to compare and obtain pid and uid.

Disadvantages: it is inefficient to call + for traversal through AIDL cross process; AIDL call may fail.

4. Call: process. By reflection according to pid readProcLines(String path, String[] reqFields, long[] outSizes)

/** @hide */

public static final native void readProcLines(String path, String[] reqFields, long[] outSizes);

In linux, there are corresponding proc nodes for all applications to record various information. proc/(pid)/status records all the information of the corresponding pid application, including uid, ppid, group information, etc. A readProcLines method is encapsulated in the Process class to read the information of the proc/(pid)/status file. For specific usage, refer to getUidForPid(pid), getParentPid(pid) and getThreadGroupLeader(tid) in the Process class.  

Disadvantages: IO operation may affect performance

5. Obtain through the proc node according to the pid [can be used in the native layer]

The api is not found in the native layer, but it can be implemented by referring to the previous point. Because everything in linux is a file, it can be solved by reading a file.

status_t getPackageNameFromPid(int pid, String8& packageName)
{
    status_t status = NO_ERROR;
    int ret;
    char cmdline[256] = {0};
    char buf[256] = {0};
    snprintf(cmdline, sizeof(cmdline), "/proc/%d/cmdline", pid);
    int fd = 0;
    fd = open(cmdline, O_RDONLY);
    if (fd < 0)
    {
        status = NAME_NOT_FOUND;
    } else {
        ret = read(fd, buf, sizeof(buf));
        if (ret <= 0)
        {
            status = BAD_VALUE;
        }
    }
    close(fd);
    if (status != NO_ERROR) {
        return status;
    }
    
    // The above is the process name obtained. Further interception is required to obtain the package name
    String8 processName = String8(buf);
    ssize_t index = processName.find(":", 0);
    if (index >= 0) {
        packageName.clear();
        packageName.setTo(processName, index);
    } else {
        packageName = processName;
    }
    return status;
}

*Note: when calling the native layer, it may fail to read the file. The error message is:

errno = ENOENT           /* No such file or directory */

Because the author needs to obtain the package name in the system development, the problem of reading file failure occurs when using the above implementation. After opening kernel print for calling and eliminating the permission problem of selinux, it is found that the process reading proc needs to be granted permission. Therefore, you can grant permissions in the rc file of the corresponding process.

service audioserver /system/bin/audioserver
    class main
    user audioserver
    # media gid needed for /dev/fm (radio) and for /data/misc/media (tee)
    group audio camera drmrpc inet media mediadrm net_bt net_bt_admin net_bw_acct readproc
    ioprio rt 4
    writepid /dev/cpuset/foreground/tasks /dev/stune/foreground/tasks
    onrestart restart audio-hal-2-0

*Note: if you need to judge whether multiple processes belong to the same application, you can confirm it in the following two ways:

1. For non system applications (the application shareUserId is not specified as "android.uid.system"), you only need to compare whether the uid of the process is consistent. For applications with shareUserId "android.uid.system" specified, they will share uid of 1000.

2. Compare package names through PID - > process name - > package name. If the package names are consistent, they belong to the same application.

reference material: https://juejin.cn/post/6877127949452050446