实战ios破解--通过UI找关键函数

on under 二进制
10 minute read

0x0 About

本文记录破解一个cydia中收费deb软件过程,如下为一个截图,其中权限所在UI显示未授权

权限截图

0x1 通过UI找函数的2种方法

  • ios通过cydia安装flex_injected,并在要破解的软件中使用flex_injected 这种方法很方便,效率很高,可通过点击app中的flex_injected功能区的select,再点击对应UI再点击views按钮,通过views中的不同颜色来直接定位对应UI和UI对应的类

  • 通过cycript注入要破解的软件,然后通过[#0x... setHidden:YES]来找到UI后再找函数 这种方法比上面的方法麻烦,需要通过这里的命令来查找,一般是通过[[UIApp keyWindow] recursiveDescription]得到的结果逐个元素进行排除来得到目标UI对象.有以下2点注意事项

    • cycript设置查看ui对应函数时用到的?expand命令失效时可以这样弥补[[UIApp keyWindow] recursiveDescription].toString()
    • cycript查找ui对应的元素可通过找几个主要的大树枝,如果大树枝[#0x... setHidden:YES]后发现要找的UI不显示了则说明要找的UI在这个大树枝里面,然后再大树枝里通过[#0x... setHidden:YES]逐渐找到最终的小树枝.通过cycript找UI这条路一般不用,除非用flex_injected找不到(有些app无法使用flex_injected)

0x2 破解过程

step1 找到ui对应的元素

本文要破解的app是cydia里安装的,可能有一些反破解机制,导致无法直接使用ida调试,也无法使用flex_injected分析ui,于是使用上面的第2种方法,也即通过cycript注入目标进程来通过排除法查找上图中权限这个ui对应的函数.

1.[[UIApp keyWindow] recursiveDescription]得到结果如下

@[#"<UIWindow: 0x1763dd20; frame = (0 0; 375 667); gestureRecognizers = <NSArray: 0x1763d390>; layer = <UIWindowLayer: 0x175c9d90>>",#"<UITextEffectsWindow: 0x1766ac70; frame = (0 0; 375 667); opaque = NO; autoresize = W+H; layer = <UIWindowLayer: 0x17779950>>"]
cy# [[UIApp keyWindow] recursiveDescription].toString()
`<UIWindow: 0x1763dd20; frame = (0 0; 375 667); gestureRecognizers = <NSArray: 0x1763d390>; layer = <UIWindowLayer: 0x175c9d90>>
   | <UIView: 0x188ca2f0; frame = (0 0; 375 667); autoresize = W+H; gestureRecognizers = <NSArray: 0x188c9dd0>; layer = <CALayer: 0x188ca290>>
      |    | <UIView: 0x188caeb0; frame = (0 0; 375 667); autoresize = W+H; layer = <CALayer: 0x188caf70>>
         |    |    | <UILayoutContainerView: 0x1776c2c0; frame = (0 0; 270 667); hidden = YES; autoresize = RM+H; gestureRecognizers = <NSArray: 0x188c8590>; layer = <CALayer: 0x188a3de0>>
            |    |    |    | <UINavigationTransitionView: 0x17690e60; frame = (0 0; 270 667); clipsToBounds = YES; autoresize = W+H; layer = <CALayer: 0x17690f40>>
               |    |    |    |    | <UIViewControllerWrapperView: 0x17618e30; frame = (0 0; 270 667); autoresize = W+H; layer = <CALayer: 0x177a19d0>>
                  |    |    |    |    |    | <UITableView: 0x18509c00; frame = (0 0; 270 667); clipsToBounds = YES; autoresize = W+H; gestureRecognizers = <NSArray: 0x18854560>; layer = <CALayer: 0x188cca20>; contentOffset: {0, 0}; contentSize: {270, 0}>
                     |    |    |    |    |    |    | <UITableViewWrapperView: 0x18509800; frame = (0 0; 270 667); gestureRecognizers = <NSArray: 0x188ca6b0>; layer = <CALayer: 0x1776f3b0>; contentOffset: {0, 0}; contentSize: {270, 667}>
                        |    |    |    |    |    |    | <UIImageView: 0x17650ce0; frame = (264.5 657; 2.5 7); alpha = 0; opaque = NO; autoresize = LM; userInteractionEnabled = NO; layer = <CALayer: 0x188d37b0>>
                           |    |    |    |    |    |    | <UIImageView: 0x17653de0; frame = (260 661.5; 7 2.5); alpha = 0; opaque = NO; autoresize = TM; userInteractionEnabled = NO; layer = <CALayer: 0x17643050>>
                              |    |    |    | <UINavigationBar: 0x188be470; frame = (0 20; 270 44); opaque = NO; autoresize = W; gestureRecognizers = <NSArray: 0x17607230>; layer = <CALayer: 0x188c8380>>
                                 |    |    |    |    | <_UINavigationBarBackground: 0x17693b10; frame = (0 -20; 270 64); opaque = NO; autoresize = W; userInteractionEnabled = NO; layer = <CALayer: 0x188c36
                                 `

2.[#0x1763dd20 setHidden:YES]之后发现看不到看不到要找的UI(权限对应的ui)了,说明目标ui在0x1763dd20的子视图中

3.查看0x1763dd20的子视图0x188ca2f0设置隐藏后的效果,[#0x188ca2f0 setHidden:YES]后发现看不到目标UI,说明目标UI还在0x188ca2f0的子视图中

4.查看0x188ca2f0的子视图设置隐藏后的效果,[#0x188caeb0 setHidden:YES]后发现看不到目标UI,说明目标UI还在0x188caeb0子视图中

5.[#0x1776c2c0 setHidden:YES]之后发现目标UI没有被隐藏,说明目标UI不在0x1776c2c0这条树枝中,但是上面[[UIApp keyWindow] recursiveDescription]的结果中可以看出0x188caeb0的子树枝中只有0x1776c2c0,而0x1776c2c0的确不是目标UI的父树枝,也许是目标app做了什么隐藏手段导致这样的结果(通过[[UIApp keyWindow] recursiveDescription]中不能直接看到目标UI)

6.于是通过[#0x188caeb0 subviews]查看,看看能不能看到除了0x1776c2c0之外的子树枝,结果如下

@[#"<UILayoutContainerView: 0x1776c2c0; frame = (0 0; 270 667); autoresize = RM+H; gestureRecognizers = <NSArray: 0x188c8590>; layer = <CALayer: 0x188a3de0>>",#"<JhAAAYzaNsFTriWR: 0x188cb0c0; frame = (0 0; 375 667); autoresize = W+H; layer = <CALayer: 0x188cb2e0>>"]

说明0x188caeb0除了0x1776c2c0之外还有0x188cb0c0这个子树枝

7.[#0x188cb0c0 subviews]结果如下

@[#"<UILayoutContainerView: 0x1763c960; frame = (0 0; 375 667); autoresize = W+H; layer = <CALayer: 0x1763c7d0>>"]

8.上面只有一个子视图,肯定不是目标UI(权限对应UI),继续查看它的子视图,[#0x1763c960 subviews],结果如下

@[#"<UITransitionView: 0x1763be80; frame = (0 0; 375 667); clipsToBounds = YES; autoresize = W+H; layer = <CALayer: 0x1763bcf0>>",#"<UITabBar: 0x1763c450; frame = (0 618; 375 49); autoresize = W+TM; tintColor = UIDeviceRGBColorSpace 0 0.733333 0.223529 1; layer = <CALayer: 0x1763c2a0>>"]

9.[#0x1763be80 setHidden:YES]之后看不到目标UI

10.[#0x1763be80 subviews]

@[#"<UIViewControllerWrapperView: 0x18e19dc0; frame = (0 0; 375 667); autoresize = W+H; layer = <CALayer: 0x18e26d30>>"]

11.[#0x18e19dc0 subviews]

@[#"<UILayoutContainerView: 0x188ba100; frame = (0 0; 375 667); autoresize = W+H; gestureRecognizers = <NSArray: 0x188bb900>; layer = <CALayer: 0x188ba1d0>>"]

12.[#0x188ba100 subviews]

@[#"<UINavigationTransitionView: 0x188bac60; frame = (0 0; 375 667); clipsToBounds = YES; autoresize = W+H; layer = <CALayer: 0x188bb2b0>>",#"<UINavigationBar: 0x188ba200; frame = (0 20; 375 44); opaque = NO; autoresize = W; gestureRecognizers = <NSArray: 0x188ba9b0>; layer = <CALayer: 0x188ba320>>"]

13.[#0x188bac60 setHidden:YES]后发现看不到目标UI

14.[#0x188bac60 subviews]

@[#"<UIViewControllerWrapperView: 0x188c2c00; frame = (0 0; 375 667); autoresize = W+H; layer = <CALayer: 0x17604980>>"]

15.[#0x188c2c00 subviews]

@[#"<UITableView: 0x17c0a600; frame = (0 0; 375 667); clipsToBounds = YES; autoresize = W+H; gestureRecognizers = <NSArray: 0x188d56d0>; layer = <CALayer: 0x18980810>; contentOffset: {0, -64}; contentSize: {375, 921}>"]

16.[#0x17c0a600 subviews]

@[#"<UITableViewWrapperView: 0x184f6c00; frame = (0 0; 375 603); gestureRecognizers = <NSArray: 0x177716e0>; layer = <CALayer: 0x177a05b0>; contentOffset: {0, 0}; contentSize: {375, 603}>",#"<UIImageView: 0x18e64bd0; frame = (3 548.5; 369 2.5); alpha = 0; opaque = NO; autoresize = TM; userInteractionEnabled = NO; layer = <CALayer: 0x18e64ba0>>",#"<UILabel: 0x1892a0f0; frame = (0 871; 375 50); text = '\xc2\xa9 361\xe4\xb8\x80\xe9\x94\xae\xe6\x96\xb0\xe6\x9c\xba'; userInteractionEnabled = NO; layer = <_UILabelLayer: 0x1892a200>>",#"<UITableViewHeaderFooterView: 0x1894ea80; frame = (0 639.5; 375 38); text = '\xe5\xb8\xae\xe5\x8a\xa9'; hidden = YES; autoresize = W; layer = <CALayer: 0x18980ab0>>",#"<UITableViewHeaderFooterView: 0x18f05eb0; frame = (0 276; 375 38); text = '\xe8\xae\xbe\xe7\xbd\xae'; autoresize = W; layer = <CALayer: 0x18f060e0>>",#"<UITableViewHeaderFooterView: 0x18f08bb0; frame = (0 96.5; 375 74); text = '\xe6\x9d\x83\xe9\x99\x90(\xe7\xbd\x91\xe7\xbb\x9c\xe4\xb8\x80\xe7\x9b\xb4\xe5\xa4\x84\xe4\xba\x8e[\xe5\x8a\xa0\xe8\xbd\xbd\xe4\xb8\xad]\xe7\x9a\x84\xe8\xa7\xa3\xe5\x86\xb3\xe6\x96\xb9\xe6\xb3\x95\xef\xbc\x9a1. \xe5\x88\x87\xe6\x8d\xa2...'; autoresize = W; layer = <CALayer: 0x18f08b80>>",#"<UIImageView: 0x18e646f0; frame = (369.5 3; 2.5 353.5); alpha = 0; opaque = NO; autoresize = LM; userInteractionEnabled = NO; layer = <CALayer: 0x18e64960>>"]"')'"]

17.[#0x184f6c00 setHidden:YES]发现看不到目标UI

18.[#0x184f6c00 subviews]

@[#"<UITableViewCell: 0x18f37a20; frame = (0 578; 375 44); text = '\xe5\xa4\x87\xe4\xbb\xbd\xe8\xbf\x81\xe7\xa7\xbb'; autoresize = W; layer = <CALayer: 0x18f379f0>>",#"<UITableViewCell: 0x18f3a5a0; frame = (0 534; 375 44); text = 'VPN\xe4\xbb\xa3\xe7\x90\x86'; autoresize = W; layer = <CALayer: 0x18f3a570>>",#"<taNoXRDjKPBbiCJk: 0x18f4d750; baseClass = UITableViewCell; frame = (0 35; 375 44); text = '\xe7\x83\xad\xe9\x97\xa8\xe6\x8e\xa8\xe8\x8d\x90'; autoresize = W; layer = <CALayer: 0x18fbeac0>>",#"<UITableViewCell: 0x18f49aa0; frame = (0 170.5; 375 44); text = '\xe6\x9c\xba\xe5\x99\xa8\xe7\xa0\x81'; autoresize = W; layer = <CALayer: 0x18f49a70>>",#"<UITableViewCell: 0x17531390; frame = (0 214.5; 375 44); text = '\xe6\x9d\x83\xe9\x99\x90'; autoresize = W; layer = <CALayer: 0x17531580>>",#"<UITableViewCell: 0x189d7520; frame = (0 314; 375 44); text = '\xe6\x96\xb0\xe6\x9c\xba\xe6\x97\xb6\xe8\x87\xaa\xe5\x8a\xa8\xe5\xa4\x87\xe4\xbb\xbd'; autoresize = W; layer = <CALayer: 0x189d7710>>",#"<UITableViewCell: 0x189e1250; frame = (0 358; 375 44); text = '\xe6\x96\xb0\xe6\x9c\xba\xe6\x97\xb6\xe6\xb8\x85\xe7\xa9\xba\xe5\x89\xaa\xe8\xb4\xb4\xe6\x9d\xbf'; autoresize = W; layer = <CALayer: 0x189e1440>>",#"<UITableViewCell: 0x189013c0; frame = (0 809.5; 375 44); text = 'Tinyapps.cn'; hidden = YES; autoresize = W; layer = <CALayer: 0x189186f0>>",#"<UITableViewCell: 0x18e18960; frame = (0 765.5; 375 44); text = '\xe6\xa3\x80\xe6\x9f\xa5\xe6\x96\xb0\xe7\x89\x88\xe6\x9c\xac'; hidden = YES; autoresize = W; layer = <CALayer: 0x18eb08d0>>",#"<UITableViewCell: 0x17530760; frame = (0 721.5; 375 44); text = '\xe8\x84\x9a\xe6\x9c\xac\xe8\xb0\x83\xe7\x94\xa8\xe6\x8c\x87\xe5\x8d\x97'; hidden = YES; autoresize = W; layer = <CALayer: 0x1908b2d0>>",#"<UITableViewCell: 0x18f3f990; frame = (0 677.5; 375 44); text = '\xe4\xbd\xbf\xe7\x94\xa8\xe8\xaf\xb4\xe6\x98\x8e'; hidden = YES; autoresize = W; layer = <CALayer: 0x18e2b090>>",#"<UITableViewCell: 0x189e6d40; frame = (0 446; 375 44); text = '\xe8\x87\xaa\xe5\x8a\xa8\xe6\x9b\xb4\xe6\x8d\xa2IP(\)'"]

19.[#0x18f37a20 setHidden:YES],[#0x18f4d750 setHidden:YES]发现目标UI没有被隐藏

20.[#0x18f49aa0 setHidden:YES]发现待破解app截图中的机器码对应UI被隐藏

21.[#0x17531390 setHidden:YES]发现待破解app截图中的权限对应UI被隐藏,说明这就是要找的UI元素

step2 找到ui元素对应的函数

1.尝试通过<<ios应用逆向工程>>这里[button_object allTargets][button_object allControlEvent]的方法没有找到对应的UI函数

2.于是尝试通过nextResponder找出关键类

对于一个view调用nextResponder,要么返回对应的C,要么返回其superview.我们可以通过recursiveDescription拿到所有view,遍历一遍则必定为出现C

对目标UI元素0x17531390调用nextResponder,结果是superview,不是Controller,继续调用0x17531390的superview的nextResponder,结果不是Controller,继续这样,大概第三次调用nextResponder时得到Controller,结果如下

#"<DfzeGXHoBCzYUNyG: 0x1884b8c0>"

3.在ida中查看这个类有什么函数,内容如下

-[DfzeGXHoBCzYUNyG initWithTitle:]	__text	0028DC58	0000006C	00000018	FFFFFFF9	.	.	.	.	.	T	.
-[DfzeGXHoBCzYUNyG viewDidLoad]	__text	0028DCC4	00000386	0000003C	00000050	.	.	.	.	.	T	.
-[DfzeGXHoBCzYUNyG viewWillAppear:]	__text	0028E076	0000020C	00000028	00000020	.	.	.	.	.	T	.
-[DfzeGXHoBCzYUNyG YnDNWxqNaCCuowFk]	__text	0028E282	00000186	00000028	FFFFFFF9	.	.	.	.	.	T	.
-[DfzeGXHoBCzYUNyG qtuIqLxznDvYaGTr]	__text	0028E408	00000186	00000028	FFFFFFF9	.	.	.	.	.	T	.
-[DfzeGXHoBCzYUNyG getIPAddresses]	__text	0028E58E	000001F2	0000004C	FFFFFFF9	.	.	.	.	.	T	.
-[DfzeGXHoBCzYUNyG DtFVEldRKFDYPxLj]	__text	0028E780	0000013A	00000034	FFFFFFF9	.	.	.	.	.	T	.
sub_28E8BA	__text	0028E8BA	0000017E	00000028	FFFFFFF9	.	.	.	.	.	.	.
-[DfzeGXHoBCzYUNyG TAKrPPOSDHgLhdlg:]	__text	0028F054	0000005C	00000018	FFFFFFF9	.	.	.	.	.	T	.
-[DfzeGXHoBCzYUNyG CjBOqjnWPaaJQnAu:]	__text	0028F0B0	0000005C	00000018	FFFFFFF9	R	.	.	.	.	T	.
-[DfzeGXHoBCzYUNyG UNTxpTxBxJoWIeZP:]	__text	0028F10C	0000017E	00000038	FFFFFFF9	.	.	.	.	.	T	.
-[DfzeGXHoBCzYUNyG TVOkxTgmPvvUQgyG]	__text	0028F28A	000000E6	00000014	FFFFFFF9	.	.	.	.	.	T	.
-[DfzeGXHoBCzYUNyG ByPwWewvzRduvJAZ:]	__text	0028F370	000006D0	00000050	0000015C	.	.	.	.	.	T	.
-[DfzeGXHoBCzYUNyG lMMzCjtHIpwhEYDe]	__text	0028FA40	0000008A	00000010	FFFFFFF9	.	.	.	.	.	T	.
-[DfzeGXHoBCzYUNyG lFgomfELMhFbEmAP]	__text	0028FACA	0000045A	00000038	000000A0	.	.	.	.	.	T	.
sub_28FF28	__text	0028FF28	000000EE	00000020	FFFFFFF9	.	.	.	.	.	.	.
sub_290126	__text	00290126	000000EE	00000020	FFFFFFF9	.	.	.	.	.	.	.
-[DfzeGXHoBCzYUNyG TsKjfpgzwErnqaRz]	__text	00290326	000003A6	00000088	00000050	R	.	.	.	.	T	.
-[DfzeGXHoBCzYUNyG dFslcfROBneVXIcP]	__text	002906CC	000000F4	00000028	FFFFFFF9	R	.	.	.	.	T	.
-[DfzeGXHoBCzYUNyG gvUiVteWORiIBItH]	__text	002908C2	000001F2	00000030	FFFFFFF9	R	.	.	.	.	T	.
-[DfzeGXHoBCzYUNyG dvgqYNRRWfWlzrMR]	__text	00290AB4	000001F2	00000024	FFFFFFF9	.	.	.	.	.	T	.
-[DfzeGXHoBCzYUNyG cYPTTHyfdZrmlGeJ]	__text	00290CA6	00000442	0000003C	FFFFFFF9	.	.	.	.	.	T	.
-[DfzeGXHoBCzYUNyG qmBOCGqdppELEuhx:]	__text	002910FC	000006AE	00000064	00000014	.	.	.	.	.	T	.
sub_2917AA	__text	002917AA	00000014			.	.	.	.	.	.	.
sub_2917BE	__text	002917BE	00000014			R	.	.	.	.	.	.
sub_2917D2	__text	002917D2	00000002			R	.	.	.	.	.	.
-[DfzeGXHoBCzYUNyG xkbtCZfVnlokDiQQ]	__text	002917DE	0000023C	00000058	FFFFFFF9	.	.	.	.	.	T	.
-[DfzeGXHoBCzYUNyG actionSheet:didDismissWithButtonIndex:]	__text	00291A1A	000000B2	0000002C	FFFFFFF9	R	.	.	.	.	T	.
sub_291ACC	__text	00291ACC	00000030			R	.	.	.	.	.	.
sub_291AFC	__text	00291AFC	00000006			R	.	.	.	.	.	.
-[DfzeGXHoBCzYUNyG QKcrTsEUijhKlYkK]	__text	00291B08	00000362	00000044	FFFFFFF9	.	.	.	.	.	T	.
sub_291E6A	__text	00291E6A	0000061C	00000068	FFFFFFF9	R	.	.	.	.	.	.
sub_292486	__text	00292486	00000078	00000010	FFFFFFF9	.	.	.	.	.	.	.
sub_2924FE	__text	002924FE	00000008			R	.	.	.	.	.	.
-[DfzeGXHoBCzYUNyG numberOfSectionsInTableView:]	__text	00292506	00000004			R	.	.	.	.	T	.
-[DfzeGXHoBCzYUNyG tableView:numberOfRowsInSection:]	__text	0029250A	00000018			R	.	.	.	.	T	.
-[DfzeGXHoBCzYUNyG tableView:titleForHeaderInSection:]	__text	00292522	0000037E	00000070	FFFFFFF9	.	.	.	.	.	T	.
-[DfzeGXHoBCzYUNyG tableView:cellForRowAtIndexPath:]	__text	002928A0	00002022	00000060	000005A4	.	.	.	.	.	T	.
-[DfzeGXHoBCzYUNyG OhUMmGPeGwZZDBtc]	__text	002950D6	00000198	00000014	00000034	R	.	.	.	.	T	.
sub_29526E	__text	0029526E	00000028			R	.	.	.	.	.	.
sub_295296	__text	00295296	00000008			R	.	.	.	.	.	.
-[DfzeGXHoBCzYUNyG jmkaknJHAflckoIm]	__text	002952A2	000003BC	00000018	00000008	R	.	.	.	.	T	.
-[DfzeGXHoBCzYUNyG rOOryYkvHSZTcyEr]	__text	002956CC	00000092	00000018	FFFFFFF9	R	.	.	.	.	T	.
-[DfzeGXHoBCzYUNyG PeRitUKptnhtvumt]	__text	00295762	0000009C	00000014	FFFFFFF9	.	.	.	.	.	T	.
-[DfzeGXHoBCzYUNyG WEGZcpPXhqEpYzTJ:]	__text	0029605E	000000FC	00000018	FFFFFFF9	.	.	.	.	.	T	.
-[DfzeGXHoBCzYUNyG VbuxthvxmYrmdAnn]	__text	002962E6	00000012			R	.	.	.	.	T	.
-[DfzeGXHoBCzYUNyG FtJrvgWmZdeEYCrm]	__text	00296308	00000010			R	.	.	.	.	T	.
-[DfzeGXHoBCzYUNyG setFtJrvgWmZdeEYCrm:]	__text	00296318	00000010			R	.	.	.	.	T	.

发现类名和大部分类函数都没有具体的意义,可能是都被混淆了,一个一个函数查看有没有线索,在DfzeGXHoBCzYUNyG tableView:cellForRowAtIndexPath函数中发现一些字符串

v25 = objc_msgSend(v24, "localizedStringForKey:value:table:", CFSTR("License"), &stru_657918, 0);
v46 = objc_msgSend(v45, "localizedStringForKey:value:table:", CFSTR("valid till %@"), &stru_657918, 0);

以及一些其他的在截图中被打码部分的对应字符串,到这里,想到应该把手机的系统语言设置成English,这样破解起来更清晰,将手机系统语言设置成英文后,app截图如下

English

step3 暴破

上图可看到对应的LicenseUnauthorized,由于这里的函数大多被混淆了,现在尝试通过关键字进行破解,在idastrings窗口中搜索Unauthorized,找到后双击,在IDA view窗口中右键查看调用了此处的代码,没有找到什么有用的信息.后来通过在app中点击使用正常功能的对应按钮,弹出警告窗口如下

alert

图中显示”License not activated,please purchase”,在strings窗口中搜索这串字符,找到调用这串字符相关的代码,如下图

purchase_ref

涉及3个函数,分别是+[UrsUiQqCjhigLsxP bYYENZFgIdldmiUx],sub_ACB60,-[UrsUiQqCjhigLsxP tableView:didSelectRowAtIndexPath:],将这3处分别patch(if xxx jump xxx,改成if not xxx jump xxx),将patch后的文件替换手机中的对应文件(find / -name "appname"),重新在手机中运行app,验证成功破解

如果需要将破解后的app保留以备后用,可将deb文件重新打包,可参考这里

0x3 后记

后来尝试重新动态调试破解,有以下绕过反调试过程

绕过反调试

这个app直接使用ida远程调试时会发现无法调试,为了找到反调试代码,在app入口start函数处下断点(可在ida的Exports视图中快速找到start函数),内容如下

int __fastcall start(int a1, int a2)
{
  int v2; // r5
  int v3; // r6
  int v4; // r0
  int v5; // r8
  void *v6; // r0
  int v7; // r0
  int v8; // r4
  int v9; // r5

  v2 = a2;
  v3 = a1;
  v4 = sub_2E3686();
  v5 = objc_autoreleasePoolPush(v4);
  v6 = objc_msgSend(&OBJC_CLASS___JefhStRvMGfrygNL, "class");
  v7 = NSStringFromClass(v6);
  v8 = objc_retainAutoreleasedReturnValue(v7);
  v9 = UIApplicationMain(v3, v2, 0, v8);
  objc_release(v8);
  objc_autoreleasePoolPop(v5);
  return v9;
}

在start函数里step over单步调试,发现运行到sub_2e3686函数中有个ptrace调用,这是一种反调试方法(其他反调试方法可参考这里).于是将ptrace的调用nop掉,然后patch原可执行文件后重新远程调试

注意

1.这里由于是远程调试,ida可能在将patch内容写入到原文件时有个bug.因为远程调试时在调试设置中的可执行文件的路径是远程手机上的路径,如这里的路径是/Applications/xxx.app/xxx,在ida中edit|patch program|apply patches to input file时无法将修改的内容写入到远程手机上的app,需要在patch前将input file的路径设置为ida所在pc本地的已经存在的可执行文件,但是这个设置不能在edit|patch program|apply patches to input file弹出的对话框中设置,在这里设置后发现没有成功path,需要在debugger|process option这里设置,设置好后再去edit|patch program|apply patches to input file可成功patch到IDA所在pc的可执行文件,patch完成后再将本地所在的可执行文件拷贝到远程手机中,再重新进行远程调试

2.在远程调试时,ida默认不勾选下图中的suspend on debugging startsuspend on process entry point,这两个选项要手动勾上,因为如果被调试的程序有反调试机制而没有勾选这两个选项,则不能在反调试代码运行前将被调试程序中断下来,因为这里是远程调试,一般需要rebase program,只有rebase program后断点才会正常中断.如果没有勾选这两个选项则会在人工rebase program前(也即正常调试目标程序前)就发生了反调试代码的运行,这样就无法调试了

3.cydia中的deb有些是32位的,要根据具体情况选择用32位的ida还是用64位的ida,如果app的位数与ida的位数不一致会导致hex-rays decompiler插件会不起作用,或者在rebase program时出问题.如果发现ida使用remote ios debugger+usb调试时ida还经常是”卡”的状态,很有可能是因为app的位数与ida位数不一致造成(如64位的app用到了32位的ida调试)

反调试要勾选

ios, UI, cycript
home
github
archive
category