通过抓包可以看到请求参数中X-App-Token: e8f1c71569a7166b6aa9723342923606edc38cb9-c72d-3bc4-8e82-6fd9212d77a00x5fdb0663
每次请求都是变化的,这里需要反编译app进行进一步的分析。
直接使用jadx反编译app并通过搜索相关参数定位相关代码
private String[] createHeaders() {
Locale locale = Locale.getDefault();
String valueOf = String.valueOf(VERSION.SDK_INT);
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append(locale.getLanguage());
stringBuilder.append(Constants.ACCEPT_TIME_SEPARATOR_SERVER);
stringBuilder.append(locale.getCountry());
String stringBuilder2 = stringBuilder.toString();
String as = AuthUtils.getAS(this.appContext, this.deviceId);
StringBuilder stringBuilder3 = new StringBuilder();
stringBuilder3.append(getAndroidId());
stringBuilder3.append("; ");
stringBuilder3.append(getImeiOrMeid());
stringBuilder3.append("; ");
stringBuilder3.append(getImsi());
stringBuilder3.append("; ");
stringBuilder3.append(getMacAddress());
stringBuilder3.append("; ");
stringBuilder3.append(Build.MANUFACTURER);
stringBuilder3.append("; ");
stringBuilder3.append(Build.BRAND);
stringBuilder3.append("; ");
stringBuilder3.append(Build.MODEL);
String replaceAll = new StringBuilder(Base64.encodeToString(stringBuilder3.toString().getBytes(), 0)).reverse().toString().replaceAll("\\r\\n|\\r|\\n|=", "");
String str = "0";
if (AppHolder.getAppTheme().isNightTheme()) {
str = "1";
} else if (AppHolder.getAppTheme().isAmoledTheme()) {
str = "2";
}
return new String[]{
HttpHeaders.USER_AGENT, this.userAgent, "X-Requested-With", "XMLHttpRequest", "X-Sdk-Int", valueOf, "X-Sdk-Locale", stringBuilder2, "X-App-Id", BuildConfig.APPLICATION_ID, "X-App-Token", as, "X-App-Version", this.appVersionName, "X-App-Code", String.valueOf(this.appVersionCode), "X-Api-Version", EntityListFragment.APK_TYPE_DYH, "X-App-Device", replaceAll, "X-Dark-Mode", str};
}
分析代码得出as的值赋给X-App-Token,as = AuthUtils.getAS(this.appContext, this.deviceId);
提示:frida-rpc远程调用某个方法时,如果该方法需要传参,需要自己手动组装正确的参数。
如上图所示调用getAS需要传递两个参数context
和str
:
context上下文组装方式如下:
//拿到context上下文
var currentApplication = Java.use('android.app.ActivityThread').currentApplication();
var context = currentApplication.getApplicationContext();
str这个参数是我们不知道的,我们可以对getAS进行普通的hook操作,来得到str的值。
import frida #导入frida模块
import sys #导入sys模块
jscode = """
Java.perform(function(){
var AuthUtils = Java.use('com.coolapk.market.util.AuthUtils') // 类的加载路径
AuthUtils.getAS.implementation = function(a,b){ // str为getAS的参数,原getAS需要几个参数就写几个
send(a);
send(b); // 这里的b就是str的值
var as = this.getAS(a,b); // 源函数有返回值 这里我们也将得到的返回值return
return as
};
});
"""
def on_message(message,data): #js中执行send函数后要回调的函数
if message["type"] == "send":
print("[*] {0}".format(message["payload"]))
else:
print(message)
process = frida.get_usb_device().attach('com.coolapk.market') # app包名
script = process.create_script(jscode) #创建js脚本
script.on('message',on_message) #加载回调函数,也就是js中执行send函数规定要执行的python函数
script.load() #加载脚本
sys.stdin.read()
注意:这种调用方式需要我们手动触发api调用getAS这个方法才会执行我们对应的脚本。
str为固定值edc38cb9-c72d-3bc4-8e82-6fd9212d77a0
通过这种调用方式去主动调用相关方法来生成加密的token
import codecs
import frida
import os
def adbforward():
os.system("adb forward tcp:27042 tcp:27042")
os.system("adb forward tcp:27043 tcp:27043")
hook_code = '''
rpc.exports = {
// 函数名gethello
gethello: function(str){
send('heelo');
Java.perform(function(){
//拿到context上下文
var currentApplication = Java.use('android.app.ActivityThread').currentApplication();
var context = currentApplication.getApplicationContext();
// use 加载的类路径
var AuthUtils = Java.use('com.coolapk.market.util.AuthUtils');
//f = tt.$new();
var sig = AuthUtils.getAS(context, str); // context,str组要自己组装
send(sig);
}
)
}
};
'''
def on_message(message, data):
if message['type'] == 'send':
print(message['payload'])
elif message['type'] == 'error':
print(message['stack'])
process = frida.get_usb_device().attach('com.coolapk.market')
script = process.create_script(hook_code)
script.on('message', on_message)
script.load()
script.exports.gethello('edc38cb9-c72d-3bc4-8e82-6fd9212d77a0')
token对比
# rpc调用生成的
4bdc740d8fff25d577ed9b28cca6b34cedc38cb9-c72d-3bc4-8e82-6fd9212d77a00x5fdb2185
# 抓包得到的
e8f1c71569a7166b6aa9723342923606edc38cb9-c72d-3bc4-8e82-6fd9212d77a00x5fdb0663
根据这种主动的调用方式我们可以搭建一个web服务,来对外使用。
正常的hook方式需要我们手动触发执行到相关方法才会执行对应脚本,rpc这种方式可以主动调用方法不需要我们手动触发。