我们再越狱手机上能用很多工具,尤其是在终端上的一些操作。那么怎么实现一个在iOS
终端的命令行工具呢?
比如我们将常用的命令封装成自己的一个命令行工具方便自己调用。在这里我以ps -A
和debugserver
的开启为例。
一、工程创建
首先用Xcode
创建一个iOS App
,这么做是因为要生成iOS
终端可执行的命令行,默认main
函数如下:
#import <UIKit/UIKit.h>
#import "AppDelegate.h"
int main(int argc, char * argv[]) {
NSString * appDelegateClassName;
@autoreleasepool {
// Setup code that might create autoreleased objects goes here.
appDelegateClassName = NSStringFromClass([AppDelegate class]);
}
return UIApplicationMain(argc, argv, nil, appDelegateClassName);
}
这样工程就创建好了,接下来就是功能的实现了。当然可以根据自己的需要配置自己支持的架构等相关内容。
二、main函数
2.1 main函数精简
由于是制作命令行工具,所以界面相关的内容都删除,只保留main
函数。精简后如下:
#import <Foundation/Foundation.h>
/**
@param argc 入参个数
@param argv 入参数组 argv[0] 为可执行文件
*/
int main(int argc, char * argv[]) {
@autoreleasepool {
//根据自己的需要做逻辑处理
}
return 0;
}
2.2 main框架
首先实现基本的框架,我们需要的功能一个是列出所有进程,一个是启动手机端debugserver
。后续可能还会扩展更多功能并且为了方便使用需要加入一个help
和容错处理。那么就有了:
-
help
函数提供说明帮助。 -
runPS
实现ps -A
列出所有进程。 -
runDebugServer
实现开启手机端runDebugServer
功能。
实现代码如下:
/**
@param argc 入参个数
@param argv 入参数组 argv[0] 为可执行文件
*/
int main(int argc, char * argv[]) {
@autoreleasepool {
if (argc == 1 || strcmp(argv[1], "-h") == 0 || strcmp(argv[1], "--help") == 0) {
//help();
} else {
if (strcmp(argv[1], "-p") == 0 || strcmp(argv[1], "--process") == 0) {
runPS();
} else if ((strcmp(argv[1], "-d") == 0 || strcmp(argv[1], "--debugserver") == 0) && argc > 2 && argv[2] != NULL) {
runDebugServer(argv[2]);
} else {
printf("illegal option:%s\n",argv[1]);
printf("Try 'HPCMD --help' for more information. \n");
}
}
}
return 0;
}
main
函数有两个参数:
-
argc
:参数个数。 -
argv
:入参数组,这个入参数组第一个参数argv[0]
就是可执行文件本身。
三、如何代码调用shell命令。
查询资料得知有3
种方式:
- 1.
system
函数,目前已经被废弃。不过应该可以找到函数地址去尝试直接调用。 -
NSTask
,不过这个只能用在macOS
中,如果写macOS
终端命令行工具可以用这个。
-
-
posix_spawn
目前也只有这个能用了。在#include <spawn.h>
中。
-
posix_spawn
函数定义如下:
int posix_spawn(pid_t * __restrict, const char * __restrict,
const posix_spawn_file_actions_t *,
const posix_spawnattr_t * __restrict,
char *const __argv[__restrict],
char *const __envp[__restrict]) __API_AVAILABLE(macos(10.5), ios(2.0)) __API_UNAVAILABLE(watchos, tvos);
posix_spawn
函数一共6
个参数
-
pid_t
:子进程pid
(pid
参数指向一个缓冲区,该缓冲区用于返回新的子进程的进程ID
) -
const char *
:可执行文件的路径path
(其实就是可以调用某些系统命令,只不过要指定其完整路径) -
posix_spawn_file_actions_t
:file_actions
参数指向生成文件操作对象,该对象指定要在子对象之间执行的与文件相关的操作 -
posix_spawnattr_t
:attrp
指向一个属性对象,该对象指定创建的子进程的各种属性。 -
argv
:指定在子进程中执行的程序的参数列表 -
envp
:指定在子进程中执行的程序的环境
这里简单封装runCMD
函数如下:
/*
posix_spawn 函数一共6个参数
pid_t:子进程 pid(pid 参数指向一个缓冲区,该缓冲区用于返回新的子进程的进程ID)
const char * :可执行文件的路径 path(其实就是可以调用某些系统命令,只不过要指定其完整路径)
posix_spawn_file_actions_t:file_actions 参数指向生成文件操作对象,该对象指定要在子对象之间执行的与文件相关的操作
posix_spawnattr_t:attrp 指向一个属性对象,该对象指定创建的子进程的各种属性。
argv:指定在子进程中执行的程序的参数列表
envp:指定在子进程中执行的程序的环境
*/
#include <spawn.h>
int runCMD(char *cmd, char *argv[]) {
pid_t pid;
//这里注意 cmd 也要包含在 argv[0]中传入。
posix_spawn(&pid, cmd, NULL, NULL, argv, NULL);
int stat;
waitpid(pid,&stat,0);
printf("run cmd:%s stat:%d\n",cmd,stat);
return stat;
}
四、功能实现
4.1 help实现
//打印help信息
void help() {
printf("-p:--process 显示进程 (等效ps -A) \n");
printf("-d:<--debugserver 应用名称/进程id>开启debugserver (等效 debugserver localhost:12346 -a 进程名/进程id) \n");
printf("-h:--help \n");
}
4.2 runPS实现
void runPS() {
char *CMD_argv[] = {
"/usr/bin/ps",
"-A",
NULL
};
//ps -A
runCMD(CMD_argv[0],CMD_argv);
}
4.2 runDebugServer 实现
//debugserver localhost:12346 -a 进程名
void runDebugServer(char *process) {
printf("process:%s\n",process);
char *CMD_argv[5] = {
"/usr/bin/debugserver",
"localhost:12346",
"-a",
NULL,
NULL
};
CMD_argv[3] = process;
runCMD(CMD_argv[0],CMD_argv);
}
这里需要注意的是最后一个参数要为NULL
。
这样整个功能就全部完成。
五、运行
1.由于创建的是App
工程,编译生成App
后将其中的MachO
文件拷贝出来。
2.将可执行文件拷贝到手机根目录
scp -P 12345 ./HPCMD root@localhost:~/
3.手机端执行HPCMD
-h
:
zaizai:~ root# ./HPCMD -h
-p:--process 显示进程 (等效ps -A)
-d:<--debugserver 应用名称/进程id>开启debugserver (等效 debugserver localhost:12346 -a 进程名/进程id)
-h:--help
-p
:
zaizai:~ root# ./HPCMD -p
PID TTY TIME CMD
1 ?? 17:09.03 /sbin/launchd
295 ?? 5:41.90 /usr/libexec/substituted
296 ?? 0:00.00 (amfid)
1585 ?? 0:00.00 /usr/libexec/amfid
1600 ?? 412:41.57 /usr/sbin/mediaserverd
-d
:
zaizai:~ root# ./HPCMD -d WeChat
process:WeChat
debugserver-@(#)PROGRAM:LLDB PROJECT:lldb-1200.2.12
for arm64.
Attaching to process WeChat...
Listening to port 12346 for a connection from localhost...
-s
:
zaizai:~ root# ./HPCMD -s
illegal option:-s
Try 'HPCMD --help' for more information.
这样就验证完整个cmd
的功能了。
可以根据自己的需求实现自己的自定义命令行工具,当然对于一些其它操作需要更多权限可以直接导出系统的SpringBoard
可执行文件从而导出它的权限文件用ldid
重签自己的命令行工具。相关操作可以参考越狱环境debugserver
参考:
代码调用shell命令