Nie wszyscy wiedzą że taki 'foreach' czy 'lock' to tylko zwykły "syntactic sugar", a nie specjalna konstrukcja języka. Rzucimy okiem na IL, co to takiego i jak można podejrzeć kod różnymi narzędziami (ildasm, Reflector, DotPeek). Pokażę także jak niektóre polecenia są w rzeczywistości tłumaczone na IL i dlaczego wiedza o tym może przydać się w rozwiązywaniu pewnych problemów. Nie pominę także nowości z C#6, czyli jaka magia się dzieje jeśli zastosujemy "string interpolation", "null-conditional operators" lub "expression-bodied function members". Na koniec przedstawię sposoby aby ukryć kod przez wścibskimi oczami innych (obfuskacja i dotfuscator).
1. Pokaż kotku,
co masz w środku
Czyli jak wygląda kod C# po przetworzeniu przez
kompilator
2. Who am I?
Ryszard Skonieczka
pl.carnifex@gmail.com
3. Agenda
IL – what is it?
How to get read compiled code and see IL?
New command or just syntactic sugar?
Usage in real life
How to protect my code?
Q & A
4. Agenda
IL – what is it?
How to get read compiled code and see IL?
New command or just syntactic sugar?
Usage in real life
How to protect my code?
Q & A
5. IL – what is it?
Common Intermediate language
Native code
Assembler for .NET
Source: wikipedia.org
6. Agenda
IL – what is it?
How to get read compiled code and see IL?
New command or just syntactic sugar?
Usage in real life
How to protect my code?
Q & A
7. How to get read compiled
code and see IL?
IL DASM
Reflector
DotPeek
JustDecompile
8. Agenda
IL – what is it?
How to get read compiled code and see IL?
New command or just syntactic sugar?
Usage in real life
How to protect my code?
Q & A
9. New command or
just syntactic sugar?
.NET vs C#
Examples
Source: wikipedia.org
24. Agenda
IL – what is it?
How to get read compiled code and see IL?
New command or just syntactic sugar?
Usage in real life
How to protect my code?
Q & A
25. Usage in real life
EventHandlerList
Use C#6 goodies on XP
Better locks
ildasm, ilasm
Emit
27. Agenda
IL – what is it?
How to get read compiled code and see IL?
New command or just syntactic sugar?
Usage in real life
How to protect my code?
Q & A
28. How to protect my code?
Obfuscation
Dotfuscator
ConfuserEx
Author: Martin Fowler
29. Agenda
IL – what is it?
How to get read compiled code and see IL?
New command or just syntactic sugar?
Usage in real life
How to protect my code?
Q & A
Krótkie info o sobie. Gdzie pracuje, jako kto, z jakimi aplikacjami mam do czynienia.
Krótkie wytłumaczenie co to jest IL przez co jest używany. Dlaczego kompilacja do kodu pośredniego jest dobra (optymalizacja maszyny wirtualnej, bez konieczności przekompilowania programu)
Krótki przykład fragmentu kodu.
Kompilacja do kodu maszynowego/nartwnego. Ngen.exe (Native Image Generator)
IL jest jak Assembler tylko że dla .NET
Pokażę narzędzia dzięki którym można dostać się do ILa i narzędzia dzięki którym można zobaczyć kod w „programmer friendy way” – czyli kod w C#
Ildasm – dostępny wszędzie, bo jest częścią .NETa, a dokładniej Framework SDK
Reflector – ostatnia darmowa wersja to 6. Ma możliwość dekompilacji do różnych języków
DotPeek – aplikacja gości od R# (JetBrains), w wersji 10 (w końcu) dodali możliwość pokazania ILa
JustDecompile – aplikacja Telerik’a – w przeszłości miała duże problemy z dekompilacją kodu
Różnica pomiędzy samym językiem (możliwościami IDE, kompilatora) a Frameworkiem (prawdziwymi poleceniami).
Jeśli wiemy co jest częścią języka, a co frameworka, można pisać kod w VS15 a uruchamiać nawet na .NET2.0
Atrybut Synchronized. Nie używać! Bo robi lock’a na this
To w rzeczywistości nie jest tłumaczone… ale taka ciekawostka jak co ten atrybut robi
Lock jest zamieniany na konstrukcję z użyciem Monitor’a. Taki wygląd jest w C#5, wcześniej nie było „lockTaken”
Foreach zostaje zamieniony na while’a, który przebiega się po enumeratorze.
W C#4.0 konstrukcja wyglądała tak. W wersji 5.0 (chyli .NET4.5) zmienna „i” została wcielona do ciała while
R# zgłasza błąd jeśli zastosujemy pokazany kod.
Pytanie do publiczności: Kto może powiedzieć jaki będzie wynik? Co zostanie wyświetlone na konsoli?
Pytanie: Który kod zadziała szybciej? Ten z foreach’em, czy for’em? Bo nie raz słyszałem różne opinie…
Taki zabieg kompilator zastosuje TYLKO jeśli kolekcja jest tablicą, jeśli zastosujemy coś innego (nawet IList<>, które ma indeksera) to dostaniemy standardowy GetEnumerator() i MoveNext().
For – także jest cukiereczkiem… zostaje zamieniony na odpowiednik while’a, który wygląda tak.
Chyba jednym z najbardziej znanych cukiereczków jest using().
Niektórzy mogli coś przypuszczać, że z lambdami jest „coś” nie tak, jak poleciał exception i w stackTrace dostaliśmy dziwne metody <>b_1.
Jeśli w lambdzie używany jest field, to kompilator stworzy nam nową metodę w klasie i utworzy delegatę do tej metody
Jeśli w lambdzie będziemy chcieli użyć zmiennych lokalnych z metody… kompilator utworzy nową klasę, doda pola, które odpowiadają użytym zmiennym, a następnie utworzy delegatę do metody z tej klasy.
Jeszcze większa „magia” dzieje się jak zastosujemy konstrukcje z „yield”.
Utworzona zostanie nowa klasa (Enumerator), a metodzie MoveNext() będziemy mieli sekwencję switch/case, odpowiadającą poszczególnym sekcją „yield return”
Ok, wspominałem wcześniej że Using() jest najbardziej znanym syntactic sugar… Ale chyba to wszyscy znają i używają
Przy eventach także dzieje się coś „ekstra” po stronie kompilatora. Kod po lewej można określić jako Auto-Implemented Events.
W rzeczywistości kompilator tworzy delegatę wskazanego typu, a do samego eventa dodaje accessory „add” i „remove”, które modyfikują tą delegatę. Jeśli w kodzie tej klasy odwołamy się do eventa, to w rzeczywistości będziemy odwoływać się do tego automatycznego delegata.
Implementacja accessorów różna jest w zależności jakim kompilatorem zostało skompilowane. Od 4.0 używany jest Interlock do podmiany delegaty, wcześniej (3.0) był zwykły Delegate.Combine z lockiem na „this” – o zgrozo…
Informacja że to jest „auto implemented” i zawsze tworzymy dodatkowe pole… dlatego w kontrolkach jest używany „EventHandlerList”
Większość nowości to cukiereczki. String interpolation, to zwykły String.Format. nameOf w czasie kompilacji jest zamieniane na stringi. A deklaracja metod jako lambdy, jest zamieniana na zwykłe metody.
W Microsoft Magazine, słowa „Marka Michaelisa” mówią same za siebie
W C# 6.0 dochodzi nowy collection initializer, czyli inicjalizacja po indekserze.
Należy jednak pamiętać że różni się to od poprzedniej wersji. Add wyrzuci exception jeśli natrafi na tą samą wartość, przypisanie indekserem – nie!! Warto o tym pamiętać.
Gdzie ta wiedza nam się może przydać?
Już wspominałem wcześniej, optymalizacja eventów.
Jak wiemy co należy do specyfikacji języka a co frameworka, można kompilować i używać aplikacji na XP
Można bardziej zoptymalizować np. locki. Wiedząc że lock() to to samo co Monitor(), można zamienić w niektórych sytuacjach na SpinLock’a
Modyfikacja exe.
ildasm Program.exe /out=Program.il
Zmiana w pliku .il
ilasm Program.il /output=Prog2.exe
Emit – umożliwia dynamiczne tworzenie kodu. Możemy dzięki temu stworzyć dowolną klasę/metodę „w locie”/w trakcie działania programu.
Oczywiście później taką wygenerowaną klasę i assembly można zapisać na dysku jako plik dll.
Działają tak mock’i, hibernate (tworzący obiekty proxy), etc.
Ok, pokazałem, jak można zobaczyć każdy kod i go zdekompilować. Czy istnieje więc sposób aby zabezpieczyć swój kod przed wścibskimi?
Najskuteczniejszą opcją jest pisanie nieczytelnego kodu, tak abyśmy tylko my go zrozumieli.
Ale nie jest wyjście – cytat Martina. Więc kod źródłowy powinien być zawsze jak najbardziej zrozumiały dla wszystkich (nie tylko dla nasz i naszego zespołu).
Obfuskacja może nastąpić przed kompilacją lub też po niej – w tym przypadku program operuje właśnie na IL.
Dostępne są płatne wersję oferujące dużo.
Można także użyć darmowych odpowiedników, które całkiem nieźle sobie radzą.
Ostatecznie jak ktoś jest zdeterminowany, nic go nie powstrzyma i zawsze dostanie się do naszego kodu :P
1drv – znajdą się binarki ze wszystkich wersji .NET, przykładowa apka HelloWorld oraz ta prezentacja