Chrono Mock
LangueFrançais

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.

L'écran de résultat de Chrono Mock avec What the application read ouvert : un tableau Function, Read from et Reads. NtCreateUserProcess est marqué comme lu sur l'horloge réelle par conception et connect comme lu sur l'horloge réelle par conception et accroché tardivement, tandis que les autres lignes - GetSystemTimeAsFileTime, NtQuerySystemTime, GetTimeZoneInformation et le reste - lisent sur l'horloge factice, chacune avec son propre compte. Deux avertissements se trouvent sous le tableau.
La même réponse dans la fenêtre. Chaque fonction que l'application aurait pu appeler, ce sur quoi elle a réellement lu, et combien de fois - y compris celles laissées exprès sur l'horloge réelle, qui sont nommées plutôt que comptées discrètement comme un succès.

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.

VerdictSortieSignification
fonctionne0tout processus qui a lu l'heure a vu l'horloge de la session
fonctionne partiellement10certains canaux couverts, d'autres non - ceux qui ne le sont pas sont listés
ne fonctionne pas11la substitution n'a pas atteint les canaux essentiels
indéterminé4la 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

L'essayer