某查查APP逆向研究和爬虫详参
2020-01-23 15:26:55 Author: bbs.pediy.com(查看原文) 阅读量:420 收藏

[原创]某查查APP逆向研究和爬虫详参

18小时前 191

关于企业公开的信息数据,在工商各网站都可以公开爬取,某查查、大眼查的数据来源便是。但是我们直接研究某查查的数据,可不就是:黄雀在后!
没有关注的朋友,关注一波,我们开冲冲冲冲!

对于APP的逆向流程,之前在饿了么那边已经讲过了,就不再多讲。不记得的话,翻一下上次的笔记。^^

基本流程大致就是:

抓包->模拟报文->逆向加密参数->还原算法->成功

我用的版本是:某查查12.6.0

某查查的抓包结果:

这个是附近的企业的报文,目前看来,需要我们逆向得出的参数分别有:Authorization(这个应该是登陆帐户相关的)、sign这么俩。

为了得到Authorization,我们还得分析登陆的报文。

再次抓包分析登陆报文,发现在登陆成功后,服务器返回了Authorization的值,但是,这个报文的请求参数里依然带了Authorization参数,那这个参数又是哪里来的呢?(登录报文是/app/v1/admin/login,自己抓一下)

再次重新对整个流程抓包分析可知。

  1. APP打开时未登录时,设备信息上传后会注册得到一个Authorization,这个是未登录态的授权码。(/app/v1/admin/getAccessToken)
  2. 触发登陆操作,如短信登陆
  3. 登录完成后,会得到第二个Authorization,这个是登录态的授权码。(/app/v1/admin/login)

注意:这里的Authorization与你上传的设备信息(即deviceid,后面会说)息息相关,如果不匹配是不被认可的。

在/app/v1/admin/getAccessToken这个报文里,我们发现了deviceId这个参数,很不幸,不是IMEI,所以我们又多了一个需要逆向的参数。

对整个流程总结一下:

  1. app初次打开,手机生成deviceId
  2. deviceId上传换取未登录态的Authorization
  3. 触发登陆操作,如短信登录
  4. 登陆成功服务器返回登录态的Authorization
  5. 正常请求数据携带登录态的Authorization

至此,思路理清楚了,我们需要逆向的也就剩下:deviceId和每个包都有的sign。这下总结的明明白白,开始逆向。

先看deviceId

分析流程直接上图。

终于找到了。

得到com.ta.utdid2.device.c类的h函数即为生成函数,通过阅读逻辑,找到下述才是真正的逻辑。


至此,我们得到了deviceid的生成算法,下来我们通过还原一下。
直接上代码。

def gen_device_id(self):

        timestamp = self.get_bytes(int(time.time()))

        random_num = self.get_bytes(random.randint(0, 0x7FFFFFFF))

        imei = self.get_bytes(self.str_to_int(self.gen_imei()))

        bytes_src = timestamp + random_num + b'\x03\x00' + imei

        sign = self.get_bytes(self.str_to_int(tool.base64_encode(tool.hmac_sha1(bytes_src, 'd6fc3a4a06adbde89223bvefedc24fecde188aaa9161'))))

        bytes_src += sign

        return tool.base64_encode(bytes_src)def gen_device_id(self):

至此生成deviceid完成。

再看sign

我们直接在刚才找到的请求列表里找到sign参数。

@FormUrlEncoded

@POST("v1/admin/getAccessToken")

g<ApiResponse<TokenVO>> a(@Field("appId") String str, @Field("deviceId") String str2, @Field("version") String str3, @Field("deviceType") String str4, @Field("os") String str5, @Field("timestamp") long j, @Field("sign") String str6);

如上,sign是时间戳后面的参数。

可看出,sign由时间戳和aXY组合后进去axq.n函数计算得出,这个aXY找到如下:

既然是固定字符串的解密结果,那他肯定也是固定的,我们就没必要每次生成了,通过hook的方式,将这个值拿到直接用就好了。

可能各个版本会不同的。

接下来继续看axq.n函数。
函数太长,截图放不下了。

经过研究你会发现,这里无论是md5算法或者是阿里聚安全的算法都是在so里面了,这就有两个思路,一个办法是逆向so找到生成算法,一个是hook这个n函数,强制调用即可。
下面给个frida hook的代码,仅供参考,或者用xposed来hook都是可以的。

rpc.exports = {

    sign: function(deviceid, timestamp, param3){

var result = "";

        Java.perform(function () {

try{

var input_params = [deviceid, timestamp, param3]

var currentApplication = Java.use("android.app.ActivityThread").currentApplication();

var class_EncryptImpl = Java.use("com.android.icredit.utils.EncryptImpl");

var context = currentApplication.getApplicationContext();

var inst = class_EncryptImpl.$new(context);

                result = inst.n(input_params);

            }catch(e){

                console.log(e)

            }

        });

return result;

    }

}

至此,所有的参数都有了。不论是登陆包、密钥置换包、数据抓取的包,都能完全仿真了。

  1. Authorization只有两个小时有效,超时之后记得要用原来的refreshtoken重新置换accesstoken
  2. 文章仅做技术研究,请勿用于非法途径。

以上。

欢迎阅读转发~想要转载的朋友请告知我之后转载,并注明原帖来源。

如有问题,请与我联系。

2020安全开发者峰会(2020 SDC)议题征集 中国.北京 7月!

最后于 18小时前 被帅逼李三郎编辑 ,原因:


文章来源: https://bbs.pediy.com/thread-257353.htm
如有侵权请联系:admin#unsafe.sh