iOS黑客攻防秘籍(第2版)
上QQ阅读APP看书,第一时间看更新

1.7 后台程序

Android 应用能够在后台创建执行代码的服务,这些服务可能会偷偷下载文件消耗流量,导致扣费。iOS 应用则不能在后台执行代码,只要用户单击 Home 键,前台应用的所有线程就都会被挂起,只有播放音乐、获取实时位置等必须在后台执行的操作才能执行。不过在 iOS 中,也是有后台程序的,这些程序被称为守护程序(daemon)。试想在打开 Safari(浏览器)上网时,突然有电话打进来,这时接听电话的界面就会在前台显示,要是没有后台程序,怎么处理来电呢?只是苹果公司并没有给开发者开放后台程序,只有越狱之后,才能开发后台程序。

iOS 的系统进程 launchd 会在系统启动后检测 /System/Library/LaunchDaemons 和 /Library/LaunchDaemons 这两个目录下的 .plist 文件,.plist 文件描述了守护程序的路径。

下面我们编写一个守护程序进行测试,该程序的名称为 daemonTest,其功能是每隔 5 秒输出一条信息,具体代码如下:

#include <stdio.h>
#include <UIKit/UIKit.h>

int main(){
    int i=0;
    while(1){
        NSLog(@"Daemon test %d", i);
        i++;
        sleep(5);
    }
    return 0;
}

编译:

clang -arch armv7 -isysroot $(xcrun --sdk iphoneos -show-sdk-path) -framework Foundation -o daemonTest main.m

签名:

codesign -s - --entitlements ~/ent.plist -f daemonTest

签名需要用到的 ent.plist 文件的内容请参考 2.5.1 节。然后我们编写用于描述 daemonTest 的 .plist 文件,文件名称为 net.exchen.daemonTest.plist,其具体内容如下:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" >
<plist version="1.0">
<dict>
    <key>KeepAlive</key>
    <true/>
    <key>Label</key>
    <string>net.exchen.daemonTest</string>
    <key>ProgramArguments</key>
    <array>
        <string>/usr/bin/daemonTest</string>
    </array>
    <key>RunAtLoad</key>
    <true/>
        <key>SessionCreate</key>
    <true/>
    <key>StandardErrorPath</key>
    <string>/dev/null</string>
    <key>inetdCompatibility</key>
    <dict>
        <key>Wait</key>
        <false/>
    </dict>
</dict>
</plist>

将 daemonTest 上传到 /usr/bin 目录,再将 net.exchen.daemonTest.plist 文件上传到 /Library/LaunchDaemons/ 目录,接着设置相应的权限,命令如下:

chown root:wheel /usr/bin/daemonTest
chmod 755 /usr/bin/daemonTest
chown root:wheel /Library/LaunchDaemons/net.exchen.daemonTest.plist

使用 launchctl load 命令启动守护程序:

launchctl load /Library/LaunchDaemons/net.exchen.daemonTest.plist

我们打开控制台查看日志,就可以看到每隔 5 秒会输出一条信息,如图 1-4 所示,并且在锁屏状态下代码也能执行,因此刚刚编写的守护程序是真正的后台程序。

图 1-4 每隔 5 秒输出一条信息

使用 launchctl unload 命令可以停止守护程序的执行:

launchctl unload /Library/LaunchDaemons/net.exchen.daemonTest.plist