Tutorial ESET CrackMe

Autorem tekstu jest Przemysław Saleta. Omawianie CrackMe można ściągnąć tutaj.

Wstępna analiza CrackMe

Wstępnie spróbujmy ustalić, z czym mamy do czynienia – skanujemy “crackme.exe” przy pomocy PEiD. “PeCompact 2.xx –> BitSum Technologies *” – aplikacja jest spakowana, prawdopodobnie plugin PEiD Generic Unpacker będzie w stanie rozpakować program automatycznie. Detekcja OEP się chyba powiodła – 56EB00 – odpakowanie niestety nie. Możemy skorzystać z dedykowanego unpackera bądź też zrobić to ręcznie, wybierzemy drugą opcję.

Ładujemy program w Interactive Disassemblera, z zaznaczoną opcją ładowania zasobów. Oczywiście możemy też posłużyć się innym debuggerem, ale IDA i tak zapewne będzie podstawowym narzędziem w dalszej analizie. Prolog unpackera wygląda następująco:

Jak widać ustawiany jest handler SEH, do którego przekazywane jest sterowanie poprzez generację wyjątku ACCESS_VIOLATION:

Na pierwszy rzut oka widać, iż modyfikowany jest kod, który spowodował rzucenie wyjątku. Zastawiamy breakpoint na koniec handlera (ustawiamy kursor na linii 0x5A0316 i wciskamy F2), następnie uruchamiamy program (F9). Po chwili IDA zgłasza wspomniany wyjątek, wznawiamy wykonywanie (F9) i potwierdzamy przekazanie wyjątku do programu. Widzimy, że kod uległ niewielkiej zmianie:

Funkcja sub_5A0317 jest względnie niewielka, na końcu widać dosyć typowy epilog unpackera:

Ustawmy kursor na adresie 0x5A03B6 i skorzystajmy z opcji Run to cursor (F4) aby przejść do skoku do OEP. PEiD się mylił, OEP to 0x4F7496.

Zrzucenie pamięci i odbudowa importów

Pozostało zrzucić proces z pamięci i odbudować importy, w tym celu skorzystamy z narzędzi LordPE i ImpREC (Import REConstructor). Wybieramy w LordPE odpowiedni proces, z menu kontekstowego zaś ‘Dump full…’, zapisujemy jako “unpacked_crackme.exe”. W ImpREC również wybieramy proces z listy, następnie wpisujemy w OEP wartość 0xF7696 (RVA), klikamy [AutoSearch], potem [Get Imports]. Teraz wystarczy skorzystać z opcji [Fix dump]. Zamykamy pozostawioną sesję debuggera.

Analiza rozpakowanego pliku

Ładujemy nowo powstały plik (“unpacked_crackme_.exe“) do Interactive Disassemblera. EP dosyć typowy dla aplikacji tworzonych przy użyciu Visual Studio, aby ułatwić sobie późniejszą analizę w oknie Signatures (Shift+F5) dodajemy sygnatury ‘Microsoft VisualC 2-9/net runtime’ i ‘MFC 3.1/4.0/4.2/8.0/9.0 32bit’.

Na początek podejmujemy próbę programu uruchomienia pod debuggerem w celu ogólnego zapoznania się z zachowaniem aplikacji (korzystając z debuggera wbudowanego w Interactive Disassemblera). Można bezpiecznie przyjąć założenie, że program nie podejmie działań destruktywnych w momencie wykrycia ingerencji, jest to w końcu wyłącznie crackme.

W chwilę po uruchomieniu zostaje zgłoszony wyjątek Privileged instruction (1):

Funkcja ta to nic innego jak powszechnie znana i stosowana IsInsideVMWare [1]. W tym konkretnym crackme dodano wywołanie ExitProcess, które ma natychmiast zamknąć aplikację w wypadku wykrycia pracy wewnątrz VMWare. Interesującym (i zapewne wartym prześledzenia) może być kontekst wywołania tej funkcji, w tym celu zaznaczamy ostatnią instrukcję właściwego epilogu (0x401E38) i korzystamy z opcji Run to cursor (F4), potwierdzając przekazanie wyjątku do programu (wyjątek jest generowany wyłącznie kiedy program pracuje poza VMWare).

Analogicznie można też posłużyć się callstackiem (Ctrl+Alt+S) i przejść do następnej instrukcji po wywołaniu IsInsideVMWare – 0x40146B. Po wyjściu z funkcji widzimy ciąg wywołań FindWindowW połączonych z warunkowym wywołaniem ExitProcess w wypadku znalezienia okna OllyDbg (także chronionego pluginem Phant0m), WinDBG… i Interactive Disassemblera. Za nimi znajduje się kolejny kod odpowiedzialny za detekcję debuggera:

Powyższy kod ma za zadanie pobrać uchwyt portu debuggera dla bieżącego procesu [2] i zamknąć aplikację jeżeli takowy istnieje. Jak łatwo się domyślić, kiedy nie stwierdzono obecności debuggera wywołanie ExitProcess jest pomijane, program przechodzi pod 0x401502, który to adres jest początkiem epilogu funkcji. Aby szybko i bezpiecznie ominąć wszystkie testy ustawiamy kursor na linii 0x401502 i korzystamy z dostępnej w menu kontekstowym opcji Set IP (Ctrl+N). Cały kod odpowiedzialny za wykrywanie debuggera nie posiada efektów ubocznych (poza ew. zamknięciem procesu…), więc zmiana EIP nie wpłynie negatywnie na działanie aplikacji. Pozwalamy na dalsze, swobodne, wykonywanie aplikacji – Run (F9).

Pojawiło się okno crackme. Wpisujemy w aktywne pole tekstowe, dla przykładu, “Jakub Dębski na premiera” i klikamy sąsiedni przycisk “CHECK”, aby zobaczyć reakcję aplikacji.

Niespodzianką jest ponowne rzucenie wyjątku wewnątrz IsInsideVMWare – postępujemy tak jak poprzednio. Kolejna niespodzianka to widziana wcześniej drabinka testów opartych o FindWindowW, najprawdopodobniej razem z wywołaniem IsInsideVMWare stanowią funkcję inline. I tym razem za nimi znajduje się antydebug:

Analogicznie do poprzedniego razu zmieniamy IP na 0x4017C3. Śledząc wykonywanie (F8) widzimy pobranie tekstu z kontrolki (0x4017FD, z użyciem GetWindowTextW) i jego konwersję z UNICODE na ANSI (0x0x40181C). Następnie tekst ten jest porównywany (przy użyciu inline’owanego strcmp) z “Let’s break to the other side.” – jest to pierwsze hasło. Aby pominąć konieczność ponownego wpisywania, tym razem prawidłowego, hasła wystarczy (będąc ‘w’ strcmp) zmienić EIP na 0x40184C – adres epilogu strcmp ‘zwracającego’ 0, oznaczające równość porównywanych c-stringów, lub też przejść za końcowy test wartości strcmp (0x401859). Następnie możemy zaobserwować, że wysyłany jest komunikat BM_SETCHECK (zaznaczający checkboksa) oraz zmieniana jest aktywność kontrolek – odblokowywany jest drugi etap zadania. Na tym kończy się metoda obsługująca pierwszy button “CHECK”, puszczamy więc program wolno (F9).

Z drugim polem postępujemy podobnie jak poprzednio, ponownie trafiamy do IsInsideVMWare, postępujemy tak jak poprzednio… Po wyjściu znajdujemy się wewnątrz sub_401900 (1):

Należy tutaj zwrócić uwagę na instrukcję oznaczoną na listingu jako (2), jest to typowa dla kompilatora CL optymalizacja, wartość zerowa z ebx będzie wykorzystywana przez (niemal) całą resztę funkcji. Przed pominięciem ciągu testów instrukcja musi zostać wykonana, bądź też rejestr wyzerowany ręcznie.

W tym miejscu można już wysnuć wniosek, że przed każdym ważnym wykonywana będzie inline’owana funkcja. W rzeczywistości jest to nie tyle zabezpieczenie co hint ułatwiający analizę (oby zamierzony…). Najlepiej świadczy o tym rozpoczynanie testów od ‘głośnej’ funkcji IsInsideVMWare.

Za pomijanymi FindWindowW napotykamy na:

Jest to kolejny trick anty-debug, opierający się na obecności flag:

Flagi te ustawiane są najczęściej z powodu obecności debuggera ring3. Docelowo zmieniamy EIP na 0x40199F. Do 0x4019F9 kod jest analogiczny do poprzedniego etapu.

Pod adresem 0x401A10 napotykamy inline’owaną funkcję strlen, której wynik razem ze stringiem przekazywany jest do funkcji sub_401260 (1). Na pierwszy rzut oka widać, iż jest to funkcja kodująca przy użyciu base64 (po zajrzeniu do jej wnętrza w oczy rzucają się charakterystyczne 3 odwołania do tablicy kodowej). Zakodowane hasło porównywane jest (0x401A30, inline strcmp) ze stringiem znajdującym się pod 0x544A80. Korzystając z IDAPython:

Odczytaliśmy w ten sposób drugie z trzech haseł.

Tak jak w wypadku poprzedniej funkcji po dojściu do początku inline’owanego strcmp (0x401A30) zmieniamy EIP na 0x401A4C – ominiemy konieczność wpisania prawidłowego hasła. Śledząc dalej można zaobserwować, analogiczne do poprzednich, zmiany stanu kontrolek, następnie pobierany i testowany jest stan obu checkboksów (0x401AA8 i 0x401ABF). Jest to o tyle zabawne, że pierwszy został zaznaczony w poprzedniej funkcji, drugi dosłownie kilka instrukcji wcześniej (0x401A7C – zaznaczenie, 0x401ABF – sprawdzenie).

Następnie ukrywane jest główne okno (0x401AD3) i wyświetlany komunikat “Stage 3 started!” (0x401AD8). Ostatnią interesującą operacją jest zaalokowanie obiektu klasy CWinThread (0x401ADF) z funkcją pod adresem 0x401B70 jako argumentem i uruchomienie jej w nowym wątku (0x401B10). W takim układzie powinniśmy przejść do debugowania nowego wątku – zastawiamy breakpoint na jego entry point (przechodzimy pod 0x401B70 i wciskamy F2) i puszczamy program (F9). Warto zaznaczyc, że opcja Run to cursor nie działa (prawidłowo) pomiędzy wątkami.

W nowym wątku (znowu…) wita nas widziana poprzednio inline’owana funkcja odpowiedzialna za większość tricków antydebug. Trochę za wiele tych podpowiedzi… Po dojściu do wywołania IsInsideVMWare (0x401BA6) zmieniamy EIP na 0x401BFC (pamiętając o wyzerowaniu ebx) – dodatkowych tricków w asortymencie chyba brakło, nic poza inline’owanymi:

Pierwsze napotkane wywołanie funkcji (1) może rzucić wyjątkiem, jest to inicjalizacja WinSock, w takim wypadku wracamy do poprzedniego widoku
(powyższego, wciskając Esc), ustawiamy kursor na następnej instrukcji i używamy Run to cursor. Chociaż IDA nie rozpoznała metody wywoływanej na rzecz gniazda sieciowego (2) to mając pewne doświadczenie z MFC można łatwo się domyślić z czym mamy do czynienia – dla części klas właściwa inicjalizacja (ze względu na możliwość niepowodzenia) została wydzielona do oddzielnej (jawnie wywoływanej) metody Create, sockety także takową posiadają [3]. Jak widzimy, argument lpszSocketAddress przyjmuje wartość NULL, socket będzie służył wyłącznie odbieraniu pakietów UDP na porcie 696. Po prześledzeniu kilku kolejnych instrukcji dochodzimy do miejsca (1):

IDA podpowiada iż jest to metoda CSocket::ReceiveFromHelper, w praktyce inline wywołania drugiej wersji przeciążonej metody RecieveFrom [4]. Rzut oka na resztę funkcji utwierdza nas w przekonaniu, iż program odbiera komendy po UDP i reaguje na nie w następujący sposób:

  • “calc” – uruchomienie Kalkulatora;
  • “help” – uruchomienie Pomocy Windows;
  • “exit” – zamknięcie procesu;
  • “more” – odpalenie funkcji sub_401D90 w nowym wątku.

Nas powinien interesować jedynie ostatni przypadek – możemy w tym miejscu postąpić dwojako:

  • wysłać odpowiedni pakiet, chociażby korzystając z IDAPython:

  • po prostu zmienić EIP na początek bloku obsługującego wiadomość ‘more’0x401CD9.

Niezależnie od przyjętej metody dochodzimy do uruchomienia nowego wątku, powinniśmy zastawić breakpoint na początek odpalanej funkcji (0x401D90) i puścić resztę wolno (F9).

Cała funkcja sprowadza się do wywołania sub_402080 i zamknięcia procesu, przejdźmy więc do pierwszej funkcji.

Ukryte zasoby

Po wstępnym przejrzeniu funkcji można wysnuć wniosek, iż wypakowuje ona plik wykonywalny (jako plik tymczasowy) z zasobów (zasób “video”, typu RC_DATA) następnie zaś uruchamia z flagą CREATE_SUSPENDED i zastępuje główny moduł aplikacji innym (przy pomocy własnego, uproszczonego loadera PE), także pochodzącym z zasobów (“music”). W praktyce na tym można zakończyć analizę crackme.exe, warto jednak dokładniej zapoznać się z mechaniką loadera:

  • zasób “video” wypakowywany jest do pliku tymczasowego (0x40209A-0x40212C);
  • tworzony jest z niego nowy, wstrzymany, proces (0x40212C-0x402197);
  • następuje załadowanie zasobu “music”;
  • alokowana jest pamięć, wedle rozmiaru z nagłówka (OptionalHeader.SizeOfImage);
  • przekopiowane zostają nagłówki (0x4021D1);
  • następnie, zgodnie z nagłówkami sekcji, rozmieszczane są ich dane (0x4021D6-0x402239);
  • alokowana jest pamięć, w której umieszczana jest instrukcja ‘retn 4’ uruchamiana następnie jako nowy wątek w zdalnym procesie (0x402239-0x4022B1) ma to na celu wymuszenie prawidłowej inicjalizacji procesu (pierwotny główny wątek nie został nigdy uruchomiony – CREATE_SUSPENDED);
  • przetwarzany jest katalog importów (0x4022B1-0x4023E4);
  • przy pomocy ntdll!ZwUnmapViewOfSection usuwany jest obraz oryginalnego głównego modułu zdalnej aplikacji, następnie pod odpowiednim adresem umieszczany jest budowany właśnie przez loader (0x4023E4-0x402458);
  • dostosowywane są atrybuty stron pamięci dla nagłówka i kolejncyh sekcji pliku wykonywalnego, zgodnie z ich charakterystykami (0x402458-0x40252C);
  • uruchamiany jest nowy wątek, entry point nowego modułu, loader czeka na jego zakończenie (0x40252C-0x402561);
  • pamięć używana przez loader do zbudowania modułu zostaje zwolniona (0x402569);
  • plik tymczasowy jest usuwany (0x40257F);

We wspomnianej implementacji loadera nie obeszło się bez kilku nieco niepewnych rozwiązań.

Funkcja remoteLoadLibrary (0x401F80) tworzy payload (ignorujący przekazany argument) mający wywołać LoadLibrary w zdalnym procesie, jest to całkowicie zbędne ponieważ prototyp LoadLibrary jest względnie kompatybilny z prototypem funkcji nowego wątku (funkcja w konwencji stdcall przyjmująca wskaźnik). Argumentem dla nowego wątku powinien być adres nazwy biblioteki, zaś wywoływaną funkcją bezpośrednio LoadLibrary. Co więcej wynikiem działania wątku – dostępnym z użyciem GetExitCodeThread – jest uchwyt-adres załadowanego modułu (tak w wypadku użycia payloadu jak i wywołania bezpośredniego), który jednak nie jest zwracany do wywołującego, co stwarza konieczność późniejszego jego pobrania. Payload:

Kolejnym niedopatrzeniem jest ładowanie biblioteki poprzez LoadLibrary w celu rozwiązania importów. Powoduje to załadowanie biblioteki w kontekście procesu loadera, wraz z zależnościami i wywołaniem DllMain. Może to być potencjalnie niebezpieczne, poza tym biblioteka może być zależna od głównego modułu aplikacji (jak chociażby pluginy wielu programów). Lepszym rozwiązaniem jest użycie LoadLibraryEx z flagą DONT_RESOLVE_DLL_REFERENCES.

Być może nieco pochopnym jest też umieszczanie nowego modułu bez sprawdzania konfliktu adresów – w tym konkretnym wypadku adres bazowy obu modułów jest taki sam. Podobnym niedopatrzeniem jest też oczekiwanie na zakończenie zdalnego wątku odpowiadającego entry pointowi modułu, jego zakończenie nie musi oznaczać zakończenia funkcjonowania programu, w efekcie czego usunięcie pliku tymczasowego mogłoby się nie powieść. W takich przypadkach zawsze należy oczekiwać na zasygnalizowanie uchwytu procesu.

Na koniec warto zauważyć, że argumenty remoteGetModuleHandle (0x401E40) są przekazywane z użyciem rejestrów, w tym także edi (zarezerwowanego przy standardowych konwencjach wywołania), co jest zapewne efektem użycia przełącznika /Og dla kompilatora CL – globalnej optymalizacji.

W tym momencie analiza crackme.exe jest zakończona, przejdźmy więc do dwóch pozostałych plików wykonywalnych. ‘Host’ dla wstrzykiwanego modułu również może być interesujacy – z jakiegoś powodu nie wykorzystano istniejącej aplikacji (przeglądarki internetowej), jak miało to miejsce w crackme z roku 2008. Najpierw należy je wydobyć, w tym celu najlepiej posłużyć się jakimś edytorem zasobów lub PE, użyty wcześniej LordPE wystarczy.

Dla ułatwienia zapisujemy oba zasoby z sekcji RC_DATA pod nazwami plików odpowiadającymi nazwom zasobów – “video.exe” i “music.exe”. Ewentualnie można posłużyć się też pluginem PE Extract dla PEiD, który automatycznie wyszuka osadzone pliki PE i zapisze obok pliku źródłowego.

Najpierw host – “video.exe”. PEiD podaje, iż jest to ‘Microsoft Visual Basic 5.0 / 6.0’. Faktycznie w importach figuruje “MSVBVM60.DLL”, co oznacza aplikację VB6 skompilowaną do formy P-Code. Spróbujmy uruchomić program. Pojawia się okno zatytułowane “Public key”, wyświetlające wartość “5518f65d” i nic więcej. Może być to kolejny hint do późniejszego wykorzystania. Na wszelki wypadek wypadałoby sprawdzić, czy program nie robi czegoś więcej – wrzucamy program w jakiś dezasembler P-Code, dla przykładu P32Dasm lub ew. VB Decompiler Lite (faktycznym dekompilatorem jest jedynie wersja płatna). Cóż, pusto, “video.exe” zawiera wyłącznie formę.

Pozostał ostatni moduł, “music.exe”. PEiD stwierdza, iż jest to ‘MEW 11 SE 1.2 -> NorthFox/HCC’, może tym razem PEiD Generic Unpacker sobie poradzi. Odpalamy plugin, wykrywanie EIP, klikamy [Unpack], potwierdzamy odbudowanie importów – tym razem chyba się udało. Uruchamiamy “music.exe.unpacked_.exe”, faktycznie działa.

Szyfrowanie asymetryczne RSA

Otwarty dialog pozwala na podanie danych oraz pary kluczy – publicznego i prywatnego, zapewne mamy tu do czynienia z jakimś algorytmem asymetrycznym (najprawdopodobniej RSA, ze względu na jego powszechność). Dla testu klikamy [Decrypt], otrzymujemy komunikat “Bad Private Key :(“. Ładujemy program w P32Dasm, zaglądamy do Strings (F8), klikamy na wzmiankowany string – znaleźliśmy się w Command1.Click():

Wiemy już jaką wartość powinien mieć klucz prywatny, wprowadzamy go w odpowiednie pole i ponownie klikamy [Decrypt]“Run-time error ’13’: Type mismatch”. Cóż, ktoś tu zapomniał o walidacji argumentów, widocznie wszystkie pola powinny być wypełnione hexstringami…

W tym momencie należy wrócić na chwilę do poprzedniego programu – zawierał klucz publiczny. Twórcy malware’u generalnie nie są zbyt kreatywni, możliwe iż klucze powiedzą nam coś o użytym algorytmie – wrzucamy parę kluczy w dowolną wyszukiwarkę internetową. Istotnie, jedynym sensownym wynikiem wyszukiwania jest moduł dla VB służący implementacji RSA [5], zaś klucze pochodzą z jego przykładów:

Zdecydowanie ciekawym jest fragment licencji biblioteki:

Cóż, autor crackme chyba jej nie czytał. W każdym bądź razie wypadałoby się jeszcze upewnić, czy faktycznie jest to ta właśnie biblioteka, niezmieniona – wprowadzamy do odpowiednich pól dane z adekwatnego przykładu, klikamy [Decrypt], otrzymujemy wynik zgodny z dokumentacją. Skorzystanie z wyszukiwarki internetowej oszczędziło nam sporo czasu – nie musimy przeprowadzać analizy i testów większej części aplikacji. Zobaczmy teraz co dzieje się z wynikiem szyfrowania:

Jeżeli długość tekstu ustawionego jako wynik operacji jest równa cztery to ładowane i otwierane jest nowe okno. Korzystając z Pythona (IDA powinna jeszcze gdzieś w tle się znajdować) szyfrujemy, dla przykładu ‘3537’:

Wprowadzamy otrzymany hexstring w pierwsze pole tekstowe, wciskamy [Decrypt]. Otworzyło się okno ‘Final’ zawierające pole na klucz, przycisk “Try the key” i pole, w którym powinno zostać wyświetlone ostatnie hasło. Z braku lepszej alternatywy ponownie zaglądamy do diassemblera, poprzez okno Procedures przechodzimy do Form2 -> Command1.Click(). Widzimy tam wywołanie funkcji oznaczonej jako “Module1 1.3”, z dwoma argumentami – pobranym z edita kluczem i stringiem:

“112D2330206235622B2A66272B2166362A65322A2065332C2C3323303620686C6B”

Funkcja ta składa się z prostej pętli liczącej od 1 do połowy długości hexstringa (tablice w VB indeksowane są od 1, nie od 0), odkodowującej kolejne wartości bajtów (po dwa znaki) i wykonujące na nich operację xor z kolejnymi znakami cyklicznie zapętlonego klucza. Należy zwrócić uwagę na fragment:

W pierwszej iteracji pętli wartość zmiennej sterującej (var_8C) wynosi 1, więc pierwszym branym pod uwagę znakiem klucza nie jest pierwszy lecz drugi (1 % len + 1 = 2).

Rozpiszmy w takim razie hexstring na kolejne bajty:

Możliwe podejścia są dwa – bruteforce, bądź kryptoanaliza. Ręczne odszyfrowanie nie powinno być specjalnie trudne, przyjmując odpowiednie założenia na bazie poprzednich haseł:

  • zdanie zaczyna się wielką literą;
  • jest zakończone znakiem interpunkcyjnym;
  • to prawidłowy tekst (prawdopodobnie) w języku angielskim, zawiera spacje.

Potencjalnie można przyjąć też dodatkowe założenia, odszyfrowany klucz z poprzedniego etapu może służyć do odszyfrowania hasła, musi więc mieć formę czteroznakowego hexstringa. Jest to jednak dosyć ryzykowne, na razie spróbujmy obejść się bez tego.

Hasło powinno zaczynać się wielką literą – zaszyfrowany znak ma niską wartość, bit różniący małe i wielkie litery jest wyzerowany, można więc wysnuć wniosek, że pierwszy znak klucza również jest wielką literą.

Tekst składa się głównie z niewielkich wartości, zapewne małych liter, przedzielonych wartościami około 0x65 – znakami interpunkcyjnymi.

Przyglądając się wartościom znaków można zauważyć, że są one niewielkie – znaki klucza są podobne do siebie, do tego są to wielkie litery (analogiczna prawidłowość jak w przypadku pierwszej litery).

Ostatnie trzy znaki są chyba znakami interpunkcyjnymi – wielokropek? Spróbujmy pogrupować tekst wedle podobieństwa występujących w nim znaków interpunkcyjnych (potencjalnych spacji – najczęściej występujące wartości to 62, 65 i 66), z jak najkrótszym cyklem klucza:

Sprawdźmy teraz nasze założenia – w trzeciej kolumnie mamy potencjalną kropkę i spację:

Wygląda dobrze. Dla drugiej kolumny wyliczamy klucz adekwatny dla spacji:

W wypadku ostatniej kolumny możemy podejrzewać, że 0x62 również jest spacją:

Pozostała pierwsza, tutaj możemy polegać wyłącznie na kropce:

Fin

Składając razem (i pamiętając o przesunięciu klucza przy deszyfrowaniu) otrzymujemy ‘BEEF’, przetestujmy klucz. Wygląda na to, że jest on prawidłowy, otrzymaliśmy ostatnie, trzecie hasło:

“There’s no end to the universe…”

Warto zauważyć, iż klucz faktycznie składa się z czterech cyfr szesnastkowych, zaś wyjście w oknie z RSA zawiera wielkie litery. Najciekawszym jest jednak fakt, iż przykład poprzedzający zacytowany wcześniej używa “beef” jako wiadomości, ta zaś po zaszyfrowaniu i odszyfrowaniu via “music.exe” przyjmie formę właśnie “BEEF”. Trudno uznać to za przypadek…

Dodatkowe materiały

[1] – http://www.codeproject.com/KB/system/VmDetect.aspx
[2] – https://msdn.microsoft.com/en-us/library/ms684280(VS.85).aspx
[3] – https://msdn.microsoft.com/en-us/library/xz019029(v=VS.80).aspx
[4] – https://msdn.microsoft.com/en-us/library/2yay34ef(v=VS.80).aspx
[5] – http://www.di-mgt.com.au/src/basModExp.bas.html

Komentarze (5)

Dodaj komentarz

Twój adres email nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *