在某特上关注了一点乱七八糟的东西,然后就看到了这么一款app。无聊业余时间的时候爬取了一些福利app的数据,于是就想顺便看下这个东西的数据是否也可以爬取。
习惯性的打开HttpCanary抓包,目前一切正常。 数据都能获取到,既然要爬数据,肯定是要能够看到图片,这个是最起码的。 图片链接如下: 09aK9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6K6M7$3W2E0k6#2)9J5k6h3u0V1P5s2S2G2i4K6u0W2j5$3&6Q4x3V1k6@1N6W2)9#2k6X3q4V1N6h3I4@1i4K6u0r3j5i4k6A6k6o6g2U0x3K6x3H3x3e0x3$3x3e0q4W2z5e0m8Q4x3X3g2B7M7r3N6Q4x3@1k6C8i4K6y4p5x3r3u0X3y4e0f1$3y4X3t1I4k6e0x3$3y4h3b7@1k6U0m8U0k6U0M7^5k6U0f1$3y4U0t1$3z5h3f1%4y4U0W2Q4x3U0k6S2L8i4m8Q4x3@1u0@1i4K6y4p5x3e0f1&6x3K6f1%4x3e0l9#2x3H3`.`. 看到后面的k和t,忽然觉得这个东西可能没这么简单,应该是服务器进行访问校验了,先不管这个,直接访问下看看。 这个,尼玛,厉害了。带着key和token访问直接返回了个黑窗口(如果时间超过了链接中的t参数表示的时间,那么直接就403了)。 把图片下载下来,拉入010,果然是加密处理了。 没有找到图片文件的文件头,所以浏览器或者图片查看器也就没有办法解析这个图片。 如何解析图片,那就要从apk入手进行分析了。最终在package net.idik.lib.cipher.so;下面找到了可疑的key和iv:
通过交叉引用,可以定位到图片解密代码位于com.ilulutv.fulao2.other.g.b:
配置jeb调试器,如果不修改ro.debuggable 直接附加进程,会出现下面的错误信息: 确定之后就直接失败了: 修改安卓的ro.debuggable属性可以通过magisk 或者mprop([https://bbs.pediy.com/thread-215311.htm]),当然也有其他的办法,修改boot.img等等。不幸的是,我在夜神模拟器上安装magisk之后,卡在了检查更新上,没有办法继续安装。知道原因的还望不吝赐教。 另外一个办法,就是通过mprop修改,下载之后,直接运行对应的bat文件即可。 需要注意的是,运行完脚本之后需要重新打开apk,否则依旧无法进行附加。 附加之后,向下滚动页面加载内容。此时断点就断下来了。 单步执行到00000014 invoke-direct SecretKeySpec-><init>([B, String)V, v1, p0, v2 这一行就可以看到具体的key和iv的值了。 默认的jeb的局部变量类型全部为int,可以根据代码来修改变量类型,这里两个参数的类型都是B[,修改之后就可以看到具体的数值了, 如下: 比较蛋疼的一点是,jeb直接复制的变量的值是下面的格式:
鉴于net.idik.lib.cipher.so的目录下的key比较多,并且key包含不可打印字符,直接复制数值也比较蛋疼。 此时frida hook就派上用场了:
由于该函数的key和为是一个byte数据,所以直接通过send函数发送。接收到的数据是个Image_iv:[object Object] 无法正常显示,所以上面的代码对数据进行了base64编码之后发送。 实际接收到的数据为:
有了这两个数据就可以去解密图片内容了:
解密之后的图片内容: 鉴于图片内容比较暴力,这里就不展示了,感兴趣的自己去解析即可。到这里图片的内容算是处理完成了。
图片可以查看之后,主要的目标是要爬取数据,那么数据来源就很关键。通过接口格式猜测,请求视频列表的接口应该是143K9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6S2M7r3W2Q4x3X3c8S2L8q4)9J5k6i4k6A6M7r3#2^5L8i4S2Q4x3X3g2U0L8W2)9J5c8Y4j5I4i4K6u0r3N6X3W2V1k6h3!0K6i4K6u0r3L8h3g2F1N6g2)9J5c8U0m8Q4x3@1k6H3j5i4W2D9L8$3q4V1i4K6y4p5c8q4)9J5y4e0u0r3f1s2u0Z5z5s2N6&6y4p5!0p5c8X3q4d9h3f1A6s2M7h3S2G2K9$3N6Q4x3U0f1K6c8q4)9J5y4e0y4p5i4K6u0W2z5g2k6b7y4K6q4S2c8p5W2K9k6$3#2K9c8X3x3$3h3o6y4D9i4K6t1#2x3V1u0X3f1r3!0q4g2r3k6H3h3r3b7@1d9Y4c8Q4x3U0f1J5b7W2c8z5y4o6W2C8M7K6c8W2k6p5D9^5N6X3N6@1L8o6q4j5d9p5q4$3c8g2m8*7b7e0W2q4b7K6N6E0g2p5u0B7g2e0f1&6M7p5#2$3g2%4N6m8f1%4S2e0L8o6W2F1g2g2q4m8i4K6t1#2x3V1u0H3P5W2c8I4K9V1&6C8x3r3S2*7b7f1!0Q4x3U0f1J5c8W2c8y4h3U0k6X3b7X3E0f1N6%4c8v1y4q4x3I4x3g2)9J5y4e0u0r3y4q4u0m8b7Y4N6o6f1g2k6K6i4K6t1#2x3V1k6D9K9K6g2h3N6f1c8^5j5@1j5$3c8q4g2k6N6g2j5%4h3r3&6w2e0#2)9J5y4e0u0r3d9e0t1#2N6$3!0K9h3r3u0a6e0W2W2H3y4o6N6A6i4K6t1#2x3V1j5I4K9o6g2a6c8$3y4i4x3@1V1&6x3f1I4X3d9U0c8s2z5r3x3H3d9q4A6u0y4$3E0D9K9e0g2d9e0r3u0Y4L8U0u0d9N6Y4q4@1y4V1A6C8z5o6V1%4k6p5S2C8L8h3&6B7y4r3^5J5N6r3u0Z5L8#2x3K6L8V1y4Q4x3U0f1J5b7Y4l9K6K9s2S2S2N6f1N6y4c8@1R3J5i4K6t1#2x3V1u0&6L8o6q4C8j5h3R3$3h3V1N6w2e0q4)9J5y4e0u0r3j5i4u0B7f1Y4N6n7d9#2t1^5i4K6t1#2x3V1u0T1N6U0N6j5b7@1q4H3e0#2)9J5y4e0u0n7g2@1#2J5K9Y4N6^5e0h3c8v1b7W2A6B7P5r3&6h3y4X3!0T1L8V1y4r3y4f1E0I4h3f1N6@1j5i4g2g2b7K6g2K9e0U0x3I4b7h3A6s2i4K6t1#2x3V1j5%4K9h3I4w2M7U0N6b7c8#2W2I4N6e0u0T1i4K6t1#2x3V1k6J5f1%4q4H3N6W2m8j5g2@1u0A6P5X3#2#2N6K6W2v1c8U0q4W2i4K6t1#2x3V1u0F1b7K6b7I4N6X3Z5$3j5V1!0n7h3s2R3@1M7%4N6m8d9s2y4n7c8V1k6w2y4U0c8o6y4o6k6T1P5f1W2^5L8%4y4p5e0V1S2z5y4r3V1#2k6r3!0X3L8$3q4c8d9l9`.`. 请求接口比较简洁,应该是把所有的参数都放到了payload下面 返回的数据比较复杂,头部包含了大量的信息: 并且返回的数据进行了加密: 要想通过接口访问数据,那么就要解析请求数据,解密返回的数据。 通过参数的payload最终可以定位到以下代码:
通过frida hook 对b.c函数进行hook:
所以如果要进行接口加密,那么只需要知道加密的key即可,以为通过上面的代码分析可以知道,iv是一个随机函数生成的长度为16的数组。如果要想模拟的真实一点可以自己写一个随机函数,当然也可以直接使用jeb解析出来的数组去请求也是ok的。 捕获到的数据如下;
将euZN1Gg3JIwWOEWhmE7C4l5dSSRU34fyuPMXjtuoqVs= base64 decode之后即可获得加密用的key。 有了这些数据,那么就可以发送请求了, 测试代码如下:
此时虽然已经能够发送请求了,但是返回的数据是加密的,如果要想获取直接可用的数据,那么就需要对返回的数据进行解密。 通过层层分析,可以定位到响应数据的解密函数为:
同样对对该函数进行hook:
获取数据:
多次请求就会发现,key是固定的。但是iv却是变的。跟踪iv的数据来源,最终可以定位到
为了简便期间,把上面的函数全部hook掉:
最终捕获到的数据如下:
通过关联可以找到,iv的数据来源为X-VTag字段。所以请求之后从response header中取出X-VTag就可以解密数据了。 解密代码:
到这里接口的解密基本就完成了,可以获取app的视频基础信息了。
虽然现在视频列表数据已经有了,但是在视频信息中并没有播放地址。所以最后的工作就是获取视频的播放地址。继续抓包可以看到视频地址信息为:aacK9s2c8@1M7s2y4Q4x3@1q4Q4x3V1k6Q4x3V1k6S2M7r3W2Q4x3X3g2T1k6s2S2^5L8#2)9J5k6h3y4F1i4K6u0r3N6U0q4Q4x3V1k6$3K9h3c8W2L8#2)9J5c8X3W2F1k6X3!0Q4x3V1j5$3y4K6b7K6x3W2)9K6c8Y4m8S2P5h3I4G2j5h3c8Q4x3@1c8Z5b7h3&6o6N6e0q4C8f1f1S2&6x3r3S2o6M7X3c8K9L8K6c8K6N6#2W2c8i4K6t1#2x3@1c8Q4x3U0f1K6c8q4)9J5k6f1u0J5d9p5u0c8P5p5A6K6b7g2)9J5y4e0u0n7k6i4k6i4j5f1S2y4j5W2A6k6e0X3A6a6K9U0k6n7y4$3E0p5h3X3D9&6z5p5W2T1f1@1Z5&6y4r3Z5J5c8h3S2Z5N6f1#2I4j5#2V1&6f1X3E0$3x3K6N6y4f1X3N6U0h3f1W2*7M7s2u0b7M7s2S2j5x3q4k6v1d9$3y4m8j5K6c8K6c8@1q4u0c8#2)9J5y4e0u0r3N6r3N6c8x3#2A6i4i4K6t1#2x3V1k6K6L8V1c8m8b7#2)9J5y4e0u0r3k6q4g2@1b7e0N6k6x3V1q4X3j5h3k6E0f1Y4y4B7P5p5q4Z5P5X3q4*7L8r3u0H3e0$3)9$3b7g2S2D9K9o6m8i4c8o6V1I4b7$3q4q4y4@1c8Q4x3U0f1J5c8Y4W2E0g2K6p5J5z5i4m8Q4x3U0f1J5c8Y4R3#2P5p5#2v1j5K6S2z5g2%4k6S2f1V1u0s2L8g2q4e0f1f1I4u0M7$3I4W2x3r3S2V1K9i4m8j5f1f1E0W2e0@1E0j5e0U0y4d9b7X3u0h3e0s2j5I4y4o6y4H3y4%4N6a6e0r3y4S2j5W2k6a6K9q4W2w2x3U0u0m8e0f1u0#2j5#2A6D9x3r3c8o6h3h3)9%4e0Y4Z5I4i4K6t1#2x3V1u0$3x3W2g2t1z5p5q4D9j5h3W2y4d9h3E0%4N6$3p5$3d9W2m8F1h3W2M7^5b7#2q4S2P5h3S2v1M7Y4u0q4h3q4f1&6x3i4m8Z5M7$3u0Q4x3U0f1J5b7X3q4E0z5s2A6z5M7U0W2o6d9i4k6e0k6W2c8^5k6#2g2S2d9g2)9J5y4e0u0n7e0#2S2J5P5i4W2@1i4K6t1#2x3V1u0q4M7$3#2&6b7V1#2E0x3V1y4y4b7W2g2g2c8o6f1J5f1e0V1#2d9p5u0J5N6K6m8J5f1$3N6d9f1g2y4^5c8Y4g2J5K9V1E0c8N6r3N6U0K9%4S2c8M7g2k6&6M7$3S2%4c8r3&6w2i4K6t1#2x3V1j5^5z5o6c8g2f1X3u0o6d9#2f1&6g2$3!0#2N6W2c8B7M7p5g2F1d9r3c8U0i4K6t1#2x3@1b7`. 使用上面分析的数据,对于请求进行解密, 并且模拟请求:
返回数据信息:
到这里全部的数据接本就都有了,不过还有最后一点需要处理那就是返回的m3u8文件也是加密的,需要进行解密。解密方式与其他请求的解密方式一致。 不仅如此,返回的播放列表的地址也是带有效期参数。 对于播放地址,请求之后进行解密就可以看到m3u8文件的全部内容了:
解密后的m3u8文件就可以扔给ffmpeg下载了:
apk文件下载地址: ZnUyLmxpdmUv
public static final String dbImgKey() {
return CipherCore.get("29993fb387b37c932b56fd54b130e0c6");
}
public static final String decodeImgIv() {
return CipherCore.get("f3d9434408e52778164db2214e3a0a22");
}
[培训]科锐逆向工程师培训第53期2025年7月8日开班!
最后于 2020-7-1 13:53
被obaby编辑
,原因: