首页
社区
课程
招聘
[原创]Android修改进程名
发表于: 2019-8-8 23:04 9224

[原创]Android修改进程名

2019-8-8 23:04
9224

刚好今天有人问到这个问题,就简述下Android怎么修改进程名,一种简单的隐藏或者混淆自身的方式。

通过分析Android应用进程的创建启动流程,知道设置应用进程的名称是在(这部分各个版本的系统实现都大同小异,还是看4.4的代码)http://androidxref.com/4.4_r1/xref/frameworks/base/core/java/android/app/ActivityThread.java#handleBindApplication

所以反射调用即可修改进程名,ddm应该是ddms调试用的,这个不改应该也可以。


结合之前的linux修改进程名,

或者这样可以改变ps、cmdline的进程名

对比下Android是如果实现的,http://androidxref.com/4.4_r1/xref/frameworks/native/libs/binder/ProcessState.cpp#305

首先把进程名覆盖了mArgV第一个数组,之后也是调用

从名字上猜应该mArgV应该就是main函数接收的argv,我们知道Android应用进程其实都是fork自zygote,而zygote的可执行文件就是app_process

http://androidxref.com/4.4_r1/xref/frameworks/base/cmds/app_process/app_main.cpp#169

所以其实Android修改进程名和Linux其实是一样的。


通过分析Android应用进程的创建启动流程,知道设置应用进程的名称是在(这部分各个版本的系统实现都大同小异,还是看4.4的代码)http://androidxref.com/4.4_r1/xref/frameworks/base/core/java/android/app/ActivityThread.java#handleBindApplication

    private void handleBindApplication(AppBindData data) {
        mBoundApplication = data;
        mConfiguration = new Configuration(data.config);
        mCompatConfiguration = new Configuration(data.config);

        mProfiler = new Profiler();
        mProfiler.profileFile = data.initProfileFile;
        mProfiler.profileFd = data.initProfileFd;
        mProfiler.autoStopProfiler = data.initAutoStopProfiler;

        // send up app name; do this *before* waiting for debugger
        Process.setArgV0(data.processName);
        android.ddm.DdmHandleAppName.setAppName(data.processName,
                                                UserHandle.myUserId());

所以反射调用即可修改进程名,ddm应该是ddms调试用的,这个不改应该也可以。


try {
            Method setArgV0 = Process.class.getDeclaredMethod("setArgV0", String.class);
            setArgV0.setAccessible(true);
            setArgV0.invoke(null,"com.tencent.mm");
        } catch (Throwable e) {
            e.printStackTrace();
        }

结合之前的linux修改进程名,

//字符串包括结尾符号\0不能超过16,而且这个只是改了proc/pid/stat/\status中的字符串
const char* new_name = "mytest";
prctl(PR_SET_NAME, new_name);


或者这样可以改变ps、cmdline的进程名

/*
gcc changetitle.c -o changetitle
*/
#include <unistd.h>
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include <stdlib.h>
#include <sys/prctl.h>

# define MAXLINE 2048

extern char **environ;

static char **g_main_Argv = NULL;    /* pointer to argument vector */
static char *g_main_LastArgv = NULL;    /* end of argv */

void setproctitle_init(int argc, char **argv, char **envp)
{
    int i;

    for (i = 0; envp[i] != NULL; i++) // calc envp num
        continue;
    environ = (char **) malloc(sizeof (char *) * (i + 1)); // malloc envp pointer

    for (i = 0; envp[i] != NULL; i++)
    {
        environ[i] = malloc(sizeof(char) * strlen(envp[i]));
        strcpy(environ[i], envp[i]);
    }
    environ[i] = NULL;

    g_main_Argv = argv;
    if (i > 0)
        g_main_LastArgv = envp[i - 1] + strlen(envp[i - 1]);
    else
        g_main_LastArgv = argv[argc - 1] + strlen(argv[argc - 1]);
}

void setproctitle(const char *fmt, ...)
{
    char *p;
    int i;
    char buf[MAXLINE];

    extern char **g_main_Argv;
    extern char *g_main_LastArgv;
    va_list ap;
    p = buf;

    va_start(ap, fmt);
    vsprintf(p, fmt, ap);
    va_end(ap);

    i = strlen(buf);

    if (i > g_main_LastArgv - g_main_Argv[0] - 2)
    {
        i = g_main_LastArgv - g_main_Argv[0] - 2;
        buf[i] = '\0';
    }
    //修改argv[0]
    (void) strcpy(g_main_Argv[0], buf);

    p = &g_main_Argv[0][i];
    while (p < g_main_LastArgv)
        *p++ = '\0';
    g_main_Argv[1] = NULL;
    
    //调用prctl
    prctl(PR_SET_NAME,buf);
}

int main(int argc, char *argv[])
{
    char argv_buf[MAXLINE] = {0}; // save argv paramters
    int i;

    for( i = 1; i < argc; i++)
    {
        strcat(argv_buf, argv[i]);
        strcat(argv_buf, " ");
    }
    
    //修改argv[0]所指向的内存空间的内容
    setproctitle_init(argc, argv, environ);
    
    //调用prctl修改进程名
    setproctitle("%s@%s %s", "littlehann-prog", "ip", argv_buf);

    for (i = 0; environ[i] != NULL; i++)
        free(environ[i]);
    getchar();

    return 0;
}

对比下Android是如果实现的,http://androidxref.com/4.4_r1/xref/frameworks/native/libs/binder/ProcessState.cpp#305

首先把进程名覆盖了mArgV第一个数组,之后也是调用

prctl(PR_SET_NAME, (unsigned long) new_name, 0, 0, 0);
// Global variables
int                 mArgC;
const char* const*  mArgV;
int                 mArgLen;

void ProcessState::setArgV0(const char* txt)
{
    if (mArgV != NULL) {
        strncpy((char*)mArgV[0], txt, mArgLen);
        set_process_name(txt);
    }
}
//http://androidxref.com/4.4_r1/xref/system/core/libcutils/process_name.c#37
void set_process_name(const char* new_name) {
#ifdef HAVE_ANDROID_OS
    char  propBuf[PROPERTY_VALUE_MAX];
#endif

    if (new_name == NULL) {
        return;
    }

    // We never free the old name. Someone else could be using it.
    int len = strlen(new_name);
    char* copy = (char*) malloc(len + 1);
    strcpy(copy, new_name);
    process_name = (const char*) copy;

#if defined(HAVE_PRCTL)
    if (len < 16) {
        prctl(PR_SET_NAME, (unsigned long) new_name, 0, 0, 0);
    } else {
        prctl(PR_SET_NAME, (unsigned long) new_name + len - 15, 0, 0, 0);
    }
#endif

#ifdef HAVE_ANDROID_OS
    // If we know we are not running in the emulator, then return.
    if (running_in_emulator == 0) {
        return;
    }

    // If the "running_in_emulator" variable has not been initialized,
    // then do it now.
    if (running_in_emulator == -1) {
        property_get("ro.kernel.qemu", propBuf, "");
        if (propBuf[0] == '1') {
            running_in_emulator = 1;
        } else {
            running_in_emulator = 0;
            return;
        }
    }

    // If the emulator was started with the "-trace file" command line option
    // then we want to record the process name in the trace even if we are
    // not currently tracing instructions (so that we will know the process
    // name when we do start tracing instructions).  We do not need to execute
    // this code if we are just running in the emulator without the "-trace"
    // command line option, but we don't know that here and this function
    // isn't called frequently enough to bother optimizing that case.
    int fd = open(PROCESS_NAME_DEVICE, O_RDWR);
    if (fd < 0)
        return;
    write(fd, process_name, strlen(process_name) + 1);
    close(fd);
#endif
}

从名字上猜应该mArgV应该就是main函数接收的argv,我们知道Android应用进程其实都是fork自zygote,而zygote的可执行文件就是app_process

http://androidxref.com/4.4_r1/xref/frameworks/base/cmds/app_process/app_main.cpp#169

int main(int argc, char* const argv[])
{
#ifdef __arm__
    /*
     * b/7188322 - Temporarily revert to the compat memory layout
     * to avoid breaking third party apps.
     *
     * THIS WILL GO AWAY IN A FUTURE ANDROID RELEASE.
     *
     * http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commitdiff;h=7dbaa466
     * changes the kernel mapping from bottom up to top-down.
     * This breaks some programs which improperly embed
     * an out of date copy of Android's linker.
     */
    char value[PROPERTY_VALUE_MAX];
    property_get("ro.kernel.qemu", value, "");
    bool is_qemu = (strcmp(value, "1") == 0);
    if ((getenv("NO_ADDR_COMPAT_LAYOUT_FIXUP") == NULL) && !is_qemu) {
        int current = personality(0xFFFFFFFF);
        if ((current & ADDR_COMPAT_LAYOUT) == 0) {
            personality(current | ADDR_COMPAT_LAYOUT);
            setenv("NO_ADDR_COMPAT_LAYOUT_FIXUP", "1", 1);
            execv("/system/bin/app_process", argv);
            return -1;
        }
    }
    unsetenv("NO_ADDR_COMPAT_LAYOUT_FIXUP");
#endif

    // These are global variables in ProcessState.cpp
    mArgC = argc;
    mArgV = argv;

    mArgLen = 0;
    for (int i=0; i<argc; i++) {
        mArgLen += strlen(argv[i]) + 1;
    }
    mArgLen--;

    AppRuntime runtime;
    const char* argv0 = argv[0];

    // Process command line arguments
    // ignore argv[0]
    argc--;
    argv++;

    // Everything up to '--' or first non '-' arg goes to the vm

    int i = runtime.addVmArguments(argc, argv);

    // Parse runtime arguments.  Stop at first unrecognized option.
    bool zygote = false;
    bool startSystemServer = false;
    bool application = false;
    const char* parentDir = NULL;
    const char* niceName = NULL;
    const char* className = NULL;
    while (i < argc) {
        const char* arg = argv[i++];
        if (!parentDir) {
            parentDir = arg;
        } else if (strcmp(arg, "--zygote") == 0) {
            zygote = true;
            niceName = "zygote";
        } else if (strcmp(arg, "--start-system-server") == 0) {
            startSystemServer = true;
        } else if (strcmp(arg, "--application") == 0) {
            application = true;
        } else if (strncmp(arg, "--nice-name=", 12) == 0) {
            niceName = arg + 12;
        } else {
            className = arg;
            break;
        }
    }

    if (niceName && *niceName) {
        setArgv0(argv0, niceName);
        set_process_name(niceName);
    }

    runtime.mParentDir = parentDir;

    if (zygote) {
        runtime.start("com.android.internal.os.ZygoteInit",
                startSystemServer ? "start-system-server" : "");
    } else if (className) {
        // Remainder of args get passed to startup class main()
        runtime.mClassName = className;
        runtime.mArgC = argc - i;
        runtime.mArgV = argv + i;
        runtime.start("com.android.internal.os.RuntimeInit",
                application ? "application" : "tool");
    } else {
        fprintf(stderr, "Error: no class name or --zygote supplied.\n");
        app_usage();
        LOG_ALWAYS_FATAL("app_process: no class name or --zygote supplied.");
        return 10;
    }
}

所以其实Android修改进程名和Linux其实是一样的。

这里就用最简单的方式反射调用setArgV0后,ps查看进程

 # ps|grep ent.mm                                             
u0_a122   2701  182   1013884 53440 ffffffff 400f773c S com.tencent.mm:push
u0_a91    8812  182   914212 42496 ffffffff 400f773c S com.tencent.mm

2701是mm的推送进程,8812为改名后的进程,可见进程名可以骗过了,uid还是出卖了自己。

argv、cmdline欺骗ps
# cat proc/8812/cmdline                                      
com.tencent.mm

prctl(PR_SET_NAME, new_name);欺骗stat、status等。
# cat /proc/8812/status                                      
Name:	com.tencent.mm
State:	S (sleeping)
Tgid:	8812
Pid:	8812
PPid:	182
TracerPid:	0


 # ps|grep ent.mm                                             
u0_a122   2701  182   1013884 53440 ffffffff 400f773c S com.tencent.mm:push
u0_a91    8812  182   914212 42496 ffffffff 400f773c S com.tencent.mm

2701是mm的推送进程,8812为改名后的进程,可见进程名可以骗过了,uid还是出卖了自己。


[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

收藏
免费 2
支持
分享
最新回复 (4)
雪    币: 574
活跃值: (405)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
学习了
2019-8-9 09:33
0
雪    币: 4633
活跃值: (760)
能力值: ( LV7,RANK:101 )
在线值:
发帖
回帖
粉丝
3

楼主好,

 Method setArgV0 = Process.class.getDeclaredMethod("setArgV0", String.class);
setArgV0.setAccessible(true);
setArgV0.invoke(null,"com.test.iamModified");

我想用这个代码反射修改的时候,总是失败。
说找不到setArgV0这个方法。总是NoSuchMethodException。

2019-8-10 11:25
0
雪    币: 107
活跃值: (1693)
能力值: ( LV6,RANK:80 )
在线值:
发帖
回帖
粉丝
4
不用权限么?app没法办到,改的是线程名吧。
最后于 2019-8-10 12:17 被frozenrain编辑 ,原因:
2019-8-10 12:16
0
雪    币: 35761
活跃值: (7155)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
5
楼主好,请问能不能直接修改包名?
因为用MT管理器修改的去广告版,无法安装到无法root的电视盒子上
2019-8-13 13:18
0
游客
登录 | 注册 方可回帖
返回
//