今日目标
这里以崔大爬虫练习站 app 的第 5 题作为逆向题目
aHR0cHM6Ly9zY3JhcGUuY2VudGVyLw==
抓包分析
先下载 app ,然后简单抓个包看看
可以看到请求中带有一个加密的参数token
返回的是一个json
字符串
下拉刷新可以看到token
是不断变化的,现在用jadx
反编译看看,找找token
的逻辑
静态分析定位逻辑
通过检索"token"
在结果处查找用例
可以找到下面的代码处
然后这里的Encrypt
可以看到使用了shaEncrypt
这个方法
通过shaEncrypt
的逻辑可以知道这里进行了一次sha1
加密
未知的就是传入的str
的值,这一步可以通过frida hook
得到结果
动态调试确认逻辑
简单写一个frida
脚本,打印一下shaEncrypt
的入参和返回值
console.log("脚本加载成功"); function main(){ Java.perform(function(){ var Encrypt = Java.use("com.goldze.mvvmhabit.utils.Encrypt"); Encrypt.shaEncrypt.implementation = function (arg1){ console.log("\Encrypt.shaEncrypt\n"); console.log("Input str=" + arg1 + "\n"); var shaEncrypt_result = this.shaEncrypt(arg1); console.log("\nOut Rc=" + shaEncrypt_result); return shaEncrypt_result; } }) } setImmediate(main)
可以看到入参的参数的就是url + , + 时间戳
算法是sha1
,这一点可以通过加密站来验证
接下来将结果和时间戳经过了一次base64
,得到最终的结果
我们来测试一下看看是不是一样的
console.log("脚本加载成功"); function main(){ Java.perform(function(){ var Encrypt = Java.use("com.goldze.mvvmhabit.utils.Encrypt"); Encrypt.shaEncrypt.implementation = function (arg1){ console.log("\Encrypt.shaEncrypt\n"); console.log("Input str=" + arg1 + "\n"); var shaEncrypt_result = this.shaEncrypt(arg1); console.log("\nOut Rc=" + shaEncrypt_result); return shaEncrypt_result; } var Base64 = Java.use("android.util.Base64"); Base64.encodeToString.overload('[B', 'int').implementation = function (arg1,arg2){ var encodeToString_result = this.encodeToString(arg1,arg2); console.log("\nOut Rc=" + encodeToString_result); return encodeToString_result; } }) } setImmediate(main)
可以看到这里打印的结果验证了我们的猜想。
所以token
的生成算法就是base64(sha1(path,时间戳),时间戳)
写一段代码测试一下
import requests import hashlib import base64 import time def encode_sha1(data, encode_method="utf-8"): """ sha1加密 :param data: 待加密字符串 :param encode_method: 编码方法,默认utf-8 :return: 40长度字符串 """ bytes_data = data.encode(encode_method) m = hashlib.sha1() m.update(bytes_data) return m.hexdigest() def encode_base64(data, encode_method="utf-8"): """ base64加密 :param data: 待加密字符串 :param encode_method: 编码方法,默认utf-8 :return: """ bytes_data = data.encode(encode_method) result = base64.b64encode(bytes_data).decode() return result def get_params(): # base64(sha1(path,时间戳),时间戳) path = "/api/movie," time_str = str(int(time.time())) sha1_result = encode_sha1( path + time_str) base64_params = sha1_result + ',' + time_str base64_result = encode_base64(base64_params) # print(base64_result) return base64_result def main(): headers = { 'log-header': 'I am the log request header.', 'Host': 'app5.scrape.center', 'Connection': 'Keep-Alive', 'Accept-Encoding': 'gzip', 'User-Agent': 'okhttp/3.10.0', } params = ( ('offset', '20'), ('limit', '10'), ('token', get_params()), ) response = requests.get('https://app5.scrape.center/api/movie/', headers=headers, params=params) print(response.text) if __name__ == '__main__': main()
结果如下
好了,以上就是今天的全部内容了。
我是没有更新就在摸鱼的咸鱼
收到请回复~
我们下次再见。