______________________________________________________________________________________________

REVERSING, DODAWANIE FUNKCJI, MODYFIKACJA ISTNIEJCEGO KODU I KLASYCZNY CRACKING TYPOWEGO CELU MICRO$OFTU : NOTEPAD.EXE.... SZCZEGӣOWY OPIS TWORZENIA HNOTEPAD

By -NeuRaL_NoiSE 1999
Tumaczenie by eclipse (eclipse@icpg1.owg.pl)

od eclipse: najlepiej czyta pod Notepad'em ;) z wczonym zawijaniem wierszy
______________________________________________________________________________________________


Swego czasu napisaem tak...

" Hiho!

A wic znw mamy spokrewniony z Micro$oftem stuff...po moim ostatnim tutorialu (dotyczcym reversingu shell32.dll), zdecydowaem da sobie spokj z Micro$stuffem... mogoby to wyglda tak, jakbym nie mg si bez niego oby :D.
W tym tutorialu szczegowo wyjanienie jak zmodyfikowa notepad.exe (a w sumie to i wikszo innych programw) tak aby doda/usun/zmodyfikowa jakie funkcje, aby lepiej przystosowa go do projektu jaki wraz ze swymi dwoma przyjacimi Anub|sem i Insanity zamierzam doprowadzi do koca. Mwic w skrcie, chodzi o modyfikacj notepad.exe i stworzenie pliku .hlp zawierajcego szczegowe info o programie w formie surowego html. Zadaniem qmpli byo stworzenie helpa (mnie trafia jak mam programowa w html :) a moim by reversing notepada i dodanie potrzebnych nowych funkcji. Oczywicie plik .hlp bdzie (jeszcze nie jest gotowy) po wosku (jako e wszyscy jestemy Wochami, zapytam si qmpli czy przetumacz go na angielski)."

Opublikowaem ju jeden tutorial o tworzeniu Hnotepad, ale jak zapewne spostrzege skupia si on kompatybilnoci z Windows 95, a nie z Windows 98, a przede wszystkim powiniene zauway, e generowanie kodu byo cile zwizane ze sprztem na jakim si odbywao. Sugerowano mi popracowa nad tym i w kocu udao si, zrobiem kod bardziej przenony i stabilny...tak wic opisz ci jak stworzy program, ktry bdzie pracowa zarwno pod 95 i 98.

Kolejnym udoskonaleniem w stosunku do poprzedniego tutorialu jest to, e dziki kilku zmianom omwionym w ostatniej czci tego tutorialu Notepad bdzie w stanie czyta pliki znacznie wiksze ni FFFF (specjalne podzikowania dla GEniusa za ten GENIALNY pomys :), ale uwaga : tylko CZYTA, a nie ZAPISYWA - pamitasz nag o braku pamici ? Pomylaem, e moe lepiej go zostawi, eby wiedzia kiedy twj tekst przekroczy 50/60 KB...
Niemniej jednak moe zmieni to w jednej z przyszych wersji, kt to moe wiedzie - Notepad jest w sumie do otwartym projektem, a zadziwiajca jest liczba znajomych proszcych mnie o usprawnienie i dodanie nowych funkcji :)

______________________

CZʌ 1: UWAGI WSTPNE
______________________


Jak ju mwiem, ten tutorial ma przedstawi rednio zaawansowanym (raczej nie nada si dla kompletnych todziobw) crackerom wiat odwrotnego engineringu, a przede wszystkim jednego z jego (imho) najciekawszych aspektw : DODAWANIE FUNKCJI DO OBCEGO CELU. W sumie to cakiem proste...jak si wkrtce przekonasz (chyba e ju wiesz jak to robi) dodawanie nowych funkcji nie jest takie straszne.
Sprbuj wytumaczy wszystko w moliwie najprostszy sposb, ale i tak musze uprzedzi ci o trzech rzeczach : po pierwsze MUSISZ zna (przynajmniej w stopniu podstawowym) asembler w32 (USILNIE namawiam do przeczytania czego o nagwkach pe i strukturze wykonywalnych plikw windy). Po drugie : angielski autora ssie, a wic prosz doceni to e podj si tumaczenia tego (cholernie DUGIEGO:) tutorialu - oryginalna woska wersja dostpna na http://ringzer0.cjb.net

(od eclipse - po trzecie : angielski tumacza te czasami ssie, wic prosz si nie wkurza na chwilowe nieudolnoci jzykowe...thanx)

WANE : Mimo e ten tutorial opisuje tworzenie przenonej wersji Hnotepad'a (pracujcej zarwno pod 95 i 98), ja bd uywa Notepad.exe pochodzcego z WINDOWS *95*... tak wic sugeruj uywa tego samego pliku (w tej wersji tutorialu uywaem angielskiej wersji Notepad, wic nie powiniene mie problemu ze zdobyciem jej).

UYTE UYTKI :)
_______________

* W32Dasm v8.93
* SoftICE v3.24
* HIEW v6.1
* Borland Resource Workshop (BRW) v4.5
* ProcDump32 v1.3
* API Reference

__________________________________

CZʌ 2 : WPROWADZENIE DO HNOTEPAD
__________________________________

Oto co zrobimy w tym tutorialu :

* Dodamy menu do Notepada, ktre bdzie otwierao nasz nowy plik .hlp

* Stworzymy okienko about 

* Znajdziemy sposb na dodanie "HTML Files" (zarwno *htm jak i *html), "JS Files" oraz "VBS Files" do masek (*.xyz) w okienkach dialogowych "Open file" i "Save as"

* Dodamy miy pliczek .INI, w ktrym bdzie zapisany status funkcji zawijania tekstu oraz nazwa ostatnio otwartego pliku. Po uruchomieniu programu funkcja zawijania bdzie albo wczana labo wyczana w zalenoci od zapisu w pliku .INI, a ostatnio otwarty plik bdzie adowany zawsze gdy Hnotepad zostanie uruchomiony bez parametru.
Co wicej plik .INI bdzie automatycznie tworzony po kadym zakoczeniu pracy programu, a wic nie bdzie problemu z jego odtworzeniem w razie uszkodzenia.

* Wyeliminujemy ograniczenie wielkoci otwieranego pliku. Aby to zrobi uyjemy funkcji API ktra nie jest wykorzystywana przez oryginalny Notepad. Zastosujemy w tym celu kod skanujcy pami, ktry, jak wkrtce zobaczysz, bdzie prawdopodobnie BARDZO uyteczn alternatyw dla GetProcAddress.

To wszystko, zaczynamy !
______________________________

CZʌ 3 : TWORZENIE HNOTEPAD'a

FAZA 1 : NOWE MENU
______________________________

No tak...na pocztku zastanwmy si CO bdziemy robi z naszym programem : musimy DODA menu do ju istniejcych w programie...pamitaj jednak, e podczas tej sesji bdziemy musieli doda fragmenty NASZEGO kodu do programu...w przypadku menu bdziemy musieli zmodyfikowa procedur analizujc ID wybranego menu. A wic najpierw przyjrzymy si jak nasz cel analizuje ID menu (jak wiesz kady element, od menu po przyciski w oknach dialogowych posiada wasne ID dziki ktremu jest poprawnie rozpoznawane przez program)...moglibymy to zrobi uywajc API RegisterClass, ale tym razem zastosujemy inn metod...od razu dostaniemy si do miejsca ktre nas interesuje. Chcemy doda menu...a wic bdziemy analizowa zachowanie programu po wybraniu menu : postawimy puapk na funkcji WinHelpA (ktra uruchamia plik winhelp.exe, niezbdny do otwarcia dowolnego pliku *.HLP, oczywicie jeli jest to help w formacie windowsa). Wchodzimy do SoftICE, nastpnie wpisujemy "BPX WinHelpA".
Wracamy do Notepada, wybieramy z menu "Help" pozycj "Help topics". Wracamy do SoftICE, F12 i oto widzimy :

:00401E51 FF7514                  push [ebp+14]
:00401E54 57                      push edi
:00401E55 FF7508                  push [ebp+08]
:00401E58 E80FF3FFFF              call 0040116C    ; <-- WRACAMY Z TEGO WYWOANIA
:00401E5D 85C0                    test eax, eax
:00401E5F 0F8582000000            jne 00401EE7
:00401E65 FF7514                  push [ebp+14]
:00401E68 57                      push edi
:00401E69 56                      push esi
:00401E6A FF7508                  push [ebp+08]

* Reference To: USER32.DefWindowProcA, Ord:0078h
                                  |
:00401E6D FF1534744000            Call dword ptr [00407434]
:00401E73 EB74                    jmp 00401EE9


Dobrze...DefWindowProcA wskazuje na t cz procedury, w ktrej wiadomoci s przetwarzane (np. gdy jaka wiadomo nie jest przetwarzana, to nie jest ona "rzucana gdziekolwiek", tylko zostaje przechwycona przez DefWindowProcA, ktry uyje jej kiedy zajdzie taka potrzeba).
Oznacza to, e warto menu przechodzi (i jest sprawdzana) przez wywoanie pod adresem 1E58 .
Sprawdmy co jest pod tym wywoaniem :

* Referenced by a CALL at Address:
|:00401E58  
|
:0040116C 55                      push ebp
:0040116D 8BEC                    mov ebp, esp
:0040116F 81EC04010000            sub esp, 00000104
:00401175 33C0                    xor eax, eax
:00401177 56                      push esi
:00401178 57                      push edi
:00401179 BE38614000              mov esi, 00406138
:0040117E 8DBDFCFEFFFF            lea edi, dword ptr [ebp+FFFFFEFC]
:00401184 B940000000              mov ecx, 00000040
:00401189 A4                      movsb
:0040118A 8DBDFDFEFFFF            lea edi, dword ptr [ebp+FFFFFEFD]
:00401190 F3                      repz
:00401191 AB                      stosd
:00401192 66AB                    stosw
:00401194 AA                      stosb
:00401195 0FB7750C                movzx esi, word ptr [ebp+0C] ; <- WARTO ID 							            WYBRANEGO MENU
:00401199 83FE20                  cmp esi, 00000020 ; PORWNUJE WARTO ID I 20h
:0040119C 8BC6                    mov eax, esi
:0040119E 7F1A                    jg 004011BA       ; JELI ID > 20h, SKACZ
:004011A0 0F84C1030000            je 00401567
:004011A6 48                      dec eax
:004011A7 83F81B                  cmp eax, 0000001B
:004011AA 7736                    ja 004011E2
:004011AC 0FB68838174000          movzx ecx, byte ptr [eax+00401738]
:004011B3 FF248DF8164000          jmp dword ptr [4*ecx+004016F8] ; W INNYM RAZIE 								   NASTPUJCO

tak wic mamy ID menu (moesz sprawdzi wszystkie wartoci uywajc BRW) w ESI, nastpnie sprawdzamy czy ESI>20h. 20h to 32 dec, wic wartoci ID < 32 powoduj skok warunkowy do odpowiedniej czci kodu (jmp pod adresem 11B3). Tak wic nadamy naszemu menu warto ID wiksz od 32, aby odby si skok JG pod adresem 119E, ktry prowadzi do :

* Referenced by a JUMP at Address:
|:0040119E(C)
|

* Possible Ref to Menu: MenuID_0001, Item: "Cut   Ctrl+X"
                                  |                                 
:004011BA 3D00030000              cmp eax, 00000300 ; 300h (768 dec) = "Cut"
:004011BF 7C21                    jl 004011E2

* Possible Ref to Menu: MenuID_0001, Item: "Copy   Ctrl+C"
                                  |
:004011C1 3D01030000              cmp eax, 00000301
:004011C6 0F8E0F030000            jle 004014DB

* Possible Ref to Menu: MenuID_0001, Item: "Paste   Ctrl+V"
                                  |
:004011CC 3D02030000              cmp eax, 00000302
:004011D1 0F8427030000            je 004014FE
..............
..........

i tak dalej dla innych sprawdze. Tak wic znalelimy dobre miejsce do wstawienia naszego kodu odwoujcego si do naszego menu. Ale najpierw dobrze by byo stworzy to menu, no nie ? :)
Aby to zrobi naley otworzy notepad.exe w BRW, w sekcji "MENU", w menu "Help"
doda nowy element, mj nazywa si "Anub|s+Insa's Help on HTML". Nadaj mu warto ID rwn 33 (21h) (patrz uwaga powyej). Nastpnie w sekcji "KEY", dodaj "VK_F1". Warto ta spowoduje, e wcinicie F1 spowoduje wywoanie tej opcji (a nie starego helpa do Notepada). Zapisz zmiany, a gdy nastpnym razem uruchomisz Notepada do w magiczny sposb pojawi si nowa opcja w menu "Help" ;), ktra posiada jak wiadomo ID rwny 21h.
Teraz musimy rozwiza nastpujcy problem : jak doda nasz kod do ju istniejcego ?
Najpierw musimy sprawdzi kilka rzeczy. Jeli otworzysz plik notepad.exe pod HIEW, ProcDump lub innym z programw, otrzymasz wszystkie informacje jakie potrzebujesz aby doda swj kawaek kodu. Oczywicie musimy DODA nasz kod na kocu pliku tak abymy mogli przekierowa skoki z PE sekcji .TEXT do sekcji gdzie dodamy nasz kod. Zazwyczaj gdy chcesz doda swj wasny kawaek kodu, najlepiej zrobi to do ostatniej sekcji. ALE w przypadku Notepada dodalimy ju nowe menu, a ono dodao sekcj .RSRC (resource) do nagwka pe...a wic BRW doda t sekcj na kocu pliku aby nie zmieni wartoci wczeniejszych bajtw innych sekcji (czyli, e zrobi co co my chcemy zrobi:)...atwo to sprawdzi uruchamiajc HIEW, naciskajc F8 (z trybu hex lub disasm) aby zobaczy infa zwizane z nagwkiem, a F6 - z sekcjami. Jak wic mwiem - pe (a take plik) zostay zmienione przez BRW, ale pamitaj, e "natywnie" notepad.exe koczy si sekcj .RELOC, gdzie moglibymy znale troszk wolnego miejsca na nasz kod, i gdzie z tych samych powodw dodamy nasz kod (przynajmniej jego cz, gdy wkrtce zabraknie nam miejsca i bdziemy sobie musieli radzi wewntrz .RSRC). Pierwsze co naley zrobi to sprawdzenie fizycznego rozmiaru (w BAJTACH) jaki mamy na nasz kod : sprawdzamy wic Virtual Size (VirtSize = 91Eh) i Physical Size (PhysSize = A00h); rozmiar wirtualny podaje nam ilo bajtw ktrych nie mona modyfikowa, rozmiar fizyczny podaje cakowity rozmiar sekcji : proste odejmowanie A00h-91Eh daje nam E2h (226 dec.) wolnych bajtw dla naszego kodu. Nie potrzebujemy zwiksza tego rozmiaru gdy w zupenoci nam wystarczy; jednak gdyby potrzebowa wicej miejsca PRZED dodaniem nowego menu w BRW, to mgby zaadowa program do ProcDump'a, wyedytowa sekcj i zwikszy fizyczny rozmiar do potrzebnej ci wartoci. Oki dokie... Ale nadal mamy drobny problem...skd wiadomo POD JAKIM OFFSETEM doda nasz kod ? To proste...musimy spojrze na pocztkowy offset (Initial_Offset) sekcji : wynosi on 5000h, a wic Initial_Offset+VirtSize = 5000h + 91Eh = 591Eh, czyli entrypoint dla naszego kodu. Teraz pozosta jeszcze jeden problem...JAKI kod powinnimy doda ? :))
Przede wszystkim wyjanijmy sobie schemat operacji jak chcemy przeprowadzi. Aby zrobi skok z sekcji .TEXT (gdzie mamy wywoanie obsugujce wartoci ID) do sekcji .RELOC (gdzie bdzie nasz kod), a wic koniecznie zamieni kilka instrukcji na jmp...zmodyfikujemy CMP pod adresem 11BA : a wic musimy znale sposb na zamian tego cmp na jmp DO INNEJ SEKCJI. Moe to stanowi problem dla niektrych crackerw, jako e ci biedni chopcy chcc doda swj kod do docelowego zwykle musz uywa kompilatora aby wygenerowa poprawne opkody aby doda je do ju istniejcego programu. Cae szczcie, e pewnego dnia na naszych PC pojawi si SoftICE wraz ze swoj funkcj "A" (Asembluj instrukcj) :))))))))
Dziki temu cudownemu toolsowi moemy asemblowa instrukcj w locie, oraz otrzymywa wane opkody, ktrymi moemy pniej spatchowa nasz programik. Aby zobaczy bajty wraz z kad lini kodu w SoftICE, wstaw "CODE ON" w winice.ini. Opkody bd uniwersalne dla wszelkich PUSHy, CMPw i innych, tak wic do TEGO typu instrukcji wystarczy HIEW, ale do odlegych SKOKW ju potrzebujemy SoftICE, gdy odlego midzy offsetem pocztkowym i kocowym nie jest atwo obliczalna pod HIEWem gdy w gr wchodz dugie skoki (zwaszcza gdy skaczemy midzy 2 sekcjami). No dobra to by byo tyle jeli chodzi o skoki, ale co z WYWOANIAMI FUNKCJI ?? Procizna...aby wywoa funkcj API (co czego uyjemy) wystarczy call do pointera o rozmiarze dword, ktry wskazuje na specyficzny offset w sekcji .IDATA (importowane dane) : kada funkcja API uyta przez program jest doczana do tej sekcji podczas kompilacji, a wic aby jej uy naley zastosowa CALL [DWORD_PTR_DO_API]. Aby dowiedzie si jaki wskanik odpowiada danej funkcji naley uy W32Dasm.
To znacznie uproci nam prac, ale nadal pozostaje jedno pytanie : GDZIE (do ktrego offsetu) naley wykona skok z sekcji .TEXT aby osign nasz kod ?? Nie pomoe nam W32Dasm, gdy dissasemblaci ulega tylko sekcja .TEXT a nie .RELOC (gdzie bdzie nasz kod)...rozwizaniem jest HIEW : otwrz notepad.exe po HIEW, przecz si na HEX lub DISASM, nastpnie nacinij ALT+F1 aby wybra tryb LOCAL dla wywietlania offsetw. Zauwaysz pewnie, e zamiast offsetw
masz teraz pene VA (adresy wirtualne, = RVA+Image Base lokacji), ktre s wszystkim czego nam potrzeba aby zasemblowa poprawny skok w SoftICE. No to po prostu asemblujemy :JMP VA_naszego_
nowego_kodu" i sice zwrci nam waciwe opkody. Tylko jeli mamy krtkie skoki nie potrzebujemy sice, ale moemy wstawi offset bezporednio przy pomocy HIEW. Od teraz jak zobaczysz kilka gwiazdek (*******) obok instrukcji, to znacz one, e zostaa ona zasemblowana pod sice i pniej spatchowaem plik zwrconymi przez sice bajtami.
Kolejny problem...wiadomo, e mamy zrobi program otwierajcy nowy plik...ten plik z pewnoci bdzie mia jak nazw (co.hlp), nawet jeli jeszcze nie wiemy jak. Zamy, e bdzie to "HNOTEPAD.HLP". Musimy wic zmusi kod do rozpoznawania nazwy "HNOTEPAD.HTM", tylko, e taka nazwa nigdzie w pliku nie figuruje...musimy wic j doda do TABLICY ACUCHW naszego pliku.
Tablica ta, to nic wicej jak miejsce, w ktrym znajduj si wszystkie acuchy wchodzce w skad zasobw programu. Moglibymy zmieni jaki stary acuch na nasz, lub bezporednio doda go do kodu programu (jeszcze do tego wrcimy) - ta metoda jest uyteczna, jeli nie moemy uzyska bezporedniego dostpu do zasobw programu.
Odpalamy wiec BRW, otwieramy nasz program, wybieramy ostatni tablic acuchw (#48), wciskamy prawy przycisk mychy i wybieramy EDIT IT AS TEXT. Nastpnie dodajemy tak linijk :

 58, "hnotepad.hlp"

Zapisujemy i ju ! Mamy nowego stringa, ktrego moemy uywa w naszym kodzie...zaczynasz spostrzega jak OLBRZYMIE moliwoci le przed nami ??? :)
Teraz musisz wiedzie (chyba, e ju wiesz :) e stringi s adowane z tablicy acuchw funkcj LoadStringA, ktrej prototyp jest nastpujcy :

int LoadString(

    HINSTANCE hInstance,// uchwyt moduu zawierajcego zasb stringw
    UINT uID,	        // identyfikator zasobu (w naszym przypadku 58 lub 3Ah)
    LPTSTR lpBuffer,	// adres bufora zasobw
    int nBufferMax 	// rozmiar bufora (ilo znakw pobieranych z acucha - jeli acuch
                        jest duszy, to nadwyka zostaje odrzucona !)
   );

Hmmm....problemem jest bufor...skd mamy wiedzie ktrego bufora powinnimy uy dla naszego stringa ? No c, trzeba troch poeksperymentowa z programem...zacznij ustawia puapki i
szybko znajdziesz bufor nadajcy si do naszych celw. Masz dwie moliwoci :
1 - znale bufor adowany TYLKO RAZ (przy uruchomieniu programu) - w tym przypadku bdziesz
    musia uy LoadStringA jeszcze raz aby umieci stringa w buforze
2 - znale bufor ktry jest adowany ZA KADYM RAZEM kiedy program potrzebuje stringa, ktry
    powinien by w buforze...w tym przypadku nie musisz si martwi zastpieniem starego
    acucha nowym, bo to zrobi za ciebie program
Druga moliwo jest zdecydowanie najlepszym sposobem na uniknicie nadmiaru pracy...
No to rozejrzyjmy si...wemy na przykad wiadomo "This file is too large for Notepad to open...wanna use Wordpad??" Jeli wybierzesz "Yes", to zobaczysz, e program umieszcza zmienn "wordpad.exe" w buforze...oto disasm (pamitaj, e wartoci s wstawiane na stos w odwrotnej kolejnoci) :


:00402D70 6804010000              push 00000104 ; NA STOS TRAFIA LICZBA ZNAKW DO POBRANIA Z
                                                ; ACUCHA
:00402D75 8D85B8FEFFFF            lea eax, dword ptr [ebp+FFFFFEB8] ; EAX=63F8C4h
:00402D7B 50                      push eax ; NA STOS TRAFIA 63F8C4h - BUFOR PRZYJMUJCY ACUCH

* Reference To: USER32.LoadStringA, Ord:0168h
                                  |
:00402D7C 8B1DB0734000            mov ebx, dword ptr [004073B0]
:00402D82 837D1001                cmp dword ptr [ebp+10], 00000001 ; (atrapa)
:00402D86 1BFF                    sbb edi, edi                     ; (atrapa)

* Possible Reference to String Resource ID=00056: "wordpad.exe"
                                  |
:00402D88 6A38                    push 00000038              ; ID STRINGA "WORDPAD.EXE"
:00402D8A FF3570514000            push dword ptr [00405170]  ; UCHWYT MODUU ZAWIERAJCEGO
                                                             ; BLICE STRINGW
:00402D90 FFD3                    call ebx                   ; WYWOANIE FUNKCJI LOADSTRING

No to super ! Mamy nasz bufor...zapisz jego adres (63F8C4h), bo jeszcze nie raz bdziemy z niego korzystali.
Nawet jak zamienimy jego zawarto na "hnotepad.hlp", to stara warto i tak zostanie w nim umieszczona, gdy program bdzie prbowa uruchomi wordpad'a.
Zauwa, e w ten sposb moemy znale rwnie "niezmienne" informacje (w tym przypadku uchwyt moduu (dword ptr [406170] - zawiera on warto 400000h). Rwnie dobrze mona by uy push 400000h (ale pamitaj, e zawsze bezpieczniej jest uywa wskanikw zamiast warto natychmiastowych.)
Wiemy ju jak dosta si do acucha "hnotepad.hlp", i gdzie go szuka w razie potrzeby...
pozosta tylko kocowy detal...JAK wywoa funkcj WinHelpA ? Po raz kolejny pomoe nam nasz opis API :

BOOL WinHelp(

    HWND hWndMain,	// uchwyt okna dajcego pomocy
    LPCTSTR lpszHelp,	// adres cieki dostpu do helpa
    UINT uCommand,	// rodzaj helpa
    DWORD dwData 	// dodatkowe dane
    );

No to jest proste...po raz kolejny zobaczymy jak to wyglda w rzeczywistoci : BPX WinHelpA, w notepadzie wybieramy "Help"/"Help topics"...

:0040121C 6A00             push 00000000 ; NIE MA DODATKOWYCH DANYCH
:0040121E A194604000       mov eax, dword ptr [00406094] ; EAX=WSKANIK NA STRINGA
                                                         ; "NOTEPAD.HLP"
:00401223 6A0B             push 0000000B ; =HELP_FINDER, JEDEN ZE SPOSBW WYWOANIA HELPA
:00401225 50               push eax      ; NA STOS TRAFIA "NOTEPAD.HLP"
:00401226 FF3500604000     push dword ptr [00406000] ; A TU MAMY WSKANIK OKNA

* Reference To: USER32.WinHelpA, Ord:0225h
                                  |
:0040122C FF154C744000     Call dword ptr [0040744C] ; WYWOANIE WINHELPA

Zapytasz si pewnie, skd wiedziaem, e 0Bh jest rwne parametrowi HELP_FINDER. Sugeruj aby
cign Masm32 i zajrza do pliku "windows.inc" w katalogu masm32/include. Zawiera on wszystkie rwnoci ktrych potrzebujesz podczas przyporzdkowywania literalnych parametrw liczb hex. Piszc program moesz uywa zarwno literaw jaki i wartoci hex - nie ma rnicy, ale kiedy patchujesz program, to MUSISZ zna wartoci numeryczne, albo nie bdziesz wiedzia co umieci na stosie.)
Okie dokie...mamy uchwyt (ktry by nam najbardziej potrzebny) - mona bdzie go znale pod adresem na ktry wskazuje dword ptr [40600]...
Ostatnia uwaga na temat tej funkcji : opis API informuje nas, e musimy uy jej z parametrem
HELP_QUIT (= 02) podczas wychodzenia z programu, ale nie musimy si tym przejmowa skoro robi to za nas Notepad.

Super ! Mamy wszystkie potrzebne informacje...moemy zanurzy si w kodzie i doda nasz programik ! Najpierw zmieniamy CMP pod adresem 4011BA (@offset5BAh) na "JMP 40891E"

byo:

:004011BA 3D00030000              cmp eax, 00000300
:004011BF 7C21                    jl 004011E2

a teraz mamy :

:004011BA E95F770000 ************ jmp 0040891E ; -> PROSTO DO NASZEGO KODU
:004011BF 90                      nop
:004011C0 90                      nop

Zamienilimy CMP i Jl na JMP i dwa NOPy. NOPy s niezbdne do wypenienia bajtw JL teraz ju zbdnych (mona by je pomin, ale tak jest adniej). Ostatnia uwaga przed dodaniem naszego kodu. Pamitaj, e jak ju wykonamy nasz kodzik, to stos i rejestry powinny wrci do poprzedniego stanu.
atwo mona to zrobi przechowujc je na stosie (PUSHAD i POPAD). Poniej jest kod, ktry musimy doda pod HIEW. Jak natkniesz si na ***** to znaczy e musisz wyj z trybu wstawiania instrukcji i wstawi konkretne bajty tak jak ci to poda sice.

UWAGA : W HIEW CHCC WSTAWI "DWORD PTR [xyz]" UYJ "D [xyz]", JAK CHCESZ WSTAWI "BYTE PTR", UYJ "B" ITD.

591Eh: cmp eax, 21    ; eax przechowuje ID celu. 21h = ID naszego nowego menu ("Anub|s+Insa..")
       jz 5933        ; jak kliknito to skacz

       cmp eax,300    ; TE DWIE LINIE ZAMIENILIMY NA JMP W SEKCJI .TEXT...PORA JE ODTWORZY
****** jl 4011E2      ; OPKOD : 0F8CB488FFFF

****** jmp 4011C1     ; kontynuuj kolejne sprawdzania, skaczc z powrotem, do .TEXT
                      ; OPKOD : E98E88FFFF  

5933h: pushad                  ; zabezpieczamy rejestry
       push 20                 ; max liczby znakw do pobrania z bufora
       push 63F8C4             ; adres bufora
       push 3a                 ; 3Ah=58 dec...ID naszego stringa "hnotepad.hlp"
       push dword ptr [405170] ; uchwyt moduu zawierajcego zasb stringw
       call LoadStringA        ; aduj 20 znakw ze stringa "hnotepad.hlp" do 63F8C4
                               ; CALL D,[4073B0]
       popad                   ; odtworzenie rejestrw

          ; teraz przyczepimy si do parametrw naszego wasnego wywoania WinHelpA
      
       push 0               ; brak dodatkowych danych
       push 3               ; 3=HELP_INDEX, bdzie mona zobaczy index helpu
       push 63f8c4             ; bufor zawierajcy "hnotepad.hlp"
       push dword ptr [406000] ; uchwyt okna dajcego Helpa
****** jmp 40122c              ; powrt do sekcji .TEXT - OPKOD : E9CE88FFFF

Super...uruchamiamy "nowego" notepada (pamitajc o umieszczeniu pliku "hnotepead.hlp" w tym samym katalogu), klikamy na nasze menu, i voila ! Wanie dodalimy zupenie now funkcj do hnotepad.exe :)

___________________

FAZA 2 : OKNO ABOUT
___________________
      
      
Zaczynamy faz drug...dlaczego zachciao mi si doda nowe okno ?? no c...przede wszystkim Insanity i Anub|s zasuyli na jakie wyrnienie, a poza tym, no c odrobina osobistej satysfakcji...:))
Oprcz tego ta procedura nauczy nas kilku nowych rzeczy, jako e wkrtce odkryjemy e notepad.exe NIE MA SWOJEGO OKNA ABOUT...a ci lamerzy z Micro$oftu umiecili tak uyteczn funkcj API w shell32.dll...mwi o ShellAboutA. To API tworzy PREDEFINIOWALNE okno z obliczonymi w procentach wolnymi zasobami, pamici itd. oraz z dodatkowymi informacjami, ktre moesz tam umieci.
Jak wic wida MUSIMY doda i tu cz naszego kodu :D W sice ustawiamy bpx na ShellAboutA (pamitaj aby zaadowa exporty dla shell32.dll), puapka prowadzi nas do kodu okienka about :


:004013D0 6A02                    push 00000002
:004013D2 A170514000              mov eax, dword ptr [00405170]
:004013D7 50                      push eax

* Reference To: USER32.LoadIconA, Ord:015Eh
                                  |
:004013D8 FF1550744000            Call dword ptr [00407450]
:004013DE 50                      push eax
:004013DF 683C614000              push 0040613C
:004013E4 FF3560604000            push dword ptr [00406060]
:004013EA FF3500604000            push dword ptr [00406000]

* Reference To: SHELL32.ShellAboutA, Ord:004Ch
                                  |
:004013F0 FF1580734000            Call dword ptr [00407380]
      

buee, bezuyteczny stuff... ju raczej zainteresujemy si sekcj .RELOC, gdzie bdzie nasz kod.

Tak jak poprzednio zacznijmy od zastanowienia si CO chcemy zrobi. Okienko about ? No to message box w zupenoci nam wystarczy. Tak wyglda prototyp dla tej prociutkiej funkcji API :

int MessageBox(

    HWND hWnd,	        // uchwyt okna
    LPCTSTR lpText,	// adres TEKSTU w message box
    LPCTSTR lpCaption,	// adres TYTUU message box 
    UINT uType 	        // styl message box
   );

Hmmm....co z tymi dwoma buforami ? Tekst ktry chcemy wstawi jest do dugi...mona by doda wicej stringw i uy dwch buforw jako tekstu i tytuu okienka, ale ma to dwie wady :
primo, kiedy patchujesz program i chcesz doda co nowego, to *MUSISZ* sprbowa zoptymizowa swj kod tak, aby by jak najszybszy i najmniejszy, a secundo to NIGDY nie zostawia si nieuytych stringw...innymi sowy zanim dodasz jakie nowe zasoby, musisz sprawdzi czy ktre ze starych s nieuywane... jeli tak to zamiast dodawa nowego resourca lepiej jest ZMIENI tego zbdnego... pamitaj OSZCZDZANIE MIEJSCA TO PODSTAWA !

No to popatrzmy jak ma si to do naszego przypadku : w fazie 5 tego tutoriala wyeliminujemy box mwicy "This file is too large for Notepad to open..." oraz limit rozmiaru otwieranego pliku, tak wic mona wstawi nasz tekst zamiast tego stringa...a wic wskanik do "This file bla bla bla" (ktry wynosi 4060B0, a o czym informuje nas puapka ustawiona na powyszym message boxie)
bdzie wskazywa na TEKST naszego okienka...a wic wszystko co mamy do zrobienia to zmodyfikowanie stringa o ID 52 z :

"This file is too large for Notepad to open.\nWould you like to use WordPad to read this file?" 

na 

"RingZ3r0's Hnotepad v1.00\nModified version of Micro$oft's Notepad.exe\n\n\n* Code reverse engineering and implementation of new functions by -NeuRaL_NoiSE\n\n* Help file on HTML programming by Anub|s and Insanity"

Moesz po prostu skopiowa i wklei powyszy tekst. "\n" oznacza przejcie do nowej linii (jak w c). Nadal jednak mamy problem z tytuem. No to moe jednak doda nowego stringa... NIE ! nic z tego :)...MUSIMY si nauczy optymizowa nasz kod (nawet jeli otrzymamy spore iloci zbdnego stuffu, ale e robimy to w celach "edukacyjnych" to niech ci to nie martwi;)...Hmm, popatrzmy...tytu naszego okienka ma by "Hnotepad" albo co w tym stylu, tak ? No to popatrzmy na stringi w tablicy acuchw...teraz zmodyfikujemy wszystkie acuchy "Notepad" na "Hnotepad"
(oczywicie z wyjtkiem "notepad.hlp"). Teraz uruchamiamy program, wstawiamy gdzie puapk i bdc w kodzie przeszukamy pami (s 0 l ffffff "Hnotepad" - mona te przeszuka zawarto pliku pod HIEW.) Jak ju znajdziesz pierwsze wystpienie, to po prostu naciskaj "s" aby przej do nastpnego...zatrzymaj si przy adresie 41027E. Zauwaysz, e jest PRZED i PO nim wystpuj
bajty 00...znaczy to, e acuch ma dokadnie tak posta jaka jest midzy tymi bajtami - "Hnotepad" - bardzo si nada na tytu naszego okienka, nie uwaasz ? ;) Moglibymy uy wprost tego adresu...ale lepiej bdzie jak poszukamy wskanika do tego bufora i przekaemy API ten wskanik, zamiast bezporedniego adresu.
Wskaniki do popularnych zmiennych znajduj si w sekcji .DATA. Ju wczeniej widzielimy par takich (np. "uchwyt moduu zawierajcego zasb stringw".) Pierwszy z nich by pod adresem 405170...na pocztek wystarczy...teraz musimy znale wskanik...w sice "DD 405170" i troszk si rozgldamy...jest ! pod adresem 406060 jest nasz wskanik.
Co jeszcze ?? Hmm, uchwyt okna...pamitasz "wanna load wordpad ?" - zauwaylimy wtedy, e [ebp+8] zawiera hwnd...a jak troch poeksperymentujesz, to zobaczysz, e to si nie zmienia !
No i mamy hwnd...
Zosta nam jeszcze styl okienka...imho najlepszym rozwizaniem jest styl nr 0 (-MB_OK - pojedynczy przycisk "OK")...
No to zaczynamy...
Co nam pozostao, to zmodyfikowa kod, tak aby wykonywa on skok do naszych wasnych instrukcji w sekcji .RELOC...VA miejsca gdzie doczylimy nasz kod jest 40895E (@offset 595Eh), tak wic musimy wstawi skok w sekcji .TEXT do tej lokacji. Dobrym miejscem jest pocztek procedury ShellAboutA (@VA 4013D0, @offset 7D0h) :

byo

:004013D0 6A02                    push 00000002
:004013D2 A170514000              mov eax, dword ptr [00405170]

a jest

:004013D0 E989750000 ************ jmp 0040895E ; --> PROSTO DO NASZEGO KODU

Dalszy kod bdzie "troszk" zmieniony, ale to nas mao obchodzi, poniewa i tak nie bdzie nam potrzebny. My kontynuowa bdziemy w sekcji .RELOC od offsetu 595Eh :

       ...

595Eh: pushad                  ; zapisz rejestry
       push 00                 ; 0 = MB_OK
       push dword ptr [406060] ; wskanik do "Hnotepad" jako TITLE
       push dword ptr [4060B0] ; wskanik do stringa "RingZ3r0 blabla..." jako TEXT
       mov esi, [ebp+8]        ; hWnd okna
       push esi                ; uchwyt na stos
       call MessageBoxA        ; wywoujemy API - CALL D,[407430]
       popad                   ; odtworzenie rejestrw
****** jmp 4016eb              ; powrt do .text - OPKOD: E96E8DFFFF
       nop                     ; zakoczenie kodu (w sumie zbdne, ale zrb tak, jeli
                               ; naladujesz moj procedur)

Bingo ! Poszo ! Wywoaj okno about...zobaczysz nasze okienko...ale jak bdziesz prbowa
zaadowa plik o dugoci wikszej ni FFFFh bajtw to zobaczysz bezsensowne okienko - jako, e
stary string "wanna load Notepad" przepad...ale to tylko kwestia czasu...

________________________________________________

FAZA 3 : DODANIE MASKI DO STRUKTURY OPENFILENAME
________________________________________________


Okiej...zdaje si, e mamy zrobi edytor do HTMLa. No to bdzie on musia wywietla pliki HTML JS i VBS kiedy sprbujesz zaadowa/zapisa cokolwiek...(szczerze mwic to MUSZ to zrobi, bo inaczej Anub|s zabije mnie...:)))) oczywicie artuj.

Zacznijmy od okienka "Open file".
Najpierw trzeba nam wiedzie, e to okno dialogowe jest predefiniowalne i jest wywoywane przez funkcj API - GetOpenFileNameA, ktra siedzi sobie w Comdlg32.dll...
Tak wic na pocztek proponuje zaadowa export sice dla tego dll'a...
Kolejn rzecz, ktra powiniene wiedzie, jest to, e maski plikw musz zosta wyszczeglnione razem z innymi parametrami (zalecam lektur wspaniaego tutoriala Iczeliona lub opisu API) w strukturze OPENFILENAME, ktra jest umieszczana na stosie przed wywoaniem GetOpenFileNameA. Ta struktura zawiera wszystko, czego nam potrzeba. Filtry s definiowane w nastpujcy sposb (na przykadzie filtru dla plikw tekstowych) :

nazwafiltru db "Text files",0,"*.txt",0,0 <--- ostatnie zero nie jest bdem, tylko jest
                                               wstawiane, jeli filtr jest OSTATNI na licie

No to mamy wszystko czego nam potrzeba. Definiujemy nowy string w tablicy acuchw, w pozycji 59 (3Bh) :

59, "HTML Files|*.htm; *.html|JS Files|*.js|VBS Files|*.vbs"

Nie przejmuj si znaczkiem "|" pomidzy opisami o waciwym filtrem. Pniej zamienimy je na bajt 00, a program bdzie myla, e jest tu KILKA acuchw...
W sice ustawiamy BPX GetOpenFileNameA, w notepadzie wybieramy "File/Open". Wrcimy do sice, wciskamy F12, pojawi si okienko "Open file", wciskamy ESC i znowu wracamy do sice :

:004012E7 6880524000              push 00405280    ; NA STOS TRAFIA STRUKTURA OPENFILENAME :004012EC C7058C52400080514000    mov dword ptr [0040528C], 00405180
:004012F6 C7059052400030524000    mov dword ptr [00405290], 00405230
:00401300 C705B452400004100000    mov dword ptr [004052B4], 00001004
:0040130A 83C003                  add eax, 00000003
:0040130D A3BC524000              mov dword ptr [004052BC], eax

* Reference To: comdlg32.GetOpenFileNameA, Ord:0005h

:00401312 E8FA350000              Call 00404911     ; <-- .......A TU MAMY WYWOANIE !

Doskonale, pomwmy zatem o lokacji 405280. Przesuwamy kursor jedn lub dwie strony w gr i wodzimy wyrane lady acuchw filtra ("Text Documents *.txt" itp), acuch ten koczy si w lokacji 4051A9 (drugim bajtem 00). Teraz wystarczy LoadSTringA na tym adresie i bdziemy mogli doda nasz filtr do ju istniejcej listy. Po raz kolejny nasz kod bdzie kontynuowany w sekcji .RELOC, od VA 40897E (@offset 597Eh). Wstawimy skok do naszego kodu zamiast instrukcji push pod adresem 4012E7 (@offset 6E7h).

byo

:004012E7 6880524000              push 00405280
:004012EC C7058C52400080514000    mov dword ptr [0040528C], 00405180

a teraz jest

:004012E7 E992760000 ************ jmp 0040897E ; --> PROSTO DO NASZEGO KODU
:004012EC C7058C52400080514000    mov dword ptr [0040528C], 00405180

Jak pewnie zauwaye, kolejna instrukcja (MOV) nie ulega zmianie, wic bdziemy mogli do niej wrci po zakoczeniu naszej procedurki.

Teraz w ten sam sposb musimy zmieni kod zwizany okienkiem "Save as". Jest ono rwnie predefiniowane i wywoywane przez funkcj GetSaveFileNameA (rwnie znajduje si ona w comdlg32.dll). Nie potrzebujemy adnych wielkich modyfikacji - wystarczy, e kod zwizany ze struktur "Save as" bdzie wskazywa nasz nowy kod (ten sam co w przypadku okienka "Open file")
No to BPX GetSaveFileNameA, i szukamy czego takiego (@offset A8Ah) :

byo

:0040168A 6880524000              push 00405280 ; struktura na stos
:0040168F E86B320000              Call 004048FF ; wywoanie GetSaveFileNameA

a jest

:0040168A E9EF720000 ************ jmp 0040897E  ; --> PROSTO DO NASZEGO KODU
:0040168F E86B320000              Call 004048FF ; wywoanie GetSaveFileNameA

Jak wida wywoanie GetSaveFilaNameA nie ulego zmianie, wic nie bdziemy musieli docza go do naszego kodu, wystarczy tylko wrci w to miejsce jak ju skoczymy z naszym programikiem...
Tylko jak nasz kod bdzie rozrnia wywoanie funkcji GetOpenFileNameA i GetSaveFileNameA (a jest to NIEZBDNE, skoro nasz program musi wiedzie DOKD ma wrci po zmodyfikowaniu
struktury) ??
Przypatrzmy si uwanie rejestrom - po wykonaniu skoku dla "Open file" w ESI bdziemy mieli 0Ah (-10 dec), bo taka jest warto ID elementu menu "File/Open". Jak wybierzemy "Save as" to ta warto bdzie inna, wystarczy wic sprawdzi czy ESI=Ah i odpowiednio ustawi skok powrotny do sekcji .TEXT.

Nasz kod bdzie wyglda tak :
       ...

597Eh: pushad                   ; zapisujemy rejestry

       push 50                  ; max liczba znakw do pobrania z acucha

       push 4051A9              ; adres bufora

       push 3b                  ; 3Bh=59 dec...to jest ID naszego stringa :
                                ; "HTML Files|*.htm; *.html|JS Files|*.js|VBS Files|*.vbs"

       push dword ptr [405170]  ; uchwyt moduu zawierajcego zasb acuchw

       call LoadStringA         ; adujemy string spod 4051A9
                                ; CALL D,[4073B0]
      
       mov byte ptr [4051b3], 0 ; wstawiamy BAJT ZERO w miejsce "|" pomidzy "HTML Files" i
                                ; "*.htm", uzyskujemy w ten sposb rozdzielenie opisu i filtra,
                                ; a program myli, e ma tam 2 rne stringi

       mov byte ptr [4051c1], 0 ; jw dla "*.html" i "JS Files"
     
       mov byte ptr [4051ca], 0 ; jw dla "JS Files" i "*.js"

       mov byte ptr [4051cf], 0 ; jw dla  "*.js" i "VBS Files"

       mov byte ptr [4051d9], 0 ; jw dla "VBS Files" i "*.vbs"

       cmp esi,0ah              ; ESI=Ah jeli trafilimy tu poprzez "Open file"

       jnz 59c7                 ; ESI != 0ah??
     
       popad                    ; jeli tak to odtworzenie rejestrw...
     
       push 405280              ; ...wrzucamy na stos zmodyfikowana struktur...

****** jmp 4012ec               ; I KONTYNUUJEMY OD GetOpenFileNameA (w .TEXT)
                                ; OPKOD : E92589FFFF
  59C7:     

       popad                    ; jeli esi!=0ah, odtwarzamy rejestry...
     
       push 405280              ; ...wrzucamy na stos zmodyfikowana struktur...

****** jmp 40168f               ; I KONTYNUUJEMY OD GetSaveFileNameA (w .TEXT)
                                ; OPKOD : E9BD8CFFFF


I ju ! Od teraz okienka "Open file" i "Save as" bd miay wicej filtrw.

Moesz doda jeszcze inne elementy do tej struktury, tylko musisz pamita, e nie moesz przekroczy bloku pamici zarezerwowanego dla niej, nie moesz napisa nic na inne elementy struktury, musisz umieci bajt 00 pomidzy kolejnymi "opis", "filtr", "opis" itd...PLUS *DWA* BAJTY ZERO NA KOCU LISTY FILTRW

___________________________

FAZA 4 : DODANIE PLIKU .INI
___________________________


Zaczynamy teraz najtrudniejszy etap tego tutoriala. Najpierw zobaczmy jak wyglda nasz domylny plik .INI :

****
FILE AUTOMATICALLY GENERATED BY HNOTEPAD v1.0
USE ONLY 'Y' OR 'N' IN THE 'AutoWrap' FIELD !!

-NeuRaL_NoiSE 1999
****

AutoWrap=N
LastFileIs=

Pomylmy tera, jak zorganizowa kod zwizany z t funkcj. Oczywicie potrzebujemy cz ODCZYTUJC plik .INI przy starcie programu i cz TWORZC/ZAPISUJC go przy wyjciu z programu.

Zajmijmy si najpierw funkcja READ :

* Przy starcie Hnotepada, kod bdzie musia sprawdzi obecno pliku C:\Windows\Hnotepad.ini.
  Jeli go nie znajdzie, to powinien si zachowywa jak by nic si nie stao.

* Jeli go znajdzie, to powinien odczytywa z niego dane, a do znaku rwnoci ("="). Po tym
  znaku bdzie umieszczona warto WordWrapping. Jeli znak "=" nie zostanie odnaleziony, to
naley kontynuowa prac programu bez zmian.

* Po odnalezieni znaku "=" naley odczyta znajdujc si po nim liter, sprawdzi czy jest to
  "Y', "y", "N" lub "n". Jeli nie jest to adna z tych liter, to kontynuujemy bez zmian.

* Jeli litera jest "Y" lub "y", to naley doczy wiadomo "WordWrapping toggle" do kolejki
  wiadomoci procesu (pniej zobaczysz jak to zrobi)
 
* Jeli litera jest "N" lub "n" to kontynuuj bez wysyania wiadomoci.

* Sprawd czy linia komend == NULL. Jeli uytkownik wybra plik do otwarcia, to naley go
  otworzy, zamiast tego wskazanego w pliku .INI, gdy ma on wikszy priorytet.

* Tylko jeli linia komend == NULL to prbujemy otworzy plik wskazywany w .INI. Rozpoczynajc
  od poprzedniej pozycji szukamy nastpnego "=". Po nim znajduje si nazwa pliku ostatnio otwieranego. Jeli nie znaleziono "=" - wracamy do sekcji .TEXT i otwieramy nowy dokument.

* Jeli znaleziono "=" to sprawdzamy czy wystpujcy po nim znak jest liter z zakresu "A" -
  "Z" lub "a" - "z" (unikamy w ten sposb prby odczytu pliku np. "7:\xyz\xyz.txt"). Jak nie
  jest to wracamy nic nie robic.

* Jak znajdziemy poprawn liter, to odczytujemy acuch : zapisujemy pozycj pocztkow, a
  pniej przeszukujemy w nim spacji (" " = 20h) lub znak koca linii (=0Dh). Jeli nie
  odnaleziono adnego z nich, to przeszukuje dalsz cz pliku. Jedno musi by jasne : jak
  zapisujemy nasze domylne .INI to po drugim "=" jest spacja (" ") ktra wskazuje koniec
  acucha. Jeli natomiast zapisujemy do .INI nazw pliku do ponownego otwarcia, to na jej
  kocu doczmy CR (=0Dh), ktrego funkcja jest taka sama jak spacji. Jeli uytkownik rcznie
  wstawi nazw pliku do .INI to te nie ma problemu, bo pniej bdziemy mieli trzeci
  kontrol - tym razem dugoci pliku. Jak dotrzemy do EOF to mamy skoczone okrelanie nazwy
  pliku.

* Jak ju mamy nazw pliku, to wystarczy j skopiowa do bufora, ktry jest uywany jeli linia
  komend!=NULL. Notepad automatycznie zaaduje ten plik, poniewa ta operacj przeprowadzimy
  PRZED natywnym sprawdzeniem linii komend. Innymi sowy uyjemy metody "brute force" do
  wstawienia nazwy pliku do bufora, ktry w normalnym ukadzie zawieraby bajty 00.

* Wrmy teraz do sekcji .TEXT i kontynuujmy...

Wana uwaga. aby doda wicej kodu, bdziemy musieli uy segmentu .RSRC, gdy wolne miejsce w sekcji .RELOC praktycznie si skoczyo. I tu jest drobne ograniczenie : chodzi o to, e za kadym razem jak modyfikujemy zasoby przy pomocy BRW, to BRW tworzy sekcj .RSRS *OD NOWA* i dlatego cay nasz dodatkowy kod zostaby ZNISZCZONY przez pojedyncz zmian jednego z zasobw (oczywicie jeli uyjesz BRW). Jest jednak kilka rozwiza : mona doda wszystkie potrzebne nam stringi to tablicy acuchw PRZED dodaniem naszego kodu do .RSRC. Pniej okae si, e potrzebujemy jeszcze kilka nowych stringw (do fazy 5), ale tym problemem zajmiemy si pniej.

Zaczynamy od dodania 2 stringw do tablicy acuchw :

 60, "c:\\windows\\hnotepad.ini"
 61, "****\nFILE AUTOMATICALLY GENERATED BY HNOTEPAD v1.0\nUSE ONLY 'Y' OR 'N' IN THE 'AutoWrap' FIELD !!\n\n-NeuRaL_NoiSE 1999\n****\n\nAutoWrap=N\nLastFileIs= "

Kolejnym problemem jest brak miejsca na nasz kod - nie tramy wic czasu, adujemy ProcDump'a
edytujemy pe notepad'a i klikamy na "Sections". Zwikszamy zarwno raw jak i virutal size z 3000
do 3200 bajtw, po czym zapisujemy zmiany.
Uzyskamy w ten sposb potrzebne miejsce.

Teraz pomylmy, gdzie umieci odwoanie do naszego kodu sprawdzajcego zawarto .INI. Naley pamita o 2 rzeczach :

1) aby poinformowa program o uyciu opcji Wrapping on, potrzebujemy zasymulowa wybr opcji "Word Wrap". To jest do proste - wystarczy uy PostMessageA lub SendMessageA. SendMessageA
powoduje natychmiastowy skok do procedury okienka, wic nie bardzo nam si przyda, poniewa my musimy doda jeszcze kilka procedurek. Tak wic uyjemy PostMessageA, ktra DODAJE wiadomo do kolejki wiadomoci wykonywanego zadania. Ale moment, aby uy PostMessageA potrzebujemy HWND (czyli w sumie okienka) do ktrego wylemy wiadomo. Czyli e pierwsz rzecz o ktrej musisz pamita, to to, e kontrola EDIT (czyli ta ktra Notepad wykorzystuje) MUSI ZOSTA STWORZONA ZANIM NASZ KOD ZOSTANIE URUCHOMIONY.

WANA UWAGA : JELI NIE WYSYAMY WIADOMO "WORD WRAP TOGGLE" TO UYWAJC KONTROLI EDIT WSZYSTKO BDZIE W PORZO (WORD WRAPPING PO PROSTU SIE NIE WCZY). ALE JELI UYJEMY KONTROLI RICHEDIT (A TAK BDZIE W FAZIE 5) TO WSZYSTKO SI PIEPRZY. POWODEM JEST TO, E SPRBUJEMY POCZY PRYMITYWNY PROGRAM JAKIM JEST NOTEPAD Z ZAAWANSOWANA KONTROL RICHEDIT. CO JA Z TEGO WSZYSTKIEGO ZROZUMIAEM TO TO, E JAK WYSLEMY *JEDN* WIADOMO "WORDWRAP" TO RICHEDIT WCZY WORDWRAPPING, ALE JAK NIE WYLEMY *ADNYCH* WIADOMOCI, TO MAMY PROBLEM (CO W STYLU OPCJA WYCZONA, ALE WORDWRAPPING WCZONY :() ABY TEGO UNIKN NALEY WYSA DWIE WIADOMO "WRAP TOGGLE" - JAK WYDA CI SI TO NIEJASNE, TO MOESZ SI ZE MN SKONTAKTOWA :)

2) ALE jak bdziemy czekali za dugo, to popenimy inny bd : Notepad stworzy kontrol edit, ale przeprowadzi rwnie sprawdzenie  linii komend. A wic : NASZ KOD MUSI ZOSATC URUCHOMIONY, ZANIM ZOSTANIE WYWOANE SPARWDZENIE LINII KOMEND.

atwo odgadn, e sprawdzenie linii komend jest wykonywane PO utworzeniu kontroli, a to jest dla nas bardzo dobra wiadomo - wystarczy znale moment midzy tymi dwoma operacjami i tam wstawi nasz kod.

Myl, e dobrym pomysem jest okienko "Cannot find the xyz.xxx file...", ktre pojawia si jak sprbujesz otworzy nieistniejcy plik. Prowadzi ono do miejsca w ktrym kontrola zostaa JU utworzona, ale sprawdzenie linii komend WANIE ZOSTAO ZAKOCZONE. Jak uyjemy BPX MessageBoxA
to trafimy na co takiego :

* Reference To: USER32.MessageBoxA, Ord:0176h
                                  |
:00402251 FF1530744000            Call dword ptr [00407430]
:00402257 8BE5                    mov esp, ebp
:00402259 5D                      pop ebp
:0040225A C21400                  ret 0014

Hmm, sprawdmy ret...

:004028D0 E84FF9FFFF              call 00402224 ; <-- POWRACAMY Z TEGO WYWOANIA
:004028D5 83F806                  cmp eax, 00000006
:004028D8 7545                    jne 0040291F

Tu mamy sprawdzenie wcinitego klawisza, ale przypatrzmy si kodowi wczeniejszemu...co to za CreateFileA ?? :)

:00402853 803B00                  cmp byte ptr [ebx], 00
:00402856 0F84F4000000            je 00402950
:0040285C 53                      push ebx
:0040285D 68D0524000              push 004052D0
:00402862 E8F6F9FFFF              call 0040225D
:00402867 6A00                    push 00000000
:00402869 6880000000              push 00000080

:0040286E 6A03                    push 00000003

* Reference To: KERNEL32.CreateFileA, Ord:0039h

:00402870 8B1D44734000            mov ebx, dword ptr [00407344]

Bardzo ciekawe...mamy to czego szukalimy - sprawdzenie linii komend !!
Bajt ptr [ebx] zawiera 00 jeli nic nie zostao podane w linii komend, ale sprawdmy bpx na sprawdzeniu (@ 402853), wrmy do dos'a i uyjmy "NOTEPAD FAKE_FILE", zadziaa puapka, wpisujemy "D EBX"...i widzimy "FAKE_FILE" - oto bufor linii komend.
Ale chwileczk...nie tego bufora musimy uy...widzisz co takiego ? :

:0040285C 53                      push ebx
:0040285D 68D0524000              push 004052D0
:00402862 E8F6F9FFFF              call 0040225D

Jak przeledzisz to wywoanie, to zobaczysz odwoanie do funkcji lstrcpy, czyli, e nazwa pliku (znajdujca si w d,[eax]) jest KOPIOWANA do bufora pod adresem 4052d0, co wicej, jak podasz w linii komend FAKE_FILE, to ta procedura zmieni go na FAKE_FILE.txt. Czyli, e najlepiej bdzie jak wrzucimy nazw naszego pliku do tego bufora. Ale pamitaj o naszych 2 zaoeniach : trzeba sprawdzi czy kontrola edit ju zostaa stworzona. W SoftICE, jak dotrzemy do 402853, wpisujemy HWND NOTEPAD (o ile nazwa pliku ktry uruchomisz jest notepad.exe, jak inna to znajdujesz nazw taska poleceniem TASK). I co widzimy ; nazw drugiej klasy jest EDIT CONTROL...bingo ! Mamy wic dobre miejsce na nasze dodatki :)

Skok do naszej procedurki umiecimy zamiast JE @ 402856.

*** UWAGA ***

Bdziemy mieli kilka powrotnych adresw z naszego kodu :
* jeli nie ma pliku .INI (lub zawiera on bdy) a user NIE poda nazwy pliku w linii komend, to wracamy do 402950 (gdzie je skakao by normalnie)
* jest .INI, ale user wybra plik w linii komend - wracamy do 40285c
* jest .INI a user NIE poda nazwy pliku - kopiujemy nazw pliku (z .INI) BEZPOREDNIO DO BUFORA 4052d0 i wracamy do 402867

*** KONIEC UWAGI ***

Nasz kod bdzie zaczyna si od 40BEED (@88edh) -- w sumie to moglibymy zaoszczdzi troch miejsca, ale tak bdzie bezpieczniej :

byo

:00402856 0F84F4000000            je 00402950

a jest

:00402856 E992960000 ************ jmp 0040BEED ; --> DO NASZEGO KODU
:0040285B 90                      nop


Oczywicie bdziemy potrzebowa paru funkcji API...za kadym razem jak w kodzie natkniesz si na ktr z nich, to zamiast niej wstawiasz (pod HIEW) : call d,[dword_wskanik_api]

A oto one :

LoadStringA:  call d,[4073b0]
_lopen:       call d,[407364]
_lread:       call d,[407368]
PostMessageA: call d,[40745c]
lstrcpyA:     call d,[40733c]
_lclose:      call d,[4072f0]

Przypatrzmy si naszemu programikowi : (wydaje mi si, e troch trudno go zrozumie majc tylko offsety jako pkt odniesienia, wic dodaem par etykiet (wraz z odpowiadajcymi im adresami).

Start (@88ed):

  pushad                      ; zapisujemy rejestry
  push 20                     ; liczna znakw do pobrania z acucha
  push 63f8c4                 ; bufor
  push 3c                     ; =60 dec, ID stringa "c:\\windows\\hnotepad.ini"
  push 400000                 ; uchwyt moduu z tablic acuchw
  call LoadStringA

  push 0                      ; wrzuca na stos lipny parametr - pniej na niego napiszemy
                              ; waciwy, jeli plik .INI zostanie znaleziony

  push dword ptr [406000]     ; zapisuje hWnd. Zawsze znajdziesz go tutaj. atwo si o tym
                              ; przekonasz, jak zajrzysz do wskanikw w sekcji .IDATA.

; TERAZ TRZEBA OTWORZY NASZ PLIK...UYJEMY _lopen :
;
; HFILE _lopen(
;
;    LPCSTR lpPathName,	// wskanik na nazw pliku
;    int iReadWrite 	// tryb dostpu
;   );	


  push 0                      ; = OF_READ, otwarcie tylko do odczytu i zwrot bdu jeli plik
                              ; nie istnieje
  push 63f8c4                 ; "c:\windows\hnotepad.ini"
  call _lopen
  cmp eax, -1                 ; by bd ??
  jnz FILE_FOUND (@8924h)

    pop eax                   ; wywalamy lipny parametr
    pop eax                   ; wywalamy hWnd
    popad                     ; odtwarzamy rejestry
    jmp ERROR_IN_FILE (@8a11h)

FILE_FOUND (@8924h):

  mov [esp+4], eax            ; uchwyt pliku zamiast lipnego parametru

; TERAZ TRZEBA ODCZYTAC DANE Z PLIKU...UYJEMY _lread:
;
; UINT _lread(
;
;     HFILE hFile,	// uchwyt pliku
;     LPVOID lpBuffer,	// wskanik na bufor
;     UINT uBytes 	// dugo bufora (w bajtach)
;    );	

  push ff                     ; ilo bajtw do odczytu; UWAGA - NALEY UY OPKODU 68FF000000,
                              ; INACZEJ HIEW WSTAWI 6AFF, KTRY ZOSTANIE ZINTERPRETOWANY PRZEZ
                              ; WIN98 (NIE 95) JAKO PUSH FFFFFFFF, A NIE PUSH 000000FF
  push 4109a1                 ; bufor "RingZ3r0's Hnotepad.....", odtwarzany przez CLOSE
                              ; (@89EBh)
  push eax                    ; uchwyt pliku
  call _lread

  mov edi, 4109a1             ; co odczytalimy z pliku
  mov ecx, eax                ; efektywna dugo pliku w ecx
  mov al, 3d                  ; '='
  repnz scasb                 ; szukaj AL ('=') w buforze wskazywanym przez EDI o dugoci
                              ; ECX bajtw
  jnz ERROR (@895Fh)          ; nie odnaleziono '='

; jak znaleziono '=' to EDI wskazuje na NASTPNY NZKA PO '='.

  mov esi, 1                  ; esi bdzie liczy ILE RAZY MUISIMY WYSA WIADOMO "WRAP
                              ; TOGGLE"

  cmp byte ptr [edi], 59      ; 'Y'
  jz SEND_AUTOWRAP (@896Dh)
  cmp byte ptr [edi], 79      ; 'y'
  jz SEND_AUTOWRAP (@896Dh)
  cmp byte ptr [edi], 4E      ; 'N'
  jz AUTOWRAP_OFF (@896Ch)
  cmp byte ptr [edi], 6E      ; 'n'
  jz AUTOWRAP_OFF (@896Ch)

ERROR (@895Fh):

  pop eax                        ; wywalamy hWnd
  mov dword ptr [63f8c4], 40c011 ; ten dword ptr bdzie lokacj zawierajc zmienny powrotny VA
                                 ; uywany przez nasz "uniwersaln" procedur powrotn CLOSE
                                 ; (@89EBh).
                                 ; 40c011 jest VA dla ERROR_IN_FILE (@8a11h)
  jmp CLOSE (@89EBh)             ; = jmps w HIEW



AUTOWRAP_OFF (896Ch):
 
  inc esi                        ; esi=2 wic wysyamy wiadomo "wrap toggle" DWA razy

SEND_AUTOWRAP (@896Dh):

; TERAZ WYSYAMY WIADOMO UYWAJC PostMessageA :
;
; BOOL PostMessage(
;
;     HWND hWnd,	// uchwyt okna docelowego
;     UINT Msg,  	// wiadomo do wysania
;     WPARAM wParam,	// pierwszy parametr wiadomo
;     LPARAM lParam 	// drugi parametr wiadomoci
;    );
;
; CHCEMY ZASYMULOWA KLIKNICIE NA ELEMENT MENU, WIC WIADOMOCI BDZIE 111h (WM_COMMAND),
; A wParam - 1Bh (=27 DEC, ID "Edit/Word Wrap")

  pop eax                        ; odtwarzamy hWnd....
  push eax                       ; ...i ponownie zapisujemy
  push ecx                       ; zapisujemy pozostae bajty dla scasb nastpnego sprawdzania,
                                 ; gdy PostMessageA modyfikuje rejestr ECX

  push 0                         ; lParam
  push 1b                        ; wParam
  push 111                       ; = WM_COMMAND
  push eax                       ; hWnd
  call PostMessageA

  pop ecx                        ; odtwarzamy pozostae bajty dla scasb
  dec esi                        ; zmniejszamy licznik
  jnz SEND_AUTOWRAP (896Dh)      ; jeli wsi byo = 2 to wyczamy word-wrapping

  cmp byte ptr [ebx], 0          ; sprawdzamy, czy CMDLINE==NULL
  jz CONTINUE (@8996h)
  pop eax                        ; wywalamy hWnd
  mov dword ptr [63f8c4], 40285c ; jak nie to powrotny VA = 40285c, patrz "*** UWAGA ***"
  jmp CLOSE (@89EBh)             ; = JMPS w HIEW

CONTINUE (8996h):

  mov al, 3d                     ; '='
  repnz scasb                    ; szukamy AL ('=') w buforze wskazywanym przez EDI o dugoci
                                 ; ECX bajtw oczywicie ecx zostao pomniejszone (przez
                                 ; poprzedni repnz scasb) o ilo bajtw midzy POCZTKIEM
                                 ; pliku i PIERWSZYM '='
  jnz ERROR (@895Fh)             ; jeli nie odnaleziono '='

; TERAZ SPAWDZAMY, CZY PIERWSZY ZNAK PO '=' JEST LITER ALFABETU. KODY ASCII TO 'a' = 61,
; 'z' = 7A, 'A' = 41 i 'Z' = 5A

  cmp byte ptr [edi], 61         ; 'a'
  jge 2_LOWCASE (@89A3h)
  jmp UPCASE (@89A8h)            ; JMPS w HIEW

2_LOWCASE (89A3h):

  cmp byte ptr [edi], 7a         ; 'z'
  jle OK (@89C1h)

UPCASE (@89A8h):

  cmp byte ptr [edi], 41         ; 'A'
  jge 2_UPCASE (@89AFh)
  jmp INVALID (@89B4)            ; = JMPS w HIEW

2_UPCASE (89AFh):

  cmp byte ptr [edi], 5a         ; 'Z'
  jle OK (@89C1h)

INVALID(@89B4h):

  pop eax                        ; wywalamy hWnd
  mov dword ptr [63f8c4], 402950 ; powrotny VA, patrz "*** UWAGA ***"
  jmp CLOSE (@89EBh)             ; = JMPS w HIEW

OK (@89C1h):

  push edi                       ; zapisujemy pozycj pierwszej litery w stringu zawierajcym
                                 ; nazw pliku

SEARCH_CR_OR_SPACE (@89C2):

      inc edi
      cmp byte ptr [edi], 20     ; ' '
      jz FOUND (@89D0h)
      cmp byte ptr [edi], 0D     ; = Carriage Return
      jz FOUND (@89D0h)
      dec ecx                    ; ECX zawiera bajty pomidzy drug '=' i EOF
      jnz SEARCH_CR_OR_SPACE (@89C2)

FOUND (@89D0):

  mov byte ptr [edi], 0          ; zaznaczenie (w pamici) koca acucha okrelajcego plik
  pop edi                        ; odtworzenie pocztkowej pozycji w acuchu (ktry teraz
                                 ; koczy si bajtem 00)
  push edi
  push 4052d0
  call lstrcpyA                  ; kopiuje EDI (pocztek nazwy pliku bajt zero) do 4052d0
                                 ; (bufor do otwarcia pliku)
  mov dword ptr [63f8c4], 402867 ; powrotny VA, patrz "*** UWAGA ***"
  pop eax                        ; wywalamy hWnd

CLOSE (@89EBh):

  pop eax                        ; uchwyt pliku do eax

; ZAMYKAMY TERAZ HNOTEPAD.INI; UYJEMY _lclose:
;
; HFILE _lclose(
;
;     HFILE hFile 	// uchwyt zamykanego pliku
;
;    );	



  push eax                       ; uchwyt pliku
  call _lclose

  push 100            --\ 
  push 4109a1           |
  push 34 ; = 52 DEC    | --> To LoadStringA odtworzy bufor "RingZ3r0's Hnotepad....."
  push 400000           |
  call LoadStringA    --/ 

  popad                          ; odtworzenie rejestrw
  jmp dword ptr [63f8c4]         ; nasz zmienny skok powrotny

ERROR_IN_FILE (@8A11h):

    cmp byte ptr [ebx], 0        ; sprawdzamy lini komend

*** jnz 40285c ; jeli CMDLINE!=NULL, OPKOD: 0F854268FFFF
*** jmp 402950 ; jeli CMDLINE==NULL, OPKOD: E93169FFFF

  NOP
  NOP ; aby zaznaczy koniec naszego kodu
  NOP

Koniec...sprbuj wyedytowa plik C:\windows\hnotepad.ini, wstawi dwa '=' do niego, po pierwszym wpisa 'Y', po drugim - nazw jakiego pliku (razem ze ciek). Jak uruchomisz hnotepad'a to ten plik zostanie automatycznie wczytany.

---

No dobra, ale rozwizalimy tylko cz problemu. Teraz zajmijmy si automatycznym ZAPISEM pliku .INI przy kadym wyjciu z hnotepad :

* Przed wyjciem program bdzie tworzy plik "C:\windows\hnotepad.ini"; jeli plik istnieje, to
  obcinamy jego dugo do 0 i tworzymy od nowa, jak tworzenie si nie uda, to nic si nie
  dzieje.

* Jak uda si stworzy plik, to adujemy "szkielet" pliku .INI (wczeniej widziany) do pamici
  i doczamy do niego niezbdne dane (nazw ostatnio otwartego pliku i stan funkcji Word
  Wrapping w czasie wyjcia z programu).

* Zapisujemy szkielet z dodatkowymi danymi do pliku.

* Wychodzimy z programu.

Aby to zrobi, musimy wiedzie 2 rzeczy :

1) GDZIE znajdziemy nazw ostatnio otwartego pliku
2) GDZIE sprawdzimy status funkcji Word Wrapping.

Okiej...pierwsza odpowied jest banalna : nazwa pliku jest w buforze uywanym do otwierania pliku ; 4052d0.

Druga jest troch trudniejsza, ale w sumie nic powanego.

Pamitasz gwne odwoanie w procedurze okienka ? to ktre odpowiada za wysanie wiadomoci do okienka ? Przyjrzyjmy si jeszcze raz :

* Referenced by a CALL at Address:
|:00401E58 
|
:0040116C 55                      push ebp
:0040116D 8BEC                    mov ebp, esp
:0040116F 81EC04010000            sub esp, 00000104
:00401175 33C0                    xor eax, eax
:00401177 56                      push esi
:00401178 57                      push edi
:00401179 BE38614000              mov esi, 00406138
:0040117E 8DBDFCFEFFFF            lea edi, dword ptr [ebp+FFFFFEFC]
:00401184 B940000000              mov ecx, 00000040
:00401189 A4                      movsb
:0040118A 8DBDFDFEFFFF            lea edi, dword ptr [ebp+FFFFFEFD]
:00401190 F3                      repz
:00401191 AB                      stosd
:00401192 66AB                    stosw
:00401194 AA                      stosb
:00401195 0FB7750C                movzx esi, word ptr [ebp+0C] ; <- WARTO ID WYBRANEGO MENU
:00401199 83FE20                  cmp esi, 00000020 ; PORWNANIE WARTOCI ID i 20h
:0040119C 8BC6                    mov eax, esi
:0040119E 7F1A                    jg 004011BA       ; JELI ID > 20h, TO SKACZ
:004011A0 0F84C1030000            je 00401567
:004011A6 48                      dec eax
:004011A7 83F81B                  cmp eax, 0000001B
:004011AA 7736                    ja 004011E2
:004011AC 0FB68838174000          movzx ecx, byte ptr [eax+00401738]
:004011B3 FF248DF8164000          jmp dword ptr [4*ecx+004016F8] ; W PRZECIWNYM WYPADKU RB TAK
                                                                
Bardzo dobrze. Intuicja podpowiada, e naley postawi "BPX 401199 if esi==1b" aby przeanalizowa zachowanie kodu po przeczeniu funkcji wrapping. Trafimy na skok zmienny pod 11b3, a stamtd do 401491 :

:00401491 833D1860400001          cmp dword ptr [00406018], 00000001 ; [406018]=0 jeli
                                                                     ; wrap=OFF
                                                                     ; [406018]=1 jeli wrap=ON
:00401498 1BC0                    sbb eax, eax
:0040149A F7D8                    neg eax
:0040149C 50                      push eax
:0040149D E8EC1E0000              call 0040338E
:004014A2 85C0                    test eax, eax
:004014A4 7415                    je 004014BB
:004014A6 833D1860400001          cmp dword ptr [00406018], 00000001
:004014AD 1BC0                    sbb eax, eax
:004014AF F7D8                    neg eax
:004014B1 A318604000              mov dword ptr [00406018], eax ; ODWIERZ WSKANIK NOWYM
                                                                ; STANEM WRAPPING'u

No i atwo spostrzec, e dword ptr [406018] jest niczym innym, jak flaga statusow, a cile mwic, flag stanu Word Wrapping :)
Jak jest rwna 0, to zawijanie jest wyczone, a ta procedura AKTUWUJE je, ustawiajc dword ptr [406018] na 1.
Jeli rwna 1 - procedura robi dokadne przeciwiestwo.
Przy wyjciu ten wskanik jest zachowywany i wyranie okrela stan funkcji zawijania wierszy podczas wychodzenia z programu - wystarczy wic sprawdzi jego warto i ju !

Najlepszym miejscem do wywoania naszej procedurki jest co zwizane z WM_DESTROY - czyli kiedy prawie wszystko zostao zamknite, a user nie moe wstrzyma zamknicia programu.
Aby znale waciwy obszar kodu, uyjemy do prostej metody : funkcji API registerClass.
W Disasm szukamy na "registerclass" i mamy co takiego :

:00402B19 C745F820604000          mov [ebp-08], 00406020
:00402B20 C745D8AD1A4000          mov [ebp-28], 00401AAD
:00402B27 C745F006000000          mov [ebp-10], 00000006
:00402B2E C745D400100000          mov [ebp-2C], 00001000
:00402B35 50                      push eax
:00402B36 897DDC                  mov dword ptr [ebp-24], edi
:00402B39 897DE0                  mov dword ptr [ebp-20], edi

* Reference To: USER32.RegisterClassExA, Ord:0196h
                                  |
:00402B3C FF15CC734000            Call dword ptr [004073CC]


Procizna, wystarczy zajrze do lokacji w [ebp-xx] przed wywoaniem, a wkrtce spostrzeesz, e
pocztek procedury okienka jest pod adresem 401aad :

:00401AAD 55                      push ebp
:00401AAE 8BEC                    mov ebp, esp
:00401AB0 56                      push esi
:00401AB1 57                      push edi
:00401AB2 8B750C                  mov esi, dword ptr [ebp+0C]
:00401AB5 83FE05                  cmp esi, 00000005
:00401AB8 7714                    ja 00401ACE
:00401ABA 0F8406010000            je 00401BC6
:00401AC0 83FE02                  cmp esi, 00000002
:00401AC3 0F84F0000000            je 00401BB9

Ustawiamy bpx 401ab5 i widzimy, e ESI zawiera wiadomo aktualnie analizowan. Nas interesuje
WM_DESTROY - no i mamy skok spod 401ac3 ktry zostaje wywoany wycznie, jeli biec wiadomoci jest WM_DESTROY. Wystarczy wic podstawi ten VA naszym (kierujcym do pocztku naszego kodu) i problem z gowy. Nasz kod rozpoczyna si od 40c022 (@8A22h), tak wic musimy zmodyfikowa ten skok.

byo

:00401AC3 0F84F0000000            je 00401BB9

a jest

:00401AC3 0F8459A50000 ********** je 0040C022 ; --> DO NASZEGO KODU

Te funkcje API bd nam potrzebne :

_lcreat:     call d,[407360]
_lwrite:     call d,[4072f8]
ExitProcess: call d,[407354]

A tak wyglda nasz kod :

Start (@8A22h):

  pushad                     ; zapisujemy rejestry
  push 20                    ; ilo znakw do pobrania
  push 63f8c4                ; bufor
  push 3c                    ; = 60 dec, "C:\\windows\\hnotepad.ini"
  push 400000                ; uchwyt moduu z list acuchw
  call LoadStringA

; TERAZ MUSIMY STWORZY PLIK; UYJEMY _lcreat
;
; HFILE _lcreat(
;
;     LPCSTR lpPathName,// wskanik na nazw pliku
;     int iAttribute 	// atrybut pliku
;    );
;
; NASZYM ATRYBUTEM BDZIE 0 ("NORMAL") - PLIK MOE BY ODCZYTYWANY I ZAPISYWANE BEZ OGRANICZE.
; JELI PLIK ISTNIEJE TO _lcreat ATOMATYCZNIE SKRACA GO DO 0 BAJTW, A JELI NIE, TO TWORZY GO.

  push 0                     ; atrybut "Normal"
  push 63f8c4                ; "C:\windows\hnotepad.ini"
  call _lcreat

    cmp eax, -1              ; bd podczas tworzenia
    jnz CREATED_OK (@8A4Fh)
    popad                    ; odtworzenie rejestrw
*** jmp 401bb9               ; tu bymy skakali normalnie bez naszych dodatkw
                             ; OPKOD : E96A5BFFFF

CREATED_OK (@8A4Fh):

  push eax                   ; zapisujemy uchwyt pliku
  push 100                   ; ilo znakw do pobrania
  push 4109a1                ; bufor
  push 3d                    ; = 61 DEC, ID stringa "****\nFILE AUTOMATICALLY GENERATED...."
  push 400000                ; uchwyt moduu z list acuchw
  call LoadStringA

  cmp dword ptr [406018], 0  ; jak zero to WordWrapping = OFF
  jz CHECK_LASTFILE (@8A77)
  mov byte ptr [410a26], 59 ; zmieniamy domylne "N" po "AutoWrap=" na "Y" (059h)

CHECK_LASTFILE (@8A77):

; SPRAWDZAMY CZY MAMY NAZWE PLIKU LUB SOWO "Untitled" OZNACZAJCE, E ADEN PLIK NIE BY
; OSTATNIO OTWIERANY

  mov eax, 4052d0          ; adres pocztkowy bufora z nazw ostatniego pliku
  cmp byte ptr [eax], 55   ; = 'U'
  jnz LASTFILE_PRESENT (@8AB3h)
  cmp byte ptr [eax+1], 6e ; = 'n'
  jnz LASTFILE_PRESENT (@8AB3h)
  cmp byte ptr [eax+2], 74 ; = 't'
  jnz LASTFILE_PRESENT (@8AB3h)
  cmp byte ptr [eax+3], 69 ; = 'i'
  jnz LASTFILE_PRESENT (@8AB3h)
  cmp byte ptr [eax+4], 74 ; = 't'
  jnz LASTFILE_PRESENT (@8AB3h)
  cmp byte ptr [eax+5], 6c ; = 'l'
  jnz LASTFILE_PRESENT (@8AB3h)
  cmp byte ptr [eax+6], 65 ; = 'e'
  jnz LASTFILE_PRESENT (@8AB3h)
  cmp byte ptr [eax+7], 64 ; = 'd'
  jnz LASTFILE_PRESENT (@8AB3h)
  cmp byte ptr [eax+8], 00 ; bajt zero wskazuje koniec nazwy
  jnz LASTFILE_PRESENT (@8AB3h)

  jmp WRITE_DATA (@8AC3h)  ; JMPS w HIEW

LASTFILE_PRESENT (@8AB3h):

  push 4052d0              ; nazwa ostatniego pliku
  push 410a33              ; bufor, ktry rozpoczyna si zaraz po drugim '=' w szkielecie .INI
                           ; ktry jest ju w pamici
  call lstrcpyA

WRITE_DATA (@8AC3h):

  pop eax                  ; wrzucamy uchwyt pliku do eax...
  push eax                 ; ...i ponownie go zapisujemy

; ZAPISUJEMY TERAZ SZKIELET DO PLIKU. UYJEMY _lwrite, ALE MAMY MAY PROBLEM. NA MOIM PC, Z
; PRZYCZYN NA RAZIE NIEZNAYCH, NIE MOG ZAPISA JEDNORAZOWO WICEJ NI 7Fh BAJTW, A PONIEWA
; TEKS MA 92h BAJTW DUGOCI, TO UZYJEMY _lwrite 2 RAZY, RAZ DLA 7Fh BAJTW, DRUGI RAZ DLA
; POZOSTAYCH 13h
;
; UINT _lwrite(
;
;     HFILE hFile,	// uchwyt pliku
;     LPCSTR lpBuffer,	// wskanik na bufor z danymi do zapisu
;     UINT uBytes 	// ilo bajtw do zapisu
;    );



  push 7f                  ; pierwsze 7Fh bajtw szkieletu
  push 4109a1              ; pocztek bufora szkieletu
  push eax                 ; uchwyt pliku
  call _lwrite

  pop eax                  ; odtwarzamy uchwyt pliku do eax...
  push eax                 ; ...i znowu go zapisujemy

  push 13                  ; pozostae 13h bajtw szkieletu
  push 410a20              ; adres pocztkowy tych 13h bajtw
  push eax                 ; uchwyt pliku
  call _lwrite

; TERAZ MUSIMY SPRAWDZI DUGO NAZWY PLIKU I DOCZY T NAZW DO PLIKU .INI

  xor eax, eax             ; zerujemy licznik dugoci nazwy pliku
  mov edi, 410a33          ; lokacja pierwszej litery nazwy pliku

CHECK_LASTFILE_NAME_LENGHT (@8AEAh):

  cmp byte ptr [edi], 0
  jz ENDCHECK (@8AF3h)
  inc edi
  inc eax
  jmp CHECK_LASTFILE_NAME_LENGHT (@8AEAh); JMPS w HIEW

ENDCHECK (@8AF3h):

  mov byte ptr [edi], 0d   ; doczamy CR (carriage return) do acucha
  inc eax
  pop edi                  ; uchwyt pliku w edi
  push eax                 ; liczba bajtw do zapisania
  push 410a33              ; pocztek nazwy pliku
  push edi                 ; uchwyt pliku
  call _lwrite

  push edi                 ; uchwyt pliku
  call _lclose

  popad                    ; odtwarzamy rejestry

  call ExitProcess         ; wychodzimy z proga

  NOP
  NOP                      ; koniec tej czci kodu
  NOP

Musze tu co wyjani. Dlaczego uyem bezporedniego wywoania ExtProcess zamiast pozwoli programowi na wykonanie PostQuitMessage (aby uzyska bardziej "czyste" wyjcie) ?
Problem jest prosty...jak sprbujesz wyj przy pewnych konkretnych warunkach (w naszym przypadku wybierajc cokolwiek innego ni File/Exit) to otrzymasz bd. Powd jest dla mnie nadal nieznany, chocia podejrzewam e moe tu chodzi o zamiecenie stosu poprzedzajce jakie LoadStringA, a bd zdarza si podczas ledzenia kodu jdra. W sumie to wywoanie ExitProcess nie sprawia adnych problemw, jest po prostu "szybsz" metod wyjcia z procesu. Uycie WM_CLOSE zamiast WM_DESTROY wiele nie zmienia.

Od teraz, za kadym razem jak wyjdziesz i wrcisz do Hnotepad'a ostatnio wczytany plik (jeli nadal istnieje) i stan Word Wrapping zostan odtworzone. Czy to nie mie :)

___________________________________________________________

FAZA 5 : ELIMINACJA OGRANICZENIA DUGOCI OTWIERANEGO PLIKU
___________________________________________________________


Rozpoczynamy pita i ostatni cz tworzenia Hnotepad'a - eliminacj ograniczenia dugoci pliku otwieranego pod Hnotepad'em. Zrobienie tego jest do proste - zastpimy kontrol Edit (ktrej uywa Notepad) na RichEdit (ktrej uywa WordPad). Jak chcesz si dowiedzie wicej o nich to polecam lektur opisu API dotyczc "RichEdit".

W sumie byby to drobiazg, gdyby nie jedna sprawa : aby uy RichEdit potrzeba nam biblioteki
RichEdit32.dll, ktra nie jest obecna w pamici w chwili uruchomienia Notepad'a. eby zaadowa t bibliotek wystarczy uy funkcji API LoadLibraryA. ALE niestety (albo na szczcie - eby si nam nie nudzio :) Notepad nie ma tych funkcji wczonych do Funkcji Importowanych (atwo to sprawdzi W32Dasm po Imported Functions, albo HIEW - wystarczy zajrze do sekcji .IDATA).
Ale to nie problem - moglibymy uy GetProceAddress w celu otrzymania adresu innej funkcji (np. GetTimeFormatA) a potem uy tej API do dynamicznego otrzymania adresu funkcji
KERNEL32!LoadLibraryA w czasie uruchamiania proga...ale zrobimy inaczej : uyjemy fragmentu kodu wirusa napisanego przez Jacky Qwerty, autora wirusw z jednej z najlepszych virii groups na scenie (29A), ktry wykonuje operacj identyczna do GetProcAddress : skanuje zadana bibliotek (znajdujc si w pamici) w poszukiwaniu danej funkcji (w naszym przypadku LoadLibrary) i zwraca jej adres. Tyle na temat kodu, jak masz szczcie ;) to znajdziesz gdzie link do zip'a zawierajcego Hnotepad.exe, tego tuta oraz archiwum SCANNING_CODE.ZIP, gdzie oprcz inkludw znajdziesz te udokumentowany source dla funkcji skanujcej (KBASE.ASM) oraz plik nazwany przeze mnie COMPILLED_SCANNING_CODE, zawierajcy skompilowany kodzik, ktry moesz skopiowa i wklei bezporednio do swojego kodu (gdziekolwiek w .exe, poniewa wszystkie skoki s wzgldem jego wasnych offsetw, a powrt nastpuje poprzez RET). Funkcja ta akceptuje 2 parametry : UCHWYT biblioteki (lub lepiej adres od ktrego si zaczyna), w naszym przypadku kernel32.dll, oraz NAZW funkcji ktra chcemy odnale (dla nas LoadLibraryA). W celu skopiowania i wklejenia bajtw hex do naszego docelowego kodu, moemy uy progw UltraEdit32
lub Hex Workshop, po prostu potraktuj go jak zwyky tekst (tylko pamitaj, eby wklei go pod dobrym adresem ;).
Jak czego nie rozumiesz, to zajrzyj do czci 4 tego tuta i zorientuj si jak si ze mn skontaktowa.

Zobaczmy jak ten system bdzie dziaa w naszych warunkach : mamy wic drobny problem o ktrym wspominaem wczeniej : potrzebujemy trzy nowe zmienne, ale nie moemy zmodyfikowa tablicy acuchw, bo najmniejsza zmiana mogaby zniszczy zmiany poczynione w sekcji .RSRC. Jak wic to zrobi ? Procizna : zapiszemy nasze zmienne BEZPOREDNIO do pliku, w miejscu ktrego nie potrzebujemy (na kocu naszego pliku).

Po pierwsze musimy zaadowa bibliotek richedit32.dll, a nastpnie musimy zmieni "EDIT" na "RICHEDIT" aby otrzyma kontrol edycji zezwalajc na dostp do duych plikw.
Zaczynamy wic od "entry point" :

:00401000 55                      push ebp
:00401001 8BEC                    mov ebp, esp
:00401003 83EC44                  sub esp, 00000044
:00401006 56                      push esi

* Reference To: KERNEL32.GetCommandLineA, Ord:00BCh
                                  |
:00401007 FF1548734000            Call dword ptr [00407348]
:0040100D 8BF0                    mov esi, eax
:0040100F 8A00                    mov al, byte ptr [eax]
:00401011 3C22                    cmp al, 22
:00401013 7513                    jne 00401028


Nasze zmiany bd w linii nastpnej po GetCommandLineA - "mov esi,eax" pod adresem 40100d
(@40Dh). Nasz kod (wliczajc w to dodane NOPy zaczyna si od 40c116 (@8B16).
A wic robimy tak :

byo

:0040100D 8BF0                    mov esi, eax
:0040100F 8A00                    mov al, byte ptr [eax]
:00401011 3C22                    cmp al, 22
:00401013 7513                    jne 00401028

i jest

:0040100D E904B10000 ************ jmp 0040C116 ; --> DO NASZEGO KODU
:00401012 90                      nop
:00401013 7513                    jne 00401028


Musimy pamita, aby odtworzy 3 usunite instrukcje przed powrotem z naszego kodu w .text.
Wrmy do naszego problemu ze zmiennymi. Zostawmy troch wolnego miejsca w sekcji .RSRC i zapiszmy tam nasze zmienne. Biorc pod uwag, e bdziemy wkleja nasz kod skanujcy i pewien margines bezpieczestwa, odpalamy HIEW, przechodzimy w tryb HEX, idziemy do offsetu 8BD0h, i wpisujemy jako ASCII :

LoadLibraryA

Nastpnie idziemy do offsetu 8BE0h i wpisujemy :

Riched32.dll

No i mamy dwie zmienne, potrzeba nam jeszcze Kernel32.dll, ale ta powinna ;) by obecna w naszym kodzie, w sekcji .IDATA (jak sprawdzisz nazwy importowanych dll'i to znajdziesz tam Kernel32.dll). Naszym VA jest 4076E0. Zrbmy teraz may schemat naszych zmiennych, jakie mamy do dyspozycji. Tak wygldaj ich VA :

LoadLibraryA = 40C1D0 (@8BD0h)
Riched32.dll = 40C1E0 (@8BE0h)
KERNEL32.DLL = 4076E0 (@48E0h)

Uyjemy take nowego API :

GetModuleHandleA = call d,[40735c]

dostarczy nam ona UCHWYT do biblioteki KERNEL32.DLL, ktr bdziemy skanowa w poszukiwaniu
naszej API LoadLibraryA. Jak dziaa GetModuleHandleA ? Zwraca w EAX ADRES BAZOWY interesujcego nas moduu, czyli w sumie adres w pamici, gdzie si dana biblioteka zaczyna (a o tym nie wspomina twj opis API :)
A oto kodzik adujcy bibliotek :

Start (@8B16):

  pushad ; zapisujemy rejestry

  push 4076e0 ; "KERNEL32.DLL"
  call GetModuleHandleA ; zwraca uchwyt (adres bazowy) biblioteki Kernel32.dll

  push 40c1d0 ; "LoadLibraryA"
  push eax ; uchwyt do KERNEL32.DLL
* call SCANNING_CODE (@8B40); WYWOANIE KODU SKANUJCEGO : OPKOD E813000000

; WANE : KOD SKANUJCY ZWRACA ADRES ZADANEJ API, ALE W *ECX* A NIE W EAX

  push 40c1e0 ; "Riched32.dll"
  call ecx    ; WYWOANIE FUNKCJI LoadLibraryA

  popad ; odtworzenie rejestrw

  mov esi, eax  --\
mov al, [eax]   |____ Odtwarzamy kod zmieniony w .TEXT naszym skokiem
  cmp al, 22      |     
  jmp 401013    --/

SCANNING_CODE (@8B40):

  ; TUTAJ MUSISZ PO PROSTU WKLEI SKOMPILOWANY PLIK COMPILED_SCANNING_CODE.
  ; DOKADNY OPIS JEGO FUNKCJI ZNAJDZIESZ W KOMENTARZACH AUTORA W PLIKU RDOWYM (KBASE.ASM)
  ; W ARCHIWUM SCANNING_CODE.ZIP

Super, nasz kod jest gotowy...pozosta jeszcze jeden problem..musimy stworzy kontrole w trybie RichEdit a nie Edit, bo inaczej wszystkie te zmiany bd bezuyteczne. Aby zmodyfikowa kontrol, musimy znale wywoanie funkcji CreateWindowExA z parametrem "Edit" umieszczonym na stosie. String ten trzeba zastpi naszym - "RichEdit". Najpierw go stworzymy. W trybie HEX, pod HIEW edytujemy offset 8BF0 i wpisujemy :

RichEdit

VA tej zmiennej jest 40C1F0.

Aby znale interesujce nas odwoanie naley postawi puapk "BPX CreateWindowExA" i uruchomi Notepada. Trafisz tutaj :

:00402785 53                      push ebx
:00402786 A100604000              mov eax, dword ptr [00406000]
:0040278B 56                      push esi
:0040278C 6A0F                    push 0000000F
:0040278E 50                      push eax
:0040278F 6890010000              push 00000190
:00402794 6858020000              push 00000258
:00402799 53                      push ebx
:0040279A 53                      push ebx
:0040279B 6804013050              push 50300104
:004027A0 688C614000              push 0040618C

* Possible StringData Ref from Data Obj ->"Edit"
                                  |
:004027A5 6890614000              push 00406190
:004027AA 6800020000              push 00000200
:004027AF FFD7                    call edi ; WYWOANIE CreateWindowExA

Oki dokie... atwo zgadn co naley zmieni...w offsecie 1BA5h :

byo

:004027A5 6890614000              push 00406190 ; "Edit"

a teraz jest

:004027A5 68F0C14000              push 0040C1F0 ; "RichEdit"

Zostay nam ju tylko DWA drobiazgi do zmodyfikowania i bdziemy mogli zakoczy ten niesamowicie dugi tutorial :)

1) Jeli sprbujesz otworzy duy plik to zobaczysz naga pytajcego, czy chcesz uruchomi WordPad'a. Uyj BPX MessageBoxA i trafisz do miejsca sprawdzajcego  rozmiar pliku :

:00402E8B 81FEFFFF0000            cmp esi, 0000FFFF
:00402E91 0F8FEC010000            jg 00403083

Po prostu wynNOPuj rozkaz JG (@2291h) i problem z gowy.

2) Jeli otworzysz duy plik i prbujesz wczy Word Wrapping to otrzymasz wkurzajcy nag mwicy co w tym stylu : "cannot carry out the wraping because there's too much text in the file..." bla, bla, bla... Po prostu uyj BPX MessageBoxA i znajdziesz si tutaj :

:004014A2 85C0                    test eax, eax
:004014A4 7415                    je 004014BB ; NIECHCIANY SKOK
:004014A6 833D1860400001          cmp dword ptr [00406018], 00000001

Unikajc tego skoku (@8A4h) unikniesz rwnie NAG'a. No wic naley go wyNOPowa.

Woooh.....KONIEC !!!! :D
___________________________________________

CZʌ 4 : Znane bugi oraz kontakt z autorem
___________________________________________

Mam nadziej poprawi je w nastpnej wersji :

* KIEDY ZAMYKSZ PLIK, ZAWSZE POJAWIA SI OKIENKO "WANNA SAVE THE FILE?", NAWET GDY NIC W TYM PLIKU NIE ZMIENIAE. PODEJRZEWAM, E MA TO ZWIZEK Z KONTROL RICHEDIT'A. KADA POMOC MILE WIDZIANA.

* CZASAMI OTWARCIE DUEGO PLIKU *Z POZIOMU* NOTEPAD'A POWODUJE POJAWIENIE SI NAG'A "WANNA LOAD WORPAD?", NAWET GDY PRACUJESZ Z RICHEDIT, A NIE Z EDIT. NA 99% JEST DRUGA KONTROLA DUGOCI PLIKU KTREJ NIE UDAO MI SI ZNALE (MIAEM DROBNE PROBLEMY NA UNIWERKU).

Jeli znajdziesz jakiego buga, prosz daj mi zna. Moesz uczyni to przez email (neural_noise@hotmail.com) albo poszuka mnie na IRCu. Czsto jestem na kanale #cracking4newbies (EFnet), mj nick to NeuRaL_N. Jeli wysyassz emaila, podaj jakiego OSa uywasz.
______________________

CZʌ 5 : Pozdrowienia
______________________

Ten tutorial jest dedykowany :
- GEniusowi
- Kill3xx
- d4eMoN (aka Patr1zia ;P)
- {Suby}
- BrahzVooZ
- Anub|s
- Insanity (nie insa|nity :)
- +MaLaTTiA
- ytc
- Tin
- Carpathia
- DEZM
- +yoshi aka _y aka yman
- j/k
- razzia
- Fravia+
- +ORC
Guybrush (^__^ ;), Quequero, N6U5, Furb3t, courier^, guiz, Corn, Crackz, Ghiribizzo, Iczelion, sortof, Alor, Along3x, Yan Orel i innym przyjacioom z #crack-it, #cracking4newbies RingZ3r0 
ktrych w tej chwili nie mog sobie przypomnie :)

Pozdrowionka od eclipse dla:
- UEO
- Nixodus
- Raisen
- tomu

TURN OFF YOUR PC AND GO TO SLEEP NOW :D (bez komentarza...)

nara...

-NeuRaL_NoiSE 1999 for RingZ3r0, absolutnie NAJLEPSZY SITE POWICONY CRACKowi I REVERSE ENGINEERINGowi WE WOSZECH (http://ringzer0.cjb.net)
 