Práctica inversa de Android de Attack and Defense World

一.fácil

1. lógica del programa de análisis jadx

Puedes ver que la clave está en la función cyberpeace.CheckString()
inserte la descripción de la imagen aquí
Después de hacer doble clic para seguir, puedes encontrar que es una función de capa nativa
inserte la descripción de la imagen aquí

2. ida ver el archivo

Lógica del programa:
1. Guarde la cadena de caracteres en el nuevo búfer de espacio
2. El primer juicio es intercambiar los primeros 16 caracteres y los últimos 16 caracteres del búfer
3. El segundo juicio es intercambiar los dos caracteres adyacentes del carácter del búfer cambio de posición por

_BOOL8 __fastcall Java_com_testjava_jack_pingan2_cyberpeace_CheckString(__int64 a1, __int64 a2, __int64 a3)
{
    
    
  const char *str; // r14
  size_t len; // rax
  int len2; // r15d
  unsigned __int64 v6; // r12
  char *newMem; // rax
  char *buffer; // r13
  bool v9; // cc
  size_t v10; // r12
  size_t i; // rbx
  char tmp; // al
  char tmp1; // al
  size_t j; // rbx
  char tmp2; // al

  str = (*(*a1 + 1352LL))(a1, a3, 0LL);
  len = strlen(str);
  len2 = len;
  v6 = ((len << 32) + 0x100000000LL) >> 32;
  newMem = malloc(v6);
  buffer = newMem;
  v9 = v6 <= len2;
  v10 = v6 - len2;
  if ( v9 )
    v10 = 0LL;
  memset(&newMem[len2], 0, v10);
  memcpy(buffer, str, len2);
  if ( strlen(buffer) >= 2 )
  {
    
    
    i = 0LL;
    do
    {
    
    
      tmp = buffer[i];
      buffer[i] = buffer[i + 16];
      buffer[i++ + 16] = tmp;
    }
    while ( strlen(buffer) >> 1 > i );
    //32>>1 = 16 也就是说i<16时执行循环
  }
  tmp1 = *buffer;
  if ( *buffer )
  {
    
    
    *buffer = buffer[1];
    buffer[1] = tmp1;
    if ( strlen(buffer) >= 3 )
    {
    
    
      j = 2LL;
      do
      {
    
    
        tmp2 = buffer[j];
        buffer[j] = buffer[j + 1];
        buffer[j + 1] = tmp2;
        j += 2LL;
      }
      while ( strlen(buffer) > j );
    }
  }
  return strcmp(buffer, "f72c5a36569418a20907b55be5bf95ad") == 0;
}

Tenga en cuenta que los resultados de desmontaje obtenidos por diferentes archivos so son diferentes.
Al principio, usé los archivos so en la carpeta arm64-v8a para obtener este resultado, que obviamente es incorrecto. Este ciclo perderá algunos datos al final y luego se
inserte la descripción de la imagen aquí
abrirá la carpeta x86_64, por lo que el archivo es normal

3. Guión de resolución de problemas:

#include <stdio.h>
int main()
{
    
    
    char flag[33] = "f72c5a36569418a20907b55be5bf95ad";
    char tmp;
    for (int i = 0; i < 32; i += 2) // 两两交换
    {
    
    
        tmp = flag[i];
        flag[i] = flag[i + 1];
        flag[i + 1] = tmp;
    }
    int i = 0;
    do
    {
    
    
        tmp = flag[i];
        flag[i] = flag[i + 16];
        flag[i++ + 16] = tmp;
    } while (i<16);
    printf("flag{%s}",flag);
    //flag{90705bb55efb59da7fc2a5636549812a}
    return 0;
}

dos.ezjni

1. Análisis de la lógica del programa

Se puede ver que la cadena también se obtiene y luego se cifra
1. Obtenga la cadena
2. Realice el cifrado base64 (la tabla base ha sido reemplazada)
3. Llame a la función nativa ncheck para juzgar el resultado
inserte la descripción de la imagen aquí
función base64encode, cambie el cifrado base64 de la tabla :
inserte la descripción de la imagen aquí
función ncheck, aquí debería ser igual que la anterior El título easyso es la misma operación, solo debido a errores de descompilación
1. Primero intercambie los primeros 16 caracteres y los últimos 16 caracteres
2. Luego recorra desde el principio e intercambie posiciones por cada grupo de dos personajes
inserte la descripción de la imagen aquí

2. Guión de resolución de problemas:

Primero genera la cadena base antes del procesamiento ncheck

#include <stdio.h>
int main()
{
    
    
    char flag[33] = "MbT3sQgX039i3g==AQOoMQFPskB1Bsc7";
    char tmp;
    for (int i = 0; i < 32; i += 2) // 两两交换
    {
    
    
        tmp = flag[i];
        flag[i] = flag[i + 1];
        flag[i + 1] = tmp;
    }
    int i = 0;
    do
    {
    
    
        tmp = flag[i];
        flag[i] = flag[i + 16];
        flag[i++ + 16] = tmp;
    } while (i<16);
    printf("%s",flag);
    //QAoOQMPFks1BsB7cbM3TQsXg30i9g3==
    return 0;
}

Primero genera la tabla base64

public class test1{
    
    
    private static final char[] table = {
    
    'i', '5', 'j', 'L', 'W', '7', 'S', '0', 'G', 'X', '6', 'u', 'f', '1', 'c', 'v', '3', 'n', 'y', '4', 'q', '8', 'e', 's', '2', 'Q', '+', 'b', 'd', 'k', 'Y', 'g', 'K', 'O', 'I', 'T', '/', 't', 'A', 'x', 'U', 'r', 'F', 'l', 'V', 'P', 'z', 'h', 'm', 'o', 'w', '9', 'B', 'H', 'C', 'M', 'D', 'p', 'E', 'a', 'J', 'R', 'Z', 'N'};

    public static void main(String[] args) {
    
    
        System.out.println("hello");
        String s="hellk";
        System.out.println(s);
        for (int i=0;i<table.length;i++)
        {
    
    
            System.out.print(table[i]);
            //i5jLW7S0GX6uf1cv3ny4q8es2Q+bdkYgKOIT/tAxUrFlVPzhmow9BHCMDpEaJRZN
        }
    }
}

Entonces usa CyberChef para hablar de ello.
inserte la descripción de la imagen aquí

3. easyjava

1. Lógica de función principal

Esta pregunta básicamente no tiene nada que ver con Android. Es principalmente para analizar la lógica del código Java. La
función principal aquí llama a un método de verificación para juzgar la bandera de entrada
inserte la descripción de la imagen aquí
y luego mira el método de verificación.
Primero juzga el formato de la bandera{ } al principio y al final, y luego obtenga los caracteres entre llaves
para crear dos La clase se usa para un procesamiento posterior
y luego use las funciones stringBuilder y func para crear una nueva cadena.
Tenga en cuenta que la función func pasa en un solo -Cadena de caracteres cada vez, por lo que cada anexo agrega un solo carácter La
inserte la descripción de la imagen aquí
función func
usa dos funciones Ven a la operación Matryoshka
inserte la descripción de la imagen aquí

2. función getIndex

Primero mire la función de índice (tenga en cuenta que el nombre de la función y el nombre de la variable aquí se modifican manualmente de acuerdo con el análisis). La
lógica de la función aquí ha sido analizada. Primero, determine si el carácter es una letra y luego obtenga el subíndice del carácter en str y
use lo siguiente Encuentre la posición correspondiente en la matriz, y luego devuelva el subíndice en la matriz.Finalmente
, use la función de cambio para cambiar la tabla (el cambio es una operación circular de desplazamiento a la izquierda)
inserte la descripción de la imagen aquí

  1. inicialización de matriz
    inserte la descripción de la imagen aquí
  2. función de cambio
    inserte la descripción de la imagen aquí

3. función getChar

Esta lógica es relativamente simple, también verifica el valor en la tabla y luego registra el índice, y busca el carácter en la tabla según el índice.
inserte la descripción de la imagen aquí

  1. lista tiene operaciones similares a la función anterior
    inserte la descripción de la imagen aquí

  2. JudgeCount, dado que los caracteres no son tan largos como 25, esta función es puramente perturbadora y hace que las personas analicen más, no tiene ningún efecto práctico.
    inserte la descripción de la imagen aquí

4. Guión de resolución de problemas

import java.util.ArrayList;
public class glass0{
    
    
    static String str = "abcdefghijklmnopqrstuvwxyz";
    static ArrayList<Integer> array = new ArrayList<>();
    static void change() {
    
    
        int value = array.get(0).intValue(); // 首个元素的int值
        array.remove(0); // 移除
        array.add(Integer.valueOf(value)); // 又加回去?
        str += "" + str.charAt(0);
        str = str.substring(1, 27); // 切割字符串并调整,左移一位的效果
    }
    public static void main(String[] args) {
    
    
        char[] flag="wigwrkaugala".toCharArray();
        String table = "abcdefghijklmnopqrstuvwxyz";
        int[] Table={
    
    7, 14, 16, 21, 4, 24, 25, 20, 5, 15, 9, 17, 6, 13, 3, 18, 12, 10, 19, 0, 22, 2, 11, 23, 1, 8};
        int[] intergerArr = {
    
    8, 25, 17, 23, 7, 22, 1, 16, 6, 9, 21, 0, 15, 5, 10, 18, 2, 24, 4, 11, 3, 14, 19, 12, 20, 13};
        ArrayList<Integer> list = new ArrayList<>();
        //初始化list
        for(int i=3;i<Table.length;i++){
    
    
            list.add(Table[i]);
        }
        for(int i=0;i<3;i++){
    
    
            list.add(Table[i]);
        }
        //初始化array
        for (int i = 2; i < intergerArr.length; i++) {
    
    
            array.add(intergerArr[i]); // 截取num~length后半段字符串
        }
        for (int j = 0; j < 2; j++) {
    
    
            array.add(intergerArr[j]); // 截取0~num-1前半段字符串
        }
        //开始解密
        for(int i=0;i<flag.length;i++){
    
    
            //获取下标值
            int index=table.indexOf(flag[i]);
            //获取num值
            int num=list.get(index);
            //这个num是getIndex函数的返回值
            int value=array.get(num);
            char chr=str.charAt(value);
            flag[i]=chr;
            change();
        }
        System.out.println(flag);//venividivkcr
    }
}

bandera{venividivkcr}

4. APK inversa

1. Análisis de la lógica del programa

Detecte el nombre de usuario y el código SN de entrada, el nombre de usuario se ha proporcionado aquí, por lo que puede verificar checkSN para verificar SN y puede ver
inserte la descripción de la imagen aquí
que
el código SN tiene 22 dígitos, y luego realice el procesamiento md5 en el nombre de usuario y el hexadecimal la cadena después de md5 es cada Tome uno cada 2 dígitos y luego envuélvalo con flag{} para obtener el código sn que necesita
inserte la descripción de la imagen aquí

2. Guión de resolución de problemas

  1. al nombre de usuario md5
  2. Tome uno por cada 2 bits del resultado md5
import hashlib
text = "Tenshine"
hash_obj = hashlib.md5()
hash_obj.update(text.encode())
encrypted_text = hash_obj.hexdigest()
for i in range(0,len(encrypted_text),2):
    print(encrypted_text[i],end='')
#bc72f242a6af3857

bandera:bc72f242a6af3857

3. Depuración dinámica

Use jeb para depurar dinámicamente.
Después de establecer un punto de interrupción, ejecute el programa e ingrese 22 caracteres para romper con éxito y ver el valor de la cadena.
inserte la descripción de la imagen aquí
jadx también se puede depurar, pero no se siente tan suave como jeb
y el rojo es el valor variable A primera vista pensé que era un error en el pasado...
inserte la descripción de la imagen aquí

android2.0

La función principal es llamar a la función nativa JNI.getResult.
inserte la descripción de la imagen aquí
La función de Init es dividir str en tres segmentos y almacenarlos en tres matrices, y luego hay algunas operaciones XOR y de comparación para resolver el
inserte la descripción de la imagen aquí
script del problema (tenga en cuenta que el ciclo es 0-3, sin incluir el quinto carácter)

#include<stdio.h>
int main()
{
    
    
	unsigned char one[5] = "LN^dl";
	unsigned char two[5] = " 5-0a";
	two[3] = 0x16;
	unsigned char three[5] = "AFBo}";
	unsigned char flag[16] = {
    
     0 };
	for (int i = 0; i < 4; i++)
	{
    
    
		three[i] ^= two[i];
		two[i] ^= one[i];
		one[i] = (one[i] ^ 0x80) / 2;
		flag[i * 3] = one[i];
		flag[i * 3 + 1] = two[i];
		flag[i * 3 + 2] = three[i];
	}
	flag[12] = one[4];
	flag[13] = two[4];
	flag[14] = three[4];
	printf("%s",flag);
	return 0;
}

bandera

En nombre del pueblo - Capture Zhao Dehan 1-200

jar, use jadx para abrir el análisis,
la función principal primero carga un objeto de verificación y luego llama al método checkPassword en el objeto para verificar si la contraseña de entrada es correcta. La
inserte la descripción de la imagen aquí
implementación del método loadCheckerObject se proporciona a continuación, y puede vea que es el descifrado AES para el archivo ClassEnc. Después del descifrado, devuelva esta clase como el valor del método del cargador
. Tenga en cuenta que el descifrado AES predeterminado en la biblioteca Java Cipher es el modo ECB, y el método de relleno predeterminado es PKCS5Padding , que es GPT dice que es un pozo de modo CBC.
inserte la descripción de la imagen aquí
Script de descifrado

import os
from Crypto.Cipher import AES
key=bytes().fromhex("bb27630cf264f8567d185008c10c3f96")
with open("ClassEnc","rb") as input: 
    data=input.read()
    cipher=AES.new(key,AES.MODE_ECB)
    decode= cipher.decrypt(data)
    
with open("ClassDec","wb") as out:
    out.write(decode)

input.close()
out.close()

Use jadx para abrir el archivo ClassDec descifrado.
Puede encontrar que la clase CheckPass implementa el método checkPassword de la interfaz CheckInterface . Se puede descifrar
inserte la descripción de la imagen aquí
un md5 simple en línea para obtener monkey99 , por lo que muchos artículos con la bandera {monkey99} dan directamente el método CheckPass que viene con el paquete jar. Sin embargo, de acuerdo con la lógica del programa, no se llama aquí. Puede ser que el autor de la pregunta se olvidó de eliminar este código.

inserte la descripción de la imagen aquí

inserte la descripción de la imagen aquí

Artículo de referencia:

  1. Explicación detallada del uso del cifrado central JCE del módulo de seguridad JDK
  2. Explicación detallada de Java JCE Cipher
  3. XCTF_MOBILE15_En nombre del pueblo - Captura Zhao Dehan 1-200

aplicación3

.ab archivo, chatgpt lo explica así:

通常情况下,.ab后缀的文件是Android应用程序备份文件,也称为“应用程序包文件”(.apk文件)的备份文件。
当您使用Android设备上的备份和重置功能时,系统将应用程序的数据和设置打包成一个.ab文件,以便稍后可以还原到设备上。
这些备份文件可以保存在本地存储设备或云存储中,以防意外数据丢失或设备更换。

Hay dos tipos de .ab: encriptado y no encriptado. Si no está encriptado, no se mostrará ninguno aquí.
inserte la descripción de la imagen aquí
Descargue la herramienta de desempaquetado: android-backup-extractor
Nota: Esta herramienta requiere Java11 y superior para
usar el comando

java -jar abe.jar unpack 399649a0e89b46309dd5ae78ff96917a.ab app3.tar

inserte la descripción de la imagen aquí

inserte la descripción de la imagen aquí
Luego, se generará el paquete comprimido app3.tar y, después de la descompresión, puede encontrar el archivo apk jadx en la carpeta para abrir la lógica de análisis.

Supongo que te gusta

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