Run a daemon (as root) on iOS11 and iOS12

daemon包括三个部分:一个可执行的二进制文件、一个plist配置文件、一个二进制文件授权文件

注意事项

  • 测试环境
    • macOS: 10.14.6
    • iPhoneOS: iOS11.0和iOS12.0
    • iPhone机型:两个iPhone6
    • 越狱工具:unc0ver3.6.2

可执行二进制文件配置

  • 下载最新版theos,利用theos来创建一个可执行二进制文件
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    $ nic.pl
    NIC 2.0 - New Instance Creator
    ------------------------------
    [1.] iphone/activator_event
    [2.] iphone/application_modern
    [3.] iphone/application_swift
    [4.] iphone/cydget
    [5.] iphone/flipswitch_switch
    [6.] iphone/framework
    [7.] iphone/ios7_notification_center_widget
    [8.] iphone/library
    [9.] iphone/notification_center_widget
    [10.] iphone/preference_bundle_modern
    [11.] iphone/tool
    [12.] iphone/tool_swift
    [13.] iphone/tweak
    [14.] iphone/xpc_service
    Choose a Template (required): 11
    Project Name (required): k9sd
    Package Name [com.yourcompany.k9sd]: com.slfh.k9sd
    Author/Maintainer Name [XX]: slfh
    Instantiating iphone/tool in k9sd/...
    Done
  • sublime打开main.mm填入以下内容
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    #include <spawn.h>

    int spawn(const char* executable, ...) {
    int ret;
    pid_t pid;
    va_list args;
    va_start(args, executable);
    setuid(0);
    ret = posix_spawn(&pid, executable, NULL, NULL, (char* const *)args, NULL);
    if (ret == 0) waitpid(pid, NULL, 0);
    return ret;
    }

    static void logout(CFNotificationCenterRef center, void *observer, CFStringRef name, const void *object, CFDictionaryRef userInfo) {
    spawn("/usr/bin/killall", "/usr/bin/killall", "-9", "SpringBoard", NULL);
    }

    int main(int argc, char **argv, char **envp) {
    NSLog(@"k9sd: k9sd is launched!");
    CFNotificationCenterAddObserver( CFNotificationCenterGetDarwinNotifyCenter(), NULL, logout, CFSTR("com.slfh.k9sd.logout"), NULL, CFNotificationSuspensionBehaviorCoalesce);
    CFRunLoopRun(); // keep it running in background
    return 0;
    }

plist文件配置

  • 创建plist文件并配置权限

    1
    2
    3
    $ cd k9sd/
    $ touch com.slfh.k9sd.plist
    $ chmod 644 com.slfh.k9sd.plist
  • 安装后把com.slfh.k9sd.plist放到iPhone上的/Library/LaunchDaemons/目录

    1
    2
    $ mkdir -p ./Layout/Library/LaunchDaemons/
    $ mv com.slfh.k9sd.plist ./Layout/Library/LaunchDaemons/
  • sublime打开com.slfh.k9sd.plist,并填入内容

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs /PropertyList-1.0.dtd">
    <plist version="1.0">
    <dict>
    <key>KeepAlive</key>
    <true/>
    <key>Label</key>
    <string>com.slfh.k9sd</string>
    <key>Program</key>
    <string>/usr/bin/k9sd</string>
    <key>RunAtLoad</key>
    <true/>
    </dict>
    </plist>

测试

  • 利用make install进行安装
  • 安装后ssh进入iPhone执行ps -e | grep k9sd,发现并没有启动
  • 使用控制台可以查看如下错误,错误是由于没有给二进制文件授权
    1
    Sandbox: hook..execve() killing k9sd[pid=14153, uid=0]: outside of container && !i_can_has_debugger

二进制文件授权

  • 新建授权文件

    1
    touch ./Layout/Library/LaunchDaemons/com.slfh.k9sd.entitlements
  • 打开com.slfh.k9sd.entitlements,填入以下内容

    1
    2
    3
    4
    5
    6
    7
    8
    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs /PropertyList-1.0.dtd">
    <plist version="1.0">
    <dict>
    <key>platform-application</key>
    <true/>
    </dict>
    </plist>
  • 新建postinst文件,作用是deb安装完成后执行相应的命令

    1
    2
    3
    $ mkdir ./bin
    $ touch ./bin/postinst
    $ chmod 755 ./bin/postinst
  • 打开postinst文件,填入以下内容

    1
    2
    3
    4
    #!/bin/sh
    /usr/bin/ldid -S/Library/LaunchDaemons/com.slfh.k9sd.entitlements /usr/bin/k9sd;
    /bin/launchctl load /Library/LaunchDaemons/com.slfh.k9sd.plist;
    exit 0;
  • 打开Makefile文件填入以下内容(如果make错误,需要把这些命令缩进对齐然后再次tab)

    1
    2
    3
    4
    5
    6
    before-package::  
    cp ./bin/postinst ./.theos/_/DEBIAN/
    rm -rf ./packages/*.deb

    after-install::
    install.exec "killall -9 SpringBoard"

再次测试

  • 利用make clean && make && make package && make install进行安装(记得要先打包然后安装!!!)

  • 安装后ssh进入iPhone执行ps -e | grep k9sd,发现已经启动了

    1
    2
    3
    4
    5
    slfh:~ root# ps -e | grep k9sd
    13572 ?? 0:00.00 (k9sd)
    14184 ?? 0:00.02 /usr/bin/k9sd
    14318 ttys000 0:00.04 grep k9sd
    slfh:~ root#
  • 使用Cycript发送通知,进行重启SpringBoard操作

    • iOS11如下
      1
      2
      3
      4
      5
      6
      7
      slfh:~ root# cycript -p SpringBoard
      cy# np = @encode(unsigned int(*)(char const*))(dlsym(RTLD_DEFAULT, "notify_post"))
      &(extern "C" unsigned int notify_post(char const*))
      cy# np("com.slfh.k9sd.logout")
      [14621] DarwinInjector.cpp[246]: _krncall(mach_vm_read_overwrite) =10000003
      *** _assert(status == 0):../Inject.cpp(143):InjectLibrary
      slfh:~ root#
    • iOS12如下
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      iPhone:~ root# cyrun -n SpringBoard -e -d -f
      applicationName: SpringBoard is running (9707)
      executableName: SpringBoard
      bundleIdentifier: com.apple.springboard
      Cycript is inactive:
      Device is not passcode locked
      Tweak Mode
      Waiting for Process to close...
      Waiting for SpringBoard to launch...
      Waiting for Cycript to become active...
      Success, you may now run
      cycript -r 127.0.0.1:8556
      cy# np = @encode(unsigned int(*)(char const*))(dlsym(RTLD_DEFAULT, "notify_post"))
      &(extern "C" unsigned int notify_post(char const*))
      cy# &(extern "C" unsigned int notify_post(char const*))
      &(extern "C" unsigned int notify_post(char const*))
      cy# np("com.slfh.k9sd.logout")
      0
      cy#
  • 成功,到此结束