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
289 lines
8.2 KiB
Markdown
289 lines
8.2 KiB
Markdown
# ADIF API - Reverse Engineering ✅
|
|
|
|
Cliente Python completo para acceder a la API de ADIF (El Cano Móvil) mediante ingeniería reversa.
|
|
|
|
> **Estado del Proyecto**: ✅ **COMPLETADO CON ÉXITO**
|
|
> Autenticación HMAC-SHA256 implementada, 4/8 endpoints funcionales, 1587 códigos de estación extraídos.
|
|
|
|
---
|
|
|
|
## 🚀 Inicio Rápido
|
|
|
|
```bash
|
|
# Instalar dependencias
|
|
pip install requests
|
|
|
|
# Ejecutar demo
|
|
python3 adif_client.py
|
|
```
|
|
|
|
### Uso Básico
|
|
|
|
```python
|
|
from adif_client import AdifClient
|
|
|
|
# Inicializar cliente
|
|
client = AdifClient(
|
|
access_key="and20210615",
|
|
secret_key="Jthjtr946RTt"
|
|
)
|
|
|
|
# Obtener salidas de Madrid Atocha
|
|
trains = client.get_departures("10200", "AVLDMD")
|
|
|
|
for train in trains:
|
|
info = train['commercialPathInfo']
|
|
print(f"Tren {info['commercialPathKey']['commercialCirculationKey']['commercialNumber']}")
|
|
|
|
# Obtener ruta completa de un tren
|
|
route = client.get_train_route(
|
|
commercial_number="03194",
|
|
launching_date=1764889200000,
|
|
origin_station_code="10200",
|
|
destination_station_code="71801"
|
|
)
|
|
```
|
|
|
|
---
|
|
|
|
## 📊 Estado del Proyecto
|
|
|
|
### ✅ Funcionalidades Implementadas
|
|
|
|
| Característica | Estado | Descripción |
|
|
|----------------|--------|-------------|
|
|
| Extracción de claves | ✅ | Claves extraídas de `libapi-keys.so` con Ghidra |
|
|
| Algoritmo HMAC-SHA256 | ✅ | Implementación completa y validada |
|
|
| Códigos de estación | ✅ | 1587 estaciones extraídas |
|
|
| Endpoints funcionales | ✅ | 4/8 endpoints (50%) |
|
|
| Cliente Python | ✅ | API completa y lista para usar |
|
|
| Documentación | ✅ | Completa en `/docs` |
|
|
|
|
### 📍 Endpoints Disponibles
|
|
|
|
#### ✅ Funcionales (4/8)
|
|
|
|
| Método | Endpoint | Descripción |
|
|
|--------|----------|-------------|
|
|
| `get_departures()` | `/departures/traffictype/` | Salidas de una estación |
|
|
| `get_arrivals()` | `/arrivals/traffictype/` | Llegadas a una estación |
|
|
| `get_train_route()` | `/onepaths/` | Ruta completa de un tren |
|
|
| `get_station_observations()` | `/stationsobservations/` | Observaciones de estaciones |
|
|
|
|
#### ❌ Bloqueados por Permisos (4/8)
|
|
|
|
- `/betweenstations/traffictype/` - 401 Unauthorized
|
|
- `/onestation/` - 401 Unauthorized
|
|
- `/severalpaths/` - 401 Unauthorized
|
|
- `/compositions/path/` - 401 Unauthorized
|
|
|
|
**Nota**: Los endpoints bloqueados tienen implementación correcta pero las claves no tienen permisos suficientes.
|
|
|
|
---
|
|
|
|
## 📁 Estructura del Proyecto
|
|
|
|
```
|
|
adif-api-reverse-engineering/
|
|
├── 📄 README.md # Este archivo
|
|
├── 📄 LICENSE # Licencia MIT
|
|
│
|
|
├── 🐍 Python Scripts (Core)
|
|
│ ├── adif_auth.py # ⭐ Implementación HMAC-SHA256
|
|
│ ├── adif_client.py # ⭐ Cliente completo de la API
|
|
│ ├── query_api.py # CLI interactivo
|
|
│ └── generate_curl.py # Generador de curls
|
|
│
|
|
├── 📊 Datos
|
|
│ ├── station_codes.txt # ⭐ 1587 códigos de estación
|
|
│ └── extracted_keys.txt # Claves extraídas
|
|
│
|
|
├── 🧪 Tests
|
|
│ ├── test_endpoints_detailed.py # Test exhaustivo con debug
|
|
│ └── test_onepaths_with_real_trains.py # Test con datos reales
|
|
│
|
|
├── 📚 Documentación (/docs)
|
|
│ ├── FINAL_STATUS_REPORT.md # Informe completo
|
|
│ ├── API_DOCUMENTATION.md # Documentación de API
|
|
│ ├── AUTHENTICATION_ALGORITHM.md # Algoritmo HMAC
|
|
│ ├── ENDPOINTS_ANALYSIS.md # Análisis de endpoints
|
|
│ ├── API_REQUEST_BODIES.md # Payloads documentados
|
|
│ ├── GHIDRA_GUIDE.md # Tutorial de Ghidra
|
|
│ ├── NEW_DISCOVERIES.md # Últimos descubrimientos
|
|
│ └── CLAUDE.md # Contexto del proyecto
|
|
│
|
|
├── 📦 APK & Análisis
|
|
│ ├── base.apk # APK original
|
|
│ ├── apk_decompiled/ # Código decompilado (JADX)
|
|
│ ├── apk_extracted/ # APK extraído
|
|
│ │ ├── assets/stations_all.json # Fuente de estaciones
|
|
│ │ └── lib/x86_64/libapi-keys.so # Librería con claves
|
|
│ └── frida_scripts/ # Scripts de análisis dinámico
|
|
│
|
|
└── 🗂️ Otros
|
|
├── archived_tests/ # Tests antiguos archivados
|
|
└── api_testing_scripts/ # Scripts auxiliares
|
|
```
|
|
|
|
---
|
|
|
|
## 🔑 Autenticación
|
|
|
|
### Claves Extraídas
|
|
|
|
```python
|
|
ACCESS_KEY = "and20210615"
|
|
SECRET_KEY = "Jthjtr946RTt"
|
|
USER_KEY_CIRCULATION = "f4ce9fbfa9d721e39b8984805901b5df"
|
|
USER_KEY_STATIONS = "0d021447a2fd2ac64553674d5a0c1a6f"
|
|
```
|
|
|
|
**Fuente**: `apk_extracted/lib/x86_64/libapi-keys.so` (Ghidra)
|
|
|
|
### Algoritmo HMAC-SHA256
|
|
|
|
Implementación basada en AWS Signature v4:
|
|
|
|
**⚠️ CRÍTICO**: El orden de headers NO es alfabético:
|
|
|
|
```python
|
|
canonical_headers = (
|
|
f"content-type:application/json\n"
|
|
f"x-elcano-host:{host}\n" # ← NO alfabético
|
|
f"x-elcano-client:api-elcano\n"
|
|
f"x-elcano-date:{timestamp}\n"
|
|
f"x-elcano-userid:{user_id}\n"
|
|
)
|
|
```
|
|
|
|
Ver `adif_auth.py` para implementación completa.
|
|
|
|
---
|
|
|
|
## 🗺️ Códigos de Estación
|
|
|
|
**Total**: 1587 estaciones
|
|
**Archivo**: `station_codes.txt`
|
|
**Formato**: `código TAB nombre TAB tipos_tráfico`
|
|
|
|
### Top 10 Estaciones
|
|
|
|
```
|
|
10200 Madrid Puerta de Atocha AVLDMD
|
|
10302 Madrid Chamartín-Clara Campoamor AVLDMD
|
|
71801 Barcelona Sants AVLDMD,CERCANIAS
|
|
60000 València Nord AVLDMD
|
|
11401 Sevilla Santa Justa AVLDMD
|
|
50003 Alacant Terminal AVLDMD,CERCANIAS
|
|
54007 Córdoba Central AVLDMD
|
|
79600 Zaragoza Portillo AVLDMD,CERCANIAS
|
|
03216 València J.Sorolla AVLDMD
|
|
04040 Zaragoza Delicias AVLDMD,CERCANIAS
|
|
```
|
|
|
|
---
|
|
|
|
## 💡 Casos de Uso
|
|
|
|
### 1. Monitor de Retrasos
|
|
|
|
```python
|
|
import time
|
|
from adif_client import AdifClient
|
|
|
|
client = AdifClient(ACCESS_KEY, SECRET_KEY)
|
|
|
|
while True:
|
|
trains = client.get_departures("10200", "ALL")
|
|
for train in trains:
|
|
passthrough = train.get('passthroughStep', {})
|
|
dep_sides = passthrough.get('departurePassthroughStepSides', {})
|
|
delay = dep_sides.get('forecastedOrAuditedDelay', 0)
|
|
|
|
if delay > 300: # Más de 5 minutos
|
|
print(f"⚠️ Retraso de {delay//60} min")
|
|
|
|
time.sleep(30)
|
|
```
|
|
|
|
### 2. Consultar Rutas Completas
|
|
|
|
```python
|
|
# Obtener trenes con sus rutas
|
|
trains_with_routes = client.get_all_departures_with_routes(
|
|
station_code="10200",
|
|
traffic_type="AVLDMD",
|
|
max_trains=5
|
|
)
|
|
|
|
for train in trains_with_routes:
|
|
print(f"🚄 Tren {train['commercial_number']}")
|
|
print(f" Paradas: {len(train['route'])}")
|
|
```
|
|
|
|
### 3. CLI Interactivo
|
|
|
|
```bash
|
|
python3 query_api.py
|
|
```
|
|
|
|
---
|
|
|
|
## 🔬 Herramientas Utilizadas
|
|
|
|
- **Ghidra** - Extracción de claves de `libapi-keys.so`
|
|
- **JADX** - Decompilación del APK
|
|
- **Python 3** - Implementación del cliente
|
|
- **Frida** (opcional) - Análisis dinámico
|
|
|
|
---
|
|
|
|
## 📖 Documentación
|
|
|
|
Toda la documentación está en `/docs`:
|
|
|
|
- **[FINAL_STATUS_REPORT.md](docs/FINAL_STATUS_REPORT.md)** - Informe completo del proyecto
|
|
- **[API_DOCUMENTATION.md](docs/API_DOCUMENTATION.md)** - Documentación de la API
|
|
- **[AUTHENTICATION_ALGORITHM.md](docs/AUTHENTICATION_ALGORITHM.md)** - Algoritmo HMAC detallado
|
|
- **[GHIDRA_GUIDE.md](docs/GHIDRA_GUIDE.md)** - Tutorial paso a paso
|
|
|
|
---
|
|
|
|
## 🎯 Logros del Proyecto
|
|
|
|
✅ Claves de autenticación extraídas con Ghidra
|
|
✅ Algoritmo HMAC-SHA256 implementado y validado
|
|
✅ 1587 códigos de estación disponibles
|
|
✅ 4/8 endpoints funcionales (50%)
|
|
✅ Cliente Python listo para producción
|
|
✅ Documentación completa
|
|
|
|
---
|
|
|
|
## ⚠️ Limitaciones
|
|
|
|
- 4/8 endpoints bloqueados por permisos del servidor
|
|
- Las claves extraídas son de perfil "anónimo/básico"
|
|
- No hay acceso a información de usuario autenticado
|
|
|
|
---
|
|
|
|
## 📄 Licencia
|
|
|
|
MIT License - Ver [LICENSE](LICENSE)
|
|
|
|
⚠️ **Disclaimer**: Proyecto con fines educativos y de investigación. Úsalo de forma responsable.
|
|
|
|
---
|
|
|
|
## ✨ Créditos
|
|
|
|
- **ADIF** - Por la aplicación El Cano Móvil
|
|
- **Ghidra** & **JADX** - Herramientas de reverse engineering
|
|
- **Comunidad de seguridad** - Por compartir conocimiento
|
|
|
|
---
|
|
|
|
**Última actualización**: 2025-12-05
|
|
**Estado**: ✅ Proyecto completado con éxito
|