Tag Archives: reverse engeneering

Désassembler, éditer et recompiler une application DotNet

Salut à tous, aujourd’hui un petit article sur les bases du dotnet, le MSIL ou Microsoft Inter médiate Langage de son doux et chaleureux nom. Le MSIL est en fait le code obtenus suite à la compilation d’une application dotnet et qui sera ensuite exécuté dans le CLR. C’est grâce à cela que l’on peut facilement porter d’une architecture à une autre. En effet la compilation d’un application dotnet ne produit pas directement du code binaire directement executable mais un code intermédiaire appel (MS)IL interpreté ensuite par la CLR. Ce pseudo langage peut facilement être lu et éditeé. Pour vous montrer cela je vais prendre comme exemple une application dans lequel nous allons rajouter une méthode qui affichera « Salut » dans la console. Nous utiliserons ILDasm pour dumper et ILAsm pour compiler.

Le premier se trouve dans le windows SDK et, est, normalement fournit avec Visual Studio (sinon suffit d’installer le windows sdk) le second est fournis avec le framework dotnet qui se trouve dans %WINDIR%/Microsoft.Net/Framework/. Pour moi ce sera : %WINDIR%/Microsoft.Net/Framework64/v4.0.30319/ilasm.exe et le premier C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\Bin\ILdasm.exe ^^
Le premier outil dispose d’un ihm mais le second non. (Il s’agit d’un compiler donc l’ihm serait un peu superflue).
Notre application console contient ce code :

using System;

namespace DemoDissamble
{
    class Program
    {
        static void Main(string[] args)
        {
            Print1();
            Console.ReadKey();
        }

        static void Print1()
        {
            Console.WriteLine("Je vous dis");
        }

        static void Print2()
        {
            Console.WriteLine("salut");
        }
    }
}

On a donc deux fonctions, mais print2 n’est pas appelé. On va régler ça.
On lance donc ILDasm.exe, on va dans Fichier->Ouvrir et on ouvre notre exe.
On devrait obtenir le résultat suivant :


On voit donc notre namespace qui contient une classe avec notre méthode main, print1 et print2. Pour le moment, on est encore en read-only. On va donc dumper en allant dans Fichier->Dump
On a toute une série de choses que l’on peut exporter, certaines très intéressantes, d’autres moins. Mais ici nous allons juste exporter le code IL, je laisse à votre discrétion l’exploration des meta-inf et cie 😉


Maintenant, j’ouvre le fichier sous visual studio (ne cherchez pas une coloration syntaxique native 😉 ), voici son contenu :

//  Microsoft (R) .NET Framework IL Disassembler.  Version 3.5.30729.1
//  Copyright (c) Microsoft Corporation. Tous droits r�serv�s.

// Metadata version: v4.0.30319
.assembly extern mscorlib
{
  .publickeytoken = (B7 7A 5C 56 19 34 E0 89 )                         // .z\V.4..
  .ver 4:0:0:0
}
.assembly DemoDissamble
{
  .custom instance void [mscorlib]System.Reflection.AssemblyTitleAttribute::.ctor(string) = ( 01 00 0D 44 65 6D 6F 44 69 73 73 61 6D 62 6C 65   // ...DemoDissamble
                                                                                              00 00 )
  .custom instance void [mscorlib]System.Reflection.AssemblyDescriptionAttribute::.ctor(string) = ( 01 00 00 00 00 )
  .custom instance void [mscorlib]System.Reflection.AssemblyConfigurationAttribute::.ctor(string) = ( 01 00 00 00 00 )
  .custom instance void [mscorlib]System.Reflection.AssemblyCompanyAttribute::.ctor(string) = ( 01 00 09 4D 69 63 72 6F 73 6F 66 74 00 00 )       // ...Microsoft..
  .custom instance void [mscorlib]System.Reflection.AssemblyProductAttribute::.ctor(string) = ( 01 00 0D 44 65 6D 6F 44 69 73 73 61 6D 62 6C 65   // ...DemoDissamble
                                                                                                00 00 )
  .custom instance void [mscorlib]System.Reflection.AssemblyCopyrightAttribute::.ctor(string) = ( 01 00 1B 43 6F 70 79 72 69 67 68 74 20 C2 A9 20   // ...Copyright ..
                                                                                                  4D 69 63 72 6F 73 6F 66 74 20 32 30 31 31 00 00 ) // Microsoft 2011..
  .custom instance void [mscorlib]System.Reflection.AssemblyTrademarkAttribute::.ctor(string) = ( 01 00 00 00 00 )
  .custom instance void [mscorlib]System.Runtime.InteropServices.ComVisibleAttribute::.ctor(bool) = ( 01 00 00 00 00 )
  .custom instance void [mscorlib]System.Runtime.InteropServices.GuidAttribute::.ctor(string) = ( 01 00 24 31 30 66 62 37 30 65 65 2D 63 34 37 30   // ..$10fb70ee-c470
                                                                                                  2D 34 66 63 62 2D 61 38 37 37 2D 35 65 30 33 66   // -4fcb-a877-5e03f
                                                                                                  36 31 38 37 39 32 34 00 00 )                      // 6187924..
  .custom instance void [mscorlib]System.Reflection.AssemblyFileVersionAttribute::.ctor(string) = ( 01 00 07 31 2E 30 2E 30 2E 30 00 00 )             // ...1.0.0.0..
  .custom instance void [mscorlib]System.Runtime.Versioning.TargetFrameworkAttribute::.ctor(string) = ( 01 00 29 2E 4E 45 54 46 72 61 6D 65 77 6F 72 6B   // ..).NETFramework
                                                                                                        2C 56 65 72 73 69 6F 6E 3D 76 34 2E 30 2C 50 72   // ,Version=v4.0,Pr
                                                                                                        6F 66 69 6C 65 3D 43 6C 69 65 6E 74 01 00 54 0E   // ofile=Client..T.
                                                                                                        14 46 72 61 6D 65 77 6F 72 6B 44 69 73 70 6C 61   // .FrameworkDispla
                                                                                                        79 4E 61 6D 65 1F 2E 4E 45 54 20 46 72 61 6D 65   // yName..NET Frame
                                                                                                        77 6F 72 6B 20 34 20 43 6C 69 65 6E 74 20 50 72   // work 4 Client Pr
                                                                                                        6F 66 69 6C 65 )                                  // ofile

  // --- The following custom attribute is added automatically, do not uncomment -------
  //  .custom instance void [mscorlib]System.Diagnostics.DebuggableAttribute::.ctor(valuetype [mscorlib]System.Diagnostics.DebuggableAttribute/DebuggingModes) = ( 01 00 02 00 00 00 00 00 )

  .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilationRelaxationsAttribute::.ctor(int32) = ( 01 00 08 00 00 00 00 00 )
  .custom instance void [mscorlib]System.Runtime.CompilerServices.RuntimeCompatibilityAttribute::.ctor() = ( 01 00 01 00 54 02 16 57 72 61 70 4E 6F 6E 45 78   // ....T..WrapNonEx
                                                                                                             63 65 70 74 69 6F 6E 54 68 72 6F 77 73 01 )       // ceptionThrows.
  .hash algorithm 0x00008004
  .ver 1:0:0:0
}
.module DemoDissamble.exe
// MVID: {7CD7C5F3-4B77-4150-8FC1-D694703BE62D}
.imagebase 0x00400000
.file alignment 0x00000200
.stackreserve 0x00100000
.subsystem 0x0003       // WINDOWS_CUI
.corflags 0x00000003    //  ILONLY 32BITREQUIRED
// Image base: 0x00970000

// =============== CLASS MEMBERS DECLARATION ===================

.class private auto ansi beforefieldinit DemoDissamble.Program
       extends [mscorlib]System.Object
{
  .method private hidebysig static void  Main(string[] args) cil managed
  {
    .entrypoint
    // Code size       12 (0xc)
    .maxstack  8
    IL_0000:  call       void DemoDissamble.Program::Print1()
    IL_0005:  call       valuetype [mscorlib]System.ConsoleKeyInfo [mscorlib]System.Console::ReadKey()
    IL_000a:  pop
    IL_000b:  ret
  } // end of method Program::Main

  .method private hidebysig static void  Print1() cil managed
  {
    // Code size       11 (0xb)
    .maxstack  8
    IL_0000:  ldstr      "Je vous dis"
    IL_0005:  call       void [mscorlib]System.Console::WriteLine(string)
    IL_000a:  ret
  } // end of method Program::Print1

  .method private hidebysig static void  Print2() cil managed
  {
    // Code size       11 (0xb)
    .maxstack  8
    IL_0000:  ldstr      "salut"
    IL_0005:  call       void [mscorlib]System.Console::WriteLine(string)
    IL_000a:  ret
  } // end of method Program::Print2

  .method public hidebysig specialname rtspecialname
          instance void  .ctor() cil managed
  {
    // Code size       7 (0x7)
    .maxstack  8
    IL_0000:  ldarg.0
    IL_0001:  call       instance void [mscorlib]System.Object::.ctor()
    IL_0006:  ret
  } // end of method Program::.ctor

} // end of class DemoDissamble.Program

// =============================================================

// *********** DISASSEMBLY COMPLETE ***********************
// AVERTISSEMENT : le fichier de ressources Win32 C:\dump.res a été créé

Dans mon cas il n’est pas très long, 100 lignes.
Notre main va de 58 à 67 suivi de Print1 de 69 à 76 et Print2 de 78 à 85.
Regardons un peu ce qui se fait, pour la suite j’utiliserai les offset qui prennent la forme IL_ pour une question de clarté par rapport aux numéros de lignes.
Dans main, IL_0000 et IL_0005 sont deux call. On comprend aisément qu’il s’agit d’appels de fonctions, ensuite on pop le top la stack et on return. En langage plus « haut niveau », on appelle deux méthodes et on return.
Ensuite nos deux méthodes Print sont sensiblement les mêmes. On crée une référence à un objet string sur le top de la stack, on y stock la valeur entre parenthèse et on appelle Writeline qui se chargera d’afficher dans la console la string sur le top de la stack. Ensuite on return. En langage plus « haut niveau », on crée une variable, que l’on passe en argument à WriteLine et on return. (Rappel de base, ce n’est pas parce que c’est void qu’il n’y a pas de return ;))
Avant de le modifier, on va le tester. Voici la ligne de commande a utiliser :
C:\Windows\Microsoft.NET\Framework64\v4.0.30319>ilasm.exe “C:\dump.il” /exe /out:”C:\run.exe” && C:\run.exe
Donc, en premier argument le chemin du dump à recompiler, ensuite le type d’output (exe ou dll) et enfin le chemin de l’output. Le && C:\run.exe me sert à exécuter le programme à condition que la compile ai réussi (c’est un & conditionnel). Ce qui devrait vous produire quelque chose comme cela :

Microsoft (R) .NET Framework IL Assembler.  Version 4.0.30319.1
Copyright (c) Microsoft Corporation.  All rights reserved.
Assembling 'C:\dump.il'  to EXE --> 'C:\run.exe'
Source file is UTF-8

Assembled method DemoDissamble.Program::Main
Assembled method DemoDissamble.Program::Print1
Assembled method DemoDissamble.Program::Print2
Assembled method DemoDissamble.Program::.ctor
Creating PE file

Emitting classes:
Class 1:        DemoDissamble.Program

Emitting fields and methods:
Global
Class 1 Methods: 4;
Resolving local member refs: 1 -> 1 defs, 0 refs, 0 unresolved

Emitting events and properties:
Global
Class 1
Resolving local member refs: 0 -> 0 defs, 0 refs, 0 unresolved
Writing PE file
Operation completed successfully
Je vous dis

Comme on le voit il nous manque un output, le salut. On va donc rajouter l’appel à cette fonction après le premier appel. Mais on a un petit « soucis ». En effet, chaque instruction a un offset, il faut donc recalculer les offset afin de pouvoir le compiler. Cela nous donnera :

.method private hidebysig static void  Main(string[] args) cil managed
{
	.entrypoint
	// Code size       12 (0xc)
	.maxstack  8
	IL_0000:  call       void DemoDissamble.Program::Print1()
	IL_0005:  call       void DemoDissamble.Program::Print2()
	IL_000a:  call       valuetype [mscorlib]System.ConsoleKeyInfo [mscorlib]System.Console::ReadKey()
	IL_000b:  pop
	IL_000c:  ret
} // end of method Program::Main

Et notre output :

Pour aller plus loin voici la liste des OpCodes : http://msdn.microsoft.com/en-us/library/system.reflection.emit.opcodes.pop.aspx
Et la référence de ILAsm : http://msdn.microsoft.com/fr-fr/library/496e4ekx%28v=vs.80%29.aspx

Inform@tiquement
Istace Emmanuel

Dossier : Reverse engeneering de manette Nes/Snes

Salut à tous, aujourd’hui un peu d’électronique avec un dossier sur le fonctionnement des controllers nes et snes. Le but final étant de l’interfacer en usb (objet d’un prochain article).

La nes

D’abord, ouvrons le controller et voyons ce qui se trouve dedans (désolé pour la qualité des photos, je vais demander à une amie avec un bon appareil si elle veut bien les refaire, mais attendant, faut faire avec ^^):


Bon, rentrons un peu dans le détail…

Le controller se compose de 4 boutons (A-B-Select-Start) et d’une croix multi directionnelle de 4 boutons aussi (haut-bas-droite-gauche) ce qui nous mènent à 8 boutons en tout. Assez joli, ce contrôleur est en plastique gris et noir, bouton rouge, très bien assortit à votre salon… Alors, première précision, un gamepad (ou controller ou manette de jeux) est un élément qui la plupart du temps pourrait être qualifié de « passif », mais j’y reviendrai plus tard.

Coté chip, il contient registre à décalage de 8 bits (4021 8 bit shift registre). Un article sur les registres est en préparation si vous ne savez pas ce que c’est, mais retenez basiquement qu’il s’agit d’un élément capable de stocker une valeur de 8bit. Dans notre cas chaque bits correspondra à l’état d’un bouton. Ainsi 0 signifie que le bouton est relâché et 1 qu’il est enfoncé.

Ensuite concernant les connections, on a un port de 7 fils. Voici la fonction de chacun :

Alors les ports 1 à 4 ne sont pas intéressant en soit. Ce qui l’est plus sont les ports 5 à 7.

Le port 5 sert à synchroniser la console et le gamepad, le port 6 sert à envoyer une demande et le port 7 à répondre. J’en vois qui sont perdu alors un exemple sera plus clair;

Comment la console connait-elle l’état de la manette ?
Et bien déjà on sait qu’on peut stocker tout l’état de la manette sur 8 bit. Chaque bit représentant un bouton. Voici l’ordre des boutons:

Définissons que 1 = off et 0 = on .
La valeur 10111101 signifie : Bouton B et bouton gauche enfoncé
De même 01011111 Signifie : A + Select ^^

Ensuite, une chose doit être bien claire; Contrairement à ce qui pourrait se concevoir dans l’imaginaire collectif, ce n’est pas la manette qui « donne les boutons à la console ». C’est la console qui demande à la manette son état qui lui renvoi ensuite là un buffer, dans notre cas, un buffer de 8 bit stocké dans le registre 8 bit.

Maintenant que le décor est planté, la console veut donc connaitre l’état de la manette.

La console va envoyer un signal sur le Latch. Cela va ordonner au Controller de stocker dans son registre l’état des boutons.

Ensuite la NES va envoyer 8 signaux haut sur la clock. A chaque signal le contrôler va renvoyer une réponse à la NES sur DATA « l’état du bouton suivant » avec un signal haut si le bouton est relâché et un signal bas sur le bouton est pressé. (En fait le bit en tête du registre vu que c’est du shifted, la notion de bouton suivante étant une vue de l’esprit)

Voici un chronogramme qui résume tout cela :

Et le schéma de connexion du 4021 :

Et pour la snes ?

Coté connectique on reste sur du 7 fils dont 5 utilisés :

Coté registre on passe de 8 à 16bits (plus de boutons ^^)
Il s’agit en fait 2 registre 8 bits en parallèles.

Et sur l’ordre des impulsions :

Conclusion

Voila, s’en est tout pour aujourd’hui. On se retrouvera bientôt pour un article sur le en555, les registres et un sur l’interfaçage en usb de ces deux controller.

Je projette aussi de faire le même reverse sur les controller megadrive, n64 et gamecube.

@ bientôt et n’hésitez pas à poser vos questions

Source

Nes : mes yeux et ma tête.
Snes (pas sous la main donc pas de teste possible…) : http://www.repairfaq.org/REPAIR/F_SNES.html#SNES_003
DataSheet 4021 : http://www.datasheetcatalog.org/datasheet/rohm/bu4021b.pdf
Les diagrammes ont été réalisé avec SDS3.
Les photos et les diagrammes sont sous licence CC by-nc-nd (pas d’utilisation commerciale, obligation de citer l’auteur et pas de modifications)

Basic Reverse Engeneering en DotNet

Yop tout le monde, voici un petit cours qui vous permettra de vous initier au reverse engeneering d’applis DotNet de manière basique. Un second cours suivra bientôt et rentrera plus dans le détail en utilisant WinDbg. Dans celui-ci nous allons tout d’abord découvrir le code IL et comment l’exploiter. Bon visionnage ^^