Dot.Blog

Consulting DotNet C#, XAML, WinUI, WPF, MAUI, IA

Debug ou Cracking ? Des outils .NET à la frange des deux mondes...

Un debugger comme celui de Visual Studio n'est que rarement comparé à un outil de cracking pour la bonne raison que son utilisation s'effectue systématiquement (ou presque) sur des applications en cours de développement / maintenance, impliquant que l'opérateur du debug a le droit d'accéder aux sources. Mais comment catégoriser les outils qui suivent ?

Les trois outils dont je vais vous parler aujourd'hui se situent tous à la limite entre debugging et cracking, non pas forcément par la volonté de leur concepteur mais bien par leur nature. Il s'agit en fait d'applications autonomes capable de percer les secrets d'applications .NET en cours de fonctionnement (2 outils sur les 3 pour être précis, l'un est un visualisateur pour VS).

Outils de debug très intéressants ne nécessitant pas forcément l'installation de VS sur la machine, ces applications sont des compagnons à mettre dans votre boîte à outils. Utilitaires autonomes pouvant être utilisés par n'importe qui, l'existence même de ces outils ouvre la voie à un cracking autrement plus simple que l'utilisation d'outils comparables pour Win32. La haute cohérence de .NET et sa "lisibilité" rendant l'opération moins ardue.

Anges ou Démons ?

Les objets n'ont pas d'âme (si tant est que les êtres vivants en aient une) mais surtout ils n'ont pas de conscience. De tels outils ne peuvent donc être taxés en eux-mêmes d'être "diaboliques". C'est l'Homme qui appuie sur la gâchette que l'on juge et condamne, non les particules de poudre et l'amorce ayant permis à la balle de sortir de l'arme... A vous d'en faire bonne usage donc. Le plus important étant même de savoir que de tels outils existent pour éventuellement réfléchir, pour des applications sensibles, à comment rendre inopérantes des attaques qui utiliseraient cette approche.

Les outils

Crack.NET

Ecrit par Josh Smith, cet outil est un "logiciel de débogage et de scripting qui vous donne accès à l'intérieur de toute application .NET desktop" (d'après la traduction de la présentation de l'auteur). Une fois lancé l'utilitaire permet de choisir l'application .NET à cracker (selon les termes mêmes du bouton de lancement). Visualiser la mémoire, traverser les grappes d'objets, il est ainsi possible de tracer l'état de l'application "victime". Imaginons un mot de passe de connexion à une base de données ou à un Service Web, même si l'exécutable est obfusqué, même si les valeurs sont cryptées sur disque, il devient possible de lire ces dernières en clair une fois en mémoire de l'application.

On flirte avec la limite cracking / debugging, mais encore une fois l'intention coupable ou non est du ressort de la conscience de l'utilisateur de l'outil.

Un outil à posséder donc.

http://joshsmithonwpf.wordpress.com/cracknet/

Mole

Mole est un outil un peu différent, c'est un visualisateur pour Visual Studio qui permet de plonger dans les arborescences d'objets, de visualiser les valeurs mais aussi de les modifier.

En tant qu'outil pour VS la frontière du cracking s'éloigne, celle du debugging étant plus clairement visible.

"Mole a été conçu pour permettre au développeur non seulement d'afficher des objets ou des données, mais aussi de percer et visualiser les propriétés de ces objets, puis de les modifier. Mole permet un nombre illimité d'objets et de sous-objets en cours d'inspection. Quand Mole trouve un objet IEnumerable, les données peuvent être visualisées dans une DataGridView ou dans une grille de propriétés. Mole gère facilement les collections qui contiennent plusieurs types de données. Mole permet aussi au développeur de voir les champs non publics de tous les objets. Vous pouvez apprendre beaucoup sur le framework. NET en inspectant ainsi les données de vos applications."

http://karlshifflett.wordpress.com/mole-for-visual-studio/

Snoop

"Snoop est un utilitaire conçu pour simplifier le débogage visuel des applications WPF à l'exécution."

Un peu comme Crack.NET il s'agit ici d'un utilitaire autonome permettant d'inspecter une application WPF lors de son exécution. Cela peut s'avérer très utile en debug, mais peu présenter certains risques entre de mauvaises mains...

 

En tout cas, si vous développez des applications WPF, il faut avoir Snoop, il peut fournir une aide appréciable en plus du debug sous VS.

http://blois.us/Snoop/

Conclusion

Objets inanimés avez-vous une âme ? Questionnait Lamartine. Les objets numériques qu'il n'a pas connus n'en ont ni plus ni moins que les objets physiques en tout cas. Cracker ou debugger, c'est à vous de voir avec votre conscience, mais dans tous les cas, il est important de connaître l'existence de tels outils qui peuvent s'avérer bien pratiques dans certaines circonstances.

Stay Tuned !

Un générateur de code C#/VB à partir d'un schéma XSD

Générer du code C# depuis un schéma XSD est un besoin de plus en plus fréquent, XML étant désormais omniprésent. On trouve dans le Framework l'outil "xsd.exe" qui permet une telle génération toutefois elle reste assez basique. C'est pour cela qu'on trouve aussi des outils tiers qui tentent, chacun à leur façon, d'améliorer l'ordinaire.

XSD2Code est un de ces outils tiers. Codé par Pascal Cabanel et releasé sur CodePlex, c'est sous la forme d'un add-in Visual Studio que se présente l'outil (le code source contient aussi une version Console).

Son originalité se trouve bien entendu dans les options de génération qui prennent en compte INotifyPropertyChanged ainsi que la création de List<T> ou ObservableCollection<T>. D'autres options comme la possibilité de générer le code pour C# ou VB.NET, le support des types nullable, etc, en font une alternative plutôt séduisante à "xsd.exe". La prise en compte des modifications de propriété (et la génération automatique du code correspondant) autorise par exemple le DataBinding sous WPF ou Silverlight... A ne pas négliger surtout que Silverlight 2 est releasé officiellement depuis hier !

Comme Pascal suit ce blog il pourra certainement m'éclairer sur le pourquoi d'un petit dysfonctionnement (j'ai aussi laissé un message dans le bug tracker du projet): lorsque l'add-in est installé, et après l'avoir activé dans le manager d'add-in je ne vois hélas pas l'entrée de menu apparaître sur le clic-droit dans l'explorateur de solution (sur un fichier xsd bien sûr). Heureusement, le code source étant fourni sur CodePlex et le projet intégrant une version console de l'outil j'ai pu tester la génération de code C# en ligne de commande. Il est vrai que l'intégration de l'outil dans l'IDE est un sacré plus que je suis triste ne n'avoir pu voir en action :-( Peut-être s'agit-il d'un problème lié au fait que ma version de VS est en US alors que mon Windows est en FR ? Cela trouble peut-être la séquence qui insère la commande dans le menu contextuel ?

Un petit détail à régler donc, mais dès que j'ai des nouvelles je vous en ferai part (Pascal tu peux aussi laisser la solution en mettant un commentaire à ce billet si tu veux).

Le projet XSD2Code est fourni en deux versions, code source et setup près à installer. Pascal a même créé une petite vidéo montrant l'add-in en action.

Un outil qui, même en version console, remplace avantageusement "xsd.exe" et qui a donc toutes les raisons de se trouver dans votre boîte à outils !

Bon dev

Et Stay Tuned ! 

Améliorer le debug sous VS avec les proxy de classes

Visual Studio est certainelement l'IDE le plus complet qu'on puisse rêver et au-delà de tout ce qu'il offre "out of the box" il est possible de lui ajouter de nombreux add-ins (gratuits ou payants) permettant de l'adapter encore plus à ses propres besoins. Ainsi vous connaissez certainement les "gros" add-ins comme Resharper dont j'ai parlé ici quelque fois ou GhostDoc qui écrit tout seul la doc des classes. Vous connaissez peut-être les add-ins de débogage permettant d'ajouter vos propres visualisateurs personnalisés pour le debug. Mais vous êtes certainement moins nombreux à connaître les proxy de classes pour le debug (Debugger Type Proxy).Plus...

Class Helper, LINQ et fichiers CSV

C# 3.0 a apporté des nouveautés syntaxiques qui ne se bornent pas à être seulement des petits suppléments qu'on peut ignorer, au contraire il s'agit de modifications de premier plan qui impactent en profondeur la façon d'écrire du code si on sait tirer partie de ces nouveautés. J'en ai souvent parlé, au travers de billets de ce blog ou d'articles comme celui décrivant justement les nouveautés syntaxiques de C#3.0. Je ne vais donc pas faire de redites, je suppose que vous connaissez maintenant tous ces ajouts au langage. Ce que je veux vous montrer c'est qu'en utilisant correctement C# 3.0 on peut écrire un code incroyable concis et clair pour résoudre les problèmes qui se posent au quotidien au développeur.

Le problème à résoudre

Vous recevez un fichier CSV, disons le résultat d'une exportation depuis un soft XY des ventes à l'export de votre société. Vous devez rapidement ajouter la possibilité d'importer ces données dans l'une de vos applications mais après les avoir interprétées, triées, voire filtrées.

La méthode la plus simple

Rappel : un fichier CSV est formé de lignes comportant plusieurs champs séparés par des virgules. Les champs peuvent être délimités par des double quotes.

A partir de cette description voyons comment avec une requête LINQ nous pouvons lire les données, les filtrer, les trier et les mettre en forme. Le but ici sera de générer en sortie une chaîne par enregistrement, chaîne contenant des champs "paddés" par des espaces pour créer un colonnage fixe. On tiendra compte des lignes débutant par le symbole dièse qui sont considérées comme des commentaires.

   1:  string[] lines = File.ReadAllLines("Export Sales Info-demo.csv");
   2:  var t1 = lines
   3:      .Where(l => !l.StartsWith("#"))
   4:      .Select(l => l.Split(','))
   5:      .OrderBy(items=>items[0])
   6:      .Select(items => String.Format("{0}{1}{2}",
   7:          items[1].PadRight(15),
   8:          items[2].PadRight(30),
   9:          items[3].PadRight(10)));
  10:  var t2 = t1
  11:      .Select(l => l.ToUpper());
  12:  foreach (var t in t2.Take(5))
  13:      Console.WriteLine(t);

La sortie (avec le fichier exemple fourni) sera :

SAN JOSE       CITY CENTER LODGE             CA
SAN FRANCISCO  KWIK-E-MART                   CA
SEATTLE        LITTLE CORNER SWEETS          WA
SEATTLE        LITTLE CORNER SWEETS          WA
IRVINE         PENNY TREE FOODS CORPORATION  CA
 

Cette méthode, très simple, ne réclame rien d'autre que le code ci-dessus. La solution est applicable à tout moment et s'adapte facilement à toute sorte de fichiers sources. Elle possède malgré tout quelques faiblesses. Par exemple les champs contenant des doubles quotes ou les champs mal formés risquent de faire échouer la séquence. Dans certains cas cela sera inacceptable, dans d'autres on pourra parfaitement protéger la séquence dans un bloc try/catch et rejeter les fichiers mal formés. Une fois encore il ne s'agit pas ici de montrer un code parfaitement adapté à un problème précis, mais bien de montrer l'esprit, la façon d'utiliser C# 3.0 pour résoudre des problèmes courants. 

Expliquons un peu ce code :

la ligne 1 charge la totalité du fichier CSV dans un tableau de strings. La méthode peut sembler "brutale" mais en réalité elle est souvent très acceptable car de tels fichiers dépassent rarement les quelques dizaines ou centaines de Ko et la RAM de nos machines modernes n'impose en rien une lecture bufferisée, tout peut tenir d'un bloc en mémoire sans le moindre souci. Cela nous arrange ici il faut l'avouer mais l'utilisation d'un flux bufferisé resterait parfaitement possible.

Nous disposons maintenant d'un tableau de chaînes, chacune étant formatée en CSV. La première requête LINQ (variable "t1" en ligne 2) fait l'essentiel du travail :

  • gestion des commentaires (ligne 3)
  • décomposition des champs (ligne 4)
  • tri sur l'un des champs (ligne 5)
  • génération d'une sortie formatée (lignes 6 à 9)

Ce qui est merveilleux ici c'est que nous avons en quelques lignes un concentré de ce qu'est une application informatique : acquisition de données, traitement de ces données, production de sorties exploitables par un être humain ou une autre application. En si peu de lignes nous avons réalisé ce qui aurait nécessité une application entière avec les langages de la génération précédente comme C++ ou Delphi. C'est bien ce bond en avant que représente C# 3.0 qui est ici le vrai sujet du billet.

Une méthode plus complète

La séquence que nous avons vu plus haut répond au problème posé. Elle possède quelques lacunes. Celles liées à sa trop grande simplicité (certains cas du parsing CSV ne sont pas correctement pris en compte) et celles liées à sa forme : c'est un bout de code qu'il faudra copier/coller pour le réutiliser et qui viendra "polluer" nos requêtes LINQ les rendant plus difficiles à lire.

Si ces lacunes sont acceptables dans certains cas (règlement ponctuel d'un problème ponctuel) dans d'autres cas on préfèrera une approche plus facilement réutilisable. Notamment si nous sommes amenés à traiter plus ou moins souvent des fichiers CSV nous avons intérêt à encapsuler le plus possible le parsing et à le rendre plus facilement reexploitable.

L'une des voies serait de créer une classe totalement dédiée à cette tâche. C'est une solution envisageable mais elle est assez lourde et amène son lots de difficultés.

Nous allons choisir ici une autre approche, celle de la création d'un class helper. C'est à dire que nous souhaitons non pas créer une classe qui traite un fichier CSV comme un tout, mais nous voulons pouvoir parser n'importe quelle chaîne de caractères formatée en CSV. L'approche est très différente. Dans le premier cas il nous faudra complexifier de plus en plus notre classe, voire créer une hiérarchie de classes pour traiter les fichiers CSV mais aussi les flux mémoire CSV, et puis encore les services Web retournant du CSV, etc, etc.

Dans le second cas nous allons plutôt ajouter la capacité à la classe string de parser une chaîne donnée. La source de la chaîne ne nous importe pas. Il pourra s'agir d'un élément d'un tableau de chaîne comme dans le premier exemple autant que d'une chaîne lue depuis un flux mémoire, une section data d'un fichier XML, etc. D'un certain sens nous acceptons d'être moins "complet" que l'option "classe dédiée CSV", mais nous gagnons en agilité et en "réutilisabilité" en faisant abstraction de la provenance de la chaîne à parser. Bien entendu nous pouvons nous offrir le luxe d'une telle approche car nous savons que nous pouvons nous reposer sur C# 3.0, ses class helpers et LINQ...

Le projet qui accompagne ce billet contient tout le code nécessaire et même un fichier CSV d'exemple, nous n'entrerons pas dans les détails de l'implémentation du class helper lui-même qui étend la classe string, parser du CSV n'est qu'un prétexte sans plus d'intérêt dans ce billet. Le code utilisé pour l'exemple provient d'ailleurs d'un billet de  Eric White dont vous pouvez visiter le blog si vous lisez l'anglais.

la façon d'écrire un class helper est décrite dans mon article sur C# 3.0, regardons juste sa déclaration :

public static string[] CsvSplit(this String source)

Cette méthode est déclarée au sein d'une classe statique de type "boîte à outils" pouvant centraliser d'autres méthodes utilitaires. La déclaration nous montre que le class helper s'applique à la classe String uniquement (this String source) et qu'elle retourne un tableau de chaîne (string[]).

Une fois le class helper défini (code complet dans le projet accompagnant l'article) il nous est possible d'écrire des requêtes LINQ du même type que celle du premier exemple. Mais cette fois-ci le parsing CSV est réalisé par le class helper ce qui permet à la fois de le rendre plus sophistiqué et surtout de ne plus avoir à le copier/coller dans les requêtes LINQ...

Voici un exemple d'utilisation du class helper sur le même fichier CSV. Ici nous parsons la source, nous la trions, nous éliminons les lignes de commentaire mais aussi nous créons en réponse une classe anonyme contenant le nom du contact, sa ville et le nom de sa société. Il est dès lors possible de traiter la liste d'objets résultat comme n'importe quelle liste : affichage, traitement, génération d'état, etc.

   1:  var data = File.ReadAllLines("Export Sales Info-demo.csv").Where(s=>!s.StartsWith("#"))
   2:      .Select(l =>
   3:  {
   4:  var split = l.CsvSplit();
   5:  return new
   6:             {
   7:                 Contact = split[0],
   8:                 City = split[1],
   9:                 Company = split[2]
  10:             };
  11:  }  ).OrderBy(x=>x.Contact);
  12:   
  13:  foreach (var d in data.Take(5))
  14:      Console.WriteLine(d);

Ce qui, avec le même fichier source, affichera à la console :

{ Contact = Allen James, City = San Jose, Company = City Center Lodge }
{ Contact = Bart H. Perryman, City = San Francisco, Company = Kwik-e-mart }
{ Contact = Beth Munin, City = Seattle, Company = Little Corner Sweets }
{ Contact = Beth Munin, City = Seattle, Company = Little Corner Sweets }
{ Contact = Bruce Calaway, City = Irvine, Company = Penny Tree Foods Corporation } 

Conclusion

La bonne utilisation de C# 3.0 permet de réduire significativement la taille du code donc de réduire dans les mêmes proportions les bugs et d'augmenter la productivité. Apprendre à utiliser cette nouvelle approche c'est gagner sur tous les plans...

 

Le projet exemple : LinqToCsv.zip (9,46 kb)

Donnez des couleurs à Blend et Design (intégration de Adobe Kuler).

Comme une coïncidence je parlais de Adobe dans mon dernier billet... Et si je n'en faisais pas forcément l'éloge pour la facette programmation de leurs outils, en revanche je reconnaissais bien volontier leur talent en ce qui concerne les outils de graphisme. En voici une illustration, et un moyen de récupérer ce savoir-faire dans les produits de design de la gamme Microsoft Expression !

Adobe a mis en ligne un site qui s'appelle Adobe Kuler, son utilité est de permettre facilement, et visuellement, de créer des nuanciers de couleurs. Les graphistes utilisent fréquemment les nuanciers car une fois ajoutés à un projet ils sont le garant du respect de la charte décidée pour celui-ci.

Bien entendu les outils tels que Expression Design ou Expression Blend savent gérés les nuanciers, chacun à sa façon. Design le gère de façon similaire à Adobe Illustrator, Blend le fait sous la forme de ressources de brosses. Mais qu'importe la technique exacte cela revient au même. Surtout, les contraintes qu'un graphiste doit prendre en compte restent les mêmes, qu'il travaille sous Illustrator ou Design ou même Blend : le respect de la charte est essentiel.

Je ne pourrais pas dire, faute de le connaître, si Jonas Follesoe est type bien ou sympa, en revanche je peux vous affirmer que c'est un bon développeur WPF qui aime Blend et Design ! Et il a créé un add-in pour ces deux produits qui permet de disposer d'une palette supplémentaire se connectant à Adobe Kuler pour aller y chercher des nuanciers !

Recherche des favoris, des plus populaires, etc, voire recherche sur un mot (tous les nuanciers "ocean" par exemple), tout cela est possible. On récupère les nuanciers par simple copie dans le logiciel (ou même par drag'n drop). C'est vraiment génial. D'autant qu'on peut aussi accéder au site Adobe Kuler pour modifier un nuancier ou en créer un totalement nouveau. Le site propose des modes intelligents comme la création de palettes à partir d'algorithmes de type couleurs complémentaires, nuancier monochromatique, etc.

Toutes les instructions pour télécharger le plugin Blend/Design ainsi que l'application WPF stand-alone sur son le blog de Jonas.

Le site Adobe Kuler vaut lui aussi une visite si vous ne connaissez pas.

Enfin, le projet de Jonas est sur CodePlex, dont open source, toujours bon pour repiquer les bonnes idées de développement et progresser dans son apprentissage !

Et comme c'est joli toutes ces couleurs, voici une petite capture écran du plugin en action sur mon Blend 2 SP1 :