iOS逆向(四)实战篇

  1. 逆向分析
    1. 探寻作墙页面的C
    2. 探寻需解锁的数据源
  2. 结语

这篇主要是更详细地讲解一步一步找出目标的方法,从定位view,到定位其Controller,再到定位目标函数,以及一些工具在实际场景下的使用过程,比如IDA等。看到最后,我可能会被读者喷是标题党,但是我也很无奈,等下次吧,会再努力尝试一下。

逆向分析

探寻作墙页面的C

在App打开被墙的页面,然后使用Reveal或者cycript来分析当前显示页面V(View)的C(ViewController)。这里拿回上一篇文章所用的方式说明,利用cycript来定位

cy# [[UIApp keyWindow] recursiveDescription].toString() 
cy# button=#0x10c22b490
cy# [button setHidden:YES]
cy# [button nextResponder]

列出keyWindow上视图的层级结构后,根据内容特征,如label的text属性值与当前页面上的内容对比,找出吻合的内容进行验证,例如设置控制的隐藏。确认是当前页面的控件后则可以开始根据响应链的关系,如子视图的nextResponder是父视图,若该父视图没有它的父视图了,则其nextResponder就是对应的Controller,通过这样来找出当前页面的Controller。

在被墙的页面上,根据确认支付按钮,找出了当前的C为XDBigNameViewController

探寻需解锁的数据源

IDA分析

然后可以先直接在IDA上开始对业务逻辑进行初步的了解,定位到关键的函数。

XDBigNameViewController在其setUI方法上创建了一个XDBigNameTool(一个View),其delegate设为当前的XDBigNameViewController对象并叠加到后者自身的view属性上,可以猜测这个XDBigNameTool就是界面上的墙。

XDBigNameViewController确认了协议XDBigNameToolDelegate,该协议只有一个必须实现的方法 - (void)clickunlock; 。

触发 clickunlock 后会初始化订单ID和价格信息并存入数据库,然后push出一个叫XDPayViewController的页面。在这个XDPayViewController里,实现了StoreKit的一个代理方法 paymentQueue:updatedTransactions: ,意味着苹果内购完成后的回调可能执行该方法。

在这个paymentQueue:updatedTransactions:方法中,当transactionState返回的结果是1uLL时,执行XDPayViewController的completeTransaction: ,并且跳转到 LABEL_11 继续执行

switch ( (unsigned __int64)objc_msgSend(*(void **)(v21 + 8 * v7), "transactionState") )
        {
...
case 1uLL:
            objc_msgSend(v4, "removeProgressingView");
            objc_msgSend(v4, "addProgressingViewWithMessage:", CFSTR("交易成功,校验信息"));
            -[XDPayViewController completeTransaction:](v4, "completeTransaction:", v8);
            v12 = objc_msgSend(&OBJC_CLASS___SKPaymentQueue, "defaultQueue");
            goto LABEL_11;
...
LABEL_11:
            v13 = (void *)objc_retainAutoreleasedReturnValue(v12);
            objc_msgSend(v13, "finishTransaction:", v8);
            v11 = (__int64)v13;
...
}

查看一下 StoreKit里SKPaymentTransactionState定义,再结合此处的提示信息,可以肯定case 1uLL里执行的操作是内购成功后的业务逻辑,调用了内部方法completeTransaction:。

XDPayViewController的completeTransaction:方法的(Pseudocode后的)反编译结果如下

image

从上面的实现可以大概看出做了以下几件事情

  1. 获取receipt-data;
  2. 生成请求验证前所需的其它参数(ordercode、paytype、payfrom、productId等);
  3. 缓存ordercode信息;
  4. 定义请求的成功和失败回调block;
  5. 发起请求。

还没研究出怎么在block中打断点,参考 对逆向中的block打断点

在Main Window的反编译里

可以看到X20这个寄存器一直保存着receipt-data,并在验证成功的回调block中被引用。

image
image

中间一段对X8的操作,是在收集请求前的参数集合,包括进行base64编码后的receipt-data

image

再经过分析,X29是方法里从头到尾没有被重新赋值过并一直保持激活的一个变量,在block中也被引用到,由此可以猜测它是方法传入的型参transaction,并在成功回调的block中对这个transaction进行finish操作。

这里尝试过使用cycript动态调用该completeTransaction:(先利用nextResponder找出当前XDPayViewController的地址,再进行调用),模拟传入nil作为transaction参数,这时会触发如下的网络请求

image

会返回错误的结果,提示验证失败。

此前已经在应用的沙盒、UserDefault、本地数据库等应用内的地方搜查过一遍,收费的数据并没有放在本地(按常理来说也不太可能这样存放)。

制作Tweak

到这里已经可以知道,收费内容是需要在receipt-data被验证成功了才会返回,到这里暂时就没辙了。

但若在知道破绽时,后续还需要做Tweak插件来hook一些方法的实现,就拿上面调用completeTransaction:并传入nil的transaction举例,做成Tweak。

首先,需要创建一个头文件,重新定义需要hook的类和方法或属性,目的是为了欺骗编译器使其能找到方法的声明

//In iosrefuguiqiming.h

@interface XDPayViewController : NSObject
- (void)completeTransaction:(id)transaction;
@end
//In Tweak.xm

#import "iosrefuguiqiming.h"

%hook XDPayViewController

- (void)paymentQueue:(id)queue updatedTransactions:(id)transactions {
	%log;

	UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"iosre" message:@"processing" delegate:self cancelButtonTitle:@"OK" otherButtonTitles:nil];
	[alert show];
	[alert release];
		  
	[self completeTransaction:nil];

	//%orig(queue,transactions);
}

%end

然后make package、make install把deb安装到设备上,自动重启springboard或者tweak指定的进程后,deb就已经生效了。此时打开target app,点击内购后就马上弹出插入的提示框和发起支付的验证请求。

结语

虽然结果未能达到目标,但过程足以让我们学会了动手去分析和改造一个app,像破壳、静态的反编译分析、动态的lldb调试、自制tweak等,让我们拥有了借鉴别人App的防御机制的能力,像这次的探索就再次印证了做苹果的内购,必须在服务端对收据进行验证,并且要建立完善的订单匹配逻辑,防止被攻击者重放或者篡改订单来获取收费资源。待之后有新思路再回来尝试重新进攻该次实践App的验证逻辑。


转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 mingfungliu@gmail.com

文章标题:iOS逆向(四)实战篇

文章字数:1.4k

本文作者:Mingfung

发布时间:2018-09-13, 22:39:04

最后更新:2018-09-13, 23:22:54

原始链接:http://blog.ifungfay.com/iOS/iOS逆向(四)实战篇/

版权声明: "署名-非商用-相同方式共享 4.0" 转载请保留原文链接及作者。

目录
×

喜欢就点赞,疼爱就打赏

宝贝回家