Skip to content
← Tous les articles
· Delta1 Labs Nebula.NETObfuscationSécurité

Report-home : savoir quand une build .NET protégée est attaquée sur le terrain

Les gardes anti-tamper et anti-debug réagissent sur la machine de l'utilisateur — mais vous n'apprenez jamais qu'ils se sont déclenchés. Le report-home de Nebula.NET (tamperReportUrl, Pro) POSTe un événement minimal à votre propre endpoint à l'instant où un garde se déclenche, de sorte qu'une attaque sur une build distribuée devienne un signal exploitable. Voici comment ça marche et comment construire le récepteur.

Vous durcissez bien une build .NET. Aplatissement du flux de contrôle, chiffrement de chaînes et de méthodes, anti-tamper, anti-debug, contrôles d’environnement : tout y est. Vous la distribuez. Et ensuite vous n’entendez rien, ce que vous vous dites être une bonne nouvelle. Mais « silence » et « personne n’attaque mon logiciel » ne sont pas la même chose. Chacun de ces gardes se déclenche sur la machine du client, y réagit, et ne laisse aucune trace que vous voyiez jamais. Un cracker passe un week-end à avancer pas à pas dans votre contrôle de licence dans un débogueur, votre garde anti-debug se déclenche une dizaine de fois, et vous n’en apprenez rien.

Le report-home de Nebula.NET (tamperReportUrl, une fonction Pro) comble ce vide. Quand un garde se déclenche, l’app protégée POSTe aussi un petit événement vers un endpoint que vous gérez — de sorte qu’une attaque sur une build sur le terrain devienne un signal de votre côté plutôt qu’un haussement d’épaules. Cet article est une plongée approfondie sur ce qu’il envoie, ce qu’il n’envoie délibérément pas, et comment construire le récepteur qui transforme ces événements en quelque chose sur quoi agir.

L’angle mort de la protection côté client

Soyons honnêtes sur ce qu’est un garde d’exécution. L’anti-tamper calcule un SHA-256 de l’image écrite au chargement et réagit si le fichier a été modifié après l’obfuscation. L’anti-debug demande au runtime managé et natif si un débogueur est attaché. Les contrôles d’environnement cherchent un profileur CLR (CORECLR_ENABLE_PROFILING) ou le patcheur d’exécution Harmony. Chacun est un fil-piège réellement utile — mais un fil-piège dont la seule sortie est une réaction locale : terminer, lever, sortir, ou appeler une méthode que vous avez désignée.

Cette réaction protège la seule machine sur laquelle elle tourne. Ce qu’elle ne fait pas, c’est vous dire quoi que ce soit. Le garde et l’attaquant sont seuls dans une pièce sur l’ordinateur de quelqu’un d’autre. Vous apprenez que votre logiciel est cracké quand un keygen apparaît sur un forum, pas quand le premier garde antiDebug se déclenche.

Sans report-homeLe garde se déclenche (machine)réagit en local → éditeur aveugleÉditeur : ne voit rienAvec report-homeLe garde se déclenche → POST{"event":"antiDebug"} puis réagitVotre endpoint (tamperReportUrl)l'attaque devient un signal exploitable

Ce que fait réellement report-home

Définissez une clé de configuration et chaque garde injecté gagne une seconde action : avant d’exécuter sa réaction, il POSTe un événement minimal vers votre URL.

{
  "obfuscate": true,
  "controlFlow": true,
  "stringEncryption": true,
  "antiTamper": true,
  "antiDebug": true,
  "environmentChecks": true,
  "tamperReportUrl": "https://telemetry.example.com/nebula-events"
}

Le corps est délibérément minuscule — juste le nom de l’événement :

{ "event": "antiTamper" }

Quatre propriétés définissent le comportement, et chacune est une décision de conception qui vaut la peine d’être comprise :

  • Il va vers votre endpoint, jamais vers nous. Le POST atteint l’URL que vous définissez dans tamperReportUrl. Delta1 Labs ne le reçoit jamais. C’est votre télémétrie sur votre serveur.
  • Seul le nom de l’événement quitte la machine. Pas de source, pas d’octets d’assembly, pas de chemins de fichiers, pas de données personnelles ou d’appareil — juste quel garde s’est déclenché. Il n’y a rien de sensible à intercepter et rien qui mécontenterait une revue de confidentialité.
  • Il est borné et auto-absorbant. L’envoi ne peut pas bloquer votre app ni lever vers elle. Si votre endpoint est lent ou injoignable, le rapport est abandonné et la réaction du garde se poursuit inchangée. Report-home ne devient jamais un nouveau mode de défaillance.
  • Il est distinct de l’analytique propre de Nebula. Nebula a un canal anonyme d’usage de l’outil au moment de la build que vous pouvez faire taire avec NEBULA_NO_TELEMETRY. Report-home n’a rien à voir avec lui — c’est un canal d’exécution de votre app vers votre serveur, contrôlé uniquement par le fait que tamperReportUrl soit défini.

Comme il ajoute du trafic sortant depuis l’app protégée, report-home n’est pas fait pour les déploiements isolés. Laissez l’URL non définie là-bas et les gardes réagissent quand même localement — ils ne peuvent simplement pas téléphoner à la maison.

Quels gardes rapportent, et ce que signifie chacun

Chaque garde d’exécution que Nebula injecte rapporte sous son propre nom d’événement, ce qui rend le signal utile plutôt qu’un unique « quelque chose s’est passé » indifférencié :

ÉvénementGardeCe que cela signifie habituellement
antiTamperIntégrité d’image au chargement (SHA-256 de l’image écrite)Le binaire a été modifié après l’obfuscation — une copie patchée/crackée, ou un téléchargement corrompu
antiDebugDétection de débogueur managé + natifQuelqu’un a attaché un débogueur — le premier mouvement classique de l’ingénierie inverse dynamique
environmentDétection de profileur CLR / patcheur HarmonyUn profileur ou le patcheur d’exécution Harmony est présent — hooking automatisé de vos méthodes
expiryGarde d’expiration / bombe à retardementUne build bêta, d’évaluation ou sous embargo tourne au-delà de son expiryUtc

Voir un pic d’antiDebug sur une seule version de build vous dit quelque chose de très différent d’un filet régulier d’antiTamper depuis les machines d’un même ID client. L’un est de l’ingénierie inverse active ; l’autre pourrait être une installation corrompue ou un réseau de redistribution. Les distinguer est tout l’intérêt de donner à chaque garde son propre nom.

Rendre le signal plus fort : les contrôles continus

Report-home est le plus utile associé à des contrôles qui tournent plus d’une fois. Par défaut environmentChecks et antiDebug sont des gardes au chargement — ils se déclenchent au démarrage. Un attaquant patient s’attache simplement après le lancement. Activer les contrôles continus change cela :

{
  "antiTamper": true,
  "antiDebug": true,
  "environmentChecks": true,
  "environmentChecksContinuous": true,
  "environmentChecksIntervalSeconds": 45,
  "autoProtectLicensing": true,
  "tamperReportUrl": "https://telemetry.example.com/nebula-events"
}

Avec environmentChecksContinuous, la détection ne tourne plus seulement au démarrage. Elle s’abonne à AppDomain.AssemblyLoad, donc un profileur ou patcheur qui s’attache après le lancement est attrapé à l’instant où il se charge ; elle re-contrôle à l’entrée des méthodes qui appellent votre SDK de licensing (les mêmes que autoProtectLicensing trouve et protège) ; et avec environmentChecksIntervalSeconds elle re-contrôle sur une minuterie de fond avec gigue. Chacun de ces déclenchements supplémentaires peut rapporter à la maison — donc au lieu d’un événement au démarrage, vous obtenez une image d’une attaque telle qu’elle se déroule au fil d’une session.

Construire le récepteur

L’endpoint est ordinaire. Il prend un petit POST JSON et l’enregistre ; tout ce qui est intéressant se passe dans la façon dont vous agrégez, pas dans le handler. Un récepteur ASP.NET Core minimal :

app.MapPost("/nebula-events", async (HttpContext ctx, TamperEvent evt) =>
{
    // Attribute the hit to a build/customer using signals you already have:
    // the User-Agent you set, a header you add at your CDN/gateway, or the
    // source address. The body itself carries only the event name by design.
    var record = new TamperHit(
        Event:   evt.Event,                       // "antiTamper" | "antiDebug" | "environment" | "expiry"
        AtUtc:   DateTime.UtcNow,
        Source:  ctx.Connection.RemoteIpAddress?.ToString(),
        Agent:   ctx.Request.Headers.UserAgent.ToString());

    await _hits.AppendAsync(record);              // your store of choice
    return Results.NoContent();                   // keep it cheap; the client ignores the response anyway
});

record TamperEvent(string Event);
record TamperHit(string Event, DateTime AtUtc, string? Source, string? Agent);

Deux choses à garder en tête côté réception. D’abord, le client ignore votre réponse et ne réessaie jamais — c’est du tir-et-oubli par conception — donc votre handler doit être bon marché et ne doit jamais attendre un protocole d’accusé de réception. Ensuite, traitez le corps comme une entrée non fiable : il arrive d’un logiciel tournant sur une machine qu’un attaquant peut contrôler, alors validez le nom de l’événement par rapport à votre ensemble connu, limitez le débit par source, et ne laissez jamais une charge utile inattendue faire autre chose que se faire journaliser et abandonner. La valeur de report-home est dans l’agrégat — un bond d’antiDebug après une version, un amas d’antiTamper depuis une région — pas dans la confiance en un événement isolé.

Ce qu’est report-home, et ce qu’il n’est pas

Report-home n’arrête pas un crack. Les gardes font l’arrêt — l’anti-tamper refuse de lancer un binaire modifié, l’anti-debug et les contrôles d’environnement réagissent aux attaques dynamiques — et rien de cela n’est absolu, parce que toute protection côté client tourne en fin de compte sur une machine que l’attaquant contrôle. Ce que report-home change, c’est votre visibilité. Aujourd’hui une attaque sur une build distribuée vous est invisible ; avec tamperReportUrl défini, c’est un événement daté et nommé sur votre propre serveur, attribuable à une build et souvent à un client. Cela transforme l’ingénierie inverse de quelque chose que vous découvrez des mois plus tard en quelque chose que vous voyez se produire — et auquel vous répondez, en distribuant une build plus dure, en révoquant une licence fuitée, ou en contactant un client dont les machines s’allument.

Définissez-le en une ligne, pointez-le vers un endpoint que vous contrôlez, et laissez-le non défini pour les cibles isolées. Voyez configuration → anti-tamper & anti-debug pour l’ensemble complet des options de gardes et de réactions, résister à la déobfuscation pour voir comment les gardes s’insèrent dans l’histoire de durcissement plus large, ou la page produit Nebula.NET pour le panorama complet.

Essayez Nebula.NET

Renforcez votre code .NET en quelques minutes — commencez avec l'édition gratuite.