通过分析Android应用进程的创建启动流程,知道设置应用进程的名称是在(这部分各个版本的系统实现都大同小异,还是看4.4的代码)http://androidxref.com/4.4_r1/xref/frameworks/base/core/java/android/app/ActivityThread.java#handleBindApplication
对比下Android是如果实现的,http://androidxref.com/4.4_r1/xref/frameworks/native/libs/binder/ProcessState.cpp#305
从名字上猜应该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应用进程的创建启动流程,知道设置应用进程的名称是在(这部分各个版本的系统实现都大同小异,还是看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