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
This commit is contained in:
591
docs/GHIDRA_GUIDE.md
Normal file
591
docs/GHIDRA_GUIDE.md
Normal file
@@ -0,0 +1,591 @@
|
||||
# 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.
|
||||
|
||||
```bash
|
||||
# Verificar versión de Java
|
||||
java -version
|
||||
```
|
||||
|
||||
**Si no tienes Java 17+:**
|
||||
|
||||
```bash
|
||||
# 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
|
||||
|
||||
```bash
|
||||
# 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
|
||||
|
||||
```bash
|
||||
# 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. **File** → **New Project**
|
||||
2. Seleccionar: **Non-Shared Project** → **Next**
|
||||
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. **File** → **Import 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)
|
||||
|
||||
4. Click **OK** (dejar opciones por defecto)
|
||||
5. 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
|
||||
|
||||
4. 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. **Window** → **Functions** (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:
|
||||
|
||||
```c
|
||||
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í:**
|
||||
|
||||
```c
|
||||
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:
|
||||
```c
|
||||
(*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:
|
||||
|
||||
```c
|
||||
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. **Window** → **Defined 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 → **References** → **Show 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:
|
||||
|
||||
```bash
|
||||
# Editar el archivo
|
||||
nano adif_auth.py
|
||||
|
||||
# O con tu editor favorito
|
||||
code adif_auth.py
|
||||
```
|
||||
|
||||
**Buscar líneas 402-403:**
|
||||
|
||||
```python
|
||||
ACCESS_KEY = "YOUR_ACCESS_KEY_HERE" # Reemplazar
|
||||
SECRET_KEY = "YOUR_SECRET_KEY_HERE" # Reemplazar
|
||||
```
|
||||
|
||||
**Reemplazar con las claves extraídas:**
|
||||
|
||||
```python
|
||||
ACCESS_KEY = "la_clave_que_encontraste_en_getAccessKeyPro"
|
||||
SECRET_KEY = "la_clave_que_encontraste_en_getSecretKeyPro"
|
||||
```
|
||||
|
||||
### 9.2 Probar la Autenticación
|
||||
|
||||
```bash
|
||||
# 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
|
||||
|
||||
```python
|
||||
# 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:**
|
||||
```bash
|
||||
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. **Window** → **Symbol 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:
|
||||
|
||||
```c
|
||||
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:**
|
||||
|
||||
```bash
|
||||
# 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
|
||||
|
||||
```bash
|
||||
# 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.
|
||||
Reference in New Issue
Block a user