Aprendizaje de verificación de firmas de una aplicación de animación

He estado lanzando ollvm recientemente, pero después de unos días de lanzamiento, la compilación no ha pasado y sigo pisando el pozo, así que tengo que dejarlo de lado temporalmente y analizar todo el sentido de la aplicación.

La aplicación es una aplicación de animación. Vi a alguien analizar esta aplicación en Kanxue: https://bbs.pediy.com/thread-258593.htm.
Sentí que el análisis no era muy detallado, así que lo analicé yo mismo y lo escribí. Un proceso de análisis

Propósito: modificar la aplicación como miembro permanente

Primero abra la apk y eche un vistazo:
Inserte la descripción de la imagen aquí

Obviamente, si desea modificar la fecha de membresía, debe encontrar la actividad correspondiente a la interfaz. Hay muchas formas de modificar, como buscar directamente la cadena de membresía, y luego puede ubicar la ubicación relevante. UserInfoActivity
Inserte la descripción de la imagen aquí
Ver getExpire:

Inserte la descripción de la imagen aquí
Ver conjunto

Inserte la descripción de la imagen aquí
Se encuentra que el objeto dateFormat se ha convertido varias veces en una cadena y se ha comparado con la cadena "2100-01-01". Siempre que sea mayor o igual a este valor, es un miembro permanente.

Tanto tiempo es muy simple, solo use androidKiller para modificar el valor de retorno de getExpire.

Luego, cuando comencé a ejecutar después de la descompilación, descubrí que no funcionaba.

Inserte la descripción de la imagen aquí

¿Qué debo hacer? Lo primero que consideré fue la cadena de búsqueda. Efectivamente, el software no es tan simple y no se puede buscar, por lo que se estima que la verificación se realiza en el lado del servidor .

Usa Fiddler para agarrar un paquete:

Inserte la descripción de la imagen aquí

me saludó imei a los ojos, solo búscalo :

Inserte la descripción de la imagen aquí

Efectivamente, lo encontré, verifique getV ():

Inserte la descripción de la imagen aquí

Resultó ser un método nativo, el tipo de retorno es String y se pasa una marca de tiempo actual. No es realista modificar directamente el valor de retorno. Solo se puede ver cómo se genera el código de verificación de análisis de código de capa.

Desafortunadamente, el uso del análisis estático de ida encontró que algunos parámetros no se mostraban, pero afortunadamente encontró un parámetro de ubicación, se puede encontrar un valor específico basado en la depuración dinámica:
Inserte la descripción de la imagen aquí
Pero Internet, dijo que jeb también se ha visto tan funcional, con su vista que se encontró muy clara:
Inserte la descripción de la imagen aquí
el Como se puede observar en la figura, hay un total de tres controles y el valor fijo "dt8re" + "rt9ws" empalmados respectivamente. Entre ellos, hay dos parámetros, uno hash1 y otro hash2, que se
calculan

En la actualidad, se han pensado dos métodos para la depuración dinámica: (1) Depuración dinámica para obtener el valor; (2) Utilice la tecnología de gancho para tomar la marca de tiempo del valor fijo e imprimir el valor de retorno, y calcular el resultado de acuerdo con el método de la variable de control.

A continuación, solo se muestra el método de gancho:

(1) Primero use el script frida hook js

Java.perform(function () {
    
    
    var CheckUtils = Java.use("info.zzjian.dididh.util.CheckUtils");
    CheckUtils.getV.overload("long").implementation = function (j) {
    
    
        var ret = this.getV(j);
        console.log(this.getV(0));
        return (ret);
    };
});

El resultado de la impresión es:

33cc6f39fdt8re3af08b80crt9ws3ff2a033f

Según los resultados, se divide en:

(check1)33cc6f39f + dt8re + (check2)3af08b80c + 9ws3f + (check3)f2a033f

Según el método de la variable de control

hash1 = -1916912749L;
hash2 = 1344359219L;

Encuentra la cadena final como:

String check1 = Long.toHexString(13904573343L + ts * 2);
        String check2 = Long.toHexString(15821486092L + ts);
        String check3 = Long.toHexString(17165845311L + ts);
        return check1 + "dt8re" + check2 + "rt9ws" + check3;

De acuerdo con el algoritmo restaurado, reescriba CheckUtils.java para que devuelva la cadena directamente en la capa de Java

public class CheckUtils {
    
    
    public CheckUtils() {
    
    
    }
 
    public String getV(long ts) {
    
    
        String check1 = Long.toHexString(13904573343L + ts * 2);
        String check2 = Long.toHexString(15821486092L + ts);
        String check3 = Long.toHexString(17165845311L + ts);
        return check1 + "dt8re" + check2 + "rt9ws" + check3;
    }
}

Use la línea de comando para convertir el archivo java escrito en un archivo pequeño. Aquí hay un script escrito que se puede ver y descargar en mi archivo de recursos (el nombre del paquete se cambia según la situación real):

.class public Linfo/zzjian/dididh/util/CheckUtils;
.super Ljava/lang/Object;
.source "CheckUtils.java"


# direct methods
.method public constructor <init>()V
    .registers 1

    .prologue
    .line 3
    invoke-direct {p0}, Ljava/lang/Object;-><init>()V

    .line 4
    return-void
.end method


# virtual methods
.method public getV(J)Ljava/lang/String;
    .registers 8

    .prologue
    .line 7
    const-wide v0, 0x33cc6f39fL

    const-wide/16 v2, 0x2

    mul-long/2addr v2, p1

    add-long/2addr v0, v2

    invoke-static {v0, v1}, Ljava/lang/Long;->toHexString(J)Ljava/lang/String;

    move-result-object v0

    .line 8
    const-wide v2, 0x3af08b80cL

    add-long/2addr v2, p1

    invoke-static {v2, v3}, Ljava/lang/Long;->toHexString(J)Ljava/lang/String;

    move-result-object v1

    .line 9
    const-wide v2, 0x3ff2a033fL

    add-long/2addr v2, p1

    invoke-static {v2, v3}, Ljava/lang/Long;->toHexString(J)Ljava/lang/String;

    move-result-object v2

    .line 10
    new-instance v3, Ljava/lang/StringBuilder;

    invoke-direct {v3}, Ljava/lang/StringBuilder;-><init>()V

    invoke-virtual {v3, v0}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;

    move-result-object v0

    const-string v3, "dt8re"

    invoke-virtual {v0, v3}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;

    move-result-object v0

    invoke-virtual {v0, v1}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;

    move-result-object v0

    const-string v1, "rt9ws"

    invoke-virtual {v0, v1}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;

    move-result-object v0

    invoke-virtual {v0, v2}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;

    move-result-object v0

    invoke-virtual {v0}, Ljava/lang/StringBuilder;->toString()Ljava/lang/String;

    move-result-object v0

    return-object v0
.end method

Luego sobrescriba la clase
en androidkiller con el código escrito y luego obtenga con éxito el resultado después de la descompilación:
Inserte la descripción de la imagen aquí

Suplemento: por supuesto, debido a que este apk no detecta ganchos, podemos usar directamente Xposed o fridahook para lograr la función de descifrar VIP. Cuando verifiqué la declaración del autor, encontré que el autor no se opuso a usar Xposed para hacer modificaciones:
Inserte la descripción de la imagen aquí
así que agradezco al autor por darlo Tengo esta oportunidad de aprender, pero la versión descifrada del apk no se proporciona aquí. Si la necesita, puede descargar la versión original directamente desde el sitio web oficial: http://dddh.pub/

Suplemento: después de la depuración dinámica, se descubre que el programa es un programa de 64 bits, por lo que ida32 no podrá mostrar la cadena y la cadena se puede ver normalmente con ida64

Inserte la descripción de la imagen aquí

Supongo que te gusta

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