piątek, październik 29, 2010

Hackowanie .NET–Rozwiązanie

Tydzień temu zaproponowałem mały konkurs, polegający na zmuszenia .NET’a do zrobienia rzeczy, której teoretycznie nie powinno dać się zrobić. Niestety trochę “przedobrzyłem” i jednym z dostępnych rozwiązań rozwiązań było użycie Reflection o co mnie w pytaniu nie chodziło. Świat się jednak nie wali, a jest nawet lepiej. Wiem, że są osoby, które o Reflection nie słyszały i dziwią się, że takie rzeczy w .NET można robić.

Tak więc zobaczmy jakie rozwiązania są dostępne:

Rozwiązania

Podstawowe czyli z użyciem Reflection:

    public class NaughtyByReflectionPlugin : IPlugin

    {       

        public void Execute(PluginData data)

        {

            var memebrs = data.GetType().GetMember("ConstString", BindingFlags.Instance | BindingFlags.NonPublic);

            var member = (FieldInfo)memebrs[0];

            member.SetValueDirect(__makeref(data), "Hacking .NET");

        }       

    }

Takie (lub podobne - oparte na Reflection) rozwiązania nadesłali: Przemysław Mynarski, Marek Grabarz, Jarosław Dubrownik, Krystian Kulig, Paweł Szczygielski, Łukasz Jezior, Adam Rafałko oraz Bo i wiero. Jak już wspominałem nie wszyscy są świadomi Reflection, tak więc dobrze, że i takie rozwiązanie się pojawiło. Dodatkowo duży plus dla Marka za sprawienie, że teraz wiem o słowie kluczowym __makeref - choć i da się bez tego. Widać człowiek uczy się cały czas.

Jaki jest minus takiego rozwiązania? A no to, że w bardzo prosty sposób możemy się przed nim zabezpieczyć. Wystarczy, że nasz program będzie miał zabrane prawa do Reflection i już nie poszalejemy.

    [ReflectionPermission(SecurityAction.Deny, Unrestricted = true)]

    class Program

    {

No więc, co możemy zrobić? Da się to obejść?

Pointery. A co to takiego?

Da się obejść powyższe ograniczenie za pomocą pointerów, ale trzeba posiłkować się kodem unsafe, więc nie wiem czy takie rozwiązanie przeszłoby przy ładowaniu z osobnego assembly. Nie miałem chwili tego sprawdzić. Zobaczmy jednak kod:

public void Execute(PluginData data)

{

    string toWrite = "Hacking .Net";

    string constdata = String.Intern("Const data");

    unsafe

    {

        GCHandle handleConst = GCHandle.Alloc(constdata, GCHandleType.Pinned);

        GCHandle hackString = GCHandle.Alloc(toWrite, GCHandleType.Pinned);

        byte* dst = (byte*)handleConst.AddrOfPinnedObject().ToPointer();

        byte* src = (byte*)hackString.AddrOfPinnedObject().ToPointer();

        //*(dst - 4) = (byte)toWrite.Length;

        for (int i = 0; i < toWrite.Length << 1; i++)

            *dst++ = *src++;

        *dst = 0;

    }

}

Takie rozwiązanie jako alternatywne nadesłał Adam Rafałko. Nie do końca ono spełniało, założenie bo Adam (chyba celowo ;)) użył krótszego stringu niż Hacking .NET i jego kod ucinał kawałek napisu. Aby wyświetlał się cały napis konieczna jest zmiana, którą już ja dodałem - zmiana długości łańcucha w pamięci (zakomentowana linia - którą trzeba by napisać prawidłowo). Dodatkowo plus za sprawienie, że wiem iż jest funkcja String.Intern, choć jeszcze nie wiem co ona daje :)

StructLayout

Każdy kto używał P/Invoke zetknął się z takowym atrybutem. Używało się, przy dodawaniu typów nieobecnych w .NET do framework’a aby można z nich było skorzystać z kodu C#. Standardowe użycie takiego parametru wyglądało mniej więcej tak:

    [StructLayout(LayoutKind.Explicit)]

    public struct _PROCESSOR_INFO_UNION

    {

        [FieldOffset(0)]

        internal uint dwOemId;

        [FieldOffset(0)]

        internal ushort wProcessorArchitecture;

        [FieldOffset(2)]

        internal ushort wReserved;

    }

Niby nic podejrzanego, ale co się stanie gdy nasz plugin napiszemy tak?

    [StructLayout(LayoutKind.Explicit)]

    class NaughtyByStructLayoutPlugin : IPlugin

    {

        internal class PluginHack

        {

            public string Text;

        }

 

        [FieldOffset(0)]

        private PluginData _original;

        [FieldOffset(0)]

        private PluginHack _hack;

 

        public void Execute(PluginData data)

        {

            _original = data;

            _hack.Text = "Hacking .NET";

        }

    }

Przeanalizujemy ten kod. Atrybut StructLayout jest wymagany, aby móc ustawiać przesunięcia danych pól w obiekcie. Następnie ustalamy przesunięcia. Widzimy ten atrybut FieldOffset z ustawionym takim samym przesunięciem wynoszącym 0 dla obu obiektów? Wszystko jasne? Dzięki takiemu potraktowaniu obiekt typu PluginData oraz obiekt typu PluginHack będą okupować ten sam fragment pamięci. A dzięki temu, że Text jest publiczny możemy go sobie jawnie przeładować czym tylko chcemy.

O takie właśnie rozwiązanie chodziło. Adrian Ciura oraz Rafał Jasica przesłali właśnie takie rozwiązanie. Brawo!

Jest jeszcze jedno rozwiązanie, choć bardziej z kategorii humorystycznych :)

public void Execute(PluginData data)

{

    int cursorPosY = Console.CursorTop;

    new Thread(p =>

    {

        Thread.Sleep(100); // time may vary

        Console.SetCursorPosition(0, cursorPosY);

        Console.WriteLine("Hacking .NET");

        Console.SetCursorPosition(0, cursorPosY + 2);

    }).Start();

}

Interesujące? :) Takie rozwiązanie nadesłał także Bo.

Niby takie małe hakowanie, ale czy da się napsuć coś więcej? Pisanie bezpośrednio do pamięci czy też dostawanie się do wewnętrznej pamięci za pomocą innych obiektów może nam już napsuć w kodzie dość mocno. No bo możemy sobie wskazać adres łańcucha na adres np. 0xbaadfeed :). Pytanie, czy za pomocą tych technik można napsuć coś w kodzie metod? Może komuś się uda? Nie wiem jak wy, ale ja uwielbiam analizować rzeczy trochę niżej niż to co mamy dostępne od ręki.

Post był inspirowany wpisem Is .NET Type-Safe? napisanym przez p. Wiktora Zychlę wykładowcę na UWr oraz byłego MVP w kategorii C#.

PS. Co do nagród to muszę jeszcze pomyśleć. Nie spodziewałem się tylko zgłoszeń :)

piątek, październik 22, 2010

Hackowanie .NET

Może nie takie prawdziwe, ale takie malutkie i niewinne :-) (a może nie takie niewinne?). Do napisania tego postu zainspirował mnie niedawno przeczytany inny post, pokazujący, jak można zmusić .NET do zrobienia czegoś co nie powinniśmy mieć możliwości zrobić. Jako, że mój post będzie związany z małą zagadką/konkursem na razie linka do inspiracji nie podam. Sposób jest w pełni legalny w .NET bo i program się kompiluje bez żadnych sztuczek. F5 i działa….

Zadanie

Zadanie będzie z typu akademickich, nie będzie pokazane tu jak zrobić coś potencjalnie niebezpiecznego, ale można od tego wyjść już do bardziej groźniejszych przypadków. Tak więc nakreślmy nasze zadanie. Mamy takowe klasy i kod:

PluginData.cs:

    public class PluginData

    {

        private readonly string ConstString = "Const data";

 

        public void Print()

        {

            Console.WriteLine(ConstString);

        }

    }

IPlugin.cs:

    interface IPlugin

    {

        void Execute(PluginData data);

    }

No i nasz Program.cs:

    class Program

    {

        static void Main(string[] args)

        {

            try

            {

                var data = new PluginData();

                var plugin = CreatePlugin();

                plugin.Execute(data);

 

                data.Print();

            }

            catch (Exception)

            {

                Console.WriteLine("Error!");             

            }

            Console.WriteLine("End");

            Console.Read();

        }

 

        private static IPlugin CreatePlugin()

        {

            //jakaś fabryka pluginów i akurat twój jest ładowany

            return new NaughtyPlugin();

        }

    }

Twój kawałek kodu to NaughtyPlugin i w założeniu powinien być ładowany z zewnętrznej biblioteki. Dla uproszczenia można mieć go w tym samym projekcie. Normalny wynik działania takiego kodu z pluginem powinien wyglądać mniej więcej tak:

normal_output

W zależności czy plugin wypisuje coś dodatkowego na konsoli i czy nie rzuca wyjątkiem. Czy da się tak go napisać, aby wynikiem było coś takiego:

output

I oczywiście program kończył swoje działanie? Tak więc oczywiste rozwiązania w którym plugin wypisuje i Hacking .NET i End odpadają ;). End jest wypisywane przez Program.cs.

Czyli opisując słowami czy da się zmienić łańcuch znaków ConstString w obiekcie PluginData? Jest readonly – raczej Reflection nic nie da, a może da? A może dynamic? A może się nie da i tylko to sobie wymyśliłem, że działa mi to w .NET 3.5/4.0 i VS 2008/2010 (choć środowisko nie ma tu znaczenia).

Niech to będzie konkurs – deadline do 29.10.2010 czyli od dzisiaj tydzień – ja mam jedno rozwiązanie (“niskopoziomowe” – niech to będzie jako podpowiedź), ale jak ktoś znajdzie inne działające to tym lepiej. Nagród wielkich nie przewiduje – w zasadzie żadne Chwała i sława. Może jednak znajdę jakąś koszulkę dla zwycięzcy. Oczywiście swoje rozwiązanie także opublikuję. Odpowiedzi w komentarzu są moderowane, więc nie będę ich publikował przed końcem albo na maila (jest w profilu).

czwartek, październik 21, 2010

Mono i Mono Develop

Ostatnimi czasy postanowiłem przyjrzeć się bliżej platformie Mono oraz środowisku Mono Develop. Z racji tego, iż będę miał potrzebę wytworzenia kawałka oprogramowanie na Mac OS postanowiłem skorzystać z tych narzędzi w tymże celu, a żeby lepiej mi to poszło trzeba na początku się z nimi zapoznać.

Uwaga: Jeśli chodzi o jakiekolwiek porównania wydajnościowe to testy były robione na wirtualnej maszynie z Windows 7 z 2 GB RAM.

Pobieranie i instalacja

Mono to tylko około 78 MB natomiast Mono Develop to tylko 20 MB. Pestka do przełknięcia na dzisiejszych łączach. Trzeba było jeszcze doinstalować gtk# i można śmigać. Żadnych problemów w tym miejscu.

Wygląd i działanie

Mono Develop po uruchomieniu prawie jak VS 2008:

MonoDevelop-Home

Projekty jakie możemy przy jego pomocy tworzyć to: konsola, konsola IL (więcej poniżej), Gtk# oraz biblioteka. Do tego dochodzi ASP.NET no i Moonlight (czyli Monowski odpowiednik SLa) Niestety nie ma projektów WPF. Możemy używać VB.NET (bez Moonlight’a) jak i C#.

W działaniu nie zauważyłem żadnych spowolnień, ani problemów. Wszystko uruchamia się i działa jak należy. InteliSense podpowiada co trzeba i bez zbędnego opóźnienia. Dostępne mamy jakieś namiastki funkcjonalności refaktoringu, ale nie jest tego tyle ile w samym gołym VS. A R# niestety dla MonoDevelop nie ma.

Prócz tego mamy oczywiście projekty do testów jednostkowych a także metryki kodu. Jest dość dobrze jeśli popatrzeć, że jest to całkowicie darmowe środowisko.

Ciekawostki

Mono Develop oferuje dość ciekawy projekt. Po stworzeniu Console IL, możemy sobie kodować w ILu bezpośrednio w IDE. Bardzo fajna funkcjonalność. Może nie do końca każdemu przydatna w codziennej pracy, ale ja jako maniak low-level stuff chętnie z takiej możliwości bym skorzystał w Visual Studio.

il

Plusy ujemne i minusy dodatnie

Co na plus:

  • Projekt IL. Możliwość kodowania w IL w IDE i debugowanie. Duży plus ode mnie!
  • Informuje o innym modelu programowania w Gtk#. Nie ma pozycjonowania absolutnego tylko pojemniki - WPF-like
  • RegEx toolkit – wiadomo co to :)

Co na minus:

  • Nadal nie wiem jak zmusić breakpoint aby był warunkowy. Niby opcje są, ale zawsze niedostępne.
  • Połowiczne spolszczenia. Często widzimy pomieszanie polskiego z angielskim. Jak dla mnie nie musi być polskiego, ale niech to będzie spójne. Da się to oczywiście zmienić na angielski.
  • Brak WPF ;(

Podsumowanie

Mono i Mono Develop to ciekawe alternatywy warte rozważenia i przyjrzenia się im z bliższa. Na razie planów na przejście całkowicie na to środowisko, ale z racji, że prawdopodobnie będę musiał stworzyć coś na MacOS będę miał z nim troszkę do czynienia.

sobota, październik 09, 2010

VS 2010 – Debugging – Nowości

Tytuł tego posta może być lekkim zeskoczeniem. Od premiery VS 2010 sporo czasu już minęło. Postanowiłem jednak spisać kilka nowości jakie udostępnia ono pod kątem debugowania. Zadanie jest o tyle trudne, że prawie wszystko co było do powiedzenia w tym temacie zostało już powiedziane przez pracowników MS w postach takich jak ten napisany przez ScottaGu. Postaram się jednak przedstawić temat z nowej perspektywy.

Dump

minidump

VS w najnowszej wersji umożliwia nam stworzenie dumpa procesu bezpośrednio z poziomu środowiska. Przydatne…

Dump summary

Skoro już jesteśmy przy samym dumpie to VS podaje nam ładne podsumowanie dumpa, którego właśnie zrzuciliśmy. Wystarczy wczytać go do VS aby pokazał nam całkiem ładne podsumowanie tego co w nim mamy.

minidump_summary

FirstChanceException

Czy czasem zastanawiasz się co oznaczają “tajemnicze” komunikaty wyświetlane w okienku Output o treści “A first chance exception of type 'System.ApplicationException' occurred in XXX.exe”? Nie będziemy się tu rozpisywać co on oznacza, bo można to przeczytać w poście What is a First Chance Exception? Natomiast to o czym napiszemy to to, że w obecnej wersji VS pozwala nam podpiąć się pod zdarzenie, gdy taki wyjątek jest generowany. Możemy to zrobić za pomocą następującego kawałka kodu:

AppDomain.CurrentDomain.FirstChanceException += CurrentDomain_FirstChanceException;

Dzięki temu dostaniemy powiadomienia o takich zdarzeniach i możemy na nie reagować.

Dodatkowe Opcje

W sekcji Debugging w opcjach mamy dodatkową pozycję Output Window. Umożliwia ono nam skonfigurowanie kilku dodatkowych opcji ułatwiających znajdywanie błędów szczególnie przydatna jest część odnośnie WPF’a.

options

Możemy powiedzieć jakie informacje o WPF chcemy widzieć w okienku Output. Mamy także możliwość wyłączenia różnych opcji, aby był on bardziej czytelny. Nadal jednak błędny Bindingi nie powodują błędów kompilacji.

Okienko rejestrów

VS posiada (także w poprzednich wersjach) podgląd rejestrów procesora (Debug –> Windows –> Registers, CTRL+ALT+G). To co dołożyli w najnowszej wersji to podgląd wartości dla rejestrów AVX oraz AVX Float. Co to jest? Czytaj tutaj – Advanced Vector Extensions.

Podsumowując

Mam nadzieję, że te kilka “tricków” przyda się wszystkim, którzy od czasu do czasu muszą pobawić się z debuggerem na poziomie wyższym niż ustawienie kilku pułapek. Na pewno nie opisałem wszystkich nowości w tym temacie, np. IntelliTrace. Sporo już o tym napisano i nie ma sensu tego powielać. Za początek niech służą te 4 artykuły na dotnetomaniak.plIntelliTraceZachęcam jeszcze do przejrzenia rzeczy w poście Scott’a Gu. Jest tam także sporo fajnych drobnych usprawnień, które spowodują, że nasz związek z debuggerem będzie przyjemniejszy :).

poniedziałek, październik 04, 2010

WPF – Filmy: Triggery, Dostępne typy projektów, AttachedProperties

Jako, że nadal nie mam czasu na pisanie nowych postów (tematów trochę jest - czasu mniej :(), postanowiłem udostępnić coś co kiedyś zostało nagrane, a jakoś nie zostało przedstawione szerszej publiczności.

Poniżej linki do trzech moich (AttachedProperties oraz Style - już był publikowany na blogu, ale na innym serwerze) filmów umieszczonych na Cyber-Flick odnośnie WPF'a. W zamyśle, miał powstać cały cykl filmów o WPF - na razie jest tylko tyle. Jak będzie pozytywny oddźwięk to może powrócę do ponownego nagrywania. Czy nagrywanie takich filmów ma sens? Czy wystarczą posty, które napisałem w ramach cyklu - WPF?

Wszelkie uwagi mile widziane!

PS. Będzie jeszcze 4, ale jak na razie coś źle się przetworzył.