【译】在iOS上以root身份运行守护进程

原文地址:http://bbs.iosre.com/t/run-a-daemon-as-root-on-ios/212
作者:snakeninny
感谢snakeninny提供的优质文章。
这篇文章在我最近项目的完成过程中给予了很大的帮助,特在此表示感谢,并翻译之。

之前译文发在我自己的博客上(博客地址:http://cubernet.cn),应邀在论坛中也发一份,有错的地方欢迎大家批评指正。:slight_smile:

下面是译文内容:

第一部分 基础理论

  1. 守护进程
    什么是守护进程?根据wikipedia的解释,守护进程是一个运行在计算机后台、不受前台用户交互影响的进程。通常,守护进程以字母d结尾,例如,syslogd是处理系统日志的后台进程,sshd是处理SSH链接请求服务的进程。你可以以backboardd,mediaserverd,apsd等 来命名iOS上的其他后台进程。 后台进程是由iOS上的第一个进程launchd启动的,launchd是开机时启动的第一个进程。那么守护进程能做什么呢?“它可以为网络请求,硬件活动以及一些处理其他任务的程序提供后台服务”。注意:以root身份运行的后台进程功能非常强大,并且非常隐蔽,很多时候也许超级管理员都不知道有一些后台进程在偷偷运行。所以,一些恶意软件就是以后台进程的形式存在的。这篇文章只是用来交流学习,如果你去做非法的事情,后果自负。

  2. 守护进程的所有者
    守护进程是由launchd启动,通过“launchctl”命令加载配置文件。我们要特别注意在这个查询手册](https://developer.apple.com/libr … n1/launchctl.1.html)中提到的,“LaunchAgents启动加载的每个配置文件必须属于启动加载它们的用户。所有的系统后台进程必须属于root用户。”配置文件不可以是属于“group-”或者任何人可写。这些限制是出于安全考虑,因为如果一个启动配置文件是任何人可写的话,那么就有可能出现在程序启动时配置文件被恶意修改的情况。因为后台进程是由launchd启动的,所以它应该属于root:wheel:

FunMaker-5:~ root# ls -l /sbin/launchd
                -r-xr-xr-x 1 root wheel 154736 Nov  8  2013 /sbin/launchd<span style="line-height: 2em; background-color: rgb(255, 255, 255);">        </span>

第二部分 组成
正如在《iOS应用逆向工程》一书中提到的那样,后台进程包括两个部分,一个可执行的二进制文件和一个配置plist配置文件。下面,让我们利用Theos来创建一个可执行二进制文件:

snakeninnys-MacBook:Code snakeninny$ /opt/theos/bin/nic.pl
        NIC 2.0 - New Instance Creator
        ------------------------------
          [1.] iphone/application
          [2.] iphone/cydget
          [3.] iphone/framework
          [4.] iphone/library
          [5.] iphone/notification_center_widget
          [6.] iphone/preference_bundle
          [7.] iphone/sbsettingstoggle
          [8.] iphone/tool
          [9.] iphone/tweak
          [10.] iphone/xpc_service
        Choose a Template (required): 8
        Project Name (required): rootdaemond
        Package Name [com.yourcompany.rootdaemond]: com.iosre.rootdaemond
        Author/Maintainer Name [snakeninny]: snakeninny
        Instantiating iphone/tool in rootdaemond/...
        Done.

然后修改main.mm文件的内容:

static void Reboot(CFNotificationCenterRef center, void *observer, CFStringRef name, const         void *object, CFDictionaryRef userInfo)
        {
                NSLog(@"iOSRE: reboot");
                system("reboot");
        }
        
        int main(int argc, char **argv, char **envp)
        {
                NSLog(@"iOSRE: rootdaemond is launched!");
                CFNotificationCenterAddObserver(CFNotificationCenterGetDarwinNotifyCenter(), NULL, Reboot, CFSTR("com.iosre.rootdaemon.reboot"), NULL,         CFNotificationSuspensionBehaviorCoalesce);
                CFRunLoopRun(); // keep it running in background
                return 0;
        }

现在,让我们处理配置文件。以“com.iosre.rootdaemond.plist”为文件名新建文件,然后将下面的代码写入文件中:

<?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.iosre.rootdaemond</string>
                <key>Program</key>
                <string>/usr/bin/rootdaemond</string>
                <key>RunAtLoad</key>
                <true/>
        </dict>
        </plist>

在这些键值对当中,Label键对应的是一个可以唯一标示你的后台进程的字符串,Program键对应的是可执行文件所在位置的绝对路径,这两个都是必填的。如果你的后台进程还有其他的参数,那么只需要在文件中增加类似下面这样的键值对即可:

<key>ProgramArguments</key>
            <array>
                <string>arg1</string>
                <string>arg2</string>
                <string>more args...</string>
            </array>

在完成了这些之后,我们把这个配置文件保存在项目根目录下的/layout/Library/LaunchDaemons/文件夹中,并在/layout下创建一个空的DEBIAN文件夹。现在,我们的项目树看上去是这个样子的:


执行make package命令,然后检查deb所属的用户:

snakeninnys-MacBook:rootdaemond snakeninny$ dpkg-deb -c /Users/snakeninny/Code/        rootdaemond/com.iosre.rootdaemond_1.0-1_iphoneos-arm.deb 
        drwxr-xr-x snakeninny/staff  0 2014-05-11 15:52 ./
        drwxr-xr-x snakeninny/staff  0 2014-05-11 14:45 ./Library/
        drwxr-xr-x snakeninny/staff  0 2014-05-11 15:48 ./Library/LaunchDaemons/
        -rwxr-xr-x snakeninny/staff 367 2014-05-11 15:37 ./Library/LaunchDaemons/        com.iosre.rootdaemond.plist
        drwxr-xr-x snakeninny/staff   0 2014-05-11 15:52 ./usr/
        drwxr-xr-x snakeninny/staff   0 2014-05-11 15:52 ./usr/bin/
        -rwxr-xr-x snakeninny/staff 197984 2014-05-11 15:52 ./usr/bin/rootdaemond

可以看到,deb中的所有文件都是属于snakeninny:staff的。还记得在第一部分中提到,后台进程必须属于root用户吗?所以,这个后台进程所属的用户不对,当你运行时将会报错。

这是为什么呢?因为这个deb文件是在OSX上打包的,所以它所属的用户就是snakeninny。为了将它的所属用户改为root:wheel,我们需要一个叫做fauxsu的工具。下载这个工具,将解压得到的fauxsu和libfauxsu.dylib复制到$THEOS/bin/ 目录下,然后运行chmod a+x。重新打包检查一次:

snakeninnys-MacBook:rootdaemond snakeninny$ dpkg-deb -c /Users/snakeninny/Code/        rootdaemond/com.iosre.rootdaemond_1.0-2_iphoneos-arm.deb 
        drwxr-xr-x root/wheel        0 2014-05-11 16:05 ./
        drwxr-xr-x root/wheel        0 2014-05-11 14:45 ./Library/
        drwxr-xr-x root/wheel        0 2014-05-11 15:48 ./Library/LaunchDaemons/
        -rwxr-xr-x root/wheel      367 2014-05-11 15:37 ./Library/LaunchDaemons/        com.iosre.rootdaemond.plist
        drwxr-xr-x root/wheel        0 2014-05-11 16:05 ./usr/
        drwxr-xr-x root/wheel        0 2014-05-11 16:05 ./usr/bin/
        -rwxr-xr-x root/wheel   197984 2014-05-11 16:05 ./usr/bin/rootdaemond

现在,文件所属用户是正确的了。执行make install来安装这个后台进程:

snakeninnys-MacBook:rootdaemond snakeninny$ make install
        install.exec "cat > /tmp/_theos_install.deb; dpkg -i /tmp/_theos_install.deb && rm /tmp/        _theos_install.deb" < "./com.iosre.rootdaemond_1.0-2_iphoneos-arm.deb"
        Selecting previously deselected package com.iosre.rootdaemond.
        (Reading database ... 2589 files and directories currently installed.)
        Unpacking com.iosre.rootdaemond (from /tmp/_theos_install.deb) ...
        Setting up com.iosre.rootdaemond (1.0-2) ...

第三部分 测试
重启手机检查后台进程是否启动:

FunMaker-5:~ root# reboot
        FunMaker-5:~ root# Connection to 192.168.1.101 closed by remote host.
        Connection to 192.168.1.101 closed.
        snakeninnys-MacBook:Code snakeninny$ ssh root@192.168.1.101
        FunMaker-5:~ root# grep iOSRE /var/log/syslog
        May 11 16:14:01 FunMaker-5 rootdaemond[20]: iOSRE: rootdaemond is launched!
        FunMaker-5:~ root# ps -e | grep rootdaemond
           20 ??         0:00.13 /usr/bin/rootdaemond
          370 ttys000    0:00.01 grep rootdaemond
        FunMaker-5:~ root#

我们可以看到,rootdaemond开机自动启动,并且保持在后台运行。最后,我们检查一下它是否在像预期的那样运行:

// compile: clang -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS7.0.sdk -o iOSRERootDaemonTester -arch armv7 /Users/snakeninny/main.mm

        #include <notify.h>

        int main(int argc, char **argv)
        {
                notify_post("com.iosre.rootdaemon.reboot");
                return 0;
        }

用scp命令将iOSRERootDaemonTester复制到iOS上,然后运行:

snakeninnys-MacBook:~ snakeninny$ scp iOSRERootDaemonTester root@192.168.1.101:/var/tmp/
        iOSRERootDaemonTester                         100%   48KB  48.3KB/s   00:00    
        FunMaker-5:~ root# /var/tmp/iOSRERootDaemonTester
        FunMaker-5:~ root# Connection to 192.168.1.101 closed by remote host.
        Connection to 192.168.1.101 closed.
        snakeninnys-MacBook:Code snakeninny$ ssh root@192.168.1.101
        FunMaker-5:~ root# grep iOSRE /var/log/syslog
        May 11 16:36:01 FunMaker-5 rootdaemond[20]: iOSRE: reboot
        May 11 16:36:58 FunMaker-5 rootdaemond[20]: iOSRE: rootdaemond is launched!
        FunMaker-5:~ root#

它神奇的运行了。

第四部分 结论
事实上,在iOS或者OSX上,后台进程和代理程序远比这篇文章中描述的要复杂的多。我强烈建议大家看一下下面相关的文章。再次强调,后台进程是一个强大的工具,但它是一把双刃剑,在你决定使用它之前,你最好非常了解自己接下来将要做什么,然后小心的使用它。谢谢阅读。

相关阅读:

  1. http://en.wikipedia.org/wiki/Daemon_(computing)
  2. https://www.chrisalvares.com/blo … hone-daemon-part-1/
  3. https://developer.apple.com/libr … n1/launchctl.1.html
  4. https://developer.apple.com/libr … ingLaunchdJobs.html
  5. https://developer.apple.com/libr … aunchd.plist.5.html

2014.5.22注:
com.iosre.rootdaemond.plist文件必须拥有644权限,否则示例后台进程将不会运行。

3 个赞

错误!/layout/Library/LaunchDaemons/

无法找到 /var/log/syslog文件。

cydia上有一个syslogd to /var/log/syslog
安装后就可以了。

楼主漏掉了原文一句重要的话,帮楼主补上
Download a compiled version from http://nix.howett.net/~dhowett/fauxsu.tar, extract fauxsu and libfauxsu.dylib to $THEOS/bin/ and “chmod a+x” them. Make another package and check again (and also notice the edit at the end of this post):
http://nix.howett.net/~dhowett/fauxsu.tar这个网址下载这个已编译版本,解压后才会有fauxsu和libfauxsu.dylib这两个文件

2 个赞