Přeskoč navigaci

.NET disassembler a tak vůbec

Programy psané v .NET jsou z principu lehce dekompilovatelné a tak je dobré pokud originální autor zná programy, které případný útočník bude používat.

.NET dekompilace

Programy v .NET jsou kompilovány na cílový procesor až za běhu a jsou na disku uloženy v předkompilované formě v bytecode, který se dá zobrazovat pro člověka jako CIL. Tento formát je získán jako výsledek práce kompilátoru .NET jazyků (třeba C#). Každý z rodiny .NET jazyků je překládán do CIL (no existují i kompilátory C# přímo pro cílový procesor, ale moc se to nepoužívá). Tento formát je standardizován a tím je umožněn vznik dekompilátorů.

Hello world v CIL

.method public static void Main() cil managed
{
     .entrypoint
     .maxstack 1
     ldstr "Hello, world!"
     call void [mscorlib]System.Console::WriteLine(string)
     ret
}

Výsledkem je, že nikdo (ani dekompilátor) nedokáže (bez přídavných souborů) určit originální programovací jazyk a z toho plynou určitá omezení a pro autora originálního programu výhody. Dekompilátor např. nezná jména lokálních proměnných (prostě nějaké vygeneruje) a některé speciální konstrukce z jiných jazyků nedokáže zobrazit pokud zvolíte jiný výsledný jazyk, nebo je převede na jiné konstrukce. Např. příkaz switch je někdy převeden na sekvenci příkazů if.

Naopak ve výsledném souboru (exe, assembly) jsou uvedeny jména funkcí, tříd, texty atd. Právě těchto informací využívají dekompilátory a to je základem jak se jim bránit.

Obfuscator

Obfuscator je program, který z výsledného kódu odebere informace, které nejsou nutné pro běh programy, přejmenuje třídy, metody a vůbec veškeré informace používané dekompilátory. Některé umí i mnohem složitější věci.

Ten pravý pro vaše použití najdete na internetu. Součástí instalace VS je sice základní verze jednoho z nich, která ale umí jen přejmenování. Ostatní vlastnosti jsou již jen v placené verzi.

Reflector

Nejlepší volně dostupný dekompilátor je Reflector. Alternativou je mu Anakrino, již nevyvíjený, ale se zdrojáky.

Reflector umí dekompilovat do C#, VB, Delphi.NET, Chrome, MC++ a CIL. Ukážeme si kde jsou slabá místa takové dekompilace. Principiálně dekompilátor určité postupy v CIL nahrazuje příkazy vyššího jazyka. Uvedeme si příklad:

Originální program

    [STAThread]
    static void Main() 
    {
      const int ciTestSwitch1 = 5;
      const int ciTestSwitch2 = 6;
      const string csTest = "test2";
      for (int iLoop = 0; iLoop < 10; iLoop++)
      {
        System.Console.WriteLine(iLoop.ToString());
        switch (iLoop)
        {
          case ciTestSwitch1:
            System.Console.WriteLine("Test1");
            break;
          case ciTestSwitch2:
            System.Console.WriteLine(csTest);
            break;
        }
      }
    }

C# (bez ladících informací .pdb), zmiznou názvy lokálních proměnných a konstanty.

[STAThread]
private static void Main()
{
    for (int i = 0; i < 10; i++)
    {
        Console.WriteLine(i.ToString());
        switch (i)
        {
            case 5:
                Console.WriteLine("Test1");
                break;

            case 6:
                Console.WriteLine("test2");
                break;
        }
    }
}

Delphi.NET - evidentně by to takto nikdy programátor nenapsal (použil by for a vypustil příkazy break). Je vidět, že for v C# je to samé co while, což pro Delphi v žádném případě neplatí (zde FOR může iterovat nad výčtem a pod.), takže proto dekompilátor zvolit variantu s while.

procedure Class1.Main;
begin
    i := 0;
    while ((i < 10)) do
    begin
        Console.WriteLine(i.ToString);
        case i of
            5:
                begin
                    Console.WriteLine('Test1');
                    break;

                end;
            6:
                begin
                    Console.WriteLine('test2');
                    break;

                end;
        end;
        inc(i)
    end
end;

Raději uvedu jak by to napsal programátor:

procedure Class1.Main;
var
  i: Integer;
begin
    for i:= 0 to 9 do
    begin
        Console.WriteLine(i.ToString);
        case i of
            5: Console.WriteLine('Test1');

            6: Console.WriteLine('test2');
        end;
    end
end;

VB.NET - také zajímavé

<STAThread> _
Private Shared Sub Main()
    Dim i As Integer
    For i = 0 To 10 - 1
        Console.WriteLine(i.ToString)
        Select Case i
            Case 5
                Console.WriteLine("Test1")
                Exit Select
            Case 6
                Console.WriteLine("test2")
                Exit Select
        End Select
    Next i
End Sub

A nakonec CIL

.method private hidebysig static void Main() cil managed
{
    .custom instance void [mscorlib]System.STAThreadAttribute::.ctor()
    .entrypoint
    .maxstack 2
    .locals init (
        [0] int32 num,
        [1] int32 num2)
    L_0000: ldc.i4.0 
    L_0001: stloc.0 
    L_0002: br.s L_0040
    L_0004: ldloca.s num
    L_0006: call instance string [mscorlib]System.Int32::ToString()
    L_000b: call void [mscorlib]System.Console::WriteLine(string)
    L_0010: ldloc.0 
    L_0011: stloc.1 
    L_0012: ldloc.1 
    L_0013: ldc.i4.5 
    L_0014: sub 
    L_0015: switch (L_0024, L_0030)
    L_0022: br.s L_003c
    L_0024: ldstr "Test1"
    L_0029: call void [mscorlib]System.Console::WriteLine(string)
    L_002e: br.s L_003c
    L_0030: ldstr "test2"
    L_0035: call void [mscorlib]System.Console::WriteLine(string)
    L_003a: br.s L_003c
    L_003c: ldloc.0 
    L_003d: ldc.i4.1 
    L_003e: add 
    L_003f: stloc.0 
    L_0040: ldloc.0 
    L_0041: ldc.i4.s 10
    L_0043: blt.s L_0004
    L_0045: ret 
}

Dekompilátor má mimochodem i dobré využití k získávání informací o samotném .NET frameworku.

Jaggni to|Linkuj

Komentáře k tomuto článku

[*] Petr Němec @ 18.5.2010 18:43:27

Velmi pěkný článek. Sice jsem hledal nějaký tutoriál o CIL v češtině, ale jinak dobré :-)



Prosím o dodržovaní určitých pravidel (tj. žádné neslušné texty, reklamy a tak prostě podobně). Komentáře porušující tyto pravidla budou odstraněny.

Před vložením komentáře je nutno provést náhled, jedná se o ochranu proti spamu.

 

Vložení komentáře
  
 
 

 

© NetCode.cz, 2006-9 | Všechna práva vyhrazena
Provozováno na mém pikoCMS, vygenerováno: 24.11.2017 6:43:28

O mně

Informace o mé maličkosti a kontakt.

Lokální tagy

amd(1) amiga(1) apple(1) aspnet(2) audio(1) borland(5) C64(1) codegear(12) delphi(39) dotnet(9) dvd(1) electone(1) embarcadero(1) emulator(11) firebird(2) flash(1) freepascal(5) gamecube(3) gigabyte(2) google(3) hardware(48) holografie(1) homebrew(29) hry(12) ibm(14) iphone(7) jidlo(1) komponenty(1) konzole(15) latex(1) lenovo(17) migrace(1) modchip(3) moje(9) mplayer(3) mssql(1) multi-touch(3) native-api(1) navody(23) nintendo(53) Nintendo3DS(2) nintendo64(6) NintendoDS(15) onestation(2) opera(1) ot(1) palm(1) pascal(1) pdf(1) pic(2) pmd85(1) pocitace(1) print-server(2) programovani(21) programy(25) R400(1) recenze(6) retro(1) satelit(1) seamonkey(5) snes(3) svepomoci(1) technika(1) thinkpad(20) usb(1) video(3) vs(3) vykriky(12) web(7) webdesign(8) wii(83) wiimote(13) wiiware(1) wiki(2) windows(7) windows-mobile(1) wl500g(2) wtf(8) zivot(1) ZX-Spectrum(5)