最近在学习逆向相关的实践+踩坑, 庆哥的视频中一个课程是对于OPlayerLite进行进行广告处理了, 因为是去年的课程App也更新了逻辑, 我沿着先辈的道路把坑撸了一把, mark这场一天一夜的战斗.

分析层级结构

定位目标对象

连接到越狱机(切换到无网络模式, 因为Oplayer lite有网络的时候加载的广告是不同的,不利于分析), 同时点击任意视频,进入到视频播放页面, 我们会看到广告的view,上面有一行文本”Buy the full version to remove ads?”
这时候我们连接到cycript打印下层级:

1
2
3
4
5


1


1
2
3
4
5


UIApp.keyWindow.recursiveDescription().toString()



由于我已去除了过了,又从App Store重新下载, 发现还是没有广告,图片暂时就没哈
其中有引起我们注意的层级是:

1
2
3
4
5
6
7
8
9
10
11


1

2

3

4


1
2
3
4
5
6
7
8
9
10
11


| | | \>

| | | | \>

| | | | | \>

| | | | \>


其中UILabel: 0x176b1380中的text属性跟我们看到的ads上是一样的,它的同级view是UIButton, 父view是UIView .
因为咱们要解决的目标是view, 尤为关注是这里的frame.size, 它们都是320 50, label也是height=50. 把这部分截图保存下来,待会查找的时候需要用到

正向分析设计

划重点: 从正向的开发的角度, 分析它是如何设计的

如果是我开发君, 我的伪代码大概如下

1
2
3
4
5
6
7
8
9
10
11


1

2

3

4


1
2
3
4
5
6
7
8
9
10
11


if (!payBuyFullViersion) {

AdsView \*adsview = \[\[AdsView alloc\] init\];

\[self.palyerView addSubview:adsview\]

}


可能其他的逻辑未必跟我符合. 但是一定必然的是, 这个adsView 必须是addSubview上去的,addSubview是UIKit中view的方法, 咱们需要静态分析这个地址, 通过断点来查看它对应的调用者/参数, 从而拿到地址,来定位到OplayerLite

静态分析

从UIKit入手

我们需要用到lldb, 连接到设备, 查看UIKit的存储地址, 然后通过IDA查看addSubview:的静态代码地址.
本地先映射一下 iproxy 1234 1234 , 然后越狱启动debugserver *:1234 -a

本地连接:

1
2
3
4
5


1


1
2
3
4
5


im list -o -f



得到了Oplayer lite的偏移地址和UIKit偏移地址
同时我们看到了UIKit的文件地址(可能有的地址是在设备上, 那么你需要拷贝到本地,不想这样子就连一下Xcode,你就会在本地看到它了)

IDA分析UIKit, 并获取addSubview:的地址:

在lldb下断点,记得加上上面看到的偏移,如:

然后进入到播放界面触发断点

体力活查询

因为上面我们讲到
[self.palyerView addSubview:adsview]
这里的adsView是作为参数的,所以我们需要Print object r2
漫长的开始 c和粘贴 po $r2,一遍持续一遍注意看打印出来的frame,是不是有我们符合的frame=(n,n,320,50)
这可能会很漫长,取决于当前页面子元素数量和人品~

…….
当你发现frame跟我们所看到符合的时候,那么基本就可以确认是它了.同时有个地方要注意:
你需要看到这个地址来自于Oplayer lite才可以, 否则执行以下ni,执行下一条汇编直到看见它

而第一条指令的地址就是我们要的地址, 减去我们上面的偏移地址,拿到静态代码的地址.

分析目标静态代码

对逻辑静态分析

通过上面拿到的地址, 我们可以看到这里是一个实例方法
-[PlayViewController addAds_OnLocalAds]

不是很仔细的看了一遍伪代码,这个方法是被调用来展示view,但是否展示的逻辑并不在这里, 我们需要看谁是它的调用方, 因为删掉之前的断点,重新在-[PlayViewController addAds_OnLocalAds]这个方法上下断点, 依然加上偏移地址(这里的偏移地址已经是OPlayerlite了).

1
2
3
4
5
6
7
8
9


1

2

3


1
2
3
4
5
6
7
8
9


br s -a '0x00052000+0x002A49F8'

#断点触发后, 打印lr寄存器的值

p/x $lr


LR寄存器(R14)可以理解当代码段执行完毕后要回到调用者的地址.
通过LR寄存器得到的值, 我们减去偏移地址,可以得到调用者在静态代码的位置.

依然借助IDA分析, 可以看到msg_send的一些部分是相关的设置方向, frame, getWidth等方法, 而调用的位置就在viewWillAppear:这里.

寻找绕弯的方法

现在, 我们定位到了调用添加广告View的代码块, 继续往上翻,能不能找到帮助我们跳过这里的逻辑呢?
果然, 神器就是神器, 留意左边这根线:

辅助IDA的伪代码,我们还能发现些神马:

这里的两个跳转对应了两个逻辑判断分支, 我在图片中表明了, 逻辑2的情况其实稍加复杂, 但我在逻辑1发现了关键点:

1
2
3
4
5


1


1
2
3
4
5


if ( !((unsigned int)+\[OlimSoftUtility isUpgraded\](&OBJC\_CLASS\_\_\_OlimSoftUtility, "isUpgraded", a3) & 0xFF) )


伪代码的意思是+[OlimSoftUtility isUpgraded]的返回值和 #0xFF 进行了逻辑与的运算, 理解到 #0xFF 是非0类型必为真, 而现在只需要+[OlimSoftUtility isUpgraded]能返回真即可跳过这段代码. 这个猜想是否正确,毕竟是伪代码,所以需要对汇编部分进行确认:

1
2
3
4
5
6
7


1

2


1
2
3
4
5
6
7


\_\_text:0029D2F8 BLX.W \_objc\_msgSend ; +\[OlimSoftUtility isUpgraded\]

\_\_text:0029D2FC TST.W R0, #0xFF


第一行很容易看出是发送了消息,也就是刚才说的调用了+[OlimSoftUtility isUpgraded]这个方法, 而第二行, 将第一行+[OlimSoftUtility isUpgraded] 返回值 与 0xFF进行了 TST指令, 对于目前汇编的底子不硬,通过查询资料得知:

TST 指令对 Rn 中的值和 Operand2 的值按位进行“与”运算。 除了结果会被丢弃以外,这与 ANDS 指令功能相同。

那么就基本能确定结论了:

1
2
3
4
5
6
7
8
9
10
11


1

2

3

4


1
2
3
4
5
6
7
8
9
10
11


if ( (\[OlimSoftUtility isUpgraded\] && 0xFF) == NO ) {

// 添加广告

}

// 0xFF 固定为YES


头文件最终确认

找到class-dump 出的头文件目录:

1
2
3
4
5


1


1
2
3
4
5


grep -rn "isUpgraded" ./headers




发现它就是一个类方法,很纯粹.那么也不用太多想法, 试试就试试了.

编写代码

code

让个惊讶的tweak.xm代码:
“当然我这样子处理应该是会引起某些问题了, 但这是目前我分析到的能力”

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21


1

2

3

4

5

6

7

8

9


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17


%hook OlimSoftUtility

\+ (BOOL)isUpgraded {

%log;

// NSLog(@"replace this method!!!!!!!!!!!!!!!!!!!");

return YES;

}

%end


Makefile代码:
我指定了IP 和 Port, 待会可以在直接调用 make install 进行安装

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27


export THEOS\_DEVICE\_IP=localhost

export THEOS\_DEVICE\_PORT=2222

export ARCHS=armv7

export TARGET=iphone:clang:latest:8.0

export THEOS\_MAKE\_PATH=/opt/theos/makefiles

export THEOS=/opt/theos

include $(THEOS)/makefiles/common.mk

TWEAK\_NAME = removeOplayerAds

removeOplayerAds\_FILES = Tweak.xm

include $(THEOS\_MAKE\_PATH)/tweak.mk

after-install::

install.exec "killall -9 SpringBoard"


一些小坑点

没找到dpkg-deb:

dpkg-deb的原名是/opt/theos/bin/dm.pl, 你需要把它的名字改为dpkg-deb,然后执行下面的语句

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15


1

2

3

4

5

6


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15


➜ removeoplayerads make package

\==> Error: /Applications/Xcode.app/Contents/Developer/usr/bin/make package requires dpkg-deb.

make: \*\*\* \[internal-package-check\] Error 1

#\## 决绝方法

➜ removeoplayerads sudo perl -i -pe 'y|\\r||d' /opt/theos/bin/dpkg-deb

Password:


BundleID最准确的获取方法

cycript 进入到目标APP进程后:

1
2
3
4
5


1


1
2
3
4
5


\[\[NSBundle mainBundle\] bundleIdentifier\]


汇编查询

干货, 大全!!!
http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0204ic/Cihbjcag.html

效果图

[没什么比实践到的收获有成就感了,它是继续前行的动力之一]