levis 发表于 2015-10-13 13:13:14

iOS客户端内购破解

      通过逆向未来学到了很多的知识,为了感谢法总,回馈逆向未来社区,把自己逆向的iOS内购破解的过程分享给大家。
      如果你指望这篇文章能带来灰色收入,看到这里就不用往下继续了,如果想学习逆向技术和分析思路,可以尽情提问,我尽量回答。
      这篇文章不是iOS逆向入门教程,需要有一定的iOS逆向思路才能看的明白。下面进入正文。
      昨天晚上玩了一个捕鱼的游戏,里面有从APPStore购买金币的功能。我想了想看看能不能成功欺骗客户端的数据,然后让服务器给我加点金币。
      晚上想了想思路,今天上班的时候凑空闲搞了搞。废话不多说,直接上过程。
      1.首先把游戏下载到手机,然后使用dumpdecryted进行砸壳。
      2.把砸好壳的文件拖入到电脑中,使用class-dump 导出头文件。
      3.熟悉iOS内购流程的人都应该知道,StoreKit去APPStore 请求商品信息,然后会通过paymentQueue:updatedTransactions:这个函数回调给客户端,于是搜索了一下导出的头文件,发现iAPTransactionObserver 该类中实现了paymentQueue:updatedTransactions:方法,该方法第一个参数不用管,第二个参数是一个NSArray,里面放的是SKPaymentTransaction 对象。SKPaymentTransaction对象中有几个比较关键的信息如下图所示:
      // Only set if state is SKPaymentTransactionFailed
@property(nonatomic, readonly, nullable) NSError *error NS_AVAILABLE_IOS(3_0);

// Only valid if state is SKPaymentTransactionStateRestored.
@property(nonatomic, readonly, nullable) SKPaymentTransaction *originalTransaction NS_AVAILABLE_IOS(3_0);

@property(nonatomic, readonly) SKPayment *payment NS_AVAILABLE_IOS(3_0);

// Available downloads (SKDownload) for this transaction
@property(nonatomic, readonly) NSArray<SKDownload *> *downloads NS_AVAILABLE_IOS(6_0);

// The date when the transaction was added to the server queue.Only valid if state is SKPaymentTransactionStatePurchased or SKPaymentTransactionStateRestored.
@property(nonatomic, readonly, nullable) NSDate *transactionDate NS_AVAILABLE_IOS(3_0);

// The unique server-provided identifier.Only valid if state is SKPaymentTransactionStatePurchased or SKPaymentTransactionStateRestored.
@property(nonatomic, readonly, nullable) NSString *transactionIdentifier NS_AVAILABLE_IOS(3_0);

// Only valid if state is SKPaymentTransactionStatePurchased.
@property(nonatomic, readonly, nullable) NSData *transactionReceipt NS_DEPRECATED_IOS(3_0, 7_0, "Use -");

@property(nonatomic, readonly) SKPaymentTransactionState transactionState NS_AVAILABLE_IOS(3_0);
transactionState这个状态值是客户端判断的关键,该状态值是枚举定义,如果该值为SKPaymentTransactionStatePurchased(1),这表示购买成功,那么现在已经找到突破点了,就是原本点击购买然后取消操作之后,返回的状态值为SKPaymentTransactionStateFailed(2),将其修改为成功标志,基本就可以讲客户端欺骗了。但是我发现SKPaymentTransaction对象的属性基本都是readonly的,于是想到了苹果的runtime机制。既然直接复制不行,那我只能用setValue:forKeyPath: 这个方法来对其属性进行修改了。为了便于测试,我加入了UIAlertView来判断是否被成功调用
下面贴上tweak的代码:
%hook iAPTransactionObserver

- (void)paymentQueue:(id)queue updatedTransactions:(id)transactions{

    for (int i = 0; i < [(NSArray *)transactions count]; ++i){
            id transaction = ;
            NSNumber *status = ;
            NSString *title = ];
            UIAlertView *alertView = [ initWithTitle:title message:@"Money" delegate:nil cancelButtonTitle:@"OK" otherButtonTitles: nil];
            ;
            ;
            if( == 2){
                    ;
                    NSString *dataString = @"success!";
                    NSData *data = length:];
                    ;
            }
    }

        %orig;       
}
%end

运行结果如下图:
刚开始调用StorKit的时候:

弹出APPStore支付信息,点击取消的时候:

同时,对方的服务器和APPStore进行了校验,最后的结果是:

哎呀~~发财梦白做了哈哈。以上就是整个逆向分析的过程,其中一部分arm汇编的东西没往上贴,感觉意义不大,看着还头疼。希望大家能从这里借鉴到思路。

听鬼哥说故事 发表于 2015-10-13 13:22:08

好资料,支持楼主~~~~~

ken 发表于 2015-10-13 13:24:55

支持楼主,支持逆向未来,支持CCAV。。。

美的随想 发表于 2015-10-13 13:29:14

非常感谢楼主分享!

sirbra 发表于 2015-10-13 13:36:30

不错哦。。

水波摇曳 发表于 2015-10-13 14:10:28

支持 多谢多谢

tingny 发表于 2015-10-14 10:28:50

支持,不错的文章

litianping 发表于 2015-10-23 14:48:49

好资料,支持楼主~~~~~

BingFeng 发表于 2015-10-23 14:49:41

好东西啊,谢谢分享!

evilknight 发表于 2015-10-23 14:54:55

好东西,感谢分享!
页: [1] 2
查看完整版本: iOS客户端内购破解