【安卓逆向】某房产app Authorization参数分析

嗯,2021年快结束了,学习忙碌一年了,年底了写点文章,总结性学习成果吧!

今天我们要分析的app是6LSd5aOzdjIuNjYuMA== (base64解码),小伙伴们可以去各大应用商定自行下载,也是一个很好的逆向分析案例。

转载文章,请注明出处,谢谢!https://blog.csdn.net/weixin_38819889/article/details/122058454

参考链接:https://core.vivcms.com/2021/10/25/637.html

1.抓包找参数

第一步,打开我们的charles直接抓包,发现这个时候没有抓到对应的包。好吧,那我们换一种vpn抓包的方式。先打开postern,然后再开启charles,这个时候就成功的抓到数据包了,如下图所示,Authorization 就是要分析研究的字段,经过多次的测试,发现其他字段可以去掉,但唯独这个字段是不能的。
在这里插入图片描述

2.反编译和静态分析

找到这个加密参数 Authorization ,接下来就是反编译apk,来把我们的贝壳app拖进去jadx里面,看看加密逻辑是咋写的。
在这里插入图片描述
搜索一波,感觉这里很像的样子map2.put("Authorization", getSignString(str3, null)); ,点进去看一看。然后我们来到这里了,可以看到(下图)这里是调用一个getSignString()方法,并传入参数str3 和null,然后计算出结果当做Authorization 的值。

在这里插入图片描述
跟进去看看 getSignString()方法是咋实现的,然后就来到了这里。

具体代码如下,没错,可以大胆的猜测下,这就是最核心的加密方法。首先,我们先静态分析一波逻辑,然后再用frida动态调试下,验证下我们的猜想对不对。

  public String getSignString(String str, Map<String, String> map2) {
        Map<String, String> urlParams = getUrlParams(str);
        HashMap hashMap = new HashMap();
        if (urlParams != null) {
            hashMap.putAll(urlParams);
        }
        if (map2 != null) {
            hashMap.putAll(map2);
        }
        ArrayList arrayList = new ArrayList(hashMap.entrySet());
        Collections.sort(arrayList, new Comparator<Map.Entry<String, String>>() { // from class: com.bk.base.netimpl.a.1
            public int compare(Map.Entry<String, String> entry, Map.Entry<String, String> entry2) {
                return entry.getKey().compareTo(entry2.getKey());
            }
        });
        String httpAppSecret = ModuleRouterApi.MainRouterApi.getHttpAppSecret();
        boolean notEmpty = Safe.C2266e.notEmpty(httpAppSecret);
        String str2 = BuildConfig.FLAVOR;
        if (!notEmpty) {
            try {
                httpAppSecret = JniClient.GetAppSecret(APPConfigHelper.getContext());
            } catch (Exception e) {
                e.printStackTrace();
                httpAppSecret = str2;
            }
        }
        String httpAppId = ModuleRouterApi.MainRouterApi.getHttpAppId();
        if (Safe.C2266e.notEmpty(httpAppId)) {
            str2 = httpAppId;
        } else {
            try {
                str2 = JniClient.GetAppId(APPConfigHelper.getContext());
            } catch (Exception e2) {
                e2.printStackTrace();
            }
        }
        StringBuilder sb = new StringBuilder(httpAppSecret);
        for (int i = 0; i < arrayList.size(); i++) {
            Map.Entry entry = (Map.Entry) arrayList.get(i);
            sb.append(((String) entry.getKey()) + "=" + ((String) entry.getValue()));
        }
        String str3 = TAG;
        LjLogUtil.m30128d(str3, "sign origin=" + ((Object) sb));
        String SHA1ToString = DeviceUtil.SHA1ToString(sb.toString());
        String encodeToString = Base64.encodeToString((str2 + ":" + SHA1ToString).getBytes(), 2);
        String str4 = TAG;
        LjLogUtil.m30128d(str4, "sign result=" + encodeToString);
        return encodeToString;
    }

可以看到getSignString()方法传入两个参数,一个是string字符串类型参数,另外一个是hashmap类型参数。首先调用getUrlParams()方法,这个方法就是就是得到请求url后面那一堆参数的。

  private Map<String, String> getUrlParams(String str) {
        if (str == null || str.length() == 0) {
            return null;
        }
        HashMap hashMap = new HashMap();
        Uri parse = Uri.parse(str);
        for (String str2 : parse.getQueryParameterNames()) {
            String str3 = str2.toString();
            hashMap.put(str3, parse.getQueryParameter(str3));
        }
        return hashMap;
    }

接着尼就是声明一个hashmap,分别把urlParamsmap2放进去,然后又定义一个arrayList数组,并对数组排个序。之后又定义了两个变量 httpAppSecrethttpAppId,具体是干嘛的,值到底是多少,没事,目前不知道 不要紧 ,我们继续往下看。

接着又定一个字符串sb,先把httpAppSecret加进去,再接着把arrayList数组里面的元素取出来,做一个拼接的操作。然后来到这个方法处DeviceUtil.SHA1ToString(sb.toString());,看关键词就能够大概的猜想到这一个sha1算法。

  public static String SHA1ToString(String str) {
        try {
            MessageDigest instance = MessageDigest.getInstance("SHA-1");
            instance.update(str.getBytes());
            byte[] digest = instance.digest();
            StringBuffer stringBuffer = new StringBuffer();
            for (byte b : digest) {
                String hexString = Integer.toHexString(b & 255);
                if (hexString.length() < 2) {
                    stringBuffer.append(0);
                }
                stringBuffer.append(hexString);
            }
            return stringBuffer.toString();
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
            return BuildConfig.FLAVOR;
        }
    }

最后把sha1计算的结果和str2参数拼接(Base64.encodeToString((str2 + ":" + SHA1ToString).getBytes(), 2);),并做了一个base64操作,这个str2 就是之前 httpAppId,计算出来的值就是最后加密结果,也就是Authorization。

3.frida动态调试

静态分析已经差不多了,是时候拿出我们的frida了,看看实际传参和结果到底是个什么样子的,以及 httpAppSecrethttpAppId到底是什么。

js代码如下:

Java.perform(function(){
    var getSig = Java.use("com.bk.base.netimpl.a");
    getSig.getSignString.implementation = function (v1, v2) {
        console.log("↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓");
        console.log("Sig参数1: " + v1);
        var it = v2.keySet().iterator();
        var result = "";
        while(it.hasNext()){
            var keystr = it.next().toString();
            var valuestr = v2.get(keystr).toString();
            result += keystr + valuestr + "        ";
        }
        console.log("Sig参数2: " + result);
        var res = this.getSignString(v1,v2)
        console.log("Sig加密后的数据:", res)
        console.log("↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑");
        return res;
    }

    var api = Java.use("com.bk.base.router.ModuleRouterApi");
    api.getHttpAppSecret = function (){
        console.log("getHttpAppSecret" + api.getHttpAppSecret());
        return api.getHttpAppSecret();
    }

    api.getHttpAppId = function () {
    console.log("getHttpAppId" + api.getHttpAppId());
    return api.getHttpAppId();
    }


    var jni = Java.use("com.homelinkndk.lib.JniClient");
    jni.GetAppId.implementation = function (v1) {
        var res  = this.GetAppId(v1);
        console.log("appId Jni param1: " + v1);
        console.log("appId Jni: " + res);
        return res;
    }

    var log = Java.use("com.bk.base.util.bk.LjLogUtil");
    log.d.overload('java.lang.String', 'java.lang.String').implementation = function (v1,v2){
        console.log("Log.d(): " + "v1:", v1, "v2:", v2);
    }

    var encrypt = Java.use('com.bk.base.util.bk.DeviceUtil');
    encrypt.SHA1ToString.implementation = function(parm1){
        console.log("SHA1加密前参数:", parm1)
        var res = this.SHA1ToString(parm1)
        console.log("SHA1加密后结果:", res)
         return res;
    }
});

httpAppId是一个固定值 20180111_android:,来源就是如下:

在这里插入图片描述
继续分析httpAppSecret的来源,先看看sha1加密的过程:

SHA1加密前参数: d5e343d453aecca8b14b2dc687c381cacity_id=110000home_ab_group=Bis_first_entry=0latitude=39.974194longitude=116.416306page=1tab_id=rentV2
SHA1加密后结果: 69afab7f7275b2b49f4b7790033498fcae22f343

可以看到在执行sha1加密传参之前,先拼接一个固定字符串d5e343d453aecca8b14b2dc687c381ca,然后是拼接请求的url后面的参数,没错 这个固定值 就是httpAppSecret。

然后说一说get和post 请求方式的不同。get请求的时候,hashmap为null,而post请求把请求的body参与计算。

在这里插入图片描述
在这里插入图片描述
然后分析就是到此结束了。

4 代码还原:

具体代码就不公布了,毕竟对别人不太友好。看看最后拿到的数据。有兴趣的可以自己尝试分析一波,肯定是会有很多收获的。

在这里插入图片描述

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
引用\[1\]中的代码片段是前端使用axios发送请求时的拦截器配置,其中将token放入请求头中。而引用\[2\]中提到的目的是为了实现代码安全,拦截除了登录请求以外的其他请求,并将token信息放入请求头中。 根据你的问题,HttpServletRequest获取不到header中Authorization参数的原因可能有以下几种可能性: 1. 请求头中没有设置Authorization参数:请确保在发送请求时,请求头中设置了Authorization参数,并且值为有效的token。 2. 请求头中的Authorization参数被修改或删除:请检查请求头中的Authorization参数是否被修改或删除,确保其值与发送请求时设置的一致。 3. 后端接收请求时未正确获取Authorization参数:请确保后端代码正确获取请求头中的Authorization参数。可以使用HttpServletRequest的getHeader方法来获取请求头中的参数值。 需要注意的是,以上是一些常见的可能性,具体原因还需要根据你的代码和环境进行具体分析。希望以上信息对你有帮助。 #### 引用[.reference_title] - *1* *2* [前后端分离 后端获取不到header解决方案](https://blog.csdn.net/qq_57581439/article/details/128041253)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insert_down1,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值