Description
Il s’agit d’une épreuve de reverse Windows à partir d’un exécutable “time.exe”.
Première exécution
Lors de l’exécution de time.exe
sans argument, sur mon ordinateur Windows 11 x64, on obtient un message :
You Are too late.
Désassemblage
Sans plus d’indication, je passe au désassemblage (avec IDA Freeware).
.text:00400303 8D 44 24 18 lea eax, [esp+2Ch+SystemTimeAsFileTime]
.text:00400307 C7 44 24 18 FF FF FF FF mov [esp+2Ch+SystemTimeAsFileTime.dwLowDateTime], 0FFFFFFFFh
.text:0040030F 89 04 24 mov [esp+2Ch+lpSystemTimeAsFileTime], eax ; lpSystemTimeAsFileTime
.text:00400312 C7 44 24 1C FF FF FF FF mov [esp+2Ch+SystemTimeAsFileTime.dwHighDateTime], 0FFFFFFFFh
.text:0040031A FF 15 58 05 40 00 call ds:GetSystemTimeAsFileTime
Sur cette première partie, on voit un appel à GetSystemTimeAsFileTime
. En faisant une petite recherche, on trouve sur le site de Microsoft que SystemTimeAsFileTime
est composé de dwLowDateTime
et dwHighDateTime
qui sont tous deux des DWORD
. Ce qui signifie donc qu’ici, le programme stock dans la mémoire les 4 premiers et les 4 derniers octets du temps (date et heure) de l’ordinateur.
.text:00400326 8B 54 24 1C mov edx, [esp+2Ch+SystemTimeAsFileTime.dwHighDateTime]
.text:0040032A 0B 54 24 18 or edx, [esp+2Ch+SystemTimeAsFileTime.dwLowDateTime]
.text:0040032E 75 49 jnz short loc_400379
Un peu plus bas, on voit que le programme stock les 4 premiers octets du temps dans edx
avant d’effectuer un OU logique entre celui-ci et les 4 derniers octets du temps.
Ensuite, un saut est effectué si le résultat de l’opération suivante est non-nul (jump if non-zero), c’est-à-dire que le flag ZF
ne vaut pas 1. Or, pour qu’un OU logique entre deux nombres soient égaux à zéro, il faut également que les deux membres valent zéro. Ce qui veut dire que la date et l’heure du PC soient à 0.
Dans une VM Windows 7, on remarque que la date la plus vieille que l’on peut mettre est le 1er janvier 1980. Cependant, le temps que l’on mette la date et qu’on lance le programme, quelques secondes seront passées et le temps ne sera plus à 0 exactement. C’est donc certainement en creusant cette voie que l’on trouvera le flag :-).
Débogage
Je me suis dit que j’allais donc utiliser un débogueur pour manuellement définir le ZF
flag à 0. Sauf qu’après l’avoir fait, on obtient le message :
This program cannot be run in WIN mode.
En cherchant ce texte précis sur Google, on tombe sur un writeup d’un CTF de 2017 expliquant qu’après avoir eu ce message, il a du exécuter le programme sous DOS via DOSBox pour obtenir le flag.
On connaît maintenant à priori les deux conditions d’obtention du flag :
- Environnement DOS.
- Date et heure définie au 01/01/1980 - 00:00:00.
Flag
J’ai donc téléchargé DOSBox et me suis renseigné sur la possibilité de suspendre le temps sans pour autant suspendre l’exécution de la box mais il semble que cela ne soit pas possible facilement. J’ai essayé d’utiliser le déboguer sans succès.
Enfin, j’ai trouvé qu’il existait un fichier de configuration dans lequel on pouvait exécuter des commandes immédiatement au lancement de la box. Et je me suis dit que peut-être qu’en modifiant le temps et exécutant le programme, ça serait assez rapide pour que cela marche.
J’ai donc ajouté ceci à la fin du fichier dosbox-x.conf
:
[autoexec]
mount c ../..
c:
date 01/01/1980
time 00:00:00
TIMMEE.EXE > a.txt
(J’ai renommé mon programme comme ceci car sinon il exécutait la commande time
)
Et, surprise en ouvrant mon a.txt
:
FCSC{D4735-4r3-d1ff1cu17-70-und3r574nd-15n7-17?}
Conclusion
Petit challenge sympathique que je suis très content d’avoir réussi avec seulement une semaine d’expérience avec le reverse et l’assembleur ! Ça donne envie de continuer.
Pour l’anecdote, j’ai flag 10 minutes avant la fin du FCSC après m’être arraché les cheveux un moment, car je faisais la commande date 01-01-1980
au lieu de date 01/01/1980
depuis le début :-)