Comment savoir si cela a fonctionné ?
Avec tous les autres outils de ce genre, vous ne le savez pas. L'application démarre, affiche une date, et vous supposez. Mais elle peut lire l'horloge par une voie que rien n'a interceptée - et alors « le test est passé » ne veut plus rien dire.
L'échec qui n'a aucun symptôme
Un outil de décalage du temps qui manque un canal ne plante pas et n'avertit pas. L'application lit simplement la vraie date par la seule fonction que personne n'a interceptée, et se comporte exactement comme elle l'aurait fait un après-midi ordinaire. Le test passe au vert. Le bug est livré.
RunAsDate est honnête à ce sujet dans sa propre documentation - il dit qu'il « n'affectera pas les applications qui obtiennent la date et l'heure courantes d'une autre source » - puis vous laisse déterminer si la vôtre en fait partie. Cet outil traite cette même phrase comme quelque chose à mesurer.
Ce qu'une session rapporte réellement
Sortie réelle, issue de l'exécution de l'outil sur l'une des sondes de test de ce projet - une qui ouvre délibérément une connexion réseau :
$ chrono run "...\pnet-x64.exe" --at 2038-01-19T03:14:07 --report session.txt Chrono Mock - session report target: C:\ChronoMock\tools\probes\bin\pnet-x64.exe verdict: WORKS - time substitution took effect (processes: 1) every process that read time saw the session clock session: fake clock reached 2038-01-19T03:14:10 real elapsed 3.4s, fake elapsed 3.4s exited: the target closed itself with code 0 covered channels (substituted, with call counts, 4 calls in all): - pid 9152: GetSystemTimeAsFileTime (1 call) - pid 9152: NtQuerySystemTime (3 calls) ... every other channel, including the ones never called observed channels (hooked but left real): - pid 9152: NtCreateUserProcess (0 calls) - pid 9152: connect (1 call) warnings: - the target opened a network connection - it may read time from a server, which no local hook can cover (source.network_at_start) requested: 2038-01-19T03:14:07 (zone +02:00 (host default), mode flow)
Les deux derniers blocs sont l'essentiel. Rien n'a échoué ici - le verdict est fonctionne - et le rapport dit pourtant, sans qu'on le lui demande, que cette application a parlé au réseau avant d'avoir fini, si bien qu'un hook local n'est peut-être pas toute l'histoire. Cette phrase fait la différence entre un test auquel on peut se fier et un test auquel on ne le peut pas.
Quatre verdicts, et un code de sortie pour chacun
Le verdict est établi de l'intérieur du processus en cours, avant que vous commenciez à travailler, et c'est le propre code de sortie de l'outil, de sorte qu'un pipeline peut bifurquer dessus.
| Verdict | Sortie | Signification |
|---|---|---|
| fonctionne | 0 | tout processus qui a lu l'heure a vu l'horloge de la session |
| fonctionne partiellement | 10 | certains canaux couverts, d'autres non - ceux qui ne le sont pas sont listés |
| ne fonctionne pas | 11 | la substitution n'a pas atteint les canaux essentiels |
| indéterminé | 4 | la couverture n'a pas pu être établie - un honnête « je ne sais pas » |
Quand le verdict est « ne fonctionne pas », le processus est arrêté immédiatement, avant que vous puissiez interagir avec lui. Le verdict ne peut pas précéder le lancement, car la seule source de vérité est une mesure prise de l'intérieur du processus en cours. Ce qui est garanti, c'est que vous apprenez la vérité avant de commencer à travailler - pas qu'un lancement voué à l'échec n'a jamais lieu. Vous pouvez passer outre et continuer, et la session est alors marquée comme non fiable partout où elle apparaît, y compris dans toute preuve que vous exportez.
D'autres codes disent que c'est l'exécution elle-même qui a échoué, et non la substitution - une erreur d'utilisation, une cible qui n'a pas pu démarrer, une exécution interrompue, une autre session déjà en cours - et aucun n'est un verdict. Le tableau complet est dans la référence de la ligne de commande.
Couverts, observés, non couverts
Les canaux tombent dans trois catégories, et celle du milieu est la plus intéressante.
- Couverts - interceptés et substitués. L'application a demandé, et a reçu l'horloge de la session. Le nombre d'appels dit combien de fois.
- Observés - interceptés, comptés et laissés délibérément dire la vérité. On y trouve les attentes sur objet, parce que raccourcir un délai d'attente pourrait simuler une expiration sur un vrai handle, et le minuteur multimédia, parce que le mettre à l'échelle décalerait le timing audio et MIDI - les deux observés quand la session accélère l'axe du temps écoulé. Les connexions réseau et un chemin de création de processus y sont dans chaque session, parce que ce sont des indices, pas des horloges. Le compteur haute résolution n'est pas dans ce groupe : il reste intact tant que vous ne le demandez pas avec
--scale-qpc, et il est alors couvert. - Non couverts - un canal que l'application a lu et que la substitution n'a pas atteint. C'est ce qui fait passer un verdict à fonctionne partiellement, et il est listé par son nom plutôt que résumé.
Un compte de zéro est aussi une information : le canal était intercepté et l'application n'a jamais demandé. C'est pourquoi le rapport les liste au lieu de les cacher.
Ce que l'audit ne peut pas voir
Le rapport est honnête sur la couverture, ce qui implique d'être honnête sur ses propres limites. Ces lectures se font sans aucun appel de fonction à intercepter, ou entièrement hors du processus :
- les lectures directes de la page de données partagée en mode utilisateur - la valeur est en mémoire, il n'y a donc rien à intercepter. Rare dans les applications ordinaires, courant dans le code de licence et d'antifalsification
- les appels système directs qui contournent les exports standard - même schéma
- l'heure obtenue hors processus, par WMI, un serveur COM hors processus ou RPC
- l'heure venue du réseau - un en-tête HTTP
Date, NTP, une réponse d'API, ou l'horloge propre d'un serveur de base de données - l'heure venue de pilotes en mode noyau
Le cas du réseau est celui que l'audit peut au moins remarquer, c'est pourquoi l'avertissement du rapport ci-dessus existe. Pour le reste, un verdict fonctionne signifie que les canaux que cet outil peut voir ont été couverts - pas qu'aucune autre voie n'existe.
Dans un pipeline
--json émet les mêmes faits sous forme lisible par une machine, --report
écrit la version pour humains dans un fichier, et une session dont le verdict est autre chose que
fonctionne place en tête de ce fichier un bandeau de preuve peu fiable plutôt que de
l'enfouir en bas.
chrono run "C:\apps\test.exe" --at 2027-12-31T23:59:59 --json --report evidence.txt