Análisis de un protocolo de inicio de sesión de una aplicación deportiva

Como he estado ocupado con los exámenes y no he estudiado durante mucho tiempo, analicé una aplicación al azar hoy y la consideré como un currículum de capacitación.

Análisis de un protocolo de inicio de sesión de APP

1. Captura de paquetes

El análisis principal es el protocolo de inicio de sesión de verificación del teléfono móvil de la APLICACIÓN. Primero, inicie Fillder para comenzar a capturar paquetes, abra la aplicación e ingrese el número de teléfono móvil y el código de verificación relevantes.

Inserte la descripción de la imagen aquí

Los paquetes capturados son los siguientes:

POST https://api.gotokeep.com/account/v2/sms HTTP/1.1
Content-Type: application/json; charset=UTF-8
Content-Length: 163
Host: api.gotokeep.com
Connection: Keep-Alive
Accept-Encoding: gzip
x-os-version: 5.1.1
x-geo: 0.0,0.0
x-channel: adhub_cpa__siruifan_04
x-ads: gYdZHMFkdTLC1JvfK4AsSmouEN3+S+OsjkFGaZ9kygpo/FGeJ5N7iJdMyIBtadqqUBgJnRBFi+Ri6KYKwFCVqFVPgWMaqbAAp5JiY9yFM4rGVByS9EsGHY0DB9ekNkSw+9v/Xu/BsbMxxEm9Et4MJT4QbLGf9ifhngIO3aDdE3bN+3aB801nvmOb8ZYsJ2U4Mw2sAGcnJrcDFU2kX3ASbUfhJYGWCkELV8Y6iKoPrPr/wNfkDmtuWUNYUSpSdYlPWWrANkgrPW5YL4wWIQwfVf7cDX5ItxTOGl00XYlKUcnwOsm6JAjdF5Voc0u9mmiT
x-locale: zh--CN
x-screen-height: 800
x-is-new-device: true
x-carrier: 70120
User-Agent: Keep+6.43.0%2FAndroid+5.1.1-24528+Xiaomi+MI+9
x-manufacturer: Xiaomi
x-keep-timezone: Asia/Shanghai
x-timestamp: 1594278593217
x-screen-width: 450
x-connection-type: 4
x-app-platform: keepapp
x-os: Android
x-device-id: 865166020644319111111111111111119da6a866
x-version-name: 6.43.0
x-user-id: 
x-version-code: 24528
x-model: MI+9
sign: 5257caf9b35de7f6f9805f3e814773036f6c73e1

Dos, anuncios X

Primero analice los anuncios x:

x-ads: gYdZHMFkdTLC1JvfK4AsSmouEN3+S+OsjkFGaZ9kygpo/FGeJ5N7iJdMyIBtadqqUBgJnRBFi+Ri6KYKwFCVqFVPgWMaqbAAp5JiY9yFM4rGVByS9EsGHY0DB9ekNkSw+9v/Xu/BsbMxxEm9Et4MJT4QbLGf9ifhngIO3aDdE3bN+3aB801nvmOb8ZYsJ2U4Mw2sAGcnJrcDFU2kX3ASbUfhJYGWCkELV8Y6iKoPrPr/wNfkDmtuWUNYUSpSdYlPWWrANkgrPW5YL4wWIQwfVf7cDX5ItxTOGl00XYlKUcnwOsm6JAjdF5Voc0u9mmiT

Buscamos la cadena directamente y recibimos anuncios x ,

Inserte la descripción de la imagen aquí

Inserte la descripción de la imagen aquí

Obviamente b () devuelve la cadena que queremos analizar, entra directamente

Inserte la descripción de la imagen aquí
Puede ver que el método b es serializar algunos parámetros y luego llamar a mb () para procesar y devolver

Seguimiento

Inserte la descripción de la imagen aquí

En este punto podemos conseguir que el algoritmo de encriptación es el algoritmo AES. Luego de encriptar por el algoritmo AES se realiza la codificación base64. Correspondiente al algoritmo AES, podemos ver que se ha dado el IV 2346892432920300y la clave es c(CypLib.a())devuelta por uno .

Inserte la descripción de la imagen aquí

Continúe analizando y encuentre que CypLib.a () tiene dos valores de retorno. Si es verdadero, ingrese el método nativo para el cálculo, si es falso, devolverá directamente una clave.
Entonces, ¿cómo juzgar esta clave? Probablemente existan las siguientes ideas

(1)查找a(Context context)的交叉引用,判断在对字符串进行加密处理时,是否调用了该方法,若没有调用
,就会返回false,直接对"Pl*Rxe76fx'fWWqR"加密,反之"Pl*Rxe76fx'fWWqR"就会进入native层进行处理。

(2)由于只有这两个key,我们可以通过穷举的方式,直接分析得出这两个key,当然也是比较复杂的

(3)动态调试smali代码,直接定位到返回的地方,获取c()方法的返回值

(4)frida Hook直接找到c()方法返回值

Obviamente, a través del análisis, es mucho más fácil usar la depuración dinámica o frida hook. Si (1) y (2) se usan para el análisis, es muy probable que el archivo so deba ser analizado. Aquí es posible que deba copiar manualmente el código pseudo-c de la capa so, y luego modificarlo y ejecutarlo. Obtenga el valor de retorno.

Frida hook se usa directamente aquí. Hay muchos tutoriales sobre frida hook, por lo que no entraré en detalles aquí. Inicie frida-server y ejecute el script de la siguiente manera

import frida, sys


def on_message(message, data):
    if message['type'] == 'send':
        print("[*] {0}".format(message['payload']))
    else:
        print(message)


jscode = """
Java.perform(function () {
    var m = Java.use('l.q.a.y.p.m');
    m.c.implementation = function (param1) {
        send("Hook Start...");
        send(param1);
        var result=this.c(param1);
        send("AESKey is :"+result);
        return result;
    }
});
"""

process = frida.get_usb_device().attach('com.gotokeep.keep')
script = process.create_script(jscode)
script.on('message', on_message)
script.load()
sys.stdin.read()

Finalmente puedes conseguir la llave

Inserte la descripción de la imagen aquí

En este punto, se ha resuelto la lógica principal del algoritmo de anuncios x,
key = 56fe59; 82g: d873c, iv = 2346892432920300

Luego inicie la operación de descifrado directamente:

import base64
from Crypto.Cipher import AES
def base64_encode(bdate):
    return base64.b64encode(bdate).decode()

def base64_decode(date_str):
    return base64.b64decode(date_str)

def aes_decrypt(Key,iv,crypted):
    decryptor=AES.new(Key,AES.MODE_CBC,iv=iv)
    return decryptor.decrypt(crypted)

def aes_encrypt(Key,iv,raw_data):
    if isinstance(raw_data,str):
        raw_data=raw_data.encode()
        #不满足8的倍数补齐
    if len(raw_data)%8 !=0:
        pad_len=8-(len(raw_data)%8)
        raw_data+=bytes([pad_len]*pad_len)
    encryptor=AES.new(Key,AES.MODE_CBC,iv=iv)
    return encryptor.encrypt(raw_data)

if __name__=='__main__':
    import json
    key='56fe59;82g:d873c'.encode()
    iv='2346892432920300'.encode()
    data='gYdZHMFkdTLC1JvfK4AsSmouEN3+S+OsjkFGaZ9kygpo/FGeJ5N7iJdMyIBtadqqUBgJnRBFi+Ri6KYKwFCVqFVPgWMaqbAAp5JiY9yFM4rGVByS9EsGHY0DB9ekNkSw+9v/Xu/BsbMxxEm9Et4MJT4QbLGf9ifhngIO3aDdE3bN+3aB801nvmOb8ZYsJ2U4Mw2sAGcnJrcDFU2kX3ASbUfhJYGWCkELV8Y6iKoPrPr/wNfkDmtuWUNYUSpSdYlPWWrANkgrPW5YL4wWIQwfVf7cDX5ItxTOGl00XYlKUcnwOsm6JAjdF5Voc0u9mmiT'
    crypted=base64_decode(data)
    decrypt=aes_decrypt(key,iv,crypted)
    print(decrypt.decode())

Ejecute el script de Python y obtenga el resultado

{"imei":"865166020644319","adua":"Mozilla\/5.0 (Linux; Android 5.1.1; MI 9) AppleWebKit\/537.36 (KHTML, like Gecko) Version\/4.0 Chrome\/70.0.3538.64 Mobile Safari\/537.36","androidId":"e2437690c1181ef5","device":"phone","oaid":""}

De la misma manera, se puede analizar x-device-id

Tres, firmar

Buscamos en el campo de letreros a nivel mundial y encontramos un lugar muy probable

Inserte la descripción de la imagen aquí

A través del análisis, podemos concluir que sb y varios valores se empalman, y luego a través de lqaypb0.a (sb.toString ()), MD5 se realiza una vez para obtener un valor de 32 bits, y luego ingresa el método CrypLib.a () para juicio

Inserte la descripción de la imagen aquí

Inserte la descripción de la imagen aquí

Aquí también podríamos ingresar a la capa nativa para ver

jstring __fastcall Java_com_gotokeep_keep_common_utils_CrypLib_getEncryptDeviceId(JNIEnv *a1, jclass a2, jstring a3)
{
    
    
  int v3; // r3
  int v4; // r0
  int v5; // r3
  jstring v7; // [sp+4h] [bp-70h]
  JNIEnv *v8; // [sp+Ch] [bp-68h]
  int v9; // [sp+14h] [bp-60h]
  signed int i; // [sp+18h] [bp-5Ch]
  char *s; // [sp+1Ch] [bp-58h]
  int v12; // [sp+24h] [bp-50h]
  int v13; // [sp+28h] [bp-4Ch]
  int v14; // [sp+2Ch] [bp-48h]
  int v15; // [sp+34h] [bp-40h]
  int v16; // [sp+38h] [bp-3Ch]
  int v17; // [sp+3Ch] [bp-38h]
  int v18; // [sp+40h] [bp-34h]
  int v19; // [sp+44h] [bp-30h]
  int v20; // [sp+48h] [bp-2Ch]
  int v21; // [sp+4Ch] [bp-28h]
  int v22; // [sp+50h] [bp-24h]
  int v23; // [sp+54h] [bp-20h]
  int v24; // [sp+58h] [bp-1Ch]
  int v25; // [sp+5Ch] [bp-18h]
  char v26; // [sp+60h] [bp-14h]
  char v27[12]; // [sp+68h] [bp-Ch]

  v8 = a1;
  v7 = a3;
  if ( getSignHashCode(a1) != 1580769512 )
    return v7;
  s = ((*v8)->GetStringUTFChars)(v8, v7, 0);
  v16 = 0;
  v17 = 0;
  v18 = 0;
  v19 = 0;
  v20 = 0;
  v21 = 0;
  v22 = 0;
  v23 = 0;
  v24 = 0;
  v25 = 0;
  v26 = 0;
  if ( strlen(s) == 32 )
  {
    
    
    v9 = 0;
    for ( i = 7; i >= 0; --i )
    {
    
    
      v27[i - 48] = s[i];
      v27[i - 40] = s[i + 8];
      v27[i - 32] = s[i + 16];
      v27[i - 24] = s[i + 24];
      v12 = get_int(s[i]);
      v13 = get_int(s[i + 8]);
      v14 = get_int(s[i + 16]);
      v4 = get_int(s[i + 24]);
      v15 = v12 + v13 + v14 + v4 + v9 + 929;
      v5 = v12 + v13 + v14 + v4 + v9 + 929;
      if ( v5 < 0 )
        v5 = v12 + v13 + v14 + v4 + v9 + 944;
      v9 = v5 >> 4;
      v27[i - 16] = get_char(v15 % 16);
    }
    ((*v8)->ReleaseStringUTFChars)(v8, v7, s);
    v3 = ((*v8)->NewStringUTF)(v8, &v16);
  }
  else
  {
    
    
    ((*v8)->ReleaseStringUTFChars)(v8, v7, s);
    v3 = v7;
  }
  return v3;
}

Es un algoritmo particularmente simple. Lo desconcertante es

Inserte la descripción de la imagen aquí
En realidad, aquí se realizó una verificación de la firma y el valor de verificación de la firma se devolvió directamente. Si desea modificar el archivo de recursos relevante, es muy fácil.

Luego, analizamos el resultado de empalme del campo sb y usamos directamente frida hook para l.q.a.y.p.b0.a(sb.toString())obtener los parámetros de entrada . El código sigue siendo similar al anterior, pero hay una pequeña diferencia aquí, es un método de sobrecarga, recuerde usar overload ('Tipo de entrada') para distinguir

import frida, sys


def on_message(message, data):
    if message['type'] == 'send':
        print("[*] {0}".format(message['payload']))
    else:
        print(message)


jscode = """
Java.perform(function () {
    var b0 = Java.use('l.q.a.y.p.b0');
    b0.a.overload('java.lang.String').implementation = function (param1) {
        send("Hook Start...");
        send("sb is"+param1);
        var result=this.a(param1);
        send("ret is :"+result);
        return result;
    }
});
"""

process = frida.get_usb_device().attach('com.gotokeep.keep')
script = process.create_script(jscode)
script.on('message', on_message)
script.load()
sys.stdin.read()

El resultado de la impresión es:

[*] Hook Start...
[*] sb is{"captcha":"1111","countryCode":"86","countryName":"CHN","mobile":"18202870881","type":"login"}/account/v3/login/smsV1QiLCJhbGciOiJIUzI1NiJ9

para resumir

En general, esta aplicación es relativamente simple y mucha lógica no está muy bien escrita, el valor clave se puede obtener rápidamente a través de frida Hook.

Supongo que te gusta

Origin blog.csdn.net/weixin_43632667/article/details/107236629
Recomendado
Clasificación