示例APP酷安
用Fiddler进行抓包,多次抓取进行对比。
用jadx打开APP,看有没有加固,有加固就脱壳
搜索请求头X-App-Token看有没有线索
在组装参数,看一下每个变量的由来
点进方法,看一下怎么生成as的
这里就可以直接使用rpc进行方法调用,传进两个参数一个是上下文,一个是uuid,就不用去管它是怎么实现的。
import frida
import sys
import os
import uuid0
hook_code = """
rpc.exports = {
gettoken: function(str){
var token = "";
Java.perform(
function(){
var AuthUtils = Java.use('com.coolapk.market.util.AuthUtils');
//拿到context上下文
var currentApplication = Java.use('android.app.ActivityThread').currentApplication();
var context = currentApplication.getApplicationContext();
token = AuthUtils.getAS(context, str);
send(token);
}
)
return token;
}
};
"""
def on_message(message, data):
if message['type'] == 'send':
print(message['payload'])
elif message['type'] == 'error':
print(message['stack'])
uuid = str(uuid0.generate()) # 自动生成uuid
process = frida.get_usb_device().attach('com.coolapk.market')
script = process.create_script(hook_code)
script.on('message', on_message)
script.load()
script.exports.gettoken(uuid)
运行后成功拿到token
有了token后就可以对app进行抓取了
import frida
import sys
import os
import uuid0
import requests
import json
import pymongo
# mongodb
MONGO_URI = 'localhost'
MONGO_DB = 'kuAn'
client = pymongo.MongoClient(MONGO_URI)
db = client[MONGO_DB]
hook_code = """
rpc.exports = {
gettoken: function(str){
var token = "";
Java.perform(
function(){
var AuthUtils = Java.use('com.coolapk.market.util.AuthUtils');
//拿到context上下文
var currentApplication = Java.use('android.app.ActivityThread').currentApplication();
var context = currentApplication.getApplicationContext();
token = AuthUtils.getAS(context, str);
//send('token:' + token);
}
)
return token;
}
};
"""
def adbforward():
"""frida 端口转发"""
os.system("adb forward tcp:27042 tcp:27042")
os.system("adb forward tcp:27043 tcp:27043")
def on_message(message, data):
if message['type'] == 'send':
print(message['payload'])
elif message['type'] == 'error':
print(message['stack'])
def process_hook():
"""启动hook程序"""
# adbforward()
process = frida.get_usb_device().attach('com.coolapk.market')
script = process.create_script(hook_code)
script.on('message', on_message)
script.load()
return script
def get_token(script,uuid):
"""得到token"""
token = script.exports.gettoken(uuid)
return token
def set_headers():
"""请求头"""
uuid = str(uuid0.generate()) # 自动生成uuid
script = process_hook()
token = get_token(script, uuid)
headers = {
"User-Agent": "Dalvik/2.1.0 (Linux; U; Android 6.0.1; Nexus 6P Build/MTC20L) (#Build; google; Nexus 6P; MTC20L; 6.0.1) +CoolMarket/9.2.2-1905301",
"X-Requested-With": "XMLHttpRequest",
"X-Sdk-Int": "23",
"X-Sdk-Locale": "zh-CN",
"X-App-Id": "com.coolapk.market",
"X-App-Token": token,
"X-App-Version": "9.2.2",
"X-App-Code": "1905301",
"X-Api-Version": "9",
"X-App-Device": "QZDIzVHel5EI7UGbn92bnByOpV2dhVHSgsjN3ozN4ozMGpjNxoDR4oDMBByOsxWduByO0ATM3AjMwIDM2gjN3YDOgsTYmRWZyITOjRTYxATMilzN",
"X-Dark-Mode": "0",
"Host": "api.coolapk.com",
"Connection": "Keep-Alive",
"Accept-Encoding": "gzip"
}
return headers
def get_Headlines_page(page):
"""得到每个专栏每页文章id"""
headers = set_headers()
# 头条专栏
url = "https://api.coolapk.com/v6/main/indexV8?page="+str(page)
# 热榜专栏
#url = "https://api.coolapk.com/v6/page/dataList?url=V9_HOME_TAB_RANKING&title=%E7%83%AD%E6%A6%9C&page="+str(page)
response = requests.get(url, headers=headers)
if response.status_code == 200:
html = response.text
# print(html)
items = json.loads(html).get('data')
# print(data)
for item in items:
yield {
'id': item.get('entityId')
}
def get_one_page(items):
"""文章详情页"""
# 头条专栏文章接口
base_url = "https://api.coolapk.com/v6/feed/detail?id={}&fromApi=%2Fv6%2Fmain%2FindexV8%3F"
# 热榜专栏文章接口
#base_url = "https://api.coolapk.com/v6/feed/detail?id={}&fromApi=V9_HOME_TAB_RANKING"
# 文章评论接口
#comment_url = "https://api.coolapk.com/v6/feed/replyList?id={}&listType=lastupdate_desc&discussMode=1&feedType=feed&blockStatus=0&fromFeedAuthor=0"
headers = set_headers()
for item in items:
# print(item)
url = base_url.format(item.get('id'))
response = requests.get(url, headers=headers)
if response.status_code == 200:
item = json.loads(response.text).get('data')
if item == None:
continue
#print(item)
yield {
'id': item.get('id'), # 文章id
'uid': item.get('uid'), # 用户id
'username': item.get('username'), # 用户名字
'title': item.get('title'), # 文章标题
'message': item.get('message'), # 文章内容
'likenum': item.get('likenum'), # 点赞数
'commentnum': item.get('commentnum'), # 评论数
'picArr': item.get('picArr') # 文章图片
}
def save_to_mongo(data):
"""将文章存到数据库"""
# 根据文章的id为主键
if db[MONGO_DB].update({'id': data['id']}, {'$set': data}, True):
print('Saved to Mongo', data['title'])
else:
print('Saved to Mongo Failed', data['title'])
def run():
"""程序入口"""
try:
for i in range(0, 100):
items = get_Headlines_page(i)
datas = get_one_page(items)
for data in datas:
# print(data)
# 存到数据库
save_to_mongo(data)
except Exception as e:
print(e)
if __name__ == "__main__":
run()
运行结果如下
到mongodb看下也有数据
整个过程还是挺简单的,使用rpc可以直接跳过加密过程得到结果。