某海外 App Auth_Token 参数逆向分析

a8c2cdf8f0f3c1e6f76239648ce9266c.gif

特别声明:本公众号文章只作为学术研究,不用于其它用途。

这是「进击的Coder」的第 761 篇技术分享

作者:TheWeiJun

来源:逆向与爬虫的故事

阅读本文大概需要 11 分钟。

 目录


一、抓包分析

二、Jadx 反编译

三、hook 调试

四、算法分析

五、思路总结


趣味模块

      小东是一名后端开发工程师,自从上次使用了魔改 md4 算法,恶意请求量得到了有效控制。但是好景不长,随着 spider 技术的提升,也就过了半个月,恶意请求量就又上来了。小东心里默默地说了一句:"去 tn 的,看来这次得使用杀手锏了。"于是小东在参数中加入了一个新的参数 auth_token,小东加上这套策略后,请求量立马下降了。接下来,让我们去分析一下小东是如何设计的此方案吧!

一、抓包分析

1、抓包分析之前,给大家推荐一个神器"AirDroid", 使用此应用可在电脑端远程控制手机及镜像手机画面。截图如下:

3f49a75833aad03dfb591411ac97f9ba.png

2、和以往一样,打开指定 App,使用 charles 工具进行 App 抓包,截图如下:

9cf1386cee29600733eaab73f3907a9b.png

经验分享:如果此处联网失败,是因为此 app 为国外 app,需要对 charles 应用进行配置,再抓包即可。

3、配置charles部分参数命令,打开本机vpn,配置截图如下:

5263d8ecb9e96801e0181a83be7a1742.png

4、再次打开 charles 应用,进行 App 抓包,应用截图如下:

1372f166bbe2301ff7dcf431ca087661.png

说明:此刻我们可以看到 app 已经能够联网并且能够抓包了,接下来进行抓包操作。

5、使用 charles 过滤指定域名后,访问指定页面,截图如下:

b1f3aa6daba6d0d04b71d8bb0c05226a.png

说明:观察上图,我们可以确定本次分析的参数为 auth_token,初步判断该参数后,无法确定使用的什么加密手段。那么,接下来让我们进入反编译调试环节吧!


二、Jadx 反编译

1、使用 jadx 打开指定 apk,截图如下:

7915392f0bf19f618a2a81d0666dd5c9.png

2、等待 jadx 反编译完毕后,使用最简单的方法(指定关键参数搜寻),截图如下:

8de7139354aa966f3b8243d15239e179.png

说明:此刻我们定位到参数结果 39 个,可以通过过滤包名接口、变量参数等方式排除一些干扰结果。

3、经过分析 java 源码,确定 auth_token 参数位置如下:

65c34b1165657f94eb01728cf21ea787.png

d9e1895f52d56f363fc4ac7aa88ae1d1.png

说明:分析上面代码,我们确定需要 hook 的函数为 a。接下来让我们去 hook 这个内部类函数的返回值,看看是不是我们想要的结果。


三、Hook 调试

1、通过分析 java 源码,构建 frida hook 代码如下:

function java_hook() {
    Java.perform(function () {
        let a = Java.use("l0.b.a.a.a");
        a.a.overload('java.lang.StringBuilder', 'java.lang.String', 'java.lang.String').implementation = function (sb, str, str2) {
            console.log('str: ' + str);
            console.log('str2: ' + str2);
            let ret = this.a(sb, str, str2);
            console.log('a ret value is : ' + ret);
            return ret;
        };
    })
}

2、启动 frida 脚本,执行 hook 方法后,点击手机,分析截图如下:

e1a84e0fd8c2fae503e976dcf12ec219.png

说明:此处我们可以看到a方法的返回值都已经全部打印出来,明文信息如上。但是 charles 抓包的 auth_token 是经过加密处理的,显然是不对的,也就是说以往的关键字查询方式无法解决这个问题。

3、hook 指定函数、构建堆栈打印输出代码,截图如下:

2c3d43c790bcf8b8f25ef6b98b54e44c.png

4、将上图的堆栈函数内嵌在需要执行的 java_hook 函数中,再次执行 hook 代码,截图如下:

4a034e85f1637b6412118cf2930a4695.png

解释说明:观察上图,此刻我们可以看到当前请求的完整堆栈信息,执行顺序从上到下。接下来,我们只需要在 jadx 中分析上面的方法即可!

5、分析堆栈函数,确定真正加密的函数位置,截图如下:

f0168208d4c346c75c67487a399ac8a0.png

6、在 IDEA 中构建此函数 hook 代码,截图如下所示:

df859d56b7957866b763fe830d4c0907.png

再次运行 frida,打印截图如下:

386fd360a0598ffd182223cf1b87e98a.png

此时 charles 中的 auth_token 的值如下所示:

{
  "auth_token": "eyJhbGciOiAiSFMyNTYiLCJ0eXAiOiAiSldUIn0.eyJzdWIiOiJjMmY3M2U3YTVjNDZkYzQzYjUzODk2Mzc3NjkzZTVmY2ExMDU5ZmNjOTkzNjljNzI0Y2U5MjhkMGQ1YmE4NWM5IiwiZXhwIjogIjE2NTM0NjE2ODUiLCJpYXQiOiAiMTY1MzQ2MDc4NSIsImVuZHBvaW50IjogIi9uYXRpdmVBcHBBcGkvbWVtYmVyL0xvZ2luLyJ9.YjdmZWFkYTE0MjA2NDdhNGQyNTQ0NTM5ZDQzZDhiZTM4MzFkZDU1YTJkODEyZGY2Mzc3MDk1ZjY0MjQ1MWE4YQ",
  "device_specific_id": "",
  "mail_address": "",
  "deviceId": ""
}

结论:此时对比 frida hook 的值和 charles 抓包的值结果一致,接下来让我们分析下加密算法吧。


四、算法分析

1、结合 java 源码分析 auth_token 参数,我们发现它其实由三个字符串拼接而成,截图如下:

95b21889478138b29be3251efb664320.png

需要还原变量如下:

  • encodeToString

  • encodeToString2

  • Base64.encodeToString(bytes2, 11)

总结:通过阅读 java 源码,我们发现上面三个参数,都是 base64 加密,接下来我们一个一个直接还原即可。

  • encodeToString 参数还原如下:

e44e33967781d8eebd8b9ed640f927a9.png

dd9f4d8fe5e07e36372e0fc9e08a2b3c.png

经验分享:不出意外的话还是出了意外,base64 解码居然失败了。然后我又看了下 java 源码,原来 android.util.Base64 在 encodeToString 编码的时候,把 == 符号去掉了,导致我在 python 中无法还原并产生报错。

修复后的正确代码及打印结果如下图所示:

21d843e1950de2531799f25c9b15580f.png

25905b531ffe87d9256ed0fcaa402cc9.png

  • encodeToString2 参数还原如下:

1099016ce9ef48d65284dffa1c4ce17b.png

总结:encodeToString2 还原后的明文信息如上图所示,exp、iat 都是时间戳,sub  为固定值,endpoint 参数为访问的当前 url 路径,此明文中不需要再还原任何加密参数,只需要模拟时间戳即可。

  • Base64.encodeToString(bytes2, 11) 参数还原如下:

e636c79ab3db74437b918de24ff3473f.png

总结:解密后的值如图所示,一串长度为 64 位字符的字符串信息,经过多次 charles 抓包后 base64 解密,我们发现这个字符串每次都不一样,接下来需要对此值进行还原。

2、通过阅读 java 源码,我们确定新的加密参数 sb3。但是 sb3 为局部变量,我们无法 hook,只能从他的来源去下手,截图如下:

3ce8b1a83b9c44c9bca57deaa0ef691c.png

3、因为上面的流程过于复杂,直接上关键函数 hook 代码,截图如下:

1c03d408381e9e5fd8820d310032d001.png

4、运行 hook 代码后,截图如下所示:

32dddd7aa4aad3f589f6d5625766b1a2.png

5、在 base64 在线解密工具中,解密刚刚的加密参数,截图如下:

ced15397ceac24ba49560e465f356a71.png

总结:对比流程 4、5 中的值,我发现 invoke 函数的返回值 value 拼接起来即为 sb3 的值;我们只需要还原此处加密即可得到 sb3 的值。

6、sb3 参数完整代码还原如下:

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.io.UnsupportedEncodingException;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;


public class Test {
    static String a3 = "token_auth的值";
    static String string5 = "AAAAB3NzaC1yc2EAAAADAQABAAABgQDLzX2Mbg+Sbv1BqbK/GY/gwT2PJ/p99zndDJ9MofK9WcvYQLMLt35MT5JduD4wWyzoDJbXJNf37YnDHYl3hESAabIUrD2Lvtn15SyFOJ5QsXtoG9gSYC2C2EI5sGgGDMWQUkmaP67EvWDElCh2LCmz0zc40kTeaovBX7Zb4P4TSayYLdKo3s+BmEtiZQ0ofv1n+xgOBxeqxiaxDbul6N2nXok5ShQzjKu5zpw9YdGSW2XKvQr4h5mCj8ak/GxpcAULlkdX+A2Wfpfs7sSB9kakae7XuIop4ymwybfn5HOiEAwMXFjNrZOzNmTBWdcOFX907PP09MwGs2klQhAbKfcfa3m0/jGhNRJ/k4iOpOM5UunWMdjF9vIL4TTLGPpyS+KK1zyrRK4j9z2fCMLovDZnvq8X6ZX+q2bMEtAgCPz8crfbZdJLhG8KQKUv+hdcnh5M6Qb3XTmCHkAo6n0cHmIGv11LW4u6HdieekUUKNE1+PWe/CynTffh/i17KbOa4zc";
    public static String invoke(Byte b) {
        Object[] objArr = {Byte.valueOf(b.byteValue())};
        String format = String.format("%02x", Arrays.copyOf(objArr, objArr.length));
        return format;
    }


    public static void main(String[] args) throws NoSuchAlgorithmException, InvalidKeyException, UnsupportedEncodingException {
        byte[] bytes = a3.getBytes(StandardCharsets.UTF_8);
        byte[] bArr4 = string5.getBytes("UTF-8");
        Mac mac = Mac.getInstance("HmacSHA256");
        SecretKeySpec secret_key = new SecretKeySpec(bArr4, "HmacSHA256");
        mac.init(secret_key);
        byte[] doFinal = mac.doFinal(bytes);
        StringBuilder sb2 = new StringBuilder();
        sb2.append((CharSequence) "");
        int i2 = 0;
        for (byte b : doFinal) {
            i2++;
            if (i2 > 1) {
                sb2.append((CharSequence) "");
            }
            if (sb2 != null) {
                sb2.append((CharSequence) invoke(Byte.valueOf(b)));
            } else {
                sb2.append((CharSequence) String.valueOf((int) b));
            }
        }
        sb2.append((CharSequence) "");
        String sb3 = sb2.toString();
        System.out.println(sb3);
    }
}

五、思路总结

      感谢大家阅读😊本篇分享到这里就结束了,欢迎大家关注下一期,我们不见不散!!!☀️

f8be1d61264c60fac8940fbed67e8aa0.png

End

崔庆才的新书《Python3网络爬虫开发实战(第二版)》已经正式上市了!书中详细介绍了零基础用 Python 开发爬虫的各方面知识,同时相比第一版新增了 JavaScript 逆向、Android 逆向、异步爬虫、深度学习、Kubernetes 相关内容,‍同时本书已经获得 Python 之父 Guido 的推荐,目前本书正在七折促销中!

内容介绍:《Python3网络爬虫开发实战(第二版)》内容介绍

79f7897925e4c4a1fe0abceab6679baf.jpeg

扫码购买

8a11115586065f5952a633aed8fa3c15.png

e2e62a28b44da594fb6e0181da2174d6.png

点个在看你最好看

outside_default.png

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值