iOS逆向经验-实战事例

实战的对象

我平时没事喜欢看小说,一般都是起点的小说,但基本上都是看免费的盗版小说,但是盗版小说的app很多,起初追书神器是不错的app,更新快而且及时,后来改了模式,只有一个源而且所谓的正版源需要扣除币,这种情况下我选择了另一个app,叫笔趣阁app,但这个名字的app在AppStore有很多版本,我选择的是Deborah Carpenter开发的版本,目标版本4.0

为什么要hook这个app呢?其实原本这个app的广告只是在书的列表页面,也就算了,如果你不小心退出后台,或者切换程序,回来后都要等好几秒的视频广告,实在忍无可忍

以下只用于学习,不可以用于商业

准备

先看看广告是怎样的

还有一个广告是在退出后台,然后进去的时候出现

我们整理下思路

如果需要去掉广告

那么就要把自己想象成开发者,你广告会怎么添加,以对方的思路去想,然后hook代码,达到去掉广告的效果

我手上的手机是为越狱的iPhone7

所以需要一个脱壳完毕的ipa安装包,先在iPad上运行AppStore版本,脱壳拿到ipa安装包

开干!

  • 新建项目,选择iOS下面的MonkeyApp,由于打算运行在未越狱手机,所以Target App可以不管,其他根据自己正常开发填写就好

  • 项目只能运行在真机上,所以模拟器是不能的,会得到错误提示:Do not support the simulator, please use the real iPhone Device.

  • 项目的文件结构可以查看官网wiki,有写清楚,前期准备工作需要先把ipa拖进/项目名/项目名/TargetApp这里面

  • 打开项目点击Build Setting 拉到最后,找到MONKEYDEV_CLASS_DUMP 改为YES,这个操作上为了可以获取ipa的全部h声明文件,方便可以找到方法名称

  • 主要工作在Logos/项目名Dylib.xm里面进行

  • 准备完成后,插入手机,点击run开始运行

  • 用Reveal进行查看

  • 随便点一个view,可以看到它所属的控制器的名字叫ShelfViewController

  • 这样我们就定位了控制器的名字,到项目文件夹里面有一个JWReader_Headers到文件夹,里面放的就是整个项目的h文件,我用文本编辑器拖入打开,定位打开ShelfViewController

  • 可以看到有很多方法,这个这个思考下到底添加广告的方法在哪里,其实做法有很多,我在里面找不到有添加广告的方法,估计可能是直接在viewdidload方法里面直接初始化,或者在数据加载的时候初始化,这种情况下是无法单独分离出来,但好在我找到了一个属性@property(nonatomic) BOOL showAd;

  • 我们可以试试这个属性能否起作用,那么在什么时候调用这个属性比较好呢

  • 在用reveal查看的时候发现这个是一个UICollectionView所以找下代理方法

  • (int)numberOfSectionsInCollectionView:(id)arg1这个方法会重复调用,当view刷新的时候也会调用,比较适合拿来用,所以在项目名Dylib.xm中,我们先清空里面原来的代码,不清空也没关系,写入一下代码:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    // 所有属性都需要声明才可以调用,interface的名字随意写,正常情况下为了看清楚都是写当前类的名字
    @interface ShelfViewController
    @property(nonatomic) BOOL showAd;
    @end

    // hook的控制器,必须指定要hook哪个服务器,这样才能让编译器知道你要修改的控制器
    %hook ShelfViewController

    - (int)numberOfSectionsInCollectionView:(id)arg1
    {
    self.showAd = NO;
    return %orig();// %orig这个是调用原代码的方法,比如源代码返回1,那么%orig也是等于1
    }

    %end
  • 写完,就试试吧,插入手机 -> 运行

  • 你会发现广告不见了,那么就证明你猜对了,我们通过修改属性达到了去掉首页广告,那么接下来我们继续,把每次重新打开app都会跳出全屏广告也去掉

  • 其实按照思路,这个也很简单,我们会发现在广告的出现是在我们回到桌面或者切换app后回到app才会出现,所以调用方法就是在AppDelegate里面,我们把AppDelegate的头文件拿出来

  • 按照app的生命周期,我们知道在AppDelegate中有些方法在退出到后台和进入app前会执行,那么我们完全可以hook那些代码,阻止运行,所以我把退出和进入都hook掉,确保不会遗漏

    1
    2
    3
    4
    5
    6
    7
    8
    9
    %hook AppDelegate

    - (void)applicationWillTerminate:(id)arg1{}
    - (void)applicationDidBecomeActive:(id)arg1{}
    - (void)applicationWillEnterForeground:(id)arg1{}
    - (void)applicationDidEnterBackground:(id)arg1{}
    - (void)applicationWillResignActive:(id)arg1{}

    %end
  • 如果方法有返回值,那么一定要返回,你可以直接返回nil,但不能不返回

  • 如果没有返回值,那么直接什么都不写,这样原先方法就会被hook掉,不会被执行原代码

  • 运行一波试试,退出到桌面再回来,嗯,没问题,那么就确定了,这是可以的,完美避过广告,虽然可能有些当法的多余的,但不影响使用.

  • 这样一个简单的hook app就这样完成了,这是最简单的hook程序,还有一些困难的,比如修改源码,修改判断if,这些就需要更多的软件去辅助,比如之前介绍的ida与hopper就是用于观察app源码与修改源码,这部分需要学习汇编代码才可以,逆向可以说简单,也可以说复杂的.

  • 学逆向不是为了去破解别人的app,对我来说,最重要的是为了防止别人破解自己的app,我们从逆向的过程中学习,想象自己的app如果被别人拿去,如何才能不被反编译,不被hook

  • 正向和逆向不会冲突,只要一起学习,才能更好的加深自己对于开发的理解,做出更好的程序.