Files
adif-api-reverse-engineering/docs/GHIDRA_GUIDE.md
Dasemu 68fac80520 Refactor: reorganización completa del proyecto y documentación consolidada
Esta actualización reorganiza el proyecto de reverse engineering de la API de ADIF con los siguientes cambios:

Estructura del proyecto:
- Movida documentación principal a carpeta docs/
- Consolidados archivos markdown redundantes en CLAUDE.md (contexto completo del proyecto)
- Organización de tests en carpeta tests/ con README explicativo
- APK renombrado de base.apk a adif.apk para mayor claridad

Archivos de código:
- Movidos adif_auth.py y adif_client.py a la raíz (antes en api_testing_scripts/)
- Eliminados scripts de testing obsoletos y scripts de Frida no utilizados
- Nuevos tests detallados: test_endpoints_detailed.py y test_onepaths_with_real_trains.py

Descubrimientos:
- Documentados nuevos hallazgos en docs/NEW_DISCOVERIES.md
- Actualización de onePaths funcionando con commercialNumber real (devuelve 200)
- Extraídos 1587 códigos de estación en station_codes.txt

Configuración:
- Actualizado .gitignore con mejores patrones para Python e IDEs
- Eliminados archivos temporales de depuración y logs
2025-12-05 11:22:13 +01:00

17 KiB

Guía Paso a Paso: Extracción de Claves con Ghidra

Objetivo: Extraer ACCESS_KEY y SECRET_KEY de libapi-keys.so

Dificultad: Principiante (no requiere experiencia previa)

Tiempo estimado: 30-45 minutos


Paso 1: Instalar Ghidra

1.1 Verificar Java

Ghidra requiere Java 17 o superior.

# Verificar versión de Java
java -version

Si no tienes Java 17+:

# Ubuntu/Debian
sudo apt update
sudo apt install openjdk-17-jdk

# Verificar instalación
java -version

Salida esperada:

openjdk version "17.0.x" ...

1.2 Descargar Ghidra

# Ir a tu directorio de trabajo
cd /home/dasemu/Hacking/adif-api-reverse-enginereeng

# Crear carpeta para herramientas
mkdir -p tools
cd tools

# Descargar Ghidra (versión 11.2.1 - última estable)
wget https://github.com/NationalSecurityAgency/ghidra/releases/download/Ghidra_11.2.1_build/ghidra_11.2.1_PUBLIC_20241105.zip

# Extraer
unzip ghidra_11.2.1_PUBLIC_20241105.zip

# Navegar a la carpeta
cd ghidra_11.2.1_PUBLIC

Estructura después de extraer:

tools/
└── ghidra_11.2.1_PUBLIC/
    ├── ghidraRun
    ├── support/
    ├── docs/
    └── ...

1.3 Ejecutar Ghidra

# Dar permisos de ejecución
chmod +x ghidraRun

# Ejecutar Ghidra
./ghidraRun

Qué esperar:

  • Se abrirá una ventana GUI de Ghidra
  • Primera vez puede tardar 30-60 segundos

Paso 2: Crear Proyecto en Ghidra

2.1 Crear Nuevo Proyecto

Una vez abierto Ghidra:

  1. FileNew Project
  2. Seleccionar: Non-Shared ProjectNext
  3. Project Name: adif-keys-extraction
  4. Project Directory: Navegar a /home/dasemu/Hacking/adif-api-reverse-enginereeng/tools
  5. Click Finish

Resultado:

  • Verás el proyecto creado en la ventana principal
  • Panel izquierdo estará vacío (sin archivos importados aún)

Paso 3: Importar libapi-keys.so

3.1 Importar el Archivo

  1. FileImport File
  2. Navegar a: /home/dasemu/Hacking/adif-api-reverse-enginereeng/apk_extracted/lib/x86_64/libapi-keys.so
  3. Click Select File to Import

Ghidra detectará automáticamente:

  • Format: ELF (Executable and Linking Format)
  • Language: x86:LE:64:default (Intel x86 64-bit)
  1. Click OK (dejar opciones por defecto)
  2. Click OK en el resumen de importación

Resultado:

  • Verás libapi-keys.so en el panel de archivos del proyecto

Paso 4: Analizar el Binario

4.1 Abrir el Archivo

  1. Doble click en libapi-keys.so en el panel de archivos
  2. Aparecerá mensaje: "libapi-keys.so has not been analyzed. Would you like to analyze it now?"
  3. Click Yes

4.2 Configurar Análisis

Aparecerá ventana "Analysis Options":

Opciones recomendadas para nuestro caso:

  • Decompiler Parameter ID (activado)
  • Function Start Search (activado)
  • ASCII Strings (activado) ← IMPORTANTE
  • Demangler GNU (activado)
  • Shared Return Calls (activado)

Resto: Dejar por defecto

  1. Click Analyze

Qué esperar:

  • Proceso de análisis tomará 2-5 minutos
  • Verás barra de progreso en la esquina inferior derecha
  • Cuando termine, el panel principal mostrará código desensamblado

Paso 5: Buscar las Funciones JNI

5.1 Abrir Ventana de Funciones

  1. WindowFunctions (o presionar Ctrl+F)

Panel de funciones se abrirá mostrando todas las funciones del binario.

5.2 Buscar getAccessKeyPro

En el panel de Functions:

  1. Click en el campo de búsqueda (arriba del panel)
  2. Escribir: getAccessKeyPro
  3. Presionar Enter

Deberías ver:

Java_com_adif_commonKeys_GetKeysHelper_getAccessKeyPro

5.3 Buscar getSecretKeyPro

Repetir búsqueda:

  1. Limpiar campo de búsqueda
  2. Escribir: getSecretKeyPro
  3. Presionar Enter

Deberías ver:

Java_com_adif_commonKeys_GetKeysHelper_getSecretKeyPro

Paso 6: Extraer ACCESS_KEY

6.1 Abrir Función getAccessKeyPro

  1. En el panel de Functions, doble click en:
    Java_com_adif_commonKeys_GetKeysHelper_getAccessKeyPro
    

Panel principal mostrará:

  • Izquierda: Código ensamblador (difícil de leer)
  • Derecha: Código C decompilado (fácil de leer)

6.2 Analizar el Código Decompilado

En el panel derecho ("Decompile: libapi-keys.so"), busca algo similar a:

JNIEnv * Java_com_adif_commonKeys_GetKeysHelper_getAccessKeyPro(JNIEnv *env, jobject obj)
{
    // ... código de inicialización ...

    // Buscar líneas que contengan cadenas o retornos
    return (*env)->NewStringUTF(env, "ALGUNA_CADENA_AQUI");
}

O puede verse así:

jstring Java_com_adif_commonKeys_GetKeysHelper_getAccessKeyPro
               (JNIEnv *param_1,jobject param_2)
{
  jstring pJVar1;

  pJVar1 = (*(*param_1)->NewStringUTF)(param_1, "LA_CLAVE_AQUI");
  return pJVar1;
}

6.3 Identificar la Clave

La ACCESS_KEY será el string entre comillas en NewStringUTF

Ejemplo:

(*env)->NewStringUTF(env, "AKIAxxxxxxxxxxxxxxxx")
                           ^^^^^^^^^^^^^^^^^^^^
                           Esta es la ACCESS_KEY

Copia ese string completo → Esa es tu ACCESS_KEY


Paso 7: Extraer SECRET_KEY

7.1 Repetir para getSecretKeyPro

  1. En el panel de Functions, doble click en:
    Java_com_adif_commonKeys_GetKeysHelper_getSecretKeyPro
    

7.2 Analizar el Código

Nuevamente, busca en el panel derecho:

jstring Java_com_adif_commonKeys_GetKeysHelper_getSecretKeyPro
               (JNIEnv *param_1,jobject param_2)
{
  jstring pJVar1;

  pJVar1 = (*(*param_1)->NewStringUTF)(param_1, "LA_SECRET_KEY_AQUI");
  return pJVar1;
}

La SECRET_KEY será el string entre comillas

Copia ese string completo → Esa es tu SECRET_KEY


Paso 8: Si No Ves Strings Directamente

8.1 Alternativa: Buscar en Strings Definidos

Si las funciones usan referencias indirectas:

  1. WindowDefined Strings
  2. Panel mostrará TODOS los strings del binario
  3. Buscar por características:
    • Longitud ~40-64 caracteres
    • Formato Base64 o alfanumérico
    • Probablemente consecutivos en la lista

8.2 Filtrar Strings Sospechosos

En el panel "Defined Strings":

  1. Click en "Filter" (arriba)
  2. Filtrar por longitud mínima: Min Length: 32
  3. Revisar manualmente strings que parezcan claves

Características de claves típicas:

  • ACCESS_KEY: ~20-40 caracteres, alfanumérico
  • SECRET_KEY: ~40-64 caracteres, alfanumérico o Base64

8.3 Verificar Referencias

Para cada string sospechoso:

  1. Click derecho → ReferencesShow References to Address
  2. Si está referenciado por las funciones JNI que buscamos, es la clave correcta

Paso 9: Usar las Claves Extraídas

9.1 Actualizar adif_auth.py

Una vez tengas ambas claves:

# Editar el archivo
nano adif_auth.py

# O con tu editor favorito
code adif_auth.py

Buscar líneas 402-403:

ACCESS_KEY = "YOUR_ACCESS_KEY_HERE"  # Reemplazar
SECRET_KEY = "YOUR_SECRET_KEY_HERE"  # Reemplazar

Reemplazar con las claves extraídas:

ACCESS_KEY = "la_clave_que_encontraste_en_getAccessKeyPro"
SECRET_KEY = "la_clave_que_encontraste_en_getSecretKeyPro"

9.2 Probar la Autenticación

# Ejecutar el script de ejemplo
python3 adif_auth.py

Salida esperada:

======================================================================
ADIF API Authenticator - Ejemplo de Uso
======================================================================

Headers generados:
----------------------------------------------------------------------
Content-Type: application/json;charset=utf-8
X-Elcano-Host: circulacion.api.adif.es
X-Elcano-Client: AndroidElcanoApp
X-Elcano-Date: 20251204T123456Z
X-Elcano-UserId: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
Authorization: HMAC-SHA256 Credential=...
User-key: f4ce9fbfa9d721e39b8984805901b5df

9.3 Probar Petición Real

# test_real_auth.py
from adif_auth import AdifAuthenticator
import requests

# Usar las claves reales
ACCESS_KEY = "tu_access_key_extraida"
SECRET_KEY = "tu_secret_key_extraida"

auth = AdifAuthenticator(access_key=ACCESS_KEY, secret_key=SECRET_KEY)

url = "https://circulacion.api.adif.es/portroyalmanager/secure/circulationpaths/departures/traffictype/"
payload = {
    "commercialService": "BOTH",
    "commercialStopType": "BOTH",
    "page": {"pageNumber": 0},
    "stationCode": "10200",
    "trafficType": "ALL"
}

headers = auth.get_auth_headers("POST", url, payload)
headers["User-key"] = auth.USER_KEY_CIRCULATION

response = requests.post(url, json=payload, headers=headers)

print(f"Status: {response.status_code}")
if response.status_code == 200:
    print("¡ÉXITO! Autenticación funcionando")
    print(response.json())
else:
    print("Error:", response.text)

Ejecutar:

python3 test_real_auth.py

Si todo funciona:

Status: 200
¡ÉXITO! Autenticación funcionando
{'departures': [...], 'totalElements': 45, ...}

Troubleshooting

Problema 1: No Veo las Funciones JNI

Solución:

  1. WindowSymbol Table
  2. Buscar manualmente: Java_com_adif
  3. Deberían aparecer todas las funciones JNI

Problema 2: El Código Decompilado es Ilegible

Solución:

  1. Click derecho en la función → Edit Function Signature
  2. Cambiar tipos de parámetros a:
    jstring function_name(JNIEnv *env, jobject obj)
    
  3. La decompilación mejorará

Problema 3: Las Claves Están Ofuscadas

Si ves algo como:

local_str[0] = 'A';
local_str[1] = 'K';
local_str[2] = 'I';
// ... muchas líneas

Solución:

  1. Las claves se construyen carácter por carácter
  2. Copiar todos los caracteres en orden
  3. Reconstruir el string manualmente

Problema 4: Ghidra No Arranca

Solución:

# Verificar Java
java -version

# Si Java < 17, actualizar
sudo apt install openjdk-17-jdk

# Reintentar
./ghidraRun

Resumen Visual del Proceso

┌─────────────────────────────────────────────────────────────┐
│ 1. Instalar Ghidra + Java 17                                │
└─────────────────┬───────────────────────────────────────────┘
                  │
                  ▼
┌─────────────────────────────────────────────────────────────┐
│ 2. Crear Proyecto → Import libapi-keys.so                   │
└─────────────────┬───────────────────────────────────────────┘
                  │
                  ▼
┌─────────────────────────────────────────────────────────────┐
│ 3. Analizar (Auto Analysis con opciones por defecto)        │
└─────────────────┬───────────────────────────────────────────┘
                  │
                  ▼
┌─────────────────────────────────────────────────────────────┐
│ 4. Window → Functions → Buscar "getAccessKeyPro"            │
└─────────────────┬───────────────────────────────────────────┘
                  │
                  ▼
┌─────────────────────────────────────────────────────────────┐
│ 5. Doble click → Ver código decompilado (panel derecho)     │
└─────────────────┬───────────────────────────────────────────┘
                  │
                  ▼
┌─────────────────────────────────────────────────────────────┐
│ 6. Encontrar NewStringUTF(env, "LA_CLAVE_AQUI")             │
└─────────────────┬───────────────────────────────────────────┘
                  │
                  ▼
┌─────────────────────────────────────────────────────────────┐
│ 7. Copiar el string → Esa es la ACCESS_KEY                  │
└─────────────────┬───────────────────────────────────────────┘
                  │
                  ▼
┌─────────────────────────────────────────────────────────────┐
│ 8. Repetir con "getSecretKeyPro" → SECRET_KEY               │
└─────────────────┬───────────────────────────────────────────┘
                  │
                  ▼
┌─────────────────────────────────────────────────────────────┐
│ 9. Actualizar adif_auth.py con las claves                   │
└─────────────────┬───────────────────────────────────────────┘
                  │
                  ▼
┌─────────────────────────────────────────────────────────────┐
│ 10. Probar peticiones → ¡SUCCESS! (Status 200)              │
└─────────────────────────────────────────────────────────────┘

Comandos Rápidos de Referencia

# Instalar Java 17
sudo apt install openjdk-17-jdk

# Descargar y extraer Ghidra
cd /home/dasemu/Hacking/adif-api-reverse-enginereeng/tools
wget https://github.com/NationalSecurityAgency/ghidra/releases/download/Ghidra_11.2.1_build/ghidra_11.2.1_PUBLIC_20241105.zip
unzip ghidra_11.2.1_PUBLIC_20241105.zip

# Ejecutar Ghidra
cd ghidra_11.2.1_PUBLIC
chmod +x ghidraRun
./ghidraRun

# Archivo a analizar
# /home/dasemu/Hacking/adif-api-reverse-enginereeng/apk_extracted/lib/x86_64/libapi-keys.so

# Funciones a buscar
# Java_com_adif_commonKeys_GetKeysHelper_getAccessKeyPro
# Java_com_adif_commonKeys_GetKeysHelper_getSecretKeyPro

Próximos Pasos Después de Extraer las Claves

  1. Actualizar adif_auth.py con las claves reales
  2. Ejecutar python3 adif_auth.py para verificar
  3. Crear script de prueba test_real_auth.py
  4. Hacer peticiones a todos los endpoints documentados
  5. Verificar que obtienes Status 200 y datos reales
  6. Actualizar documentación con resultados finales

Notas Importantes

⚠️ Seguridad:

  • Las claves extraídas son secretos de ADIF
  • No las compartas públicamente
  • No las subas a repositorios públicos
  • Usa variables de entorno en producción

⚠️ Legalidad:

  • Este análisis es para fines educativos
  • Usa la API responsablemente
  • Respeta rate limits
  • No abuses del servicio

⚠️ Mantenimiento:

  • Las claves pueden cambiar en futuras versiones de la app
  • Verifica periódicamente si hay actualizaciones
  • Repite el proceso si las claves dejan de funcionar

Ayuda Adicional

Si encuentras problemas durante el proceso:

  1. Revisa la sección Troubleshooting arriba
  2. Consulta la documentación de Ghidra: https://ghidra-sre.org/
  3. Busca en el proyecto archivos relacionados:
    • FINAL_SUMMARY.md - Resumen del proyecto
    • AUTHENTICATION_ALGORITHM.md - Detalles del algoritmo
    • README_FINAL.md - Guía general

¡Éxito con la extracción! 🔑

Una vez tengas las claves, habrás completado el 100% del reverse engineering de la API de ADIF.