Aprendizaje inverso de Android Frida inverso y captura de paquetes notas prácticas de estudio (actualización continua)

Materiales de aprendizaje: "Android Frida Reverse y Packet Capture Actual Combat" Chen Jialin / Autor

entorno básico

  1. Instalar Android Studio y configurar adb
  2. Una máquina real rooteada o una máquina virtual Android

Capitulo 3 Frida entrada inversa Gancho de capa Java

3.1 Fundamentos de Frida

3.1.3 Conocimientos básicos de Frida

Frida tiene dos modos de operación

  1. CLI (modo de línea de comandos)
    inyecta código js en el proceso a través de la línea de comandos
  2. Modo RPC
    Inyecte el código js en el proceso a través de python, esencialmente use el código js para el gancho

Frida tiene dos formas de operar la aplicación

  1. En el modo spwan
    , Frida tiene derecho a iniciar la aplicación. Incluso si se inicia la aplicación de destino,
    Frida la reiniciará. Se puede especificar el parámetro -f para operar la aplicación en modo spwan.
  2. Se ha iniciado la aplicación del modo adjuntar
    y frida inyecta el programa a través de ptrace para ejecutar el enlace.

3.1.4Configuración del IDE de Frida

  1. Instalar nodo y entorno npm
  2. git descargar repositorio frida-agent-example
git clone https://github.com/oleavr/frida-agent-example.git 下载frida-agent-example仓库
cd frida-agent-example/
npm install

Use vscode para abrir, cree una carpeta en la carpeta frida-agent-example para escribir scripts
inserte la descripción de la imagen aquí

3.2 Primeros pasos con el guion de frida

3.2.1 El concepto de guion frida

Ejemplo:

setTimeout(function(){
    
    
    Java.perform(function(){
    
    
        console.log("hello,world")
    })
})

代码分析:
1. 调用setTimeout方法将匿名函数注册到js运行库中
2. 在函数中调用Java.perform方法,将匿名函数注册到App的java运行库中,并执行函数

Después de ejecutar frida-server en el teléfono móvil, puede usar el comando frid-ps -U para ver el proceso en ejecución
Por favor agregue una descripción de la imagen
y luego usar frida -U -l test0.js android.process.media para inyectar el script en el proceso, y puede encontrar que helloworld se imprime después de la inyección
Por favor agregue una descripción de la imagen

En los parámetros anteriores, -U especifica el dispositivo usb, -l especifica la ruta donde se encuentra el script de inyección y el último androdi.process.media es el nombre del proceso que se ejecuta en el dispositivo

3.2.2 Conceptos básicos de gancho de capa Java

1. Un estudio preliminar sobre anzuelos

código de proyecto de estudio android

package com.example.hooktest1;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import java.util.Locale;

public class MainActivity extends AppCompatActivity {
    
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
    
    
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        int x=0,y=0;
        while(true){
    
    
            try {
    
    
                Thread.sleep(1000);
            } catch (InterruptedException e) {
    
    
                e.printStackTrace();
            }
            fun(x,y);
            x++;y++;
        }
    }
    void fun(int x,int y)
    {
    
    
        Log.d("sum=",String.valueOf(x+y));
    }
}

Ejecución de resultados: la consola de Android Studio continuará emitiendo x+y, y x e y aumentarán gradualmente
Por favor agregue una descripción de la imagen

código de secuencia de comandos de enlace:

function main(){
    
    
    console.log("Script loaded success")
    //Java.perform是frida的api函数,可以将其中的脚本注入到java运行库,参数是一个匿名函数
    //函数的主体内容是监控和修改java函数逻辑的主题内容,任何针对java层的操作都必须在这个api函数中
    Java.perform(function(){
    
    
        console.log("Inside java perform!")
        //java.use获取hook函数所在类的类名
        var Mainactivity=Java.use('com.example.hooktest1.MainActivity')
        console.log("Java.use.success!")
        //通过.连接函数名,比如这里的函数名是fun,表示想hookfun函数
        //implementation表示实现该函数,也就是hook掉,这里可以写自己的函数
        Mainactivity.fun.implementation=function(x,y)
        {
    
    
            console.log("x=",x,"y=",y,"x+y=",x+y)   //打印参数,这里应该是函数原本没有被修改时的参数,即函数正常执行时的参数情况
            var retvalue=this.fun(666,66)           //再次调用原函数并且传递原本的参数fun,即重新执行原函数,在这里就可以修改参数
            return retvalue      //返回函数返回值,返回值最好不要修改类型,否则可能出错
        }
    })
}
//参数是要被执行的函数,例如传入main,表示frida注入app后立刻执行main
//setTimeout可以指定frida注入app多久之后执行函数,用于延时注入
setImmediate(main)

Inyecte el script en el proceso frida -U -l test0.js com.example.hooktest1
Puede ver que después de la inyección, la consola de comandos generará el contenido de la función de script js
Por favor agregue una descripción de la imagen
Mire la consola de comandos de Android Studio, puede encontrar que la consola ha estado generando sum=: 732
Indica que llamar a this.fun(666,66) en el script es exitoso
Por favor agregue una descripción de la imagen

2. El gancho de la función sobrecargada

Código ligeramente modificado:

package com.example.hooktest1;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import java.util.Locale;
public class MainActivity extends AppCompatActivity {
    
    
    private String total="hello";
    @Override
    protected void onCreate(Bundle savedInstanceState) {
    
    
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        int x=0,y=0;
        while(true){
    
    
            try {
    
    
                Thread.sleep(1000);
            } catch (InterruptedException e) {
    
    
                e.printStackTrace();
            }
            fun(x,y);
            x++;y++;
            Log.d("hooktest:",fun("HelloWorld!"));
        }
    }
    void fun(int x,int y)
    {
    
    
        Log.d("sum=",String.valueOf(x+y));
    }
    String fun(String s){
    
    
        return s.toLowerCase();
    }

Resultado de la ejecución del programa:
Por favor agregue una descripción de la imagen

guión de gancho:

//定位重载函数,使用overload即可,overload内指定重载函数参数类型,如果函数有返回值要注意返回
 function main(){
    
    
    console.log("Loaded sucess!")
    Java.perform(function(){
    
    
        console.log("Inside java perform")
        var activity=Java.use("com.example.hooktest1.MainActivity")
        console.log("定位activity成功")
        activity.fun.overload('java.lang.String').implementation=function(x){
    
    
            console.log("hook fun string=",x)
            return x
        }
        activity.fun.overload('int','int').implementation=function(x,y){
    
    
            console.log("x=",x,"y=",y)
           var ret= this.fun(66,55)
           return ret;
        }
    })
 }
 setImmediate(main)

resultado de gancho
Por favor agregue una descripción de la imagen

Consola:
Por favor agregue una descripción de la imagen

3.2.3 Llamada activa de la capa Java

La implementación anterior es una llamada pasiva: es decir, la función se ejecuta con la lógica normal de la aplicación. La
llamada activa puede llamar directamente a la función clave sin necesidad de que la aplicación ejecute la función.
Aquí hay dos situaciones:

  1. Función de clase (método estático) Simplemente use Java.use para encontrar la clase donde se encuentra la función
  2. Método de instancia (método dinámico) Use la función Java.choose api para encontrar la instancia de clase especificada en el montón de Java

1. Ejemplo de llamada activa 1

Código del programa:
se agregaron dos métodos de secreto y staticSecret

package com.example.hooktest1;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import java.util.Locale;

public class MainActivity extends AppCompatActivity {
    
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
    
    
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        int x=0,y=0;
        while(true){
    
    
            try {
    
    
                Thread.sleep(1000);
            } catch (InterruptedException e) {
    
    
                e.printStackTrace();
            }
            fun(x,y);
            x++;y++;
            Log.d("hooktest:",fun("HelloWorld!"));
        }
    }
    void fun(int x,int y)
    {
    
    
        Log.d("sum=",String.valueOf(x+y));
    }
    String fun(String s){
    
    
        return s.toLowerCase();
    }
    void secret(){
    
    
        Log.d("this is secret","find secret func!");
    }
    static void staticSecret(){
    
    
        Log.d("this is staticSecret","Find static!");
    }
}

Resultado de la ejecución del programa:
Por favor agregue una descripción de la imagen

guión de gancho:

function main(){
    
    
    Java.perform(function(){
    
    
        console.log("Inside java perform")
        var MainActivity=Java.use("com.example.hooktest1.MainActivity")
            
        MainActivity.staticSecret()
        //动态函数主动调用
        //java.choose先从内存中寻找类的实例对象,然后再调用实例对象的函数
        Java.choose('com.example.hooktest1.MainActivity',{
    
    
            onMatch: function(instance){
    
    
                console.log("instance found",instance)
                instance.secret()
            },
            onComplete: function(){
    
    
                console.log('search Complete')
            }
        })

    })
}
setImmediate(main)

Resultados de enlace
Puede ver que la clase y la dirección del objeto de instancia se imprimen correctamente
Por favor agregue una descripción de la imagen

La consola puede ver que las dos funciones secret y staticSecret se han llamado con éxito
Por favor agregue una descripción de la imagen

Nota: Los resultados de llamar a estas dos funciones están en la consola de Android Studio, no en la consola de Frida. La consola de Frida genera el contenido en el script js.

2. Ejemplo de llamada activa 2

Modifique ligeramente el código del programa anterior, agregue dos variables privadas, intente enganchar el valor de la variable

package com.example.hooktest1;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import java.util.Locale;

public class MainActivity extends AppCompatActivity {
    
    
    private String total="hello";
    private int count=0;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
    
    
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        int x=0,y=0;
        while(true){
    
    
            try {
    
    
                Thread.sleep(1000);
            } catch (InterruptedException e) {
    
    
                e.printStackTrace();
            }
            fun(x,y);
            x++;y++;
            Log.d("hooktest:",fun("HelloWorld!"));
        }
    }
    void fun(int x,int y)
    {
    
    
        Log.d("sum=",String.valueOf(x+y));
    }
    String fun(String s){
    
    
        return s.toLowerCase();
    }
    void secret(){
    
    
        total+="call"+count;
        count++;
        Log.d("this is secret","find secret func!");
    }
    static void staticSecret(){
    
    
        Log.d("this is staticSecret","Find static!");
    }
}

Resultado de la ejecución del programa:
Por favor agregue una descripción de la imagen

guión de gancho:

//调用secret函数,需要控制台手动进行,
function callSecretFunc(){
    
    
    Java.perform(function(){
    
    
        Java.choose('com.example.hooktest1.MainActivity',{
    
    
            onMatch:function(instance){
    
    
                instance.secret()
            },
            onComplete:function(){
    
    

            }
        })
})
}

//获取total的值
function getTotalValue(){
    
    
    Java.perform(function(){
    
    
        Java.choose('com.example.hooktest1.MainActivity',{
    
    
            onMatch:function(instance){
    
    
                console.log("find instance=",instance)
                console.log("totalAddr=",instance.total)//获取类变量的值要使用.value,total本身是一个引用类型
                console.log("total=",instance.total.value)
            },
            onComplete:function(){
    
    
                console.log("search end")
            }
        })
    })
}
setImmediate(getTotalValue)

El resultado del enlace
muestra que el programa primero llama a la función getTotalValue y genera el valor del total.
Luego llamamos a la función de script callSecretFunc() en la consola de Frida para llamar a la función secreta para modificar el valor del total.
Llame a getTotalValue nuevamente para generar el valor del total y encuentre que la modificación es exitosa.
Por favor agregue una descripción de la imagen

Resumir:

  1. Para obtener la variable de instancia en la clase, debe usar .value para obtener su valor. Si no puede obtener el valor imprimiendo directamente (puede obtener información sobre la variable, porque el total en sí mismo es un tipo de referencia)
  2. En la consola frida, podemos llamar repetidamente a la función de script para lograr el propósito de llamar repetidamente a la función del programa.

Capítulo 4 Objeción Inicio rápido

4.2 Instalación y uso de Objeción

4.2.1 instalación de objeciones

pip install -U objeción

Nota: Dado que frida se actualiza rápidamente, es necesario asegurarse de que la versión de objeción se publique después de frida. La última versión de objeción es 1.11.0, la versión de frida correspondiente es hasta 14.2.14 y frida-tools es 9.2.2

4.2.2 uso de objeciones

1. Inyectar proceso en REPL

La objeción está conectada al dispositivo a través de USB de manera predeterminada, y no es necesario usar el parámetro -U para especificar usb
para 'configurar' el comando del proceso de inyección de demostración de la aplicación como Frida: objeción -g com.android.settings explore
La inyección exitosa lo hará mostrar la siguiente información:
Por favor agregue una descripción de la imagen

De esta manera, ha ingresado con éxito a la interfaz de objeción REPL y puede ingresar exit to exit

2. Comandos comunes:

Indicaciones de la barra espaciadora para los comandos
Por favor agregue una descripción de la imagen

  1. ayuda Si no conoce el efecto del comando actual, puede usar la ayuda antes del comando, y se generará la información de explicación del comando.
    Por favor agregue una descripción de la imagen

  2. El comando de trabajos
    lista de trabajos muestra el trabajo actual
    trabajos matar elimina el trabajo
    Por favor agregue una descripción de la imagen

  3. comando frida
    Ver información de frida
    Por favor agregue una descripción de la imagen

  4. Comandos relacionados con la itinerancia de memoria
    (1) las clases de la lista de conexión de Android
    imprimen todas las clases en la memoria
    Por favor agregue una descripción de la imagen

    (2) la clave de clases de búsqueda de enganche de Android
    busca todas las clases que contienen la clave de palabra clave
    Por favor agregue una descripción de la imagen

    (3) la clave de métodos de búsqueda de enganche de Android
    busca todos los métodos que contienen la clave de palabra clave
    Por favor agregue una descripción de la imagen

    (4) lista de enganches de Android class_methods classname
    Ver todos los métodos de la clase llamada classname
    Por favor agregue una descripción de la imagen

    (5) las actividades de la lista de enganches de Android (proveedores de receptores de servicios)
    imprimen cuatro componentes principales, enumeran todas las actividades de actividad del proceso (proveedor de receptores de servicios)
    Por favor agregue una descripción de la imagen

  5. Enganche los comandos relacionados con
    android hooking watch class_method methodName
    enganche el método especificado
    Por favor agregue una descripción de la imagen

Actualizando continuamente...

Supongo que te gusta

Origin blog.csdn.net/OrientalGlass/article/details/130903086
Recomendado
Clasificación