注册

iOS 自定义命令行工具

我们再越狱手机上能用很多工具,尤其是在终端上的一些操作。那么怎么实现一个在iOS终端的命令行工具呢?

比如我们将常用的命令封装成自己的一个命令行工具方便自己调用。在这里我以ps -Adebugserver的开启为例。


一、工程创建

首先用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函数,目前已经被废弃。不过应该可以找到函数地址去尝试直接调用。
    1. NSTask,不过这个只能用在macOS中,如果写macOS终端命令行工具可以用这个。
    1. 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:子进程pidpid 参数指向一个缓冲区,该缓冲区用于返回新的子进程的进程ID
  • const char * :可执行文件的路径path(其实就是可以调用某些系统命令,只不过要指定其完整路径)
  • posix_spawn_file_actions_tfile_actions 参数指向生成文件操作对象,该对象指定要在子对象之间执行的与文件相关的操作
  • posix_spawnattr_tattrp 指向一个属性对象,该对象指定创建的子进程的各种属性。
  • 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.3 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重签自己的命令行工具



作者:HotPotCat
链接:https://www.jianshu.com/p/d7f0eca98198

0 个评论

要回复文章请先登录注册