[越狱开发] 忘带手机?莫怕!未读消息自动邮件提醒

欲练此功,必先...越狱

当有了root权限,手机还是手机吗?-自言自语

自从有一次在用XCode模拟地理位置等待唤醒App的时候,忽然内心某处一个声音想起:Hey!你可是拥有root权限的男人!为什么不看下是哪个方法唤起的App,直接调用这个方法呢?然后折腾了几个小时终于实现了这样一个“模拟地理位置唤醒App到后台”的越狱App,从此便对越狱开发有了更进一步的认识。

直到有一天我把手机落在了家里,当时十分担心会错过什么重要的信息,尽管这只是个略大于0的小概率事件,而且即便是有也不见得会是什么好消息。然而那个声音再次响起。毕竟,错过白条的最后还款日是会影响信用的。于是便有了下文。

最初走的一些弯路就按下不表了,起初我是希望从短信应用入手,看下能不能hook收到短信息时执行的方法,我先后dump了MobileSMS、 commoncenter、 imagent、 MessagesNotificationViewService、 MessagesViewService 的头文件,但是找了个遍也没找到“看起来有用”的方法。也许这里面是有一些神奇的方法的,但是我没有找到。

[越狱开发] 忘带手机?莫怕!未读消息自动邮件提醒

(此处应感谢10086提供的大力支持)

上述方法行不通以后,我把目光放在了SpringBoard的锁屏通知页上。

[越狱开发] 忘带手机?莫怕!未读消息自动邮件提醒

(再次感谢)

是的,我是在iOS8上面实现的功能。对于iOS9以上的系统,由于通知界面的变化,事情也许会更复杂一些。但这不是我使用iOS8的原因,我之所以这么做的主要动因是——这是我唯一的越狱设备。(我发现我从国外的技术书里学到的似乎比我想象的要多)

显然,这是一个tableView,每一条通知对应一个cell。但是只有当我们知道了具体是哪个类,才能施展Hook大法。如何找到这个类呢?

Cycript(http://www.cycript.org/)

此神器可以令你在任何运行中的App里随意进出。如果你不是很了解,不用担心,其基本用法十分简单,一看便知。

首先我们要使用该神器进入SpringBoard,也就是iOS的桌面应用。

[越狱开发] 忘带手机?莫怕!未读消息自动邮件提醒

我们打印出了SpringBoard当前的keyWindow!这简直就是无需源代码、无需打断点的lldb

于是,找到那个tableView便十分简单了。

你可以通过打印recursiveDescription来查找这个类,事实上,Cycript提供了更简单的方法:choose()

[越狱开发] 忘带手机?莫怕!未读消息自动邮件提醒

SBLockScreenNotificationTableView,嗯,我喜欢苹果的命名方式

嗯,我们来暴力证明一下:

cy# choose(UILabel)

搜索下关键字找到“10086”所在的label

#"<UILabel: 0x13eedefb0; frame = (52 12.6667; 42.3333 18); text = '10086'; userInteractionEnabled = NO; layer = <_UILabelLayer: 0x174c8e100>>"

沿nextResponder一路向上直到tableView

cy# [#0x13eedefb0 nextResponder].nextResponder() .nextResponder() .nextResponder() .nextResponder() 
#"<SBLockScreenNotificationTableView: 0x13e5d3200; baseClass = UITableView; frame = (0 0; 414 419.667); clipsToBounds = YES; opaque = NO; gestureRecognizers = <NSArray: 0x175845280>; layer = <CALayer: 0x175432c00>; contentOffset: {0, 0}; contentSize: {414, 168.66666158040366}>"

(如果存在优雅的方法请立即告诉我)

有了目标,就可以下钩了

另一个神器:THEOS(https://github.com/theos/theos)

我们通过Cycript找到了SBLockScreenNotificationTableView,接下来只剩下勾住这个类的某些方法,并执行我们自己的代码。在越狱开发的圈子里,这样一个东西被称作一个tweak。而THEOS便是创建tweak的工具之一(还有一个叫iOSOpenDev,但是已经很久没人维护了)。

我们使用THEOS创建一个tweak,并设置目标APP为SpringBoard

[越狱开发] 忘带手机?莫怕!未读消息自动邮件提醒

THEOS将为我们创建好几乎所有东西。其中的Tweak.xm便是放置钩子代码的地方。

首先我们如上所述钩住SBLockScreenNotificationTableView (Tweak语法也是一目了然的)

static id <UITableViewDataSource> theDataSource;
static id <UITableViewDelegate> theDelegate; %hook SBLockScreenNotificationTableView    // 指定需要hook的类

- (void)setDelegate:(id)orgDlg   // 重写需要hook实例方法{  %orig;    // 执行原方法体  theDelegate = orgDlg; } - (void)setDataSource:(id)orgDS {  %orig;   // 执行原方法体  theDataSource = orgDS; } %end

这里先保存了tableViewdelegatedataSource,这样便能随时获取任意一个cell了。(delegate暂时没用上)

然后经过一番调试,发现每次有新消息都是调用了tableView- (void)insertRowsAtIndexPaths:(NSArray<NSIndexPath *> *)indexPaths withRowAnimation:(UITableViewRowAnimation)animation插入的新cell

接下来的事情就十分简单了,我们勾住这个方法便可以知道新消息到达的时机,然后通过上面保存的dataSource便可以拿到最新的cell。我们需要的一切信息也都包含在这个cell里了。

- (void)insertRowsAtIndexPaths:(NSArray<NSIndexPath *> *)indexPaths withRowAnimation:(UITableViewRowAnimation)animation
{
  %orig; 

  NSIndexPath *lastIndexPath = [indexPaths firstObject];
 id cell = [theDataSource tableView:(UITableView *)self cellForRowAtIndexPath:lastIndexPath];
 if ([cell isKindOfClass:NSClassFromString(@"SBLockScreenBulletinCell")])  {
     // 在cell的子view中找到消息内容,消息发送者等信息      // 把这些信息通过邮件发送出去      // 完整代码请移步我的github(https://github.com/YangXinlei)  } }

是不是很简单?

可是!等一下!

我知道用openURL:就可以打开邮箱,但是谁来帮你点的“发送”按钮呢!!?

显然,这件事情并没有想象中那么简单。经过又一番的dump各种相关系统程序的头文件,我沮丧的发现,iOS并没有提供明显的API来做“静默”发送邮件的事情!不过在神奇的*上有位大神提到 MIME.framework里的 MFMutableMessageHeaders 是可以做这件事的。

有了关键字,接下来就好办了。偷偷发邮件的代码大概是下面这样的 ::

if (! shouldIgnore) //不在过滤列表里,邮件发送
{
   static NSString *xl_subject = @"iPhone未读消息";
   static NSString *xl_mailTo = @"1019158142@qq.com";
   static NSString *xl_mailBy = @"杨 鑫磊 <yangxinlei007@live.com>";
   if ([xl_relativeDate isEqualToString:@"现在"])    {
       NSLog(@"发现未读消息,发送邮件: %@。", xl_mailTo);        MFMessageWriter *messageWriter = [[%c(MFMessageWriter) alloc] init];        MFMutableMessageHeaders *headers = [[%c(MFMutableMessageHeaders) alloc] init];        [headers setHeader:xl_subject forKey:@"subject"];        [headers setAddressListForTo:@[xl_mailTo]];        [headers setAddressListForSender:@[xl_mailBy]];        MFOutgoingMessage *message = [messageWriter createMessageWithString:[NSString stringWithFormat:@"消息源:%@\n内容:%@", xl_sender, xl_message] headers:headers];        MFMailDelivery *messageDelivery = [%c(MFMailDelivery) newWithMessage:message];        [messageDelivery deliverAsynchronously];    } }

(发件箱需要添加到系统邮件账户里)

[越狱开发] 忘带手机?莫怕!未读消息自动邮件提醒

上一篇:如何用python抓取js生成的数据 - SegmentFault


下一篇:【ybt金牌导航6-1-2】向量问题