Trop d'IQ
Transformée de Fourier discrète, ça se reverse...
Description du challenge
- Nom du CTF : 404CTF 2025
- Catégorie : Hardware
- Difficulté : Intro
- Date : Mai 2025
On nous donne le challenge suivant :
On nous donne le fichier chall.iq
à analyser : fichier
Analyse préliminaire
On nous informe que le challenge consiste à démoduler un signal passé par une transformée de Fourier discrète (DFT). On peut donc appliquer une transformée de Fourier inverse (IDFT) pour récupérer le signal original.
On sait aussi que la fréquence d'échantillonage est de 44,1 kHz et que le fichier est au format IQ Complex128.
Démodulation avec Python
On peut utiliser les bibliothèques numpy
et scipy
pour effectuer la transformée de Fourier inverse. On suppose aussi que le signal est modulé FM :
import numpy as np
from scipy import signal
from scipy.io import wavfile
from scipy.fft import ifft
def demodulate_fm_iq(iq_file_path, output_wav_path="output_audio.wav", sample_rate=44100):
"""
Démodule un fichier IQ contenant un signal FM transformé par DFT.
Args:
iq_file_path (str): Chemin vers le fichier IQ
output_wav_path (str): Chemin où sauvegarder le fichier WAV démodulé
sample_rate (int): Taux d'échantillonnage du signal (Hz)
"""
# Lecture du fichier IQ (format complex128)
try:
iq_data = np.fromfile(iq_file_path, dtype=np.complex128)
print(f"Données IQ chargées: {len(iq_data)} échantillons")
except Exception as e:
print(f"Erreur lors de la lecture du fichier IQ: {e}")
return
# Conversion des données du domaine fréquentiel au domaine temporel
print("Application de la transformée de Fourier inverse...")
# Application de la transformée de Fourier inverse
time_domain = ifft(iq_data)
# Pour un signal audio standard, on peut utiliser directement la partie réelle
# ou prendre l'amplitude du signal complexe
audio = np.real(time_domain)
# Normalisation de l'audio
audio = audio / np.max(np.abs(audio))
# Filtre passe-bas pour éliminer le bruit haute fréquence
print("Application d'un filtre passe-bas...")
cutoff = 15000 / (sample_rate / 2)
b, a = signal.butter(8, cutoff, 'lowpass')
audio_filtered = signal.filtfilt(b, a, audio)
# Normalisation pour le format WAV
audio_normalized = np.int16(audio_filtered * 32767)
# Sauvegarde en WAV
print(f"Enregistrement du fichier audio: {output_wav_path}")
wavfile.write(output_wav_path, sample_rate, audio_normalized)
# Également essayer la partie imaginaire (au cas où)
audio_imag = np.imag(time_domain)
audio_imag = audio_imag / np.max(np.abs(audio_imag))
audio_imag_filtered = signal.filtfilt(b, a, audio_imag)
audio_imag_normalized = np.int16(audio_imag_filtered * 32767)
wavfile.write("output_imag.wav", sample_rate, audio_imag_normalized)
print("Démodulation terminée!")
return audio_filtered
if __name__ == "__main__":
audio = demodulate_fm_iq("chall2.iq", "output.wav")
FLAG
404CTF{45D0587}