table des matières
1. Utilisez Fiddler pour capturer l'application
En capturant le paquet, vous pouvez voir que X-App-Token: e8f1c71569a7166b6aa9723342923606edc38cb9-c72d-3bc4-8e82-6fd9212d77a00x5fdb0663
chaque requête dans les paramètres de la requête change. Ici, vous devez décompiler l'application pour une analyse plus approfondie.
Deuxièmement, décompilez l'application pour localiser les codes clés
Utilisez directement jadx pour décompiler l'application et recherchez le code pertinent en recherchant les paramètres pertinents
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};
}
Analysez le code pour trouver que la valeur de as est attribuée à X-App-Token,as = AuthUtils.getAS(this.appContext, this.deviceId);
Conseil: lorsque frida-rpc appelle une méthode à distance, si la méthode doit passer des paramètres, vous devez assembler manuellement les paramètres corrects par vous-même.
Comme le montre la figure ci-dessus, l'appel de getAS nécessite de passer deux paramètres context
et str
:
Le contexte est assemblé comme suit:
//拿到context上下文
var currentApplication = Java.use('android.app.ActivityThread').currentApplication();
var context = currentApplication.getApplicationContext();
Le paramètre str nous est inconnu. Nous pouvons effectuer des opérations de hook ordinaires sur getAS pour obtenir la valeur de 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()
Remarque: Cette méthode d'appel nous oblige à déclencher manuellement l'API pour appeler la méthode getAS pour exécuter notre script correspondant.
str est une valeur fixeedc38cb9-c72d-3bc4-8e82-6fd9212d77a0
Trois méthodes liées aux appels Frida-RPC
Utilisez cette méthode d'appel pour appeler activement les méthodes associées afin de générer des jetons chiffrés
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')
comparaison de jetons
# rpc调用生成的
4bdc740d8fff25d577ed9b28cca6b34cedc38cb9-c72d-3bc4-8e82-6fd9212d77a00x5fdb2185
# 抓包得到的
e8f1c71569a7166b6aa9723342923606edc38cb9-c72d-3bc4-8e82-6fd9212d77a00x5fdb0663
Selon cette méthode d'appel active, nous pouvons créer un service Web à usage externe.
La méthode de hook normal nous oblige à déclencher manuellement l'exécution de la méthode appropriée avant d'exécuter le script correspondant. La méthode rpc peut appeler activement la méthode sans que nous la déclenchions manuellement.