Algorytmy (de)szyfrowania wykorzystywane przez twórców trojanów bankowych.

Post otwierający serie postów traktujących o sposobie szyfrowania i deszyfrowania czy to:
– plików konfiguracyjnych
– skradzionych danych
– ciągów znaków reprezentujących np. nazwę winapi

wykorzystywanym przez twórców trojanów bankowych.
Przedstawiając kolejne rodziny trojanów postaram się je ułożyć w kolejności zaczynając od tych stosujących najmniej skomplikowany sposób szyfrowania do tych prezentujących coraz to bardziej złożony rodzaj algorytmów ( o ile ,którykolwiek z nich można tak określić :P).
Pierwszy twór, któremu się przyjrzymy na VirusTotal przedstawia się w sposób następujący: 7050369f20acdb4587872ff1eccf43f3cccddf5dc03c7cd6a936a383a6863aac
[=]Dane[=]

Antivirus	Version	Last Update	Result
AhnLab-V3	5.0.0.2	2009.04.26	Dropper/Agent.61440.AF
AntiVir	7.9.0.156	2009.04.25	TR/BHO.gcw
Authentium	5.1.2.4	2009.04.25	W32/Dropper.AHBB
Avast	4.8.1335.0	2009.04.25	Win32:Trojan-gen {Other}
AVG	8.5.0.287	2009.04.26	Dropper.Agent.LCJ
BitDefender	7.2	2009.04.26	Trojan.Generic.1252968
CAT-QuickHeal	10.00	2009.04.25	TrojanDropper.Agent.abjf
Comodo	1130	2009.04.25	TrojWare.Win32.Trojan.Agent.Gen
DrWeb	4.44.0.09170	2009.04.26	Trojan.Fakealert.3764
F-Prot	4.4.4.56	2009.04.25	W32/Dropper.AHBB
F-Secure	8.0.14470.0	2009.04.25	Trojan-Dropper.Win32.Agent.abjf
Fortinet	3.117.0.0	2009.04.26	PossibleThreat
GData	19	2009.04.26	Trojan.Generic.1252968
Ikarus	T3.1.1.49.0	2009.04.26	Trojan-Dropper.Agent
K7AntiVirus	7.10.716	2009.04.25	Trojan-Dropper.Win32.Agent.abjn
Kaspersky	7.0.0.125	2009.04.26	Trojan-Dropper.Win32.Agent.abjf
McAfee	5596	2009.04.25	Generic.dx
McAfee+Artemis	5596	2009.04.25	Generic.dx
McAfee-GW-Edition	6.7.6	2009.04.26	Trojan.BHO.gcw
Microsoft	1.4602	2009.04.26	Trojan:Win32/Relbma.A
NOD32	4035	2009.04.25	Win32/BHO.NDB
Norman		2009.04.24	W32/Agent.KPCN
nProtect	2009.1.8.0	2009.04.26	Trojan-Dropper/W32.Agent.61440.AW
Panda	10.0.0.14	2009.04.26	Generic Trojan
Prevx1	3.0	2009.04.26	High Risk Worm
Sophos	4.41.0	2009.04.26	Mal/Generic-A
Sunbelt	3.2.1858.2	2009.04.24	Trojan-Downloader.Win32.FraudLoad.vdxo
Symantec	1.4.4.12	2009.04.26	Trojan Horse
TheHacker	6.3.4.1.314	2009.04.26	Trojan/Dropper.Agent.abjf
TrendMicro	8.700.0.1004	2009.04.25	TROJ_AGENT.PRPR
VBA32	3.12.10.3	2009.04.25	Trojan-Dropper.Win32.Agent.abjf
VirusBuster	4.6.5.0	2009.04.25	Trojan.DR.Agent.IMHD

Additional information
File size: 61440 bytes
MD5   : fa1faad9a5db4f33173ee0b439e410f6
SHA1  : 5aea25ef14f52930ebc3520a1bf43b1b74573899
SHA256: 7050369f20acdb4587872ff1eccf43f3cccddf5dc03c7cd6a936a383a6863aac
PEiD  : Armadillo v1.71

Jak widać nazwy sygnatur, są bardzo ogólne co może wskazywać jedynie na wieeeeele mutacji tej rodziny pojawiających się w sieci.

[=]Prolog[=]
Tak jak wspominałem wcześniej będziemy się przyglądać trojanom stosującym coraz to bardziej wyrafinowane metody szyfrowania, więc zgodnie z nasza konwencją niniejszy
sampel, a dokładnie metody stosowane przez niego nie powinny szokować( no chyba, że prostotą :D).
Jakie elementy będą „wymagały” tu deszyfrowania:
– plik konfiguracyjny
– dll’ka, która jest instalowana w systemie jako BHO
– adres url wskazujący na drop host

Napisałem „wymagały” ,ponieważ tak na dobrą sprawę akurat w tym konkretnym samplu np.autor postanowił ułatwić badaczowi sprawę i plik konfiguracyjny jest dropowany do filesystem’u już po deszyfrowaniu :D. Inna kwestią jest to, że zamiast deszyfrować konkretne elementy, można zrobić dump’a całego procesu i np. w przypadku kiedy config jest deszyfrowany przez trojana tylko i wyłącznie na czas użycia, liczyć na to, że w dump’e znajdziemy go już w plain-text’e. Podejść do sprawy jest wiele, ale w naszych badaniach zależeć nam będzie na tym, żeby poznać algorytm szyfrowania i w miarę możliwości go odwrócić. Oczywiście zdarzają się przypadki gdzie:
– nie zależy nam na poznawaniu algorytmu używanego przez trojana, bo jest to sampel należący do rodziny, która widzimy pierwszy raz i nie koniecznie będzie dla nas użyteczny z różnych względów. Wtedy oczywiście idziemy po najmniejsze lini oporu.
– procedura deszyfrująca jest na tyle duża, a my na tyle leniwi ;], lub mało zainteresowani jej odwracaniem nie podejmujemy się pisania dekryptora od zera, ale np. wykorzystujemy prockę używaną przez trojana w charakterze shellcode’u (o tym więcej w dalszych postach).

[=] Analiza [=]
Ok., pora na analizę naszego celu. Jako, że zależy nam tylko na procedurach (de)szyfrującyh to bezpośrednio będę wskazywał elementy oraz ich lokalizacje, które będą wymagały naszej interwencji. Ewentualne pokaże sposoby na znalezienie interesujących nas części kodu procedur.
Tak na dobrą sprawę wszystkich istotne elementy, które postaramy się deszyfrować znajdują się w zasobach(‘Resource Directory’) pliku wykonywalnego. Może podejrzeć zasoby używając do tego celu np.
CFF Explorer’a:
resource_dirView

Jak widać na powyższym screen’e dane w takiej postaci niczego nam nie mówią, ale w miarę wykonywanej przez nas deszyfracji wszystko stanie się bardziej klarowne. Deszyfrować zwartość zasobów zaczniemy od końca czyli od „WFP”.Zanim zaczniemy, wykonajmy dump zasobu do plik np.
C:config i sprawdźmy jego entropię:
config_entropy

Już spieszę z wyjaśnieniami. Skala, którą widać po prawej reprezentuje poziom entropii w zakresie od 0-8. Tak jak obiecywałem algorytm(y) szyfrowania użyty w tym trojanie będzie prosty o czym już teraz możemy się przekonać analizując wykres. Wartości funkcji, są dość nie regularne i rozciągają się w zakresie od 4,2 do 5,4. Od razu wspomnę, że ciekawszych procek szyfrujących można się spodziewać w przypadku entropii na poziomie 7-8.
Dla porównania wykres entropii dump’a traffic’u zawierającego dll’ki, ściągane przez Mebroot’a:
C&C_response_entropy

[=]Analiza procedur szyfrujących[=]
Jak już wiemy interesujące nas bloki danych znajdują się w resource directory. Teraz rodzi się pytanie w jaki sposób odnaleźć funkcje (de)szyfrującą/e? Każdy kto pisał aplikacje z użyciem winapi, korzystającą z katalogu zasobów skojarzył od razu funkcje „FindResourceA/W”, która zwraca uchwyt do zasobu, którego nazwę podamy jako jeden z parametrów tego api.
Więc nasuwają się tutaj dwa podejścia, a tak naprawdę jedno chyba najbardziej logiczne ;].
– wyszukać wszystkie referencje do wywołań api FindResourceA/W
albo odnaleźć wszystkie referencje do stringu „WFP” .

Oczywiście posłużymy się tutaj podejściem drugim które najprawdopodobniej od razu wskaże nam okolice kodu zawierającego procedurę deszyfrującą.
wfp_resource

Ohoo…wygląda na strzał w dziesiątkę, co prawda na razie nie widać jakichkolwiek manipulacji na uzyskanym pointerze do zasobu, zerknijmy jednak do procedury :
CALL zly_troj.0040155F
mając na uwadze, że argumentami tej procki są:
arg1 : pointer do zasobu „WFP”
arg2 : rozmiar zasobu „WFP”

wfp_decryption_proc
Ahhh udało nam się zlokalizować prockę deszyfrującą!(zielona ramka).
Jak widać okazała się nią prosta operacja xorująca każdy bajt z kluczem o wartości:
0x13.

[=]Deszyfrowanie[=]
Oczywiście po tym co właśnie zobaczyliśmy stworzenie własnego deszyfratora, który „sksoruje”, każdy bajt dumpu zasobu, który wcześniej wykonaliśmy z kluczem 0x13.
Świetnie się do tego nada JEDNOLINIJKOWY skrypt w python’e:

"".join(map(lambda x: chr(ord(x)^0x13),file(r’C:config’,’rb’).read()))
, a oto rezultat:
decrypted_wfp
widać teraz, że rzeczywiście jest to plik konfiguracyjny zapisany w xml’u.

Przejdźmy do następnego zasobu.
„REM”
Rzućmy okiem na entropię:
rem_entropy
Mhmm…tutaj już entropia wygląda ciekawiej, więc z pewnością możemy się spodziewać czegoś więcej niż tylko prostego xor’owania.
Oczywiście, miejsce z istotną dla nas procką znajdujemy analogicznie do poprzedniego przypadku, a naszym oczom ukazuje się taki o to kod:
rem_decryption_routine

Jak widzimy, w tym przypadku klucz xor’ujący nie jest stały. Jego wartość będzie zmieniała się cyklicznie po każdej iteracji, stąd też widoczne na wykresie entropii zmiany w kierunku wyższego zbioru wartości.
Warto zwrócić uwagę na dwie istotne kwestie, które są wykonywane przed wejściem do pętli:

ESI – pointer na zaalokowaną pamięć, która będzie zawierać deszyfrowane dane.
004013CD  |.  C606 4D       MOV BYTE PTR DS:[ESI],4D
004013D3  |.  C646 01 5A    MOV BYTE PTR DS:[ESI+1],5A

4D5A ,czy coś wam to mówi ?:D. Oczywiście jest to magic number, który zawsze powinien znaleźć się na początku pliku PE.
Jak widać autor trojana dodaje magic number dopiero w momencie deszyfrowania. Takie podejście może świadczyć jedynie o tym iż autor chciał utrudnić wykrycie potencjalnie niebezpiecznego zasobu antywirusą czy innym skanerą. Drugą kwestią jest wyliczenie stałej która będzie wykorzystywana do indexowania zaszyfrowanych danych. Jej wyliczenie wygląda następująco:

004013D9  |.  895D FC       MOV [LOCAL.1],EBX ; EBX = encrypted_data
004013DC  |.  2975 FC       SUB [LOCAL.1],ESI     ; ESI   = decrypted_data

następnie w pętli mamy: (stale wartości odpowiednie do pierwszej iteracji)

EDI = 2 ;
004013E5  |.  8D0C37        |LEA ECX,DWORD PTR DS:[EDI+ESI]
…
004013EA  |.  8B45 FC       |MOV EAX,[LOCAL.1]
…
004013EF  |.  321408        |XOR DL,BYTE PTR DS:[EAX+ECX]

widzimy, że w momencie xor’owania :
DL – cyklicznie zmieniający się klucz
a na co wskazuje BYTE PTR DS:[EAX+ECX]?
Prosty zapis matematyczny wszystko wyjaśnia:

LOCAL.1 = encrypted_data - decrypted_data
ECX = decrypted_data + 2
EAX = LOCAL.1
I w momencie xor’owania:
XOR DL,BYTE PTR DS:[LOCAL.1+decrypted_data+2]
podstawiajac za LOCAL.1
XOR DL,BYTE PTR DS:[ encrypted_data - decrypted_data
+decrypted_data+2]
,więc w ostateczności mamy
XOR DL,BYTE PTR DS:[ encrypted_data + 2]

ot taki troszeczkę nie intuicyjny sposób indexowania ;).
Przykładowy skrypt deszyfrujący:


def decrypt(encrypted):
    decrypted = []
    edi = 2
    decrypted.append('M')# 0x4d
    decrypted.append('Z')# 0x5a

    while edi != len(encrypted):
        edx = edi % 0x78
        edx = (edx << 1) & 0xFF
        decrypted.append(chr( (ord(encrypted[edi])^edx)&0xFF ))
        edi = edi + 1
    return "".join(decrypted)

if __name__ == "__main__":

    f = file(r"c:evil_dll",'rb')
    fw = file(r"c:decrypted_evil_dll",'wb')
    fw.write(decrypt(f.read()))
    f.close()
    fw.close()

i rezultat deszyfrowania:
decrypted_dll
Jak widać na screen’e w katalogu zasobów „REM” ukrywała się dll’ka.

Ostatni już katalog zasobów „CAS”. Jako, że danych w każdej pozycji katalogu CAS jest niewiele, trudno tutaj mówić/prezentować wykres rozkładu entropii. Przejdziemy więc od razu do sposobu ich deszyfrowania. Co prawda dane z tego zasobu, są ekstraktowane do systemu , (a dokładnie do rejestru )lecz w formie nie zmienionej. Dopiero dll’ka , która wcześniej mieliśmy przyjemność deszyfrować(a która jest dropowana do C:WINDOWSsystem32sxmg4.dll i rejestrowana jako BHO)
będzie pobierała te dane i deszyfrowała tylko w momencie zaistniałem potrzeby.

Zaszyfrowane dane w rejestrze prezentują się w następujący sposób(interesują nas tylko wartości Ad i Ad2):
cas_encrypted
HKEY_LOCAL_MACHINESOFTWARETSoft

Ok, weźmy pod lupę więc dll’ke: Stosując identyczne podejście jak w dwóch poprzednich przypadkach znajdujemy następujący kod:
cas_decryption
Kolejna różna od pozostałych procedura bazująca wciąż na xor’owaniu, lecz tym razem użyto stałego klucza o długości 3 bytów. Warto wspomnieć jakie konsekwencje niesie za sobą takie podejście oraz jak to rozwiązano w niniejszej implementacji:

ECX = ilość odczytanych(zaszyfrowanych) bajtów z wartości rejestru
100053B0  |.  6A 02         PUSH 2
100053B2  |.  33C0          XOR EAX,EAX
100053B4  |.  5A            POP EDX
100053B5  |.  889C0D F0FDFF>MOV BYTE PTR SS:[EBP+ECX-210],BL
100053BC  |.  3BCA          CMP ECX,EDX
100053BE  |.  76 31         JBE SHORT sxmg4.100053F1

Jak widać sprawdzane jest tutaj czy ilość bajtów które mają być odszyfrowane przekracza 2, ponieważ przy mniejszej ilości, w pętli już po pierwszej iteracji dostalibyśmy błędne dane (akurat przy tej implementacji nie wystąpi ,ani BO ani Off-by-One). To jedna kwestia, kolejną jest to, że długość danych do rozszyfrowania może nie być wielokrotnością 3’ki.
Więc należy tutaj zadbać o sprawdzanie czy w kolejnym kroku deszyfrowania mamy przynajmniej 3 bajt do przetworzenia. Jeśli nie, pętla powinna się zakończyć a pozostałe bajty( max 2) należy deszyfrować indywidualnie.
Sprawdźmy jak to zostało tu zaimplementowane:
Przed wejściem do pętli mamy :

EDX = 2
100053C0  |.  8DB5 F1FDFFFF LEA ESI,DWORD PTR SS:[EBP-20F]
100053C6  |.  2BD6                     SUB EDX,ESI
EBP – 210h = encrypted_data
,więc EBP – 20Fh == encrypted_data +1

w pętli:

…
100053E3  |.  8D3402        |LEA ESI,DWORD PTR DS:[EDX+EAX]
100053E6  |.  8DB435 F1FDFF>|LEA ESI,DWORD PTR SS:[EBP+ESI-20F]
100053ED  |.  3BF1          |CMP ESI,ECX
100053EF  |.^ 72 D7         JB SHORT sxmg4.100053C8

kiedy przyjrzymy się temu kawałkowi kodu mamy:

ECX = encrypted_data_length
EAX = index
EDX = 2 – (encrypted_data+1)
ESI = EDX + EAX
ESI <-  EBP + ESI – 20F == EBP -20F + ESI ==
(encrypted_data+1) + 2 –(encrypted_data+1)+ index
czyli ostatecznie
ESI = 2+index

,więc co iteracje w pętli( a jest to pętla do while) sprawdzane jest czy
index+2 < encrypted_data_length, jeżeli tak to pętla jest kontynuowana.
Po zakończeniu pętli możemy zauważyć to o czym wspominałem, a mianowicie indywidualne xor’owanie bajtów, które pozostały lub w przypadku kiedy długość zaszyfrowanych danych < 3:

100053F1  |> 3BC1          CMP EAX,ECX
100053F3  |.  73 08         JNB SHORT sxmg4.100053FD
100053F5  |.  80B405 F0FDFF>XOR BYTE PTR SS:[EBP+EAX-210],0F
100053FD  |>  8D50 01       LEA EDX,DWORD PTR DS:[EAX+1]
10005400  |.  3BD1          CMP EDX,ECX
10005402  |.  73 0F         JNB SHORT sxmg4.10005413
10005404  |.  80B405 F1FDFF>XOR BYTE PTR SS:[EBP+EAX-20F],10

Prosty kod który powinien działać 😀 przy dowolnej długości klucza:


def decrypt(buffer,key):
    decrypted = []
    notAligned = len(buffer) % len(key)
    secureLen  = len(buffer) - notAligned
    for i in range(0,secureLen,len(key)):
        for j in range(0,len(key)):
            decrypted.append( chr( ord(buffer[i+j])^key[j] ) )
    #dekrypcja pozostalych NIE odszyfrowanych bajtow o ile takie istnieja
    if notAligned:
        for i in range(secureLen,len(buffer)):
            decrypted.append( chr( ord(buffer[i])^ key[-secureLen+i]) )

    return "".join(decrypted)

if __name__ == "__main__":
    key  = [0xf,0x10,0x11]
    print decrypt(file("c:\evil_host1").read(),key)
    print decrypt(file("c:\evil_host2").read(),key)

oto rezultat działania kodu:
(evil_host1 i evil_host2 to oczywiście wartości z rejestru Ad1 i Ad2)
decrypted_hosts_cas
Jak widać zaszyfrowane dane przedstawiają najprawdopodobniej adresy drop hostów, albo hostów z których mają być pobierane dodatkowe moduły, nowe plik konfiguracyjne ,etc.

[=]Epilog[=]
To już wszystko odnośnie tego trojana, jak mieliśmy okazje zobaczyć jego autor „nie ograniczał” swojej fantazji jeżeli chodzi o rożnego typu algorytmy szyfrowania choć bazowały one na prostym xor’owaniu to jednak zobaczyliśmy parę mutacji;]. Wspomnę jeszcze, że trojan ten zawiera jeszcze parę zaszyfrowanych bloków danych jednak ze względu na identyczne metody dekodowania ( zmienia się np. klucz xor’ujacy z 0x13 na 0xc) postanowiłem je pominąć. W następnych postach (o ile czas w najbliższym okresie wakacyjnym pozwoli :D) zajmiemy się trochę bardziej złożonymi algorytmami, sposobami ustalania formatu pliku konfiguracyjnego ,etc.

Opublikowano Analiza, Malware, RE | Otagowano , , , , , , , , | 2 komentarze

Filtry

Ostatnio miałem okazje trochę pobawić się w pisanie filtrów używanych w grafice, m.in. filtru okienkowego oraz medianowego co okazało się całkiem niezłym fun’em, szczególnie jeżeli chodzi o rezultat ich działania. Swoją implementacje filtrów wykonałem w C++ Builder’e i na koniec posta postaram się dołączyć co nieco kodu ,ale nie będzie to całość, z tego względu, że imo całość nie jest tak dojrzała(co nie przeszkodziło im uzyskać max pkt. za to zadanie na uczelni :P) aby ujrzeć światło dzienne :P.

Cała filozofia filtru okienkowego polega na wybraniu rozmiaru okna (najpopularniejsza wartością jest 3×3) czyli ilości pixeli branych pod uwagę podczas filtrowania oraz odpowiedniemu dobraniu dla nich współczynników.
Grid
Tablica pixeli. Przykład okna filtrującego o rozmiarze 3×3.

Powyższy rysunek prezentuje zastosowanie okna o rozmiarze 3×3 gdzie pixel zaznaczony na fieletowo jest pixelem wyróżnionym. Iterując po tablicy pixeli musimy sprawić, aby każdy pixel w pewnym momencie iteracji był pixelem wyróżnionym, czyli jest to nic innego jak poruszanie się po niej od pozycje x = 0,y =0 do x = image_width -1 , y = image_height -1.

Przenosząc te informacje na kod :

	for(int x = 0;x < bmp->Width;++x)
	{
	  for(int y = 0;y < bmp->Height;++y)
	  {
	      //loopy odpowiedzialne za operowanie na oknie filtrujacym
	      for(int j = -(windowSize/2); j < windowSize - 1; ++j)
	       {
		for(int i = -(windowSize/2); i < windowSize - 1;++i)
		{
                         //pobranie pixela z uwzględnieniem
                        //wysokości i szerokości bitmap’y
		color = getProperPixel(bmp,x+i,y+j);
		( … )

Warto tutaj zauważyć , że indexy “i” oraz „j” , są tak dobrane tak iż pixel wyróżniony znajduje się w środku okna, czyli od razu mamy wniosek taki, że aby móc wyznaczyć środek okna jego wielkość musi być liczbą nie parzystą >1 (bynajmniej nie spotkałem się z zastosowaniem innych wartości, jeżeli ktoś miał taka przyjemność to piszcie).
No tak ,ale nie powiedzieliśmy sobie jeszcze co tak naprawdę oznacza to „wyróżnienie”. Oznacza ono tyle iż wartość tego pixela zostania zmieniona na podstawie banalnego algorytmu , o którym za chwilę. UWAGA!!! Nie zmieniamy wartości pixeli w obrazie źródłowym , a więc należy sobie przygotować kolejny obiekt reprezentujący nasz image po filtrowaniu, który będzie podlegał modyfikacją. Ok., teraz jak przedstawia się sam algorytm wyliczający nową wartość dla pixela wyróżnionego.

Zapis matematyczny dla okna o wymiarach 3×3:
formulka_1
oraz
formulka_1
oraz w przypadku kiedy suma współczynników równa się 0.

Myślę, że sprostowania wymaga jedynie oznaczenie W(i,j) – jest to oczywiście tablica współczynników okna filtrującego.
Rzućmy teraz okiem jak ten zapis przedstawia się w kodzie(wielkość okna dowolna ze wspomnianego wyżej przedziału):

(   …   )
for(int j = -(windowSize/2); j < windowSize - 1; ++j)
{
  for(int i = -(windowSize/2); i < windowSize - 1;++i)
   {
      //pobierz odpowiedni pixel
      tmpColor = getProperPixel(SrcPixels, x+i , y+j );
      r =  GetRValue(tmpColor)  * window[index];
      g = GetGValue(tmpColor)  * window[index];
      b = GetBValue(tmpColor)  * window[index];

      totalR +=   r;
      totalG +=  g;
      totalB +=  b;
      index++;
      }
}

//zsumowanie wartości wszystkich współczynników
suma = accumulate(window.begin(),window.end(),0);
if(suma == 0)
    suma = 1;

totalR /= suma;
totalG /= suma;
totalB /= suma;

totalR = min(255, max(0, totalR));
totalG = min(255, max(0, totalG));
totalB = min(255, max(0, totalB));

//modyfikacja wartości pixela w obrazie docelowym
DstPixels->Canvas->Pixels[x][y] = (TColor)RGB(totalR,totalG,totalB);
//zeruj index pozycji w oknie współczynników
index = 0;
//zeruj wartości
totalR = 0;
totalG = 0;
totalB = 0;

To czego nie objął wzór matematyczny ,a co raczej jest oczywiste to wykonanie całego algorytmy dla każdego kanału RGB osobno. Oczywiście można zastosować np. konwersje z formatu RGB na YUV i tam jedynie manipulować wartości Y , a następnie już przy samej aktualizacji obrazu docelowego zamienić YUV na RGB, ale w tym zapisie chodziło mi o prostotę.
Ok. czas na przykładowy interface aplikacji:
interface

,aż razi swoją prostotą ;].

Teraz cała zabawa polega na tym, aby dobrać odpowiednie współczynniki dla okna filtrującego.
Przyjrzyjmy się rezultatom działania filtrów z różnych kategorii (jako modela wybrałem myślę wszystkim dobrze znaną postać Dexter’a 😀 ):

Filtr dolnoprzepustowy
dolno
Filtr górnoprzepustowy
gorno
Filtry krawędziowe
krawedziowe1
krawedziowe2
Filtr konturowy
konturowe

Myślę, że efekty całkiem ciekawe;).

Przejdźmy teraz do filtru medianowego. Jego zasada działania jest nieco odmienna choć nadal będziemy korzystać z okna lecz w tym wypadku nie definiujemy żadnych wartości współczynników. Myślę ,że kawałek kodu wyjaśni sprawę:

void CFilters::medianFilter(Graphics::TBitmap *bmp,
Graphics::TBitmap *bmpRez,
int windowSize)
{

	vector pixels;
	TColor color;
	//glowny loop dla siatki pixeli wyznaczajacy tzw pixel wyrozniony
	for(int x = 0;x < bmp->Width;++x)
	{
	  for(int y = 0;y < bmp->Height;++y)
	  {
		//loopy odpowiedzialne za operowanie na oknie filtrujacym
		for(int j = -(windowSize/2); j < windowSize - 1; ++j)
		{
			for(int i = -(windowSize/2); i < windowSize - 1;++i)
			{
				  color = getProperPixel(bmp,x+i,y+j);
				  pixels.push_back(color);
			}
		}

	sort(pixels.begin(),pixels.end());
	bmpRez->Canvas->Pixels[x][y] = (TColor)pixels[pixels.size()/2];
	pixels.clear();
	  }
	}

}

Tak ja wspomniałem powyżej nadal posługujemy się oknem lecz w tym wypadku tylko i wyłącznie w celu zgromadzenia wartości pixeli „pokrytych” przez okno. Wartość pixela wyróżnionego zastanie zastąpiona poprzez wartość środkową zgromadzonych pixeli , stąd widoczne sortowanie w kodzie:
sort(pixels.begin(),pixels.end());
oraz wskazanie elementu środkowego:
(TColor)pixels[pixels.size()/2];
(Np. dla filtru o rozmiarze okna 3×3 elementem środkowym będzie element o indexe 5).
Oczywiście , żeby móc obserwować efekty działania filtra medianowego należy wcześniej dodać „szum„.Oto kod prostego „zaszumiacza” 😀 :

 //glowny loop dla siatki pixeli wyznaczajacy tzw pixel wyrozniony
for(int x = 1;x Width - 5;++x)
{
  for(int y = 1;y Height - 5;++y)
  {
 bmp->Canvas->Pixels[x][y] = bmp->Canvas->Pixels[x+rand()%5][y+rand()%5];
  }
}

i efekt jego działania:
szum

Czas na przyjrzenie się działaniu tego filtra:
wielkość okna 3×3
med1

wielkość okna 9×9
med2

W razie jakiś pytań ,ciekawie „przefiltrowanych fotek” ,sugestii piszcie ;).
Obiecany kod – > Filters.zip.

Opublikowano Aplikacja, Grafika | Otagowano , , , , | 4 komentarze

Confidence 2009

LGIM0007
W ostatni weekend to jest 15-16 Maj 2k9 miałem przyjemność uczestniczyć( tak ja w zeszłym roku z resztą :P) w piątej już edycji konferencji traktującej o bezpieczeństwie IT Confidence 2009. Na wstępie powiem co mi się chyba już zdarzyło na tym blogu, że lepszej konferencji od Confidence w Polsce nie było i jak na razie nie widać „rywala” ;).

Postępując chronologicznie:

/* Podróż */
W tym roku bez żadnych dodatkowych kłopotów z PKP( tak tak ,warto o tym wspomnieć ,bo w tamtym roku czekaliśmy z Coldwind’em ok.3.5h na spóźniony pociąg, a jego delay time co 45min był sukcesywnie inkrementowany o kolejne 45 :D) w sielankowej atmosferze podziwiając krajobrazy ,przemierzaliśmy z Gyn’em kolejne setki kilometrów. Gdzieś po drodze do przedziału zainjectował się j00ru i już pełną tegoroczną ekipa zmierzaliśmy do celu.

/* Camp place */
Camp place tudzież miejsce noclegowania to dość nietuzinkowy tegoroczny pomysł organizatorów nazwany Hackers’ Squad.
LGIM0011
Pomysł polegał na umieszczenie uczestników we dwóch hostelach przy czym uczestniczy trafiali do pokojów w sposób losowy :D. Powiem szczerze, że na początku miałem mieszane uczucia co do tego pomysłu, ale ostatecznie muszę postawić wielkiego plusa za hostel/śniadania i ekipę jaką można tam było poznać ;). Dodatkowym atutem
hostelu była jego lokalizacja :D, jakieś 300m od Kina Kijów gdzie odbywała się konferencja
Fotka z pokoju:
hs3
j00ru & me

/* Before party */
Kolejna innowacja :D. Jako, że Kino Kijów ma własny klub to organizatorzy postanowili wykorzystać i tą możliwość do zagospodarowania nam pierwszego wieczoru poprzez projekcje następujących tytułów:

Gry Wojenne (Wargames)
Metropolis
PI
Wróg Publiczny (Enemy of the State)
H4ck3rs Are People Too
LGIM0004
me & Gynvael Coldwind na seansie w klubie Kijów

Napisałem „oglądając”, bo wytrwaliśmy do końca pierwszego filmu :P, ale w sumie bez większych strat, bo widziałem wcześniej już:
H4ck3rs Are People Too jak najbardziej polecam i jakby ktoś nie reflektował tego dokumentu to jest to video o społeczności związanej z security, a film ten został po raz pierwszy zaprezentowany na DefCon’e 2008.
PI – bardzo klimatyczny film, polecam jeżeli lubisz nie przeciętne kino
Gry Wojenne – ten film właśnie udało mi się obejrzeć w całości w klubie i powiem, że czasami był zabawny:D Najlepszy tekst z filmu:
Teacher: „Who first suggested the idea of reproduction without sex?”
David: „Your wife?”

I tak upłynął pierwszy wieczór.

/* Dzień pierwszy */
Kolejną delikatna zmianą, która pojawiła się w tym roku (można ją było odczuć rano)jest godzina rozpoczęcia się wykładów. Przesunięto ją z 9:00 na 10:00 😀 (imo bardziej ludzka godzina).
Oczywiście jak to zwykło bywać na konferencjach po rejestracji zostaliśmy obdarzeni przez piękne hostessy torbą z gadgetami:
LGIM0008
Konferencje rozpoczęła się prezentacja:
Bruce Schneier’a – „Reconceptualizing Security”
Mówił on o tym jak odczuwamy bezpieczeństwo ,kiedy czujemy się bezpieczni, a tak w ogóle nie jest oraz kiedy jesteśmy bezpieczni, a tego bezpieczeństwa nie odczuwamy. No…., moim zdaniem prezentacja nietuzinkowa ze szczyptą filozofii tak jak lubię, widać tu po prostu wieloletnie doświadczenie w branży oraz ogrom przemyśleń na temat security. Mistrzostwo po prostu;).

Joanna Rutkowska – „Thoughts about Trusted Computing”
Bardzo dobra prezentacja (czego można się było z resztą spodziewać;)) ,m.in. omawiająca składniki
Trusted Computing: takie jak : TPM,TXT,VT. W szczególności muszę wspomnieć, że forma samej prezentacji przypadła mi do gustu ponieważ slajdy były przejrzyste(bez zbędnego przerostu formy nad treścią oraz wodotrysków), czarne tło kilka bloków/schematów objaśniających bieżące zagadnienie i to wszystko. Co do ciekawostek to Joanna zapowiedziała opublikowanie najnowszych badań w najbliższe wakacje m.in. na temat Trusted Computing :D. Czyżby wspomniane komponenty nie były tak bezpieczne jak zakładają ich twórcy ?Przekonamy się w wkrótce.

Eddie Schwarz – „Understanding Social Networking Threats Using Live Threat Intelligence”
Prezentacja dość na czasie zważając na to, że niektórzy wydają się żyć portalami społecznościowymi.

no i nadszedł czas na …

/* Lunch Break */

Jeżeli chodzi o same snacki, które są cały czas dostępne podczas konferencji to jest git, ale niestety ja jako wielki smakosz musze niestety przyznać minusa za obiad, bo to były dania w stylu:
„prawie zupa” oraz „prawie szaszłyk”. Także zdecydowanie to nie było to co misie lubią najbardziej. W swojej opinii nie byłem osamotniony ,bo moje zdanie podzieliło jeszcze parę osób, także coś w tym musi być :).

Po wydłużonym lunch’u ,zdecydowałem się( tak tak ,sesje NIESTETY zostały podzielone po 3’im wykładzie) na prezentacje:

Alexander Kornbrust – “Oracle SQL Injection in Webapps”
Dla mnie interesująca prezentacja z tego względu, że o ile przeprowadznie pentestów na bazach MSSQL czy MySQL to jest chleb powszedni to jednak bazy Oracle chodź tak powszechne i lubiane w świecie biznesu to widywane są przeze mnie rzadko, a wręcz wcale. Także miło było zobaczyć co do „zaoferowania” mają funkcjonalności w różnych wersjach baz Oracle podczas ataków np. SQL (Blind) Injection :D.

Walter Belgers – „Lockpicking 101”
To był jeden z wyczekiwanych przeze mnie tematów ponieważ panowie zajmujący się Lockpicking’em mieli pojawić się na zeszłorocznej konferencji, a niestety się to nie udało. To co można było zobaczyć na prezentacji to masa różnego rodzaju zamków oraz metod, którymi można je otworzyć w sposób mniej lub bardziej inwazyjny. Widać było także wieloletnie doświadczenie prelegenta w tej branży.
Zabawna historia związana z tym tematem, którą przytoczę wydarzyła się wieczorem podasz powrotu do hostelu kiedy to równocześnie doszliśmy do drzwi(ja,Gyn,j00ru) i cześć ekipy loockpickerów już w środku kamienicy. Chwila konsternacji ,każdy uderza się po kieszeni gdzie te klucze po czym ,któryś lockhackerów chciał się pochwalić skillem i zamierzając otworzyć zamek niczym szpieg z krainy deszczowców świecąc miniaturowa latarką zaczął wyciągać picka ,ja nacisnąłem po prostu dzwonek do drzwi i ktoś otworzył je od wewnątrz 😀 ..hahah..byłem szybszy. Kolejny raz potwierdza się reguła, że najprostsze metody są najlepsze ;).

Michał Sajdak – „Zdalny root na ruterze klasy SOHO”
Prezentacja ok., bez jakiś większych rewelacji, ale ukazująca potencjał wykorzystania błędów w tanich powszechnie używanych router’ach .

Martin Mocko – „Race to baremetal: UEFI and hypervisors”
Interesująca prezentacja oraz ciekawa dyskusja, która wywiązała się tuż po niej, pomiędzy Joanna( w tym temacie to było do przewidzenia :P) oraz prelegentem.
. Tam trzeba było po prostu być.

… i tak minął pierwszy dzień prelekcji. Wieczorem w klubie kijów było o czym rozmyśla jak i dyskutować, także pozytywnie ;).

/* Dzień drugi */

Rich Smith – „VAASeline: VNC Attack Automation Suite”
Rich jest członkiem firmy Immunity, myślę, że jest to firma, którą większość z was kojarzy m.in. przez takie projekty jak CANVAS czy Immunity Debugger. Rich stworzył bardzo użyteczną biblioteka dla pythona ułatwiającą proces automatyzacji ataków na VNC, której moim zdaniem warto się przyjrzeć;).

Jacob Appelbaum – „Tor Network”
Było technicznie ,było filozoficznie czyli bardzo dobra mieszanka.
Na tej prezentacji można było się dowiedzieć o tym jak działa sieć tor jak można stać się jej aktywnym węzłem , itd. , ale nie tylko. Jacob wspomniał także jaki jest sens tworzenia takiej sieci. Na szczęście w Polsce nie mamy takich problemów jak np. w Chinach, że rządowi nie podoba się youtube no to trach!!! i nikt już nie zobaczy kolejnego odcinka Tiger Team’u, a dzięki Tor’wi można to ominąć. Prelegent wspominał także o takich krajach, w których anonimowość, jaką daje Tor np. dziennikarzom, którzy piszą otwarcie na swoich blogach o tym co nie podoba się im w ich kraju ,jest na wagę ich życia.
Zabawną historią była opowieść o dwóch obozach FBI, które wzajemnie się kłócą czy Tor przynosi im więcej korzyści czy kłopotów :D.

Alessio Pennasilico – „Bakeca.it DDoS: How evil forces have been defeated.”
Hehhe jeden z moich ulubionych prelegentów confidence. Niesamowity sposób opowiadania oraz zabawny akcent (wyrażenie brzmiące “eso hon” rozkminiałem sporo czasu w tamtym roku, aż udało mi się odganąć, że chodzi tu o „and so on” :D). Jeżeli chodzi o sprawy techniczne związane z prezentacja to tak jak w temacie Alessio opowiadał o ataku DDoS na firmę Bakeca.it ( coś ala allegro),
która pozwoliła mu jak widać zresztą ( i brawa dla niej) na opisania i opowiedzenie całego zdarzenia.
Genialnie opowiedziane kolejne kroki postępowania ataku oraz środków przeciw działania.

Michael Kemp – „Rootkits are awesome: Insider Threat for Fun and Profit”
To wystąpienie było mega zabawne, a zarazem tragiczne :D. Inaczej skomentować tego nie mogę, bo jeżeli, ktoś pokazuje listing Dll’ek wykorzystywanych przez dwie aplikacje, porównuje je, dochodzi do wniosku że są one identyczne i na tej podstawie stwierdza, że obie aplikacje działają identycznie to sorry 😀 Po prostu po parunastu minutach słuchania zacząłem się obawiać o tego człowieka jak daleko posunie się on w swoich fantazjach i jak wiele osób naskoczy na niego po prezentacji :D.
Tłumaczyć go może jedynie fakt, że tak jak wspomniał na samym wstępie był na dużym kacu i nie bardzo pamięta jak wrócił do hotelu:D…mam też nadzieje, że cała tą prezentacje tworzył w podobnym stanie wtedy jestem w stanie o tym zapomnieć. Oczywiście zgodnie z moimi oczekiwaniami po prezentacji znalazło się „parę” osób entuzjastycznie (tak to nazwijmy :D) wytykających prelegentowi pewne nieścisłości w jego rozumowaniu. No niestety, Michael chciał zareklamować swoją nową firmę,
ale imo nie robi się tego w takim stylu ;).

Raoul Chiesa – „Corporate Security and Intelligence: the dark links”
Niestety obiecałem, że nic nie powiem :D. Prezentacja naprawdę bardzo ciekawa, a fakty przerażające.

I tym sposobem dotarliśmy do końca konferencji……
Podsumowując, wielki plus dla orgów za przygotowania i organizacje pozostaje mi tylko mieć nadzieję, że za rok znów się tam pojawię ;).

Opublikowano Konferencje, Security | Otagowano , , , , | 2 komentarze