第一篇有关app逆向的文章,可能篇幅较长,请耐心阅读。
首先来介绍一下需要用到的部分工具和安装方式,然后借助某漫画app,来详细讲解一下工具的使用,以及如何查找加密的流程。
文章中用到的安装包,下载速度超慢,不想下载或者下载不了的,可以直接联系我。
声明本文章只做技术交流,如有侵权请联系删除。
一、目标网站:
aHR0cHM6Ly93d3cud2FuZG91amlhLmNvbS9hcHBzLzY1MTM5ODA=
打开网站下载对应版本的apk,本文使用的是最新3.0.1版本。
二、环境安装:
jdk下载地址:
https://www.oracle.com/java/technologies/javase/javase-jdk8-downloads.html
官网下载需要注册oracle账号,找到对应版本下载安装即可。
另外需要安装配置虚拟机或者配置真机用来抓包。
三、工具介绍:
1.dex2jar
功能:反编译apk得到Java源代码
下载地址:
https://sourceforge.net/projects/dex2jar/files/
下载最新版本解压即可,后面会介绍如何使用。
2.jd-gui
功能:打开classes-dex2jar.jar查看源码
下载地址:
http://java-decompiler.github.io/
下载对应的系统版本解压。
四、抓包分析
打开app,随意点击一部漫画作品,进入到目录页面,点击任一章节进入漫画展示页面。
Charles中通过查看响应,确定接口,查看参数信息。
继续下滑,翻到下一章节,查看接口参数信息。
对比两个章节的请求接口,找到变动的参数分别是client_sign、client_time,其中client_time为13位的时间戳,而client_sign即为需要找的加密签名。
五、反编译apk
1、反编译apk
修改apk文件后缀为.rar,解压,打开找到classes.dex文件
拷贝classes.dex到下载好的dex2jar-2.0目录下
打开终端,进入到dex2jar-2.0目录下执行反编译命令
./d2j-dex2jar.sh ./classes.dex
我这里已经执行过,生成了.jar包
注意win下执行的命令跟mac下不同
./d2j-dex2jar.bat ./classes.dex
执行过程中,如果出现没有权限的问题,解决方法如下
sudo chmod +x ./d2j-dex2jar.sh # 增加可执行权限
2、打开jar包
打开安装好的jd工具
将反编译后的jar包,拖拽到jd工具里即可。
六、加密定位
定位方法:直接搜索加密字段client_sign
继续在jd工具上,点击搜索,设置字符串查找,双击b.class文件。
跳转到如下图所示位置
向上查看完整代码部分,点击str2高亮显示。
注意看下图中几行a1.L()部分,是不是跟抓包的接口参数名称十分相似,找其中的几个固定参数对比下,可以得到如下结论,client_sign的加密值就是str2的值。
继续查看第二个红框,str2的值是str3的结果,而str3是由l.aT()调用字符串组合的参数生成的。
接着继续分析l.aT()的参数
分别点击str4,str5,str6,str1,str7使其高亮显示,可以很直观的看到具体代表的参数名称。
最后分析aT(),点击aT进入到函数内部,可以看到整个java代码就是对参数进行md5的简单加密。
七、代码实现
1、验证client_sign
查看请求参数
提取请求参数值,构造加密参数,用python实现md5加密
对比两处生成的结果,client_sign结果一致,加密逻辑正确。
2、验证接口请求
修改时间,测试请求,代码如下
import requests
import time
import hashlib
ts = int(time.time()*1000)
def get_sign():
str4 = '3.0.1'
str5 = str(ts)
str6 = '569A83D51DBC08D59CCC9E67EAE13CB4'
str1 = '0'
str7 = ''
sign_param = str4 + "android" + str5 + "e571dd8bd67803995b9bdcfefb58662b" + str6 + str1 + str7 + "{54563A97-2BBA-7F31-D4C1-8EF72F4A98E6}"
hm = hashlib.md5()
hm.update(sign_param.encode('utf-8'))
return hm.hexdigest()
def get_image_link():
search_api = 'http://api.manhua.weibo.com/client/comic/play?chapter_id=204732'
sign = get_sign()
print(sign)
data = {
"app_devicetoken": "e571dd8bd67803995b9bdcfefb58662b",
"client_sign": sign,
"client_time": str(ts),
"client_type": "android",
"client_ver": "3.0.1",
"phone_mark": "569A83D51DBC08D59CCC9E67EAE13CB4",
"sina_token": "",
"sina_uid": '0',
}
headers = {
'VREADREFER': 'vmh_client',
'Host': 'api.manhua.weibo.com',
'Content-Type': 'application/x-www-form-urlencoded; charset=utf-8',
'User-Agent': 'okhttp/3.8.0',
}
response = requests.post(search_api, headers=headers, data=data).json()
items = response['data']['json_content']['page']
for item in items:
image_link = item['mobileImgUrl']
print(image_link)
if __name__ == '__main__':
get_image_link()
返回结果如下
搞定,如果要执行后续翻页操作,在目录页面拿到每页的ID即可。
对你有帮助,请扫码关注!感谢!
公众号:逆向旅行
微信号:fzcoder888888
定期分享Python进阶技术,爬虫