关闭打开APP蜂窝数据

目标

实现对App蜂窝数据开关控制。

环境:

iOS 9.1 arm64

前言

对于这方面的分析资料可能比较少,我把自己的一些分析过程和踩过的一些坑记录下来,花了几天时间调试和整理,分享在此。

开始
WechatIMG8.jpeg

我们来查找地图开关,先用FLEX查看switch是属于哪个cell

WechatIMG9.jpeg

可以看到他是属于PSSubtitleSwitchTableCell,接下来我们ssh手机使用Cycript挂载。

WX20170930-115301.png

然后查看Preferences界面结构

cy# [[UIApp keyWindow] _autolayoutTrace].toString()
`
UIWindow:0x1366c8060
|   UILayoutContainerView:0x1366ec6c0
|   |   UIView:0x136759130
|   |   UILayoutContainerView:0x1365f0110
|   |   |   UINavigationTransitionView:0x1365f7c30
|   |   |   |   UIViewControllerWrapperView:0x13676bba0
|   |   |   |   |   UILayoutContainerView:0x1367abcf0
|   |   |   |   |   |   UINavigationTransitionView:0x13783e820
|   |   |   |   |   |   |   UIViewControllerWrapperView:0x13799b0a0
|   |   |   |   |   |   |   |   PSListContainerView:0x137987af0
|   |   |   |   |   |   |   |   |   UITableView:0x136892000
|   |   |   |   |   |   |   |   |   |   UITableViewWrapperView:0x136805600
|   |   |   |   |   |   |   |   |   |   |   PSSubtitleSwitchTableCell:0x13700de00'PSSubtitleSwitchTableCell...'
|   |   |   |   |   |   |   |   |   |   |   |   UITableViewCellContentView:0x1379f6480
|   |   |   |   |   |   |   |   |   |   |   |   |   UITableViewLabel:0x137daa030'\u5fae\u4fe1'
|   |   |   |   |   |   |   |   |   |   |   |   |   UITableViewLabel:0x137d5a070'19.8 MB'
|   |   |   |   |   |   |   |   |   |   |   |   |   UIImageView:0x137b66940
|   |   |   |   |   |   |   |   |   |   |   |   _UITableViewCellSeparatorView:0x1378bc320
|   |   |   |   |   |   |   |   |   |   |   |   UISwitch:0x1378b5750
|   |   |   |   |   |   |   |   |   |   |   |   |   _UISwitchInternalViewNeueStyle1:0x13789de80
|   |   |   |   |   |   |   |   |   |   |   |   |   |   UIView:0x137d84960
|   |   |   |   |   |   |   |   |   |   |   |   |   |   |   UIView:0x137d67b10
|   |   |   |   |   |   |   |   |   |   |   |   |   |   UIView:0x137d895c0
|   |   |   |   |   |   |   |   |   |   |   |   |   |   |   UIView:0x137a357a0
|   |   |   |   |   |   |   |   |   |   |   |   |   |   UIView:0x137b22360
|   |   |   |   |   |   |   |   |   |   |   |   |   |   |   UIImageView:0x1379995d0
|   |   |   |   |   |   |   |   |   |   |   |   |   |   |   UIImageView:0x1379ce5d0
|   |   |   |   |   |   |   |   |   |   |   |   |   |   UIImageView:0x1378bafc0
|   |   |   |   |   |   |   |   |   |   |   PSSubtitleSwitchTableCell:0x13698f400'PSSubtitleSwitchTableCell...'
|   |   |   |   |   |   |   |   |   |   |   |   UITableViewCellContentView:0x137d87f00
|   |   |   |   |   |   |   |   |   |   |   |   |   UITableViewLabel:0x137dbd670'\u901a\u8baf\u5f55'
|   |   |   |   |   |   |   |   |   |   |   |   |   UIImageView:0x1379e33a0
|   |   |   |   |   |   |   |   |   |   |   |   _UITableViewCellSeparatorView:0x1378812b0
|   |   |   |   |   |   |   |   |   |   |   |   UISwitch:0x137a07b40
|   |   |   |   |   |   |   |   |   |   |   |   |   _UISwitchInternalViewNeueStyle1:0x137a365b0
|   |   |   |   |   |   |   |   |   |   |   |   |   |   UIView:0x137d888c0
|   |   |   |   |   |   |   |   |   |   |   |   |   |   |   UIView:0x137d84fe0
|   |   |   |   |   |   |   |   |   |   |   |   |   |   UIView:0x137da4280
|   |   |   |   |   |   |   |   |   |   |   |   |   |   |   UIView:0x13665a400
|   |   |   |   |   |   |   |   |   |   |   |   |   |   UIView:0x137b2e140
|   |   |   |   |   |   |   |   |   |   |   |   |   |   |   UIImageView:0x137999230
|   |   |   |   |   |   |   |   |   |   |   |   |   |   |   UIImageView:0x1379854c0
|   |   |   |   |   |   |   |   |   |   |   |   |   |   UIImageView:0x1378f46f0
|   |   |   |   |   |   |   |   |   |   |   PSSubtitleSwitchTableCell:0x1371ac400'PSSubtitleSwitchTableCell...'
|   |   |   |   |   |   |   |   |   |   |   |   UITableViewCellContentView:0x1379bd1a0
|   |   |   |   |   |   |   |   |   |   |   |   |   UITableViewLabel:0x137db1ee0'\u5929\u6c14'
|   |   |   |   |   |   |   |   |   |   |   |   |   UIImageView:0x137b36020
|   |   |   |   |   |   |   |   |   |   |   |   _UITableViewCellSeparatorView:0x1379e1590
|   |   |   |   |   |   |   |   |   |   |   |   UISwitch:0x1378bdef0
|   |   |   |   |   |   |   |   |   |   |   |   |   _UISwitchInternalViewNeueStyle1:0x1378e9570
|   |   |   |   |   |   |   |   |   |   |   |   |   |   UIView:0x137d87d60
|   |   |   |   |   |   |   |   |   |   |   |   |   |   |   UIView:0x137a24e00
|   |   |   |   |   |   |   |   |   |   |   |   |   |   UIView:0x137db1a50
|   |   |   |   |   |   |   |   |   |   |   |   |   |   |   UIView:0x137d678d0
|   |   |   |   |   |   |   |   |   |   |   |   |   |   UIView:0x1365a3740
|   |   |   |   |   |   |   |   |   |   |   |   |   |   |   UIImageView:0x137b22ec0
|   |   |   |   |   |   |   |   |   |   |   |   |   |   |   UIImageView:0x1379cdfe0
|   |   |   |   |   |   |   |   |   |   |   |   |   |   UIImageView:0x1378a64f0

我们随便选取一个UISwitch地址定位其action selector:

cy# [#0x137a07b40 allTargets]
[NSSet setWithArray:@[#"<PSSubtitleSwitchTableCell: 0x13698f400; baseClass = UITableViewCell; frame = (0 1276; 320 45); text = '\xe9\x80\x9a\xe8\xae\xaf\xe5\xbd\x95'; autoresize = W; tag = 6; layer = <CALayer: 0x137d588b0>>"]]]
cy# [#0x137a07b40 actionsForTarget:#0x13698f400 forControlEvent:[#0x137a07b40 allControlEvents]]
@["controlChanged:"]
cy#

1 先用Cycript打印出[button allTargets],是一个数组不过我们这里只有一个对象
2 遍历数组,得到每一个target,然后打印
[button actionsForTarget:target forControlEvent:[button allControlEvents]]
得到selector。

controlChanged:就是Switch点击事件调用的函数
下面我们来寻找它干了什么

首先我们需要查找PSSubtitleSwitchTableCell.h头文件,如果你没有系统头文件点这里

/*
* This header is generated by classdump-dyld 0.7
* on Thursday, January 14, 2016 at 3:32:07 AM Eastern European Standard Time
* Operating System: Version 9.0.2 (Build 13A452)
* Image Source: /System/Library/PrivateFrameworks/Preferences.framework/Preferences
* classdump-dyld is licensed under GPLv3, Copyright © 2013-2014 by Elias Limneos.
*/

#import <Preferences/PSSwitchTableCell.h>

@interface PSSubtitleSwitchTableCell : PSSwitchTableCell
+(long long)cellStyle;
-(void)refreshCellContentsWithSpecifier:(id)arg1 ;
-(BOOL)canReload;
@end

我们可以看到它是属于Preferences.framework
/System/Library/PrivateFrameworks/Preferences.framework/Preferences

继承关系:
PSSubtitleSwitchTableCell
PSSwitchTableCell
PSControlTableCell
PSTableCell
UITableViewCell

开启lldb

一、SSH连接手机(USB模式)

1.映射端口
2.连接手机,并且用grep命令快速筛选当前我们要调试的应用Preferences,附加debugserver开始12345端口等待lldb调试
3.完成以上两步接下来就可以进行lldb调试了,首先要把远端(手机)的12345端口映射到本地,跟前面提到的SSH端口映射一样

WX20170930-135830@2x.png

下面我们需要借助lldb找到/Preferences.framework/Preferences

(lldb) image list -o -f
[  0] 0x0000000000084000 /var/db/stash/_.E79Odv/Applications/Preferences.app/Preferences(0x0000000100084000)
[  1] 0x00000001000bc000 /Library/MobileSubstrate/MobileSubstrate.dylib(0x00000001000bc000)
[  2] 0x0000000003e18000 /Users/qweqwe/Library/Developer/Xcode/iOS DeviceSupport/9.1 (13B143)/Symbols/System/Library/PrivateFrameworks/BulletinBoard.framework/BulletinBoard
`
`
`
[ 44] 0x0000000003e18000 /Users/qweqwe/Library/Developer/Xcode/iOS DeviceSupport/9.1 (13B143)/Symbols/System/Library/PrivateFrameworks/Preferences.framework/Preferences

看到[44]号地址就是我们要找的Preferences.framework二进制文件
拉进IDA进行查找controlChanged

WX20170930-141135@2x.png
使用lldb动态调试

我们对其函数头部下断点

(lldb) br s -a 0x0000000003e18000+0x000000019087F7DC
Breakpoint 3: where = Preferences`-[PSControlTableCell controlChanged:], address = 0x00000001946977dc
(lldb)

然后去设置里点一下Switch,我们看到断点命中。

Process 1576 stopped
* thread #1: tid = 0x166aa, 0x00000001946977dc Preferences`-[PSControlTableCell controlChanged:], queue = 'com.apple.main-thread', stop reason = breakpoint 3.1
    frame #0: 0x00000001946977dc Preferences`-[PSControlTableCell controlChanged:]
Preferences`-[PSControlTableCell controlChanged:]:
->  0x1946977dc <+0>:  stp    x24, x23, [sp, #-64]!
    0x1946977e0 <+4>:  stp    x22, x21, [sp, #16]
    0x1946977e4 <+8>:  stp    x20, x19, [sp, #32]
    0x1946977e8 <+12>: stp    x29, x30, [sp, #48]
(lldb)

使用命令n单步来到objc_msgSend函数


WX20170930-144155@2x.png
(lldb) dis
Preferences`-[PSControlTableCell controlChanged:]:
    0x1946977dc <+0>:   stp    x24, x23, [sp, #-64]!
    0x1946977e0 <+4>:   stp    x22, x21, [sp, #16]
    0x1946977e4 <+8>:   stp    x20, x19, [sp, #32]
    0x1946977e8 <+12>:  stp    x29, x30, [sp, #48]
    0x1946977ec <+16>:  add    x29, sp, #48              ; =48
    0x1946977f0 <+20>:  mov    x19, x0
    0x1946977f4 <+24>:  adrp   x8, 53838
    0x1946977f8 <+28>:  ldr    x21, [x8, #2680]
    0x1946977fc <+32>:  mov    x1, x21
->  0x194697800 <+36>:  bl     0x19aa51bc0               ; objc_msgSend
    0x194697804 <+40>:  mov    x29, x29
    0x194697808 <+44>:  bl     0x19aa59ef0               ; objc_retainAutoreleasedReturnValue
    0x19469780c <+48>:  mov    x22, x0
    0x194697810 <+52>:  cbz    x22, 0x1946978ec          ; <+272>
(lldb) po $x0
<PSSubtitleSwitchTableCell: 0x13691c800; baseClass = UITableViewCell; frame = (0 967; 320 45); text = '地图'; autoresize = W; tag = 6; layer = <CALayer: 0x1378a0980>>

(lldb) po (char*)$x1
"cellTarget"

(lldb)

对应OC代码

[PSSubtitleSwitchTableCell cellTarget]

objc_retainAutoreleasedReturnValue作用是处理返回值是否跳过autorelease机制

0x194697804 <+40>:  mov    x29, x29
0x194697808 <+44>:  bl     0x19aa59ef0  ; objc_retainAutoreleasedReturnValue

单步来到 0x194697810 <+52>: cbz x22, 0x1946978ec ; <+272>

WX20170930-153825@2x.png

x0返回值给了x22,cbz意思是为0则跳,打印x22

0x19469780c <+48>:  mov    x22, x0
0x194697810 <+52>:  cbz    x22, 0x1946978ec          ; <+272>
(lldb) po $x22
<PSUIAppCellularUsageGroupController: 0x1379c32c0>

因为我们x22有值所以没跳,还原OC代码

PSUIAppCellularUsageGroupController *vc = [PSSubtitleSwitchTableCell cellTarget];
if(vc){
‘’‘’‘
}

然后我们单步来到0x194697824

    0x194697810 <+52>:  cbz    x22, 0x1946978ec          ; <+272>
    0x194697814 <+56>:  adrp   x8, 53837
    0x194697818 <+60>:  ldr    x20, [x8, #1168]
    0x19469781c <+64>:  mov    x0, x19
    0x194697820 <+68>:  mov    x1, x20
->  0x194697824 <+72>:  bl     0x19aa51bc0               ; objc_msgSend
(lldb) po $x0
<PSSubtitleSwitchTableCell: 0x13691c800; baseClass = UITableViewCell; frame = (0 967; 320 45); text = '地图'; autoresize = W; tag = 6; layer = <CALayer: 0x1378a0980>>

(lldb) po (char*)$x1
"specifier"

(lldb)

继续单步查看返回值

    0x194697814 <+56>:  adrp   x8, 53837
    0x194697818 <+60>:  ldr    x20, [x8, #1168]
    0x19469781c <+64>:  mov    x0, x19
    0x194697820 <+68>:  mov    x1, x20
    0x194697824 <+72>:  bl     0x19aa51bc0               ; objc_msgSend
    0x194697828 <+76>:  mov    x29, x29
    0x19469782c <+80>:  bl     0x19aa59ef0               ; objc_retainAutoreleasedReturnValue
->  0x194697830 <+84>:  mov    x23, x0
(lldb) po $x0
<PSSpecifier 0x137b79680: ID com.apple.Maps, Name '地图' target <PSUIAppCellularUsageGroupController: 0x1379c32c0>>

发现是PSSpecifier,我们找到之前的类的头文件,发现这个类有一个叫做properties的实例方法

(lldb) po [$x0 properties]
{
    appIDForLazyIcon = "com.apple.Maps";
    cellClass = PSSubtitleSwitchTableCell;
    cellObject = "<PSSubtitleSwitchTableCell: 0x13691c800; baseClass = UITableViewCell; frame = (0 967; 320 45); text = '\U5730\U56fe'; autoresize = W; tag = 6; layer = <CALayer: 0x1378a0980>>";
    cellSubtitleText = "5.7 MB";
    control = "<UISwitch: 0x1378e3680; frame = (254 7; 51 31); layer = <CALayer: 0x137855c00>>";
    enabled = 1;
    id = "com.apple.Maps";
    roamingNetworkUsage = 0;
    totalNetworkUsage = 5981087;
    useLazyIcons = 1;
}

可以看到这个类包含了AppBundID和UISwitch一些信息

继续走
    0x194697834 <+88>:  bl     0x19aa58150               ; objc_release
    0x194697838 <+92>:  mov    x0, x22
    0x19469783c <+96>:  bl     0x19aa58150               ; objc_release
    0x194697840 <+100>: cbz    x23, 0x1946978ec          ; <+272>

来到这0x194697840

还原OC代码

PSSpecifier *specifier = [PSSubtitleSwitchTableCell specifier];
if(specifier){

}

    0x194697844 <+104>: adrp   x8, 53838
    0x194697848 <+108>: ldr    x1, [x8, #2688]
    0x19469784c <+112>: mov    x0, x19
    0x194697850 <+116>: bl     0x19aa51bc0               ; objc_msgSend
    0x194697854 <+120>: mov    x22, x0
    0x194697858 <+124>: mov    x0, x19
    0x19469785c <+128>: mov    x1, x21
    0x194697860 <+132>: bl     0x19aa51bc0               ; objc_msgSend
    0x194697864 <+136>: mov    x29, x29
    0x194697868 <+140>: bl     0x19aa59ef0               ; objc_retainAutoreleasedReturnValue
    0x19469786c <+144>: mov    x21, x0
    0x194697870 <+148>: adrp   x8, 53840
    0x194697874 <+152>: ldr    x1, [x8, #2376]
    0x194697878 <+156>: mov    x0, x19
    0x19469787c <+160>: bl     0x19aa51bc0               ; objc_msgSend
    0x194697880 <+164>: mov    x29, x29
    0x194697884 <+168>: bl     0x19aa59ef0               ; objc_retainAutoreleasedReturnValue
    0x194697888 <+172>: mov    x23, x0
    0x19469788c <+176>: mov    x0, x19
    0x194697890 <+180>: mov    x1, x20
    0x194697894 <+184>: bl     0x19aa51bc0               ; objc_msgSend
    0x194697898 <+188>: mov    x29, x29
    0x19469789c <+192>: bl     0x19aa59ef0               ; objc_retainAutoreleasedReturnValue

这段汇编主要为取值为了节省时间读者可自行分析。
对应OC代码
SEL setAppCellularData = [PSSubtitleSwitchTableCell cellAction];

PSUIAppCellularUsageGroupController *vc = [PSSubtitleSwitchTableCell cellTarget];

NSinteger controlValue = [PSSubtitleSwitchTableCell controlValue];

    0x1946978a0 <+196>: mov    x19, x0
    0x1946978a4 <+200>: mov    x0, x22
    0x1946978a8 <+204>: mov    x1, x21
    0x1946978ac <+208>: mov    x2, x23
    0x1946978b0 <+212>: mov    x3, x19
->  0x1946978b4 <+216>: bl     0x1946bb2b4               ; PSPerformSelector2
(lldb) po (char*)$x0
"setAppCellularDataEnabled:forSpecifier:"

(lldb) po $x1
<PSUIAppCellularUsageGroupController: 0x1379c32c0>

(lldb) po $x2
0

(lldb) po $x3
<PSSpecifier 0x137b79680: ID com.apple.Maps, Name '地图' target <PSUIAppCellularUsageGroupController: 0x1379c32c0>>

(lldb)

PSPerformSelector2(setAppCellularData,vc, controlValue, specifier);
等价于
[PSUIAppCellularUsageGroupController setAppCellularDataEnabled:NO forSpecifier: specifier];

完整OC


PSUIAppCellularUsageGroupController *vc = [PSSubtitleSwitchTableCell cellTarget];
if(vc){
      PSSpecifier *specifier = [PSSubtitleSwitchTableCell specifier];
      if(specifier){
          SEL setAppCellularData = [PSSubtitleSwitchTableCell cellAction];

          PSUIAppCellularUsageGroupController *vc = [PSSubtitleSwitchTableCell cellTarget];

          NSinteger controlValue = [PSSubtitleSwitchTableCell controlValue];

          PSPerformSelector2(setAppCellularData,vc, controlValue, specifier);
      }
}

setAppCellularDataEnabled看这个函数名字已经能确定了,也可以用Cycript试验一下,我这里就不试了。
到这里我们已经找到了设置开关的函数,但是这是UI层面上的,我们还需要继续深入寻找底层函数。

继续上边的套路查找PSUIAppCellularUsageGroupController头文件


/*
* This header is generated by classdump-dyld 0.7
* on Thursday, January 14, 2016 at 3:32:09 AM Eastern European Standard Time
* Operating System: Version 9.0.2 (Build 13A452)
* Image Source: /System/Library/PrivateFrameworks/PreferencesUI.framework/PreferencesUI
* classdump-dyld is licensed under GPLv3, Copyright © 2013-2014 by Elias Limneos.
*/

#import <libobjc.A.dylib/UsageFeedDelegate.h>
#import <libobjc.A.dylib/PSSpecifierGroupController.h>

@class NSArray, NSNumber, PSExpandableAppListGroupController, NSDictionary, NSString;

@interface PSUIAppCellularUsageGroupController : NSObject <UsageFeedDelegate, PSSpecifierGroupController> {

我们看到他是定义在PreferencesUI.framework
/System/Library/PrivateFrameworks/PreferencesUI.framework/PreferencesUI

重复上边lldb寻找过程拖进IDA搜索setAppCellularDataEnabled:forSpecifier:

WX20170930-191849@2x.png

在函数头部下断点,并且命中。

(lldb) br s -a 0x0000000003e18000+0x0000000190936274
Breakpoint 6: where = PreferencesUI`-[PSUIAppCellularUsageGroupController setAppCellularDataEnabled:forSpecifier:], address = 0x000000019474e274
Process 1576 stopped
* thread #1: tid = 0x166aa, 0x000000019474e274 PreferencesUI`-[PSUIAppCellularUsageGroupController setAppCellularDataEnabled:forSpecifier:], queue = 'com.apple.main-thread', stop reason = breakpoint 6.1
    frame #0: 0x000000019474e274 PreferencesUI`-[PSUIAppCellularUsageGroupController setAppCellularDataEnabled:forSpecifier:]
PreferencesUI`-[PSUIAppCellularUsageGroupController setAppCellularDataEnabled:forSpecifier:]:
->  0x19474e274 <+0>:  stp    x26, x25, [sp, #-80]!
    0x19474e278 <+4>:  stp    x24, x23, [sp, #16]
    0x19474e27c <+8>:  stp    x22, x21, [sp, #32]
    0x19474e280 <+12>: stp    x20, x19, [sp, #48]
(lldb)

单步往下走


    0x19474e274 <+0>:   stp    x26, x25, [sp, #-80]!
    0x19474e278 <+4>:   stp    x24, x23, [sp, #16]
    0x19474e27c <+8>:   stp    x22, x21, [sp, #32]
    0x19474e280 <+12>:  stp    x20, x19, [sp, #48]
    0x19474e284 <+16>:  stp    x29, x30, [sp, #64]
    0x19474e288 <+20>:  add    x29, sp, #64              ; =64
    0x19474e28c <+24>:  sub    sp, sp, #48               ; =48
    0x19474e290 <+28>:  mov    x20, x3
    0x19474e294 <+32>:  mov    x22, x0
    0x19474e298 <+36>:  adrp   x25, 46941
    0x19474e29c <+40>:  ldr    x25, [x25, #1672]
    0x19474e2a0 <+44>:  ldr    x25, [x25]
    0x19474e2a4 <+48>:  str    x25, [sp, #40]
    0x19474e2a8 <+52>:  mov    x0, x2
    0x19474e2ac <+56>:  bl     0x19aa580a0               ; objc_retain
    0x19474e2b0 <+60>:  mov    x19, x0
    0x19474e2b4 <+64>:  mov    x0, x20
->  0x19474e2b8 <+68>:  bl     0x19aa580a0               ; objc_retain

对其一些参数做retain暂不关心

    0x19474e2bc <+72>:  mov    x20, x0
    0x19474e2c0 <+76>:  adrp   x8, 53665
    0x19474e2c4 <+80>:  ldr    x1, [x8, #760]
    0x19474e2c8 <+84>:  bl     0x19aa51bc0               ; objc_msgSend
(lldb) po $x0
<PSSpecifier 0x137b79680: ID com.apple.Maps, Name '地图' target <PSUIAppCellularUsageGroupController: 0x1379c32c0>>

(lldb) po (char*)$x1
"identifier"

(lldb)

这里获取PSSpecifier的identifier


    0x19474e2cc <+88>:  mov    x29, x29
    0x19474e2d0 <+92>:  bl     0x19aa59ef0  ;   objc_retainAutoreleasedReturnValue
    0x19474e2d4 <+96>:  mov    x21, x0
(lldb) po $x0
com.apple.Maps
    0x19474e2d8 <+100>: adrp   x8, 46941
    0x19474e2dc <+104>: ldr    x8, [x8, #1736]
    0x19474e2e0 <+108>: ldr    x0, [x8]
    0x19474e2e4 <+112>: movz   x3, #0
    0x19474e2e8 <+116>: adrp   x1, 46948
    0x19474e2ec <+120>: add    x1, x1, #3536             ; =3536
    0x19474e2f0 <+124>: adrp   x2, 46941
    0x19474e2f4 <+128>: ldr    x2, [x2, #1680]
->  0x19474e2f8 <+132>: bl     0x19320cbe4
(lldb) po $x0
<nil>

(lldb) po $x1
com.apple.Preferences

(lldb) po $x2
<OS_dispatch_queue: com.apple.main-thread[0x1a1d07080] = { xrefcnt = 0x80000000, refcnt = 0x80000000, suspend_cnt = 0x0, locked = 1, target = com.apple.root.default-qos.overcommit[0x1a1d07700], width = 0x0, running = 0x0, barrier = 1 , thread = 0xb07 }>

(lldb) po $x3
<nil>

我们s跟进去看看他是什么函数

(lldb) s
Process 1576 stopped
* thread #1: tid = 0x166aa, 0x000000019320cbe4, queue = 'com.apple.main-thread', stop reason = instruction step into
    frame #0: 0x000000019320cbe4
->  0x19320cbe4: b      0x18b4eedb4
    0x19320cbe8: b      0x18b4efbf0
    0x19320cbec: b      0x18b4ee68c
    0x19320cbf0: b      0x18b4ee818
(lldb) s
Process 1576 stopped
* thread #1: tid = 0x166aa, 0x000000018b4eedb4, queue = 'com.apple.main-thread', stop reason = instruction step into
    frame #0: 0x000000018b4eedb4
->  0x18b4eedb4: b      0x186a1953c               ; _CTServerConnectionCreateOnTargetQueue
    0x18b4eedb8: b      0x186a21024               ; _CTServerConnectionDropIPPackets
    0x18b4eedbc: b      0x186a115c4               ; _CTServerConnectionGetRadioAccessTechnology
    0x18b4eedc0: b      0x186a11e54               ; _CTServerConnectionGetSignalStrength
(lldb)

_CTServerConnectionCreateOnTargetQueue私有的C函数
它有4个参数

    0x19474e2fc <+136>: mov    x23, x0
    0x19474e300 <+140>: cbz    x23, 0x19474e3b0          ; <+316>
    0x19474e304 <+144>: adrp   x8, 46941
    0x19474e308 <+148>: ldr    x8, [x8, #1904]
    0x19474e30c <+152>: ldr    x8, [x8]
    0x19474e310 <+156>: stp    x8, x19, [sp, #24]
    0x19474e314 <+160>: adrp   x8, 53668
    0x19474e318 <+164>: ldr    x0, [x8, #2624]
    0x19474e31c <+168>: adrp   x8, 53665
    0x19474e320 <+172>: ldr    x1, [x8, #3168]
    0x19474e324 <+176>: add    x2, sp, #32               ; =32
    0x19474e328 <+180>: add    x3, sp, #24               ; =24
    0x19474e32c <+184>: orr    w4, wzr, #0x1
->  0x19474e330 <+188>: bl     0x19aa51bc0               ; objc_msgSend
    0x19474e334 <+192>: mov    x29, x29
    0x19474e338 <+196>: bl     0x19aa59ef0               ; objc_retainAutoreleasedReturnValue
    0x19474e33c <+200>: mov    x24, x0
(lldb) po $x0
NSDictionary

(lldb) po (char*)$x1
"dictionaryWithObjects:forKeys:count:"

(lldb)

单步看其返回值是kCTCellularUsagePolicyDataAllowed
也就是构造一个字典,值是0和1

(lldb) po $x0
{
    kCTCellularUsagePolicyDataAllowed = 0;
}
    0x19456e340 <+204>: mov    x0, x23
    0x19456e344 <+208>: mov    x1, x21
    0x19456e348 <+212>: mov    x2, x24
->  0x19456e34c <+216>: bl     0x19302d3cc
(lldb) po $x0
<CTServerConnection 0x130934e90 [0x1a1b2db68]>

(lldb) po $x1
com.apple.Maps

(lldb) po $x2
{
    kCTCellularUsagePolicyDataAllowed = 0;
}

(lldb) s
Process 683 stopped
* thread #1: tid = 0x0d99, 0x000000019302d3cc, queue = 'com.apple.main-thread', stop reason = instruction step into
    frame #0: 0x000000019302d3cc
->  0x19302d3cc: b      0x18b30fde0
    0x19302d3d0: b      0x18b30f1ac
    0x19302d3d4: b      0x18b30ef70
    0x19302d3d8: b      0x18b30f1c8
(lldb) s
Process 683 stopped
* thread #1: tid = 0x0d99, 0x000000018b30fde0, queue = 'com.apple.main-thread', stop reason = instruction step into
    frame #0: 0x000000018b30fde0
->  0x18b30fde0: b      0x18685544c               ; _CTServerConnectionSetCellularUsagePolicy
    0x18b30fde4: b      0x185dccb38               ; CFTimeZoneResetSystem
    0x18b30fde8: b      0x1867fe9f4               ; CTCallDial
    0x18b30fdec: b      0x1867ffd34               ; CTCallGetCallSubType
(lldb)'

_CTServerConnectionSetCellularUsagePolicy私有C函数
3个参数
x0是_CTServerConnectionCreateOnTargetQueue它的返回值

调用

用到的是CoreTelephony.framework里的两个私有C函数

CTServerConnection* _CTServerConnectionCreateOnTargetQueue(CFAllocatorRef, NSString *, dispatch_queue_t, void*/*一个block类型的参数*/)

void _CTServerConnectionSetCellularUsagePolicy(CTServerConnection *, NSString *, NSDictionary *)

要调用私有C函数,需要用dlsym,简单示意如下:

void *CoreTelephonyHandle = dlopen("/System/Library/Frameworks/CoreTelephony.framework/CoreTelephony", RTLD_LAZY);

//用函数指针来调用私有C函数,用符号名从库里寻找函数地址
CFTypeRef (*connectionCreateOnTargetQueue)(CFAllocatorRef, NSString *, dispatch_queue_t, void*) = dlsym(CoreTelephonyHandle, "_CTServerConnectionCreateOnTargetQueue");
int (*changeCellularPolicy)(CFTypeRef, NSString *, NSDictionary *) = dlsym(CoreTelephonyHandle, "_CTServerConnectionSetCellularUsagePolicy");

CFTypeRef connection = connectionCreateOnTargetQueue(kCFAllocatorDefault,@"com.apple.Preferences",dispatch_get_main_queue(),NULL);

changeCellularPolicy(connection, @"需要授权的app的bundle id", @{@"kCTCellularUsagePolicyDataAllowed":@YES});

dlclose(CoreTelephonyHandle);
权限

CommCenter就是这几个私有API通信的对应进程,用于管理设备的网络,如果想在其他进程与CommCenter通信改写数据状态需要Entitlements.plist添加相应权限后对其签名。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 225,226评论 6 524
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 96,509评论 3 405
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 172,523评论 0 370
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 61,181评论 1 302
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 70,189评论 6 401
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 53,642评论 1 316
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 41,993评论 3 431
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 40,977评论 0 280
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 47,527评论 1 326
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 39,547评论 3 347
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 41,661评论 1 355
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 37,250评论 5 351
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 42,991评论 3 340
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 33,422评论 0 25
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 34,571评论 1 277
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 50,241评论 3 382
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 46,737评论 2 366

推荐阅读更多精彩内容