关闭打开APP蜂窝数据

目标

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

环境:

iOS 9.1 arm64

前言

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

开始
关闭打开APP蜂窝数据_第1张图片
WechatIMG8.jpeg

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

关闭打开APP蜂窝数据_第2张图片
WechatIMG9.jpeg

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

关闭打开APP蜂窝数据_第3张图片
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:@[#">"]]]
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 

@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端口映射一样

下面我们需要借助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

使用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函数


(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
>

(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>

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

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

因为我们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
>

(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,我们找到之前的类的头文件,发现这个类有一个叫做properties的实例方法

(lldb) po [$x0 properties]
{
    appIDForLazyIcon = "com.apple.Maps";
    cellClass = PSSubtitleSwitchTableCell;
    cellObject = ">";
    cellSubtitleText = "5.7 MB";
    control = ">";
    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


(lldb) po $x2
0

(lldb) po $x3
>

(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 
#import 

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

@interface PSUIAppCellularUsageGroupController : NSObject  {

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

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

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

(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
>

(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


(lldb) po $x1
com.apple.Preferences

(lldb) po $x2


(lldb) po $x3

我们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


(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添加相应权限后对其签名。

你可能感兴趣的:(关闭打开APP蜂窝数据)