Quantcast
Channel: Essence Sharing | 干货分享 - iOSRE
Viewing all articles
Browse latest Browse all 301

浅谈ldrestart指令如何在不重启设备电源的情况下刷新用户环境

$
0
0

@Lakr233 wrote:

不知道各位有没有注意到一个很有一的情况,那就是越狱软件在注销桌面的时候多了一个选项,名字叫做“Reload System Daemon”。LaunchDaemon作为系统的守护者,有着神圣不可轻犯的权威。你每次kill一个守护者,作为boss代号为launchd的守护着就会负责重启他。当launchd被kill,你的设备就失去了用户环境,内核会立即panic。那怎样在不丢失用户态环境的情况下“重启设备”,并且不产生崩溃日志呢?答案也很简单,我们要让除了launchd以外的所有进程被爸爸干掉。

首先,我们需要导入头文件。能力有限,不一一叙述头文件。(我太菜了

#include <cstdio>
#include <cstdlib>
#include <errno.h>
#include <signal.h>
#include <sysexits.h>
#include <unistd.h>
#include <launch.h>
#include <sys/stat.h>

继续我们在main里面添加代码。我们要做的事情有三件。

  1. 获取进程列表
  2. 让进程自己死去
  3. 清理环境并且自己结束自己

获取进程列表

我们需要先创建一个请求,然后发送请求给launchd。在获取到数据以后,便可以释放我们创建的请求。这里没有auto_release_pool所以要额外的小心。咱们的守护者会死去,所以可能没有人来搭理善后。内核能做的非常有限。

    launch_data_t req = launch_data_new_string(LAUNCH_KEY_GETJOBS);
    launch_data_t res = launch_msg(req);
    launch_data_free(req);

接下来我们需要验证数据的合法性,检查他是否存在,并确认眼神撒

if (res == NULL || launch_data_get_type(res) != LAUNCH_DATA_DICTIONARY)
    return EPERM; // Error Permit

让我们来看看我们获取到了什么 这里的数据很有意思。

<OS_xpc_dictionary: dictionary[0x103089ca0]: { /* GREAT STUFF*/ }>

我们拿到了一份清单。接下来我们写一个自己的方法,并通过迭代器来让每一个进程都作为参数执行我们需要的代码。

void execEach(launch_data_t v1, const char *name, void *baton) 
launch_data_dict_iterate(res, &execEach, NULL); // 接力开始!

让进程自己死去

首先我们从迭代器传入的launch_data_t中提取进程pid,然后给他发送信号。

if (launch_data_get_type(v1) != LAUNCH_DATA_DICTIONARY) // 再次检查
        return;
launch_data_t _Nullable v2(launch_data_dict_lookup(v1, LAUNCH_JOBKEY_PID)); 
if (v2 == NULL || launch_data_get_type(v2) != LAUNCH_DATA_INTEGER) // 检查pid data
        return; // 并不觉得我们需要这个但是做作更健康
long long qaqPID = launch_data_get_integer(v2); // 从data获取PID
if (kill(qaqPID, 0) == -1)
        return; // 我们没有权限给他发送信号,差不多就是一些boos了。

那么问题来了,为什么我们不kill(qaqPID, 9)呢?因为这样进程就会产生一个没有被handle的sig,进而被其他守护者或kernel捕捉产生crash log。我们发送0的意义在于检查这个进程是不是真的需要被kill我们有没有能力让他kill以避免ldrestart在执行过程中崩溃。

接着我们获取进程在注册字典中的名字。

launch_data_t _Nullable v3 = launch_data_dict_lookup(v1, LAUNCH_JOBKEY_LABEL);
if (v3 == NULL || launch_data_get_type(v3) != LAUNCH_DATA_STRING)
        return; // 通用检查

接下来到了让他自己死去的环节了。我们创建一个请求并发送。

launch_data_t dadHere = launch_data_alloc(LAUNCH_DATA_DICTIONARY); // 分配一个data
// 在爸爸指令里面插入停止代码 lol 注意v3是进程标识符 他是launch_data_t
auto hi(launch_data_dict_insert(dadHere, v3, LAUNCH_KEY_STOPJOB));
auto rettt(launch_msg(dadHere));
// 好了 结束了 他已经躺好了 轮到我们善后自己了 launch_data_t 似乎都需要手动释放
launch_data_free(dadHere); launch_data_free(rettt);

这种方式同样适用于检测到越狱以后无crash无追踪退出,但是具体的实现这里就不详细叙述了。

另外,现在还有更加优秀的sbreload来加速桌面环境的刷新。一般来说越狱开发者注销桌面有四个选择,按照推荐顺序分别是【sbreload】【ldrestart】【killall backboardd】【killall SpringBoard】。sbreload用户体验应该是最好的,ldrestart更加彻底。而干掉backboardd一定程度上解决的SpringBoard死得不够彻底的问题,也能够很神奇的解决一些循环等待SpringBoard加载而锁死的问题。虽然SpringBoard有超时自动kill的机制,但是这个时间经测试大概在5分钟左右。>> iOS 11.3.1

有错误还请各位指出咯。

Posts: 1

Participants: 1

Read full topic


Viewing all articles
Browse latest Browse all 301

Trending Articles