Recorder-lite是IOS上一个比较简洁的录音软件,有收费版本,免费的版本和收费版本区别就是广告。下面我们实战Recorder-lite的广告去除。
首先看下广告的位置,我现在安装的版本为2.1.5版,广告如下:

这个图片是在Reveal工具中截图出来的。可以看到,广告是在这个GADBannerView里。
用Clutch解密出程序,class-dump-z dump出头文件。找到GADBannerView.h文件。

1
2
3
4
5
6
7
8
9
10
@interface GADBannerView : XXUnknownSuperclass <GADSlotAdEventDelegate, GADSlotDelegate> {
BOOL _hasLoadedAd;
BOOL _hasInitialized;
BOOL _autoloadEnabled;
UIViewController* _rootViewController;
id<GADBannerViewDelegate> _delegate;
id<GADInAppPurchaseDelegate> _inAppPurchaseDelegate;
UIView* _rootAdView;
GADSlot* _slot;
}

用类名检索引用,检索到以下几个文件,查看引用上下文,我们锁定了AdHelper.h。

AdHelper看名字看不出什么,但是打开一看可以发现他显然是一个广告管理的一个类。
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
@interface AdHelper : XXUnknownSuperclass <GADInterstitialDelegate, ADInterstitialAdDelegate, ADBannerViewDelegate, GADBannerViewDelegate> {
GADInterstitial* mobInterstitialAd_;
ADInterstitialAd* interstitialAd_;
DFPInterstitial* dfpInterstitialAd_;
GADBannerView* boxAd_Amob;
DFPBannerView* boxAd_Dfp;
ADBannerView* boxAd_Apple;
FPPopoverController* _popover;
UIView* _contentView;
UIView* _targetView;
UIView* _boxAd;
CGSize _oContentSize;
}
@property(assign, nonatomic) __weak UIView* boxAd;
@property(readonly, assign, nonatomic) BOOL isBoxAdLoaded;
...
+(id)sharedAdHelper;
-(void).cxx_destruct;
-(void)clearContentSubViews;
-(void)layoutForCurrentOrientation;
-(void)showFullAd;
-(void)createFullAd;
-(void)createAppleFullAd;
-(void)createAdmobFullAd;
-(void)createDFPFullAd;
-(void)createBoxAd;
...
@end

从类的成员函数我们可以顾名思义,showFullAd应该是现实所有的广告,createFullAd创建所有广告。以及一些创建广告的方法。使用Hopper查看:
1
2
3
4
5
6
7
8
9
10
void -[AdHelper createFullAd](void * self, void * _cmd) {
[self createBoxAd];
[self createAdmobFullAd];
[self createAppleFullAd];
Pop();
Pop();
Pop();
r0 = loc_187474(self, @selector(createDFPFullAd));
return;
}

作者挺为我们考虑的,这里应该是初始化广告的函数了。直接建个tweak工程键入代码,为了简单,我hook了他所有创建ad的函数:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
@interface AdHelper {

}
-(void)showFullAd;
-(void)createFullAd;
-(void)createAppleFullAd;
-(void)createAdmobFullAd;
-(void)createDFPFullAd;
-(void)createBoxAd;
@end

%hook AdHelper
-(void)showFullAd{return;}
-(void)createFullAd{return;}
-(void)createAppleFullAd{return;}
-(void)createAdmobFullAd{return;}
-(void)createDFPFullAd{return;}
-(void)createBoxAd{return;}
%end

编译发送到手机测试,发现广告已经不加载了:

不过我们看到,录音机上边有几个按钮,两个购物车按钮,一个下载的按钮。一个是wifi web连接。还有一个是mp3格式切换的按钮。虽然广告不加载了,但是如果点击这些按钮下载购物车按钮,会跳转到appstore里去下载软件。这样作为强迫症的我们是不能接受的。下面我们来分析隐藏一下这些按钮。
我们在hopper里搜索itunes,找到练到itunes的连接,根据引用查找到想过的代码,
1
2
3
XREF=-[RootViewController reviewAction]+88
XREF=-[RootViewController moreApp]+326
XREF=-[RecordingViewController buyAction]+72, -[RootViewController cloud:]+72

总共找到4处引用,涉及RootViewController和RecordingViewController两个类。
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
 @interface RecordingViewController : XXUnknownSuperclass <RecorderDelegate> {
double lowPassResults_;
UIButton* recordOrPauseButton;
UIButton* listOrStopButton;
UIImageView* timeBackground;
UILabel* timeLable;
UIButton* formatButton;
Recorder* recorder;
NSTimer* levelTimer_;
int count;
UIButton* buyButton;
id<RecordingViewControllerDelegate> _delegate;
UIView* _firstResponderView;
}
@interface RootViewController : XXUnknownSuperclass <FPPopoverControllerDelegate, FilesViewControllerDelegate, RecordingViewControllerDelegate, PlayingViewControllerDelegate> {
FilesViewController* filesViewController;
UIView* lineView;
UIButton* cloudButton;
UIButton* recordingButton;
UIButton* wifiButton;
UIView* emptyView;
UIImageView* emptyImageView;
UILabel* emptyLabel;
FPPopoverController* popover;
RecordingViewController* recordingViewController;
PlayingViewController* playingViewController;
WiFiViewController* wiFiViewController;
UIView* handView;
UIButton* downloadButton;
UIImageView* imageN;
}

对比程序界面,我们发现了几个可疑的UIButton:buyButton、cloudButton、downloadButton,我们试试在界面加载完成的时候隐藏掉。修改tweak代码:
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
#import <UIkit/UIkit.h>
#import <RootViewController.h>
#import <AdHelper.h>
#import <RecordingViewController.h>

%hook AdHelper
-(void)showFullAd{return;}
-(void)createFullAd{return;}
-(void)createAppleFullAd{return;}
-(void)createAdmobFullAd{return;}
-(void)createDFPFullAd{return;}
-(void)createBoxAd{return;}
%end

%hook RootViewController
-(void)viewDidLoad
{
%orig;
UIButton* downloadButton = MSHookIvar<UIButton* >(self,"downloadButton");
downloadButton.hidden = YES;
UIButton* cloudButton = MSHookIvar<UIButton* >(self,"cloudButton");
cloudButton.hidden = YES;
}
%end

%hook RecordingViewController
-(void)viewDidLoad
{
%orig;
UIButton* buyButton = MSHookIvar<UIButton* >(self,"buyButton");
buyButton.hidden = YES;
}
%end

我们惊喜的发现RootViewController上边的按钮被顺利隐藏了,但是RecordingViewController上的按钮却没被隐藏。

经过测试发现,隐藏buyButton的时候buyButton还没被创建。在录音按钮响应函数里加入隐藏代码,发现可以生效,而每次加载这个录音页面的时候,这个按钮会重新加载进来,所以这个按钮应该是动态创建的。我们在hopper里搜索buyButton。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
001fdb9b         db  0x00 ; '.'
objc_ivar_offset_RecordingViewController_buyButton:
001fdb9c db 0xcc ; '.' ; XREF=-[RecordingViewController dealloc]+50, -[RecordingViewController dealloc]+52, -[RecordingViewController viewDidAppear:]+58, -[RecordingViewController viewDidAppear:]+60, -[RecordingViewController .cxx_destruct]+16, -[RecordingViewController .cxx_destruct]+18

void -[RecordingViewController viewDidAppear:](void * self, void * _cmd, char arg2) {
......
r8 = *objc_ivar_offset_RecordingViewController_buyButton;
r0 = [UIButton buttonWithType:0x0];
r0 = [r0 retain];
r1 = *(r4 + r8);
*(r4 + r8) = r0;
[r1 release];
r5 = *(r4 + r8);
r6 = [[UIImage imageNamed:@"buy.png"] retain];
[r5 setBackgroundImage:r6 forState:0x0];
[r6 release];
......
}

动态加载buyButton的代码在RecordingViewController viewDidAppear函数里,我们hook掉他试试。
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
#import <UIkit/UIkit.h>
#import <RootViewController.h>
#import <AdHelper.h>
#import <RecordingViewController.h>

%hook AdHelper
-(void)showFullAd{return;}
-(void)createFullAd{return;}
-(void)createAppleFullAd{return;}
-(void)createAdmobFullAd{return;}
-(void)createDFPFullAd{return;}
-(void)createBoxAd{return;}
%end

%hook RootViewController
-(void)viewDidLoad
{
%orig;
UIButton* downloadButton = MSHookIvar<UIButton* >(self,"downloadButton");
downloadButton.hidden = YES;
UIButton* cloudButton = MSHookIvar<UIButton* >(self,"cloudButton");
cloudButton.hidden = YES;
}
%end

%hook RecordingViewController
-(void)viewDidAppear:(BOOL)view
{
%orig;
UIButton* buyButton = MSHookIvar<UIButton* >(self,"buyButton");
buyButton.hidden = YES;
}
%end


我们的app界面已经相当的简洁了。