Cel : Opera 3.50 Skad : http://www.operasoftware.com/ Rozmiar: 1,2 MB Czym : Wdasm, Hiew
Wstep:
Opera jest alernatywa dla M$ Internet Explorer'a i Netscape Navigator'a. Jest jednak od nich mniejsza, szybsza i bardziej 'konfiguowalna'.
Procedura rejestracyjna jest standardowa - wymaga podania odpowiedniego kodu rejestracyjnego. Tym razem nie bedziemy jednak uzywac Softice, by zdobyc 'wlasciwy' serial (to robilismy w poprzednich dwoch ;)). Sprobujemy zlokalizowac zabezpieczenie w kodzie programu (Wdasm) i je zmodyfikowac (Hiew) :-)
Tutorial ten, oprocz analizy samej Opery, zawiera rowniez ogolne zagadnienia zwiazane z uzywaniem Wdasm i Hiew. Jezeli wiec nigdy nie uzywales w/w narzedzi, tez sobie poradzisz :))) Kewl, let's go!
Opis:
Newbies Note! Prace z programem nalezy zaczac od wstepnego rozpoznania celu, tzn. jak sie go rejestruje, jakie efekty (komunikaty, dzwieki) temu towarzysza, kiedy i gdzie pojawia sie informacja o tym, ze jest niezarejestrowany itp.
OK, do okienka rejestracyjnego mozemy dotrzec na dwa sposoby:
- zaraz po uruchomieniu pojawia sie okienko;
z opcji Evalute/Purchase/Register wybieramy ta ostatnia ;),
- z menu Help -> Register Opera...
Mozemy teraz wpisac jakies dane i nacisnac OK. Pojawia sie mily ;) komunikat:
'The registation information you have entered is invalid. Please make sure that you have entered your name and registration code correctly'.
Jezeli chcielibysmy uzyc Softice, w tym momencie zastawiona przez nas pulapka powinna byla zadzialac i zaczelibysmy analizowac program krok po kroku. W przypadku Wdasm zrobimy to inaczej - na podstawie jakiegos komunikatu pojawiajacego sie w programie w dead listing'u programu znajdziemy jakis punkt zaczepienia i zaczniemy analizowac kod 'na sucho'
Newbies Note!
Dead listing to czysty kod programu w asemblerze. Uzyskac go mozemy za pomoca Wdasm. W tym celu z menu Disassembler wybieramy 'Open File to Disassemble...' i otwieramy pozadany plik.
Zamykamy wiec Opere i odpalamy Wdasm. Rozkladamy ('disasemlujemy' 8-|) plik opera.exe. To moze chwile potrwac :(
Newbies Note! Jezeli uzywasz Wdasm po raz pierwszy, z pewnoscia zobaczysz mase dziwnych znaczkow. No prob, wystarczy zmienic czcionke (menu Disassembler -> Font... -> Select Font) na ulubiona i zapamietac to ustawienie, by nastepnym razem uniknac tego problemu (menu Disassembler -> Font... -> Save Default Font).
Warto tez od razu zachowac plik w formacie tekstowych, by jego kolejne otwarcie nie zabieralo tak duzo czasy oraz by mozna go otworzyc w ulubionym edytorze tekstu (menu Disassembler -> Save Disassembly Text File and Create Project File).
Dobra, mamy juz dead listing Opery. Sporo tego, nie? Ktos wlozyl w to troche prace, moze wiec warto mu za to zaplacic?
Sprobujemy teraz w kodzie Opery znalezc komunikat (lub jego czesc), ktory pojawia sie po wprowadzeniu nieprawidlowych danych. Mozemy to zrobic dwojako:
- z menu Search -> Find Text (lub trzecia ikonka),
- z menu Refs -> String Data References (lub przedostatnia ikonka).
Uzyjmy drugiej metody. Wsrod wszystkich komunikatow szukamy naszego, czyli czegos zaczynajacego sie od 'The registration information...'.
Szukamy i nic. Po co wiec o tym pisze? Otoz jest to dosc skuteczna metoda, od ktorej zazwyczaj zaczynam. Pozwala ona latwo znalezc fragment kodu programu odnoszacy sie do zabezpieczenia. Choc tym razem zrobimy to inaczej, zasada dzialania jest identyczna.
Co zrobic, gdy komunikatu nie mozna znalezc w String Data References?
Rozejrzyjmy sie, co innego mozemy tam znalezc. Wsrod wielu ciekawych rzeczy uwage zwraca cos, co wydlada tak: "(unregistered)" (String Resource ID=21428). Zastanowmy sie przez chwile, gdzie cos takiego pojawia sie w programie (jesli nie pamietasz, odpal jeszcze raz Opere i poszukaj ;)). Ja zlokalizowalem (unregistered) w dwoch miejscach:
- w nazwie okna programu (Opera 3.50 (unregistered)),
- w pierwszym okienku, ktore pojawia sie jeszcze przed okienkiem z Evaluate/Purchase/Register; widzimy tam (oprocz nazwy programu) cos takiego:
Registered to: (unregistered).
Jak latwo sie domyslic, po prawidlowym zarejestrowaniu programu pojawiaja sie tu dane uzytkownika.
OK, wracamy do Wdasm, do znalezionego przez nas (unregistered) w String Data References.
Newbies Note! Podwojne klikniecie wybranego komunikatu w String Data References umozliwia znalezienie go w kodzie programu. Jezeli komunikat pojawia sie w kodzie programu wiecej razy, kolejne podwojne klikniecia pozwalaja odszukac jego kolejne lokalizacje.
(unregistered) znajdujemy w dwoch miejscach w kodzie Opery. Nie pozostaje nam nic innego, jak zabrac sie do ich analizy :)).
Zacznijmy od pierwszego wywolania. Znajdujemy tam cos takiego:
* Referenced by a CALL at Addresses:
|:0045BF4A , :004850C6
|
:0045F872 803D9055500000 cmp byte ptr [00505590], 00
:0045F879 56 push esi
:0045F87A 57 push edi
:0045F87B 8BF9 mov edi, ecx
:0045F87D BE90555000 mov esi, 00505590
:0045F882 7532 jne 0045F8B6
:0045F884 6A40 push 00000040
:0045F886 56 push esi
* Possible Reference to String Resource ID=21110: "Opera 3.50"
|
:0045F887 6876520000 push 00005276
:0045F88C E8400B0000 call 004603D1
:0045F891 56 push esi
:0045F892 E8F9CA0700 call 004DC390
:0045F897 59 pop ecx
:0045F898 A344555000 mov dword ptr [00505544], eax
:0045F89D 6A40 push 00000040
:0045F89F 59 pop ecx
:0045F8A0 2BC8 sub ecx, eax
:0045F8A2 8D8090555000 lea eax, dword ptr [eax+00505590]
:0045F8A8 51 push ecx
:0045F8A9 50 push eax
(!!! TU WYLADOWALISMY !!!)
* Possible Reference to String Resource ID=21428: " (unregistered)"
|
:0045F8AA 68B4530000 push 000053B4
:0045F8AF 8BCF mov ecx, edi
:0045F8B1 E81B0B0000 call 004603D1
Newbies Note! Kolejnym etapem analizy kodu w Wdasm jest (moze byc;)) znalezienie odpowiedniego skoku(-ow) przed wybranym wywolaniem, ktory odpowiada za ewentualna decyzje zarejestrowany/niezarejestrowany i zmienienie go (ich) na przeciwne (do samej zmiany uzyc mozna np. Hiew).
Od razu powiem, ze w ten fragment nie bedziemy bezposrednio ingerowac, nie dotyczy on bowiem interesujacego nas okienka (lecz raczej tytulu okna glownego Opery). Skad ten wniosek? Juz wyjasniam.
Po pierwsze jezeli zmienilibysmy jne 0045F8B6 w linii :0045F882 na skok przeciwny (je), to nie pojawilby sie ani "(unregistered)", ani tez "Opera 3.50". Skok przenioslby nas do linii 0045F8B6, a wiec za "Opera 3.50" i "(unregistered)". W okienku nie byloby wiec nic... a to jest raczej malo prawdopodobne.
Po drugie... by to wyjasnic, potrzebny jest nam drugi fragment kodu zawierajacy (unregistered). Wracamy wiec do String Data References, klikamy (unregistered) i znajdujemy sie tu (umieszcze tu dluzszy fragment kodu, by jego analiza byla latwiejsza ;)):
* Possible Reference to String Resource ID=21110: "Opera 3.50"
|
:00491E84 6876520000 push 00005276
:00491E89 FF3528595000 push dword ptr [00505928]
:00491E8F FFD7 call edi
* Reference To: USER32.SetDlgItemTextA, Ord:022Ch
|
:00491E91 8B35A4C44E00 mov esi, dword ptr [004EC4A4]
:00491E97 8D85C4FEFFFF lea eax, dword ptr [ebp+FFFFFEC4]
:00491E9D 50 push eax
:00491E9E 53 push ebx
:00491E9F FF7508 push [ebp+08]
:00491EA2 FFD6 call esi
:00491EA4 8D8540FBFFFF lea eax, dword ptr [ebp+FFFFFB40]
:00491EAA 83C3FE add ebx, FFFFFFFE
:00491EAD 50 push eax
:00491EAE 53 push ebx
:00491EAF FF7508 push [ebp+08]
:00491EB2 FFD6 call esi
:00491EB4 8D856CFCFFFF lea eax, dword ptr [ebp+FFFFFC6C]
:00491EBA 50 push eax
* Possible Reference to Dialog: SPLASH, CONTROL_ID:2B26, "Text"
|
:00491EBB 68262B0000 push 00002B26
:00491EC0 FF7508 push [ebp+08]
:00491EC3 FFD6 call esi
:00491EC5 833DB45D500000 cmp dword ptr [00505DB4], 00000000
:00491ECC 7526 jne 00491EF4
:00491ECE 8D85C4FEFFFF lea eax, dword ptr [ebp+FFFFFEC4]
:00491ED4 68FF000000 push 000000FF
:00491ED9 50 push eax
(!!! TU WYLADOWALISMY !!!)
* Possible Reference to String Resource ID=21428: " (unregistered)"
|
:00491EDA 68B4530000 push 000053B4
:00491EDF FF3528595000 push dword ptr [00505928]
:00491EE5 FFD7 call edi
:00491EE7 8D85C5FEFFFF lea eax, dword ptr [ebp+FFFFFEC5]
:00491EED 50 push eax
:00491EEE 53 push ebx
:00491EEF FF7508 push [ebp+08]
:00491EF2 FFD6 call esi
Wrocmy teraz do drugiegio uzasadnienia zalozenia, ze wlasnie ten, a nie poprzedni fragment kodu powinien nas zainteresowac. Latwo zauwazyc, ze w okienku, do ktorego chcemy sie dobrac, miedzy "Opera 3.50" i "(unregistered)" znajduje sie jeszcze cos, co po rejestracji najprawdopodbniej sie nie zmieni -> "Copyright 1995-1998 Opera Software". Sprobujmy wiec w Wdasm znalezc (menu Search -> Find Text) ciag
Copyright 1995-1998
Znajdujemy go raz. Na poczatku linii, w ktorej znajduje sie znaleziony tekst jest cos takiego:
ControlID:2B28
Spojrzmy teraz na powyzszy fragment kodu. Miedzy wywolaniem "Opera 3.50" i "(unregistered)" znajdujemy "Text". Jezeli zauwazymy, co go poprzedza (CONTROL_ID:2B26), szybko domyslimy sie, ze tu wlasnie pojawi sie "Copyright...".
Kewl. Wiemy juz, ze znalezlismy fragment kodu, o ktory nam chodzilo. Czas na jego analize.
W pierwszym fragmencie kodu, ktory analizowalismy, znalezlismy skok zarowno ponad "(unregistered)", jak i "Opera 3.50". Stwierdzilismy, ze jest to raczej nielogiczne. Zacznijmy wiec patrzec na drugi fragment od linii z "(unregistered)" do gory. Cztery linie wyzej znajdujemy pierwszy skok i ,jedna linie wyzej, porownanie:
:00491EC5 833DB45D500000 cmp dword ptr [00505DB4], 00000000 :00491ECC 7526 jne 00491EF4
Wyglada dobrze i spelnia nasze wymagania - pozwala na wyswietlenie "Opera 3.50" i "Copyright 1995-1998 Opera Software" i jezeli poprzedzajace go porownanie nie jest prawdziwe (rowne), skacze do 00491EF4, czyli omija "(unregistered)". Zastanownmy sie wiec, kiedy jne zostanie wykonany. 'Jne' to 'jump not equal', czyli 'skok, gdy nie jest rowne'. Widzimy wiec, ze cos, co znajduje sie pod [00505DB4] nie moze byc zerem - wtedy skok zostanie wykonany, a tego wlasnie chcemy.
OK, fajnie by bylo zmienic ten skok na przeciwny (jne->je, czyli 75->74). Sprobuj. (Btw, jezeli nie wiesz, jak to sie robi, dowiesz sie za chwile). "(unregistered)" w okienku rzeczywiscie sie nie pokazuje, program jednak nadal wyswietla okno Evaluate/Purchase/Register, a nazwa glownego okna programu to nadal "Opera 3.50 (unregistered)". Wyjasnimy to za chwile. A na razie jedziemy dalej... :)
Pod [00505DB4] nie ma wiec byc zera. A co tam jest? Sprobujmy do tego dojsc. Jezeli cmp dwort ptr [00505DB4] odczytuje cos stamtad, to najpierw to cos musialo sie tam znalezc :), najprawdopodobniej na skutek komendy mov dword ptr [00505DB4]. Zweryfikujmy nasze domysly w Wdasm i po prostu sprobujmy znalezc taki ciag w kodzie Opery. A wiec:
Wdasm -> Search -> Find Text -> mov dword ptr [00505DB4].
Jest:
:00491D5F A3B45D5000 mov dword ptr [00505DB4], eax
Widzimy, ze pod [00505DB4] umieszczana zostaje wartosc EAX. A skad mamy wiedziec, co jest wtedy w EAX? Spojrzmy dwie linijki wyzej:
:00491D58 E8DE1A0200 call 004B383B
Wypadaloby zajrzec pod wskazany adres (004B383B) ;). Widzimy:
* Referenced by a CALL at Addresses: |:0045BF21 , :00491D58 | :004B383B 8D8138010000 lea eax, dword ptr [ecx+00000138] :004B3841 85C0 test eax, eax :004B3843 741A je 004B385F :004B3845 803800 cmp byte ptr [eax], 00 :004B3848 7415 je 004B385F :004B384A 81C190030000 add ecx, 00000390 :004B3850 51 push ecx :004B3851 E82FA5FDFF call 0048DD85 :004B3856 85C0 test eax, eax :004B3858 59 pop ecx :004B3859 7404 je 004B385F :004B385B 6A01 push 00000001 :004B385D 58 pop eax :004B385E C3 ret * Referenced by a (U)nconditional or (C)onditional Jump at Addresses: |:004B3843(C), :004B3848(C), :004B3859(C) | :004B385F 33C0 xor eax, eax :004B3861 C3 ret
Newbies Note! Linia:
* Referenced by a CALL at Addresses: :adres1 :adres2
informuje, ze ponizsza procedura zostala przywolana przez instrukcje CALL znajdujaca sie pod adres1 i adres2.
Jak latwo zauwazyc, fragment kodu, ktory zaraz przeanalizujemy (i ktory okaze sie byc miejscem naszej modyfikacji :)) zostaje przywolany nie tylko przez CALL, ktory pozwolil nam tu dotrzec (:00491D58 call 004B383B), lecz rowniez przez CALL z linii :0045BF21. Dlatego wlasnie prosta zmiana jne w linii :00491ECC nie zadzialala. Jednak analize tego drugiego CALL'a pozostawiam dociekliwym. My zajmijmy sie teraz powyzszym fragmentem kodu.
Jak pamietamy, zalezy nam na tym, by po wyjsciu z tej procedury (ret) w EAX nie bylo zera. W tym fragmencie znajdujemy az trzy identyczne skoki je 004B385F, z ktorych kazdy wysyla nas do
:004B385F xor eax, eax
ZXORowanie 'czegos z samym soba' daje nam jednak zawsze zero.
Newbies Note! Jezeli nie znasz jeszcze XOR, przytaczam fragment FAQ numer 2 mNICHA, z ktorego ja sie tego nauczylem (thx mNICH):
"XOR jest bardzo czesto stosowana instrukcja przeroznych zabezpieczeniach !!!. Jest to tzw. wykluczajaca sie alternatywa ... nie przerazaj sie nazwa ;) ... o co tu chodzi ? ... to jest tak :
porownywane sa bity z pierwszego operandu i drugiego jesli sa przeciwne(1 i 0) to w wyniku bit ma wartosc 1, w przeciwnym przypadku ma 0. Wynik zapisywany jest w operandzie pierwszym !
oto tabelka ktora pamietamy z matmy:
a | b | c
==========
1 | 1 | 0
0 | 1 | 1
1 | 0 | 1
0 | 0 | 0"
a XOR b = c
Jezeli jednak nie zostalyby spelniony zaden z warunkow wykonania kolejnych trzech skokow do:
:004B385B 6A01 push 00000001 :004B385D 58 pop eax :004B385E C3 ret
a wiec:
- wypchniecia 1 na stos,
- sciagniecia 1 ze stosu do EAX,
- powrotu z CALL'a z EAX=00000001, co ostatecznie doprowadzi do tego, ze program bedzie myslal, ze jest zarejestrowany :)) Kewl.
Jakie wiec modyfikacje wprowadzic? Rozwiazan jest pare. Mozna:
- usunac wszystkie trzy skoki je 004B385F (czyli zamienic kolejno 741A, 7415 i 7404 na 9090),
- usunac xor eax, eax w linii :004B385F (czyli zamienic 33C0 na 9090),
- skierowac pierwszy z trzech skokow bezposrednio do linii z push 00000001 (czyli zamienic 741A na EB16).
Wszystkie trzy rozwiazania sa prawidlowe. Ostatnie wydaje sie byc jednak najszybsze z punktu widzenia optymalizacji kodu programu. Proponuje wyprobowac wszystkie trzy.
OK, ale jak te zmiany wprowadzic? Ja uzywam do tego celu Hiew. Zanim jednak go odpalimy, trzeba (najlepiej uzywajac Wdasm) sprawdzic, jaki offset odpowiada kolejnym liniom, ktore chcemy zmienic. Jak to zrobic, wytlumacze na przykladzie pierwszego skoku:
:004B3843 741A je 004B385F
Musisz do niego dotrzec w dead listingu i podswietlic linie (czyli umiescic na linii kursor ;)). Wtedy na dole okna zobaczysz cos takiego:
Line:39587 Pg 4768 of 6299 Code Data @:004B3843h @Offset 000B3843h in File:Opera.exe
Latwo sie domyslec, co oznaczaja poszczegolne elementy tej linii. Nas interesuje teraz jednak offset. Zapisz go (bez h, ktore informuje o zapisie w trybie szesnastkowym). Mamy wiec offset pierwszego skoku (B3843), zera na poczatku mozna pominac.
Jezeli sprawdzisz dalej, znajdziesz:
- offset B3848 dla drugiego skoku,
- offset B3859 dla trzeciego skoku,
- offset B385F dla xor eax, eax.
Teraz mozemy juz wylaczyc Wdasm.
Na koniec napisze (w telegraficznym skrocie), jak wprowadzic zmiany w Hiew.
Newbies Note!
1. Zanim zaczniesz mieszac w pliku, zrob jego kopie.
2. Nie zmienisz nic w kodzie programu, ktory wlasnie uzywasz.
Wylaczamy wiec Opere. Odpalamy Hiew i docieramy do Opera.exe (ew. zmiana dysku -> F1(drive)). Otwieramy go. Wow, co to za szlaczki? F4(mode) i Decode rozwiaze ten problem (mozna rowniez dwa razy nacisnac ENTER :)). Teraz F5(goto) i... wpisujemy offset, pod ktorym bedziemy dokonywac zmian. Zalozmy, ze chcemy zastosowac druga modyfikacje (usuniecie xor eax, eax). Wpisujemy wiec B385F i ENTER. Bach, jestesmy na miejscu. F3(edit) i zmieniamy (w tym wypadku 33C0 na 9090). Teraz tylko F9(update) i F10(quit).
Odpalamy Opere. Kewl. Zrobione :)))
Jezeli szukasz tu jedynie seriali, to zle trafiles.
Dzialania opisane powyzej maja na celu analize kodu programu i poznanie schematu jego zabezpieczenia. Jezeli masz zamiar uzywac tego programu dluzej, kup go (nie dotyczy M$).
Pozwoli to producentom udoskonalac oferowane programy, jak rowniez ich zabezpieczenia.
11-02-99 by iwan (iwy@friko.onet.pl)