Copa de primavera y otoño de 2023 Competición de primavera de la Liga de seguridad de red Vuelve a aparecer el tema inverso

Uno.sum

1. Analizar la lógica del programa

Pegue los resultados del análisis en ese momento directamente aquí.De acuerdo con el comportamiento del programa, no es difícil adivinar que es un problema de Sudoku (hay que adivinar)
principal:

int __cdecl main(int argc, const char **argv, const char **envp)
{
    
    
  char *mart; // rbp
  int flagValue; // r14d
  int sum; // r12d
  __int64 i; // rbx
  char chr; // al
  int tmp; // eax
  char *md5str; // rax

  mart = matrix;
  flagValue = 1;
  sum = 0;
  puts("Welcome to Solver!");
  do
  {
    
    
    for ( i = 0LL; i != 9; ++i )
    {
    
    
      if ( !mart[i] )                           // 如果矩阵元素为零则输入字符
      {
    
    
        chr = getchar();
        if ( (chr - '1') > 8u )                 // 所以输入的必须是数字,否则错误
          flagValue = 0;
        else
          mart[i] = chr - '0';                  // 数字
      }
      tmp = mart[i];
      sum += tmp;
    }
    mart += 9;                                  // 一次处理九个字符
  }
  while ( mart != &matrix[81] );                // 一共81
  if ( flagValue && verify() )                  // 盲猜是数独
  {
    
    
    puts("You Win!");
    __snprintf_chk(buf, 32LL, 1LL, 32LL, "%d"); // 405
    md5str = str2md5(buf, strlen(buf));
    __printf_chk(1LL, "flag is: flag{%s}\n\n", md5str);// flag{bbcbff5c1f1ded46c25d28119a85c6c2}
    exit(0);
  }
  puts("Again~");
  return 0;
}

verificar (verificación):
especialmente cuando vi un grupo de nueve y revisé por columna, me di cuenta de que debería ser Sudoku

__int64 verify()
{
    
    
  char *matr; // rsi
  __int64 j; // rcx
  _DWORD *CHECK; // rdi
  __int64 tmp; // rdi
  char *matr2; // rsi
  __int64 k; // rcx
  _DWORD *check2; // rdi
  __int64 chr; // rdi
  __int64 iii; // r8
  char *matr3; // r9
  __int64 len3; // rcx
  _DWORD *check3; // rdi
  int cout; // r10d
  char *matr4; // rdi
  __int64 i; // rcx
  __int64 tmpchr; // rbx

  matr = matrix;
LABEL_2:
  j = 10LL;
  CHECK = check;
  while ( j )
  {
    
    
    *CHECK++ = 0;                               // 初始化空间
    --j;
  }
  while ( 1 )
  {
    
    
    tmp = matr[j];
    if ( check[tmp] )                           // 不能访问已访问过的
      return 0LL;
    ++j;
    check[tmp] = 1;                             // 置一
    if ( j == 9 )
    {
    
    
      matr += 9;                                // 九个一组
      if ( matr != &matrix[81] )
        goto LABEL_2;
      matr2 = matrix;
LABEL_9:
      k = 10LL;
      check2 = check;
      while ( k )
      {
    
    
        *check2++ = 0;                          // 再次清空check数组
        --k;
      }
      while ( 1 )
      {
    
    
        chr = matr2[9 * k];                     // 检查第一列
        if ( check[chr] )
          return 0LL;
        ++k;
        check[chr] = 1;
        if ( k == 9 )
        {
    
    
          if ( ++matr2 != &matrix[9] )
            goto LABEL_9;
          iii = 0LL;
          while ( 2 )
          {
    
                                         // 检查第二列
            matr3 = &matrix[iii];
            do
            {
    
    
              len3 = 10LL;
              check3 = check;
              cout = 3;
              while ( len3 )                    // 清空check
              {
    
    
                *check3++ = 0;
                --len3;
              }
              matr4 = matr3;
              while ( 2 )
              {
    
    
                for ( i = 0LL; i != 3; ++i )
                {
    
    
                  tmpchr = matr4[i];
                  if ( check[tmpchr] )          // 也是不能有1
                    return 0LL;
                  check[tmpchr] = 1;
                }
                matr4 += 9;
                if ( --cout )
                  continue;
                break;
              }
              matr3 += 3;
            }
            while ( matr3 != &matr2[iii] );
            iii += 27LL;
            if ( iii != 81 )
              continue;
            break;
          }
          return 1LL;
        }
      }
    }
  }
}

2. Resolver la Matriz de Sudoku

Haga un seguimiento primero con martix y luego lea los datos,
inserte la descripción de la imagen aquí
luego pídale a ChatGpt que obtenga la respuesta directamente
inserte la descripción de la imagen aquí
y proporcione el código de resolución de problemas y los resultados de ejecución:
inserte la descripción de la imagen aquí
luego complete Sudoku y listo

3. Guión de resolución de problemas

#include<stdio.h>
int main()
{
    
    
    int sum = 0;
    unsigned char matrix[81] =
    {
    
    
        5,   3,   0,   0,   7,   0,   0,   0,   0,   6,
        0,   0,   1,   9,   5,   0,   0,   0,   0,   9,
        8,   0,   0,   0,   0,   6,   0,   8,   0,   0,
        0,   6,   0,   0,   0,   3,   4,   0,   0,   8,
        0,   3,   0,   0,   1,   7,   0,   0,   0,   2,
        0,   0,   0,   6,   0,   6,   0,   0,   0,   0,
        2,   8,   0,   0,   0,   0,   4,   1,   9,   0,
        0,   5,   0,   0,   0,   0,   8,   0,   0,   7,
        9
    };
    int grid[81] = {
    
    
    5, 3, 4, 6, 7, 8, 9, 1, 2,
    6, 7, 2, 1, 9, 5, 3, 4, 8,
    1, 9, 8, 3, 4, 2, 5, 6, 7,
    8, 5, 9, 7, 6, 1, 4, 2, 3,
    4, 2, 6, 8, 5, 3, 7, 9, 1,
    7, 1, 3, 9, 2, 4, 8, 5, 6,
    9, 6, 1, 5, 3, 7, 2, 8, 4,
    2, 8, 7, 4, 1, 9, 6, 3, 5,
    3, 4, 5, 2, 8, 6, 1, 7, 9
    };
     int len = 0;
    for (int i = 0; i < 81; i++)
    {
    
    
        if (!matrix[i])
        {
    
    
            len++;
            printf("%d", grid[i]);//输出需要填充的序列
            //468912723481342575971422657913948591537428763345261
        }
    }
    return 0;
}

Ejecute el programa bajo Linux, ingrese la secuencia: 468912723481342575971422657913948591537428763345261
para obtener la respuesta:
inserte la descripción de la imagen aquí

二.Poisoned_tea_CHELL

1. Reidentificar funciones y análisis lógico del programa

Esto puede ser un problema de identificación. Busque las tres áreas rojas y verifique el ensamblado
inserte la descripción de la imagen aquí
, y puede encontrar que cuatro bytes de datos están definidos aquí inexplicablemente. Presione u para cancelar la definición de la instrucción a continuación,
inserte la descripción de la imagen aquí
y luego presione p desde el encabezado de datos (0x763) para identificarlo como una función. Puede ver la lógica del té.
inserte la descripción de la imagen aquí
Las otras dos áreas rojas son las mismas. Después de la reidentificación, puede ver la función principal (si no puede verla, busque la cruz -referencia de la función de té).
inserte la descripción de la imagen aquí
Aquí está la función principal después de mi análisis y embellecimiento:
pero un problema clave aquí es que su clave y los datos clave no se pueden ver a través del análisis estático , por lo que se requiere un análisis dinámico

__int64 __fastcall Main()
{
    
    
  __int64 result; // rax
  int i; // [rsp+Ch] [rbp-464h]
  int j; // [rsp+10h] [rbp-460h]
  int chr1; // [rsp+14h] [rbp-45Ch] BYREF
  int chr2; // [rsp+18h] [rbp-458h]
  int v5; // [rsp+1Ch] [rbp-454h]
  int key[8]; // [rsp+20h] [rbp-450h] BYREF
  int d1; // [rsp+40h] [rbp-430h]
  int d2; // [rsp+44h] [rbp-42Ch]
  int b1; // [rsp+48h] [rbp-428h]
  int b2; // [rsp+4Ch] [rbp-424h]
  int v11; // [rsp+50h] [rbp-420h]
  int buffer[258]; // [rsp+60h] [rbp-410h] BYREF
  unsigned __int64 v13; // [rsp+468h] [rbp-8h]

  v13 = __readfsqword(0x28u);
  key[0] = 5;
  key[1] = 2;
  key[2] = dword_7FA16F6F8464;                  // 猜测也是一位数,可以爆破
  key[3] = dword_7FA16F6F8454;
  key[4] = 0;
  memset(buffer, 0, 0x400uLL);
  sub_7FA16F6F5524();
  sub_7FA16F6F5554();
  sub_7FA16F6F5594();                           // 这几个函数找不到
  sub_7FA16F6F5574(&unk_7FA16F6F6469, buffer);
  chr1 = 0;
  chr2 = 0;
  v5 = 0;
  for ( i = 0; buffer[i]; i += 2 )              // 也就是每次对buffer的两个字符进行tea加密
  {
    
    
    chr1 = buffer[i];
    chr2 = buffer[i + 1];
    Tea(dword_7FA16F6F8474, &chr1, key);        // 一次加密两个字符
    buffer[i] = chr1;                           // 更新buffer串
    buffer[i + 1] = chr2;
  }
  d1 = 0;
  d2 = 0;
  b1 = 0;
  b2 = 0;
  v11 = 0;
  for ( j = 0; buffer[j]; j += 2 )              // 比较函数
  {
    
    
    d1 = desStr[j];
    d2 = desStr[j + 1];
    b1 = buffer[j];
    b2 = buffer[j + 1];
    if ( d1 != b1 || d2 != b2 )
      break;
  }
  sub_7FA16F6F5524();
  result = 0LL;
  if ( v13 != __readfsqword(0x28u) )
    return sub_7FA16F6F5544();
  return result;
}

2. Depuración dinámica de IDA (adjuntar depuración adicional)

Si usa directamente el ajuste remoto de ida, se mostrará un error:
El archivo de entrada es una biblioteca dinámica, no se puede ejecutar por sí mismo.
Especifique la aplicación host (Depurador, Opciones de proceso) Le indicará
inserte la descripción de la imagen aquí
que se trata de un archivo de biblioteca dinámica y se requiere un proceso adicional para la depuración, entonces podemos usar las funciones de depuración adicionales de IDA

  1. La máquina virtual Linux usa privilegios de raíz para ejecutar linux_server64 de ida,
    debe usar privilegios de raíz; de lo contrario, la depuración adicional posterior fallará, porque el servidor IDA no tiene privilegios suficientes.
    inserte la descripción de la imagen aquí
  2. ejecuta el programa
    inserte la descripción de la imagen aquí
  3. Depuración adicional
    Depurador> Adjuntar al proceso
    inserte la descripción de la imagen aquíy luego busque el proceso del té venenoso, haga doble clic para
    inserte la descripción de la imagen aquí
    seleccionar el mismo
    inserte la descripción de la imagen aquí

3. Ingrese las opciones para recorrer

Después de adjuntar con éxito, encontrará que no hay respuesta al presionar f7 o f8. En este momento, el programa está esperando la salida. Primero, ingrese una opción en la máquina virtual de Linux. Si ingresa 1, será
difícil para encontrar la depuración posterior. En resumen, puede encontrar la cadena de carga y tenga cuidado de no omitirla
(no puede encontrarla buscando la cadena directamente. Esta pregunta debería ser que hay una operación SMC para descifrar el programa código.)
La llamada sun_7f006f7c2536 a continuación es la función principal. Haga un seguimiento y vuelva a identificarse para ver la lógica (no haré una introducción detallada aquí, tome la opción 2 como la función principal) host)
inserte la descripción de la imagen aquí

Si ingresa 2
y presiona f7 todo el tiempo, finalmente puede encontrar que el programa se atascará y aún puede ver la cadena InputFlag, aquí está la función principal. Desplácese hacia arriba para encontrar la dirección de inicio
inserte la descripción de la imagen aquí
y presione p para identificar loc_loc_7F3BB0FB6536 como una función, y puede ver la lógica de la función principal Luego,
inserte la descripción de la imagen aquí
todavía hay algunas funciones que no se han identificado correctamente. Debe hacer un seguimiento manual y presionar p para identificarlas como funciones, y luego regresar a la interfaz de desmontaje. y presione f5 para volver a identificarlos
inserte la descripción de la imagen aquí
.veces
inserte la descripción de la imagen aquí
en lugar de 32 veces):
inserte la descripción de la imagen aquí
datos cifrados, el seguimiento puede extraer los datos
inserte la descripción de la imagen aquí

4. Guión de resolución de problemas

#include<stdio.h>
void Tea(int len, unsigned int* buffer, int* key)
{
    
    
	int i; // [rsp+24h] [rbp-14h]
	unsigned int v5; // [rsp+28h] [rbp-10h]
	unsigned int v6; // [rsp+2Ch] [rbp-Ch]
	unsigned int v7; // [rsp+30h] [rbp-8h]

	v5 = *buffer;
	v6 = buffer[1];
	v7 = 0xd9b6d99c;
	for (i = 0; i < len; ++i)
	{
    
    
		v6 -= (v5 + ((v5 >> 5) ^ (16 * v5))) ^ (key[(v7 >> 11) & 3] + v7);
		v7 += 0x41104111;
		v5 -= (v6 + ((v6 >> 5) ^ (16 * v6))) ^ (key[v7 & 3] + v7);
	}
	*buffer = v5;
	buffer[1] = v6;
}
int main()
{
    
    
	int  buffer[14] =
	{
    
    
	  -318921983,
	  1639894517,
	  -1197577091,
	  -835265432,
	  1265521566,
	  1680782596,
	  1425658684,
	  1829167973,
	  -360235693,
	  -1537112825,
	  -676229584,
	  -1000652734,
	  0,
	  0,
	};
	int key[5] = {
    
     5,2,9,7,0 };
	int chr[2] = {
    
     0 };
	for (int i = 0; buffer[i]; i += 2)              // 也就是每次对buffer的两个字符进行tea加密
	{
    
    
		chr[0] = buffer[i];
		chr[1] = buffer[i + 1];
		Tea(36, chr, key);						// 一次加密两个字符
		buffer[i] = chr[0];                           // 更新buffer串
		buffer[i + 1] = chr[1];
	}
	unsigned char* p = (unsigned char*)buffer;
	printf("%s", p);
	//Thisisflag{cdfec405-3f4b-457e-92fe-f6446098ee2e}
	return 0;
}

BWBA

Después de un breve análisis de la lógica del programa,
inserte la descripción de la imagen aquí
le pedí a ChatGpt que me respondiera sobre el algoritmo FFT en lugar de DCT cuando lo reproduje aquí, y el script de descifrado de salida siempre estaba mal. Parece que debería aprender más sobre este algoritmo. Consulte el artículo: 2023 Spring and Autumn Cup
Spring Competition WP-REVERSE (AK)
se puede procesar con funciones de biblioteca cv2

import numpy as np
import cv2

x = np.array([370.75,234.362,-58.0834,59.8212,88.8221,-30.2406,21.8316,49.9781,-33.5259,2.69675,43.5386,-30.2925,-28.0754,27.593,-2.53962,-27.1883,-5.60777,-0.263937,6.80326,8.03022,-6.34681,-0.89506,-6.80685,-13.6088,27.0958,29.8439,-21.7688,-20.6925,-13.2155,-37.0994,2.23679,37.6699,-3.5,9.85188,57.2806,13.5715,-20.7184,8.6816,3.59369,-4.5302,4.22203,-28.8166,-23.695,31.2268,6.58823,-39.9966,-20.7877,-19.7624,-22.031,16.3285,2.07557,-26.2521,16.1914,18.3976,-26.9295,3.03769,41.0412,20.2598,14.991,6.99392,-22.3752,-7.24466,8.96299,-10.4874], dtype=np.float64)
x = cv2.idct(x)
x = x.ravel()
flag=''

for i in range(len(x)):
    flag+=chr(round(x[i]))
print(flag)#flag{9ab488a7-5b11-1b15-04f2-c230704ecf72}

Hay algunos buenos artículos sobre el algoritmo DCT:

  1. Transformada de coseno discreta DCT
  2. Transformada de coseno discreta detallada (DCT)

ViejoCódigoSimbólico

Supongo que te gusta

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