抓包分析PP助手IOS版,获取历史版本下载列表

原文发于本人小笔记 http://leanote.bitcode.tk:251/blog/post/sma11case/%E9%80%86%E5%90%91PP%E5%8A%A9%E6%89%8BIOS%E7%89%88%EF%BC%8C%E8%8E%B7%E5%8F%96%E5%8E%86%E5%8F%B2%E7%89%88%E6%9C%AC%E4%B8%8B%E8%BD%BD%E5%88%97%E8%A1%A8 此处做个备份,转载请保留此段文字,原文有结果结构解析详细方法以及已编译好的命令行版本下载。

抓包分析PP助手IOS版,获取历史版本下载列表


PP助手IOS版可以安装APP的历史版本,而Mac版没这功能,今天闲着无事抓包分析了对应接口。

抓包过程略过不表,由于此APP构造自定义数据结构进行通讯,因此需要分析数据构造,然后组装数据进行接口调用。

历史版本接口需要APPID,因此先通过Mac版抓包获取APP信息的接口(接口已写成脚本,方便调用)。

#!/bin/sh

JBCHANNEL='4262469664'
StoreChannel='4262469686'

type="$1"
KEYWORD="$2"

if [ '' = "${KEYWORD}" ]; then
    echo "usage: ipasearch.sh <store|jb> <keyword>"
    exit 0
fi

POST1='-d{"dcType":0, "keyword":"'
POST2='", "clFlag":1, "perCount":15, "page":0}'
POST="${POST1}${KEYWORD}${POST2}"

CHANNEL="${JBCHANNEL}"
if [ 'store' = "${CHANNEL}" ]; then
    CHANNEL="${StoreChannel}"
fi

curl -Lk 'http://jsondata.25pp.com/index.html' -H 'Content-Type: application/x-www-form-urlencoded' -H "Tunnel-Command: ${CHANNEL}" "${POST}"

exit 0

随便拿个APP开刀,比如微信,调用脚本 ppsearch.sh jb 微信(表示搜索越狱应用,关键字微信)得到如下信息,其中id便是APPID,获取历史版本需要用到。


    {
      "id": 620065,
      "itemId": 414478124,
      "price": 0,
      "package": 0,
      "buid": "com.tencent.xin",
      "version": "6.6.6",
      "downurl": "http://r11.25pp.com/soft/2018/04/02/20180402_24703_218980057839.ipa",
      "title": "微信",
      "fsize": "100.29MB",
      "dcType": 3,
      "thumb": "http://img.25pp.com/uploadfile/app/icon/20180402/1522646114148240_54x54.jpg",
      "desc": "微信是一款全方位的手机通讯应用,帮助你轻松连接全球好友。微信可以(通过SMS/MMS网络)发送短信、进行视频聊天、与好友一起玩游戏,以及分享自己的生活到朋友圈,让你感受耳目一新的移动生活方式。  为什",
      "stars": 60,
      "updatetime": 1523157809,
      "downloads": 301217387,
      "resType": 1
    }

贴上历史版本接口数据结构,其中unknow1应该是对应接口哪个功能,不用理会,直接填充为固定的即可,device_token填充为40长度的随机16进制字符串,plat_name为对应手机平台字符串,可通过uname()函数获得,一般写死即可,pkgId便是上面提到的APPID。

struct __attribute__ ((packed)) QueryInfo {
    char unknow1[0x10-1];    // 4b 00 00 00 14 00 e0 fd 01 7a 00 00 00 00 00
    char device_token[40+1]; // device token, length=40
    char plat_name[9+1];     // iPhone7,2
    char unknow2[5];         // 00 02 00 09 00
    int32_t pkgId;           // 21 76 09 00 ==> 620065
};
typedef struct QueryInfo QueryInfo;

调用实例(语言OC,仅贴关键代码,细节部分自行填充)

static NSString *const kQueryAppInfoUrl = @"http://mobileup.25pp.com/index.php";

static const unsigned char unknow1[] = { 0x4b, 0x00, 0x00, 0x00, 0x14, 0x00, 0xe0, 0xfd, 0x01, 0x7a, 0x00, 0x00, 0x00, 0x00, 0x00 };
static const unsigned char unknow2[] = { 0x00, 0x02, 0x00, 0x09, 0x00 };

    QueryInfo info = {0};
    memcpy(info.unknow1, unknow1, sizeof(unknow1));
    memcpy(info.unknow2, unknow2, sizeof(unknow2));
    strcpy(info.device_token, [NSString randomStringWithKeys:HexLowerCaseKeys length:40].UTF8String);
    strcpy(info.plat_name, "iPhone7,2");
    info.pkgId = 620065;
    
    NSData *post = [NSData dataWithBytes:&info length:sizeof(info)];
    NSDictionary *header = @{
//                             @"Cookie":@"UM_distinctid=16179b283d11f2-01c14a4f3-4c1e3b41-3d10d-16179b283d222",
                             @"User-Agent":@"PPHelperNS/122 CFNetwork/758.0.2 Darwin/15.0.0",
                             };

post数据和header通过POST方式提交到http://mobileup.25pp.com/index.php即可获得返回,header经测试不设置也是可以的,但设置一下防止被发现的伪造的包~~~

接口调用后返回的数据也是Binary结构,通过以下函数简单粗暴的转换为字符串。


inline static NSMutableArray *sc_parseData(const char *ptr, size_t len)
{
    NSMutableArray *res = NewMutableArray();
    
    NSMutableData *temp = nil;
    
    for (long a= 0; a < len; ++a)
    {
        unsigned char x = ptr[a];
        
        if (0 == x)
        {
            temp = nil;
            continue;
        }
        
        if (nil == temp)
        {
            temp = NewClass(NSMutableData);
            [res addObject:temp];
        }
        
        [temp appendBytes:&x length:sizeof(x)];
        BreakPointHere;
    }
    
    BreakPointHere;
    return res;
}

inline static NSMutableArray *sc_parseString(const char *ptr, size_t len)
{
    NSMutableArray *res = sc_parseData(ptr, len);
    NSMutableArray *sss = NewMutableArray();
    [res enumerateObjectsUsingBlock:^(id  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
        id obj1 = [obj toUTF8String];
        if (obj1) [sss addObject:obj1];
    }];
    
    BreakPointHere;
    return sss;
}

把返回结果的NSData扔进sc_parseString()函数即可获得所有可见字符串,过滤一下需要的信息即可,码字不易,尽可能直接说中心,好心的看官可以点个赞或打赏个咖啡钱~~~(不点不打也没所谓 _

推荐阅读更多精彩内容

  • @synthesize和@dynamic分别有什么作用?@property有两个对应的词,一个是 @synthes...
    笔笔请求阅读 316评论 0 1
  • 猜想runloop内部是如何实现的?一般来讲,一个线程一次只能执行一个任务,执行完成后线程就会退出。如果我们需要一...
    笔笔请求阅读 244评论 0 0
  • 偶然发现,用过一些,分享给大家 { "XcodeChaJian": [ { "Dname":"...
    MonkeyHan阅读 2,993评论 0 4
  • 反复听薛之谦的歌那几天大概是我来到这个城市最难过的那几天。 我记得舍友在那几天几乎嫌弃我嫌弃的要死。 今天是201...
    惜棠阅读 243评论 0 0
  • 古韵,既担一个“韵”字,便绝不是白水之流囫囵吞进去只作解渴之用,却也不是酸甜可口的碳酸饮料,入肚后方得一时之快...
    幸运的贝壳阅读 110评论 0 0
  • 基础篇 郭金名叫郭金阳正,大家都简称他郭金!名字起的很高大尚,但若说起学习,那要打一个大大的问号了。 我四年级接班...
    孤心如水阅读 108评论 0 0
  • 长春——机场 今天是个不错的天气。我收拾行李去北京。我的行李本来就不多,再扔掉那些可要可不要的,就只剩下很少的一部...
    自嗨罗阅读 605评论 0 0