Primer paso de la investigacion. Se aportan el .apk, las carpetas con el apk extraido y el apk descompilado. El archivo API_DOCUMENTATION.md es un archivo donde se anotaran los descubrimientos del funcionamiento de la API, y los .py son scripts para probar la funcionalidad de la API con los métodos que vayamos encontrando. Finalmente, los archivos .js son scripts de Frida para extraer informacion de la APP durante la ejecucion.
This commit is contained in:
240
README.md
240
README.md
@@ -1,2 +1,240 @@
|
||||
# adif-api-reverse-enginereeng
|
||||
# Ingeniería Reversa de la API de Adif (Elcano)
|
||||
|
||||
Este proyecto contiene la documentación y herramientas para interactuar con la API no documentada de Adif (sistema Elcano) obtenida mediante ingeniería reversa de la aplicación móvil oficial.
|
||||
|
||||
## Archivos
|
||||
|
||||
- `base.apk` - Aplicación móvil original de Adif
|
||||
- `API_DOCUMENTATION.md` - Documentación completa de la API descubierta
|
||||
- `adif_client.py` - Cliente Python para interactuar con la API
|
||||
- `decompiled/` - Código fuente descompilado de la APK (generado)
|
||||
- `apk_extracted/` - Contenido extraído de la APK (generado)
|
||||
|
||||
## Hallazgos Principales
|
||||
|
||||
### URLs Base
|
||||
- **Estaciones**: `https://estaciones.api.adif.es`
|
||||
- **Circulaciones**: `https://circulacion.api.adif.es`
|
||||
- **Avisa (Incidencias)**: `https://avisa.adif.es`
|
||||
|
||||
### Autenticación
|
||||
|
||||
La API usa **User-keys** en los headers HTTP en lugar de autenticación OAuth tradicional:
|
||||
|
||||
```http
|
||||
Content-Type: application/json;charset=utf-8
|
||||
User-key: f4ce9fbfa9d721e39b8984805901b5df # Para circulaciones
|
||||
User-key: 0d021447a2fd2ac64553674d5a0c1a6f # Para estaciones
|
||||
```
|
||||
|
||||
### Endpoints Principales
|
||||
|
||||
#### Circulaciones (Trenes)
|
||||
- `POST /portroyalmanager/secure/circulationpaths/departures/traffictype/` - Salidas
|
||||
- `POST /portroyalmanager/secure/circulationpaths/arrivals/traffictype/` - Llegadas
|
||||
- `POST /portroyalmanager/secure/circulationpaths/betweenstations/traffictype/` - Entre estaciones
|
||||
- `POST /portroyalmanager/secure/circulationpathdetails/onepaths/` - Detalles de ruta
|
||||
|
||||
#### Estaciones
|
||||
- `GET /portroyalmanager/secure/stations/allstations/reducedinfo/{token}/` - Todas las estaciones
|
||||
- `POST /portroyalmanager/secure/stations/onestation/` - Detalles de estación
|
||||
|
||||
## Uso del Cliente Python
|
||||
|
||||
### Instalación
|
||||
|
||||
```bash
|
||||
# Crear y activar entorno virtual
|
||||
python3 -m venv venv
|
||||
source venv/bin/activate # En Linux/Mac
|
||||
# O en Windows: venv\Scripts\activate
|
||||
|
||||
# Instalar dependencias
|
||||
pip install requests
|
||||
```
|
||||
|
||||
### Ejemplo Básico
|
||||
|
||||
```python
|
||||
from adif_client import AdifClient, TrafficType, State
|
||||
|
||||
# Crear cliente
|
||||
client = AdifClient(debug=True)
|
||||
|
||||
# Obtener salidas de una estación
|
||||
departures = client.get_departures(
|
||||
station_code="10200", # Madrid Atocha
|
||||
traffic_type=TrafficType.CERCANIAS,
|
||||
size=10
|
||||
)
|
||||
|
||||
# Obtener trenes entre dos estaciones
|
||||
trains = client.get_between_stations(
|
||||
origin_station="10200", # Madrid Atocha
|
||||
destination_station="10302", # Madrid Chamartín
|
||||
traffic_type=TrafficType.ALL
|
||||
)
|
||||
|
||||
# Obtener detalles de una estación
|
||||
station = client.get_station_details("10200")
|
||||
```
|
||||
|
||||
### Ejecutar el ejemplo
|
||||
|
||||
```bash
|
||||
./venv/bin/python adif_client.py
|
||||
```
|
||||
|
||||
## Estructura de la Aplicación
|
||||
|
||||
La app está construida con:
|
||||
- **Kotlin** como lenguaje principal
|
||||
- **Retrofit** para las llamadas HTTP
|
||||
- **Hilt** para inyección de dependencias
|
||||
- **Coroutines** para operaciones asíncronas
|
||||
- **Firebase** para analytics
|
||||
|
||||
### Arquitectura
|
||||
|
||||
```
|
||||
com.adif.elcanomovil/
|
||||
├── serviceNetworking/ # Capa de red
|
||||
│ ├── circulations/ # Servicios de circulaciones
|
||||
│ ├── stations/ # Servicios de estaciones
|
||||
│ ├── compositions/ # Composiciones de trenes
|
||||
│ ├── avisa/ # Sistema de incidencias
|
||||
│ └── subscriptions/ # Suscripciones
|
||||
├── repositories/ # Repositorios (patrón Repository)
|
||||
├── domain/ # Lógica de negocio
|
||||
└── ui*/ # Capas de presentación
|
||||
```
|
||||
|
||||
## Información Técnica
|
||||
|
||||
### Estados (State Enum)
|
||||
- `YES` - Sí
|
||||
- `NOT` - No
|
||||
- `BOTH` - Ambos
|
||||
|
||||
**Nota**: En BuildConfig aparece como "ALL" pero en el código real es "BOTH"
|
||||
|
||||
### Tipos de Tráfico (TrafficType)
|
||||
- `CERCANIAS` - Trenes de cercanías
|
||||
- `MEDIA_DISTANCIA` - Media distancia
|
||||
- `LARGA_DISTANCIA` - Larga distancia
|
||||
- `ALL` - Todos los tipos
|
||||
|
||||
### PageInfo
|
||||
La paginación solo usa `pageNumber` (no incluye `size`):
|
||||
|
||||
```json
|
||||
{
|
||||
"page": {
|
||||
"pageNumber": 0
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## ⚠️ ACTUALIZACIÓN IMPORTANTE: Sistema de Autenticación
|
||||
|
||||
**Los tests iniciales fallaron porque la API usa un sistema de autenticación HMAC-SHA256 similar a AWS Signature V4.**
|
||||
|
||||
### El Problema Real
|
||||
|
||||
La API NO usa simples API keys. Cada petición requiere:
|
||||
|
||||
1. **Headers especiales**:
|
||||
- `X-Elcano-Host`
|
||||
- `X-Elcano-Client: AndroidElcanoApp`
|
||||
- `X-Elcano-Date` (timestamp ISO UTC)
|
||||
- `X-Elcano-UserId` (ID único)
|
||||
- `Authorization` con firma HMAC-SHA256
|
||||
|
||||
2. **Claves secretas** almacenadas en librería nativa (`libapi-keys.so`):
|
||||
- `accessKey` (método nativo)
|
||||
- `secretKey` (método nativo)
|
||||
|
||||
3. **Firma de cada petición** que incluye:
|
||||
- Método HTTP
|
||||
- Path y parámetros
|
||||
- Payload (body JSON)
|
||||
- Headers canónicos
|
||||
- Timestamp
|
||||
|
||||
### Cómo Obtener las Claves
|
||||
|
||||
**Método recomendado: Frida**
|
||||
|
||||
```bash
|
||||
# 1. Instalar Frida
|
||||
pip install frida-tools
|
||||
|
||||
# 2. Conectar dispositivo Android / iniciar emulador
|
||||
adb devices
|
||||
|
||||
# 3. Instalar la app
|
||||
adb install base.apk
|
||||
|
||||
# 4. Ejecutar el script de extracción
|
||||
frida -U -f com.adif.elcanomovil -l frida_extract_keys.js --no-pause
|
||||
|
||||
# 5. Interactuar con la app (ver trenes, etc.)
|
||||
# Las claves aparecerán en la consola
|
||||
```
|
||||
|
||||
Ver `AUTH_EXPLAINED.md` para detalles completos del sistema de autenticación.
|
||||
|
||||
## Limitaciones Conocidas
|
||||
|
||||
1. **⚠️ Sistema de autenticación complejo**: Requiere extracción de claves nativas (ver arriba)
|
||||
|
||||
2. **Certificate Pinning**: La app implementa certificate pinning (bypasseable con Frida)
|
||||
|
||||
3. **UserID dinámico**: Se genera por instalación, no es fijo
|
||||
|
||||
4. **Autenticación Avisa**: El sistema Avisa requiere OAuth2 con flujo de password adicional
|
||||
|
||||
## Códigos de Estación Comunes
|
||||
|
||||
- `10200` - Madrid Puerta de Atocha
|
||||
- `10302` - Madrid Chamartín-Clara Campoamor
|
||||
- `71801` - Barcelona Sants
|
||||
- `50000` - Valencia Nord
|
||||
- `11401` - Sevilla Santa Justa
|
||||
|
||||
## Herramientas Utilizadas
|
||||
|
||||
- **jadx** - Descompilador de Android APK a código Java
|
||||
- **unzip** - Para extraer contenido de la APK
|
||||
- **Python requests** - Cliente HTTP
|
||||
- **curl** - Pruebas de endpoints
|
||||
|
||||
## Descompilación
|
||||
|
||||
Para descompilar la APK manualmente:
|
||||
|
||||
```bash
|
||||
# Descargar jadx
|
||||
wget https://github.com/skylot/jadx/releases/download/v1.5.0/jadx-1.5.0.zip
|
||||
unzip jadx-1.5.0.zip -d jadx
|
||||
|
||||
# Descompilar
|
||||
./jadx/bin/jadx -d decompiled base.apk
|
||||
```
|
||||
|
||||
## Próximos Pasos
|
||||
|
||||
- [ ] Investigar el formato exacto de los objetos de petición
|
||||
- [ ] Obtener un token válido para el endpoint de estaciones
|
||||
- [ ] Implementar autenticación OAuth para Avisa
|
||||
- [ ] Documentar códigos de estación
|
||||
- [ ] Crear mappings de respuestas JSON
|
||||
- [ ] Implementar manejo de errores robusto
|
||||
|
||||
## Advertencia Legal
|
||||
|
||||
Este proyecto es solo para fines educativos y de investigación. La API de Adif es propiedad de ADIF y debe usarse respetando sus términos de servicio. No se debe abusar de la API ni usarla para fines comerciales sin autorización.
|
||||
|
||||
## Autor
|
||||
|
||||
Proyecto de ingeniería reversa educativa.
|
||||
|
||||
Reference in New Issue
Block a user