niedziela, 30 listopada 2014

Penetrujemy aplikacje napisane w języku C - narzedzie GDB

Tak jak pisałem ostatnio, dziś będę używał narzędzia GDB. Służy ono do analizowania kodu programów napisanych w C lub C++. Niestety jeżeli chodzi o składnie desasemblera to znam tylko Intela i nim będę się posługiwał i tym programie, co powoduje to że muszę je skonfigurować i to wygląda następująco:

 gdb -q  
 (gdb) set disassembly-flavor intel   
 (gdb) quit  
po skonfigurowaniu, mogę teraz przejść do pracy, tylko jeszcze będę musiał prze-kompilować program przy użyciu gcc z parametrem -g, który jest odpowiedzialny za wprowadzenie dodatkowych informacji jak będę debugował.
 gdb -q ./a.out  
 Reading symbols from /home/domek/c/a.out...done.  
 (gdb) list  
 1     #include <stdio.h>  
 2       
 3     int main() {  
 4          int i;  
 5          for(i = 0; i < 10; i++) {   
 6               puts("Hello, world!\n");   
 7          }  
 8          return 0; // Informuje OS o zakonczeniu programu  
 9     }  
 (gdb) di  
 directory  disable   disassemble disconnect  display     
 (gdb) dis  
 disable   disassemble disconnect  display     
 (gdb) disassemble main  
 Dump of assembler code for function main:  
   0x000000000040055c <+0>:     push  %rbp  
   0x000000000040055d <+1>:     mov  %rsp,%rbp  
   0x0000000000400560 <+4>:     sub  $0x10,%rsp  
   0x0000000000400564 <+8>:     movl  $0x0,-0x4(%rbp)  
   0x000000000040056b <+15>:     jmp  0x40057b <main+31>  
   0x000000000040056d <+17>:     mov  $0x400634,%edi  
   0x0000000000400572 <+22>:     callq 0x400440 <puts@plt>  
   0x0000000000400577 <+27>:     addl  $0x1,-0x4(%rbp)  
   0x000000000040057b <+31>:     cmpl  $0x9,-0x4(%rbp)  
   0x000000000040057f <+35>:     jle  0x40056d <main+17>  
   0x0000000000400581 <+37>:     mov  $0x0,%eax  
   0x0000000000400586 <+42>:     leaveq   
   0x0000000000400587 <+43>:     retq    
 End of assembler dump.   
 (gdb) run  
 Starting program: /home/domek/c/a.out   
 Missing separate debuginfo for /lib64/ld-linux-x86-64.so.2  
 Try: zypper install -C "debuginfo(build-id)=ecb8ef1a6904a2a3ec60a527f415f520c8636158"  
 Missing separate debuginfo for /lib64/libc.so.6  
 Try: zypper install -C "debuginfo(build-id)=bd1473e8e6a4c10a14731b5be4b35b4e87db2af7"  
 Breakpoint 1, main () at zad1.c:5  
 5          for(i = 0; i < 10; i++) {   
 (gdb)   
Widzę, że mam problemy przy uruchomieniu tego programu w debuggerze, ale spokojnie Suse podpowiedział mi co muszę zainstalować i powtórzę tą operacje. Zainstalowałem brakującą bibliotekę i oto wynik:
 (gdb) break mian   
 Function "mian" not defined.  
 Make breakpoint pending on future shared library load? (y or [n]) y  
 Breakpoint 1 (mian) pending.  
 (gdb) run  
 Starting program: /home/domek/c/a.out   
 Hello, world!  
 Hello, world!  
 Hello, world!  
 Hello, world!  
 Hello, world!  
 Hello, world!  
 Hello, world!  
 Hello, world!  
 Hello, world!  
 Hello, world!  
 [Inferior 1 (process 15408) exited normally]  
 (gdb) info registers eip  
 The program has no registers now.  
 (gdb)   
Jak już mam wszystko to mogę omówić co tu robiłem, na początku sprawdziłem jak wygląda kod, później zobaczyłem maina w wersji assemblera i jak można zaobserwować, tutaj podawane są na początku zakresy pamięci, nie jak było to w przypadku objdumpa. Chciałem uzyskać informacje o instrukcji RIP, który wskazuje on na adres pamięci instrukcji deasemmblacji funkcji main i udało mi się uzyskać :
 break main  
 Breakpoint 1 at 0x400564: file zad1.c, line 5.  
Debbuger GDB ma możłiwośc bezpośredniego badania pamięci i jest to polecenie x.Sprawdzanie pamięci jest bardzo ważne dla każdej osoby, która chce poznać dokładnie program, bo możemy zmienić składnie z systemu szesnastkowego na inny. Proponuje każdemu posprawdzanie tego jak to działa bo u mnie wygląda to tak:
 (gdb) x/x $rip  
 0x400564 <main+8>:     0x00fc45c7  
 (gdb) x/u $rip  
 0x400564 <main+8>:     16532935  
 (gdb) x/t $rip  
 0x400564 <main+8>     00000000111111000100010111000111  
Dziś narazie wystarczy i mam nadzieje, wy czytający ten post, dowiedzieliście się czegoś więcej i spokojnie jeszcze do tego postu wrócę by opisać co możemy dalej z tym robić :)

czwartek, 20 listopada 2014

Penetrujemy aplikacje napisane w języku C

Dziś wracam do podstaw programowania w języku C, lecz nie będzie to typowa nauka języka programowania. Aplikacje w języku C są kompilowane i składnia którą piszemy, musi być najpierw przetłumaczona na język maszynowy, gdzie zwykle programiści nie zaglądają. Ja będę tym złym i będę sprawdzał jak moje programy wyglądają od środka.
Początkowo skupie się na instrukcjach warunkowych, pętlach, mechanizmami wejścia i wyjścia itp. i nawet udowodnię moc wskaźników.
Początkowo zaczynam od prostego przykładu:
 #include <stdio.h>  
 int main() {  
      int i;  
      for(i = 0; i < 10; i++) {   
           puts("Hello, world!\n");   
      }  
      return 0; // Informuje OS o zakonczeniu programu  
 }  
Pewnie wszyscy od takiego przykładu zaczynają i można spotkać w wielu kursach do nauki języka C, developerzy - zwłaszcza po ukończonych studiach, myślą, że jak zna płynnie składnie języka, to zna język od deski do deski i takie rozumowanie jest błędne. Kiedyś też tak myślałem, że jak napisze program to znam dobrze C, lecz gdy dowiedziałem się, o tym, że do skompilowanego programu mogę zajrzeć i go troszkę po penetrować, zrozumiałem jak mało wiem o tym języku.
Teraz wracając do przykładu chciałbym pokazać jak można zajrzeć do skompilowanego programu i przeczytać jego zapis w języku maszynowym. Komputer, który użytkuje jest w architekturze x86 i pod tą architekturę będę pokazywał kod asemblera, a do tego posłuży mi narzędzie objdump. I ten prosty program wygląda u mnie tak.
Polecenie:

  objdump -D zad1.o | grep -A20 main.:  
Wynik:

 0000000000000000 <main>:  
   0:  55           push  %rbp  
   1:  48 89 e5        mov  %rsp,%rbp  
   4:  48 83 ec 10       sub  $0x10,%rsp  
   8:  c7 45 fc 00 00 00 00  movl  $0x0,-0x4(%rbp)  
   f:  eb 0e          jmp  1f <main+0x1f>  
  11:  bf 00 00 00 00     mov  $0x0,%edi  
  16:  e8 00 00 00 00     callq 1b <main+0x1b>  
  1b:  83 45 fc 01       addl  $0x1,-0x4(%rbp)  
  1f:  83 7d fc 09       cmpl  $0x9,-0x4(%rbp)  
  23:  7e ec          jle  11 <main+0x11>  
  25:  b8 00 00 00 00     mov  $0x0,%eax  
  2a:  c9           leaveq   
  2b:  c3           retq    
 Disassembly of section .rodata:  
 0000000000000000 <.rodata>:  
   0:  48           rex.W  
   1:  65           gs  
   2:  6c           insb  (%dx),%es:(%rdi)  
Standardowo wartości są podawane w trybie szesnastkowym, lecz zawsze można to odpowiednio zmienić, dodatkowo ta adnotacja kodu maszynowego jest pokazana do architektury AT&T i jeżeli chcemy zmienić adnotacje to wystarczy podać to w parametrze M, co przedstawiam poniżej:
  objdump -M intel -D zad1.o | grep -A20 main.:  
Wynik:
 0000000000000000 <main>:  
   0:     55               push  rbp  
   1:     48 89 e5            mov  rbp,rsp  
   4:     48 83 ec 10          sub  rsp,0x10  
   8:     c7 45 fc 00 00 00 00      mov  DWORD PTR [rbp-0x4],0x0  
   f:     eb 0e             jmp  1f <main+0x1f>  
  11:     bf 00 00 00 00         mov  edi,0x0  
  16:     e8 00 00 00 00         call  1b <main+0x1b>  
  1b:     83 45 fc 01          add  DWORD PTR [rbp-0x4],0x1  
  1f:     83 7d fc 09          cmp  DWORD PTR [rbp-0x4],0x9  
  23:     7e ec             jle  11 <main+0x11>  
  25:     b8 00 00 00 00         mov  eax,0x0  
  2a:     c9               leave   
  2b:     c3               ret    
Początkowo kod jest bardzo trudny do odczytu, lecz od razu mozna zobacyzć, zę na początku jest deklarowane rejestry od akumulatorów, liczników, danych i bazowych. Później polecenia:
  • mov - deklaruje zmienią do pamięci rdp-0x4 == 4, 
  • jmp - służy do przeskoków pamięci, call wykonuje odpowiedni rozkaz w tym przypadku wywołuje polecenie putsa, 
  • add - dodaje nam do zmiennej plus jeden,
  • cmp - jest instrukcją porównania czy zmienna z pamięci rdp-0x4 jest równa 9 i później wykonanie tego warunku, a jak nie to wraca do punktu 0
Teraz można zobaczyć, że porównanie w kodzie maszynowym wygląda inaczej niż ten co zapisałem, w prostym przykładzie w C. 
Objdump jest przydatnym narzędziem, jeśli chcę zobaczyć aplikacje w kodzie maszynowym, ale nie pomoże jeśli aplikacja zawiera błędy, w poszczególnych instrukcjach, czy też jeżeli sprawdzam odpowiedni fragment kodu aplikacji.
Na szczęście jest narzędzie idealne do większej analizy kody, przeznaczonej dla programistów, czy tez testerów penetracyjnych i zwie się gdb i tak to jest debuger, które omówię już w następnym poście. 

środa, 12 listopada 2014

Django + Rest = power cz3

Kolejny post o Django z RESTem, lecz tym razem już będę implementował prosty przykład. Postanowiłem zrobić prosty system wyświetlający pole do wypełnienia o użytkowniku, czyli wziąłem pierwszy i przykład ze stronki o RESTfulu z Django. Jestem w tej sprawie troszkę zielony, więc muszę zaczynać od prostych przykładów.
Początkowo skupie się od razu nad konfiguracją już przygotowanej struktury do tworzenia aplikacji MVC i tak jak już otworzyłem swoje Ninja IDE to przystępie od tworzenia nowego moduły o nazwie: serializers.py, . Poniżej jest pokazany kod tego pliku.

1:  from django.contrib.auth.models import User, Group  
2:  from rest_framework import serializers  
3:  """  
4:  This class define 3 fields  
5:  """  
6:  class UserSerializer(serializers.HyperlinkedModelSerializer):  
7:    class Meta:  
8:      model = User  
9:      fields = ('url', 'username', 'email', 'groups')  
10:  """  
11:  Bext class generate anotger fields ;)  
12:  """  
13:  class GroupSerializer(serializers.HyperlinkedModelSerializer):  
14:    class Meta:  
15:      model = Group  
16:      fields = ('url', 'name')  
Teraz skonfiguruje środowisko by korzystał z frameworka RESTowego, czyli muszę edytować plik settings.py. Na początku do INSTALLED_APPS dodaje:
1:  'rest_framework',   
I jeszcze pod koniec lub w dowolnym miejscu pliku, definiuje odwołanie do odwołanie do resta:
1:  REST_FRAMEWORK = {  
2:    'DEFAULT_PERMISSION_CLASSES': ('rest_framework.permissions.IsAdminUser',),  
3:    'PAGINATE_BY': 10  
4:  }  
Teraz przechodzę do pierwszego testu. Posłużę się poleceniem
1:  python ./manage.py runserver  
Okazało się, że zapomniałe skonfigurowac pliku urls.py, który prawidłowo powinien wyglądac tak:
1:  from django.conf.urls import url, include  
2:  from django.contrib.auth.models import User  
3:  from rest_framework import routers, serializers, viewsets  
4:  # Serializers define the API representation.  
5:  class UserSerializer(serializers.HyperlinkedModelSerializer):  
6:    class Meta:  
7:      model = User  
8:      fields = ('url', 'username', 'email', 'is_staff')  
9:  # ViewSets define the view behavior.  
10:  class UserViewSet(viewsets.ModelViewSet):  
11:    queryset = User.objects.all()  
12:    serializer_class = UserSerializer  
13:  # Routers provide an easy way of automatically determining the URL conf.  
14:  router = routers.DefaultRouter()  
15:  router.register(r'users', UserViewSet)  
16:  # Wire up our API using automatic URL routing.  
17:  # Additionally, we include login URLs for the browseable API.  
18:  urlpatterns = [  
19:    url(r'^', include(router.urls)),  
20:    url(r'^api-auth/', include('rest_framework.urls', namespace='rest_framework'))  
21:  ]  
Teraz jeszcze raz uruchamiam test, czyli uruchomienie serwera pythona na porcie 8000 i zależnie od tego jak skonfigurujemy serwer bazy danych to powinniśmy dostać podobny wynik do tego:
Brakuje mi jeszcze widoku, który powinien wyglądac tak:
1:  from django.contrib.auth.models import User, Group  
2:  from rest_framework import viewsets  
3:  from tutorial.quickstart.serializers import UserSerializer, GroupSerializer  
4:  class UserViewSet(viewsets.ModelViewSet):  
5:    """  
6:    API endpoint that allows users to be viewed or edited.  
7:    """  
8:    queryset = User.objects.all()  
9:    serializer_class = UserSerializer  
10:  class GroupViewSet(viewsets.ModelViewSet):  
11:    """  
12:    API endpoint that allows groups to be viewed or edited.  
13:    """  
14:    queryset = Group.objects.all()  
15:    serializer_class = GroupSerializer  
Teraz jest już wszystko i jestem gotowy do rozpoczęcia przygody z RESTem na poważnie, czyli od razu pójdę na głęboką wodę i rozpocznę z moimi kumplami/kumpelą od razu aplikacje RESTową i ps. zacznę pracować na Linuxie, bo ja nie lubię troszkę Windowsa. Następny post będzie o tym jak zagłębić się w podstawy języka C i poznać go troszkę od środka, a następny post tego o Django + REST pojawi się tylko jak wymagania rozbite będą na zadania.

wtorek, 4 listopada 2014

Poznawanie PERLa

Trochę mi to trwało, by znów coś napisać - spowodowane to było ilością pracy. Teraz chciałbym napisać krótką niedzielo-poniedziałkową przygodę z językiem PERL i przerobiłem tylko podstawy by dowiedzieć i jak znajdę chwilę czasu to przejdę do obiektowej wersji tego języka i zbuduje jakiś mały serwis internetowy.
Przejdę teraz do języka PERL, jest o językiem skryptowym a w składni przypomina PHP, BASHa i nie upodabniał bym go do języków Python i Ruby, bo mają one znaczącą różnice (Python i Ruby są typowo obiektowymi językami, a PERL nie). Posiada tez pewne cechy języka C, ale nie będę się za wiele w tym wypowiadał i przejdę od razu do pokazania składni.
Pierwsze co rzuciło mi się w oczy to komentarze zbudowane z wielu linii. 
 =comment  
  to jest długi komwntarz  
 =cut  
Jest trochę podobny to Adnotacji w języku Ruby, ale rozpoczęcie komentarza jest długie i pewnie męczące - pewnie mało kto tego komentarza używa w kodzie, zwłaszcza, że podstawowy komentarz jest identyczny co ten z Basha.
Następnie bez czytania, na temat PERLa przeszedłem do praktykowania z nimi tak oto powstały poniższe programy - wybrałem tylko dwa, bo sprawdzałem też i CGI w PERlu, ale to opisze następnym razem.
Program1:

 #!/usr/bin/perl  
 use warnings; use strict;  
 =comment  
  to jest długi komwntarz  
 =cut  
 print "Start programu\n";  
 print "Podaj liczbe całkowita niejuemną:";  
 my $zm = <STDIN>;  
 &bity($zm);  
 print "Podaj dzielnik:";  
 my $zm1 = <STDIN>;  
 my $ans = &nwd($zm,$zm1);  
 print $ans;  
 sub bity {  
      my $zmCal = $_[0];  
      my $i =0;  
      for(; $i < $zmCal; $i++) {  
           $i = 2*$i + $zmCal%2;  
      }  
      print "Odwrotna kolejnosc bitów to: ", $i;  
      print "\n";   
 }  
 # nwd  
 sub nwd {  
      my $m = $_[0];  
      my $n = $_[1];  
      my $r; # tmp memory  
      # lets play  
      while($n) {  
           $r = $m % $n;  
           $m = $n;  
           $n = $r;  
      }  
      return $m;  
 }  
Po zapoznaniu się z podstawową składnią, jak wyglądają pętle, komentarze i funkcje zrobiłem drugi program:
 #!/usr/bin/perl  
 =comment  
  Aplikacja będzie przeliczac z liczby calkowitej dodatniej na adnotacje rzymską.  
  Do tego wykorzystam petle  
 =cut  
 use warnings; use strict;  
 #użyje tego :P  
 my @liczby = (1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1, 0) ;  
 #hmmm, teraz zrobię do tego algorytm  
 #na poczatku trzeba podac jakąs wartość :)  
 print "Podaj liczbe całkowita niejuemną:";  
 my $zm = <STDIN>;  
 =comment  
  zastanawiam sie nad sensownym rozwiazaniem   
  dajmy liczby: 1410, 2525  
  1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1  
   1        1        1  
   2     1             2   1  
  Wygląda na to, że trzeba to zrobić, przez dzielenie całkowite :)  
 =cut  
 print wylicz(\@liczby, $zm);  
 #ale to nie optymalne :(  
 sub wylicz {  
      my %rzymskie = (1000 => 'M', 900 => 'CM', 500 => 'D', 400 => 'CD', 100 => 'C',  
                90 => 'XC', 50 => 'L', 40 => 'XL', 10 => 'X', 9 => 'IX',   
                5 => 'V', 4 => 'IV', 1 => 'I');  
      # tak wyglada referencja o.O => dobrze, że perl nie ma wskazników :D  
      my $liczby2 = shift;  
      pop @$liczby2;  
      my $liczba = $_[0];  
      my $rest = 0;   
      my $rzym = "";  
      foreach my $zmienna (@$liczby2) {  
           $rest = int($liczba / $zmienna);  
           if($rest > 0) {  
                $liczba -= ($rest* $zmienna);  
                for(my $i = 0; $i < $rest; $i++) {  
                     $rzym .= $rzymskie{$zmienna};  
                }       
           }  
      }  
      return $rzym;  
 }  
Także nie jest on skomplikowany, a dodatkowo jest on nie optymalny - trudno. Przejdę teraz do krytykowania języka. Pierwsze co mnie zdziwiło to jak wygląda referencja, troszkę według mnie jest skomplikowana i mało kto by się kapnął że "\" oznacza referencję i nie ma tutaj utrapienia ze wskaźnikami, które występują w C i C+. Patrząc dalej można zauważyć dziwną zmienną:
 my %rzymskie
Jest to nic innego jak taka lita, zwana hashem i powiem, ma dużo zalet, ale też ma wadę - nie można jej sortować, a dane są rozmieszczone inaczej niż jak one były wprowadzane do hasha.
Kończę te narzekanie i stwierdzam, że mimo wielu dziwnych wynalazków PERL jest prostym w opanowaniu językiem to że nie ma wielu rozwiązań problemów, które możemy znaleźć w innych językach, nie oznacza że nie napiszemy porządnej, wydajnej i funkcjonalnej aplikacji. Niestety kończę moje wywody na temat języka PERL i jak znajdę chwilę, to pewnie znów coś o nim napisze.