TeStON's ReverseMe #1 by FiNS

-=[ Wstp ]=-

Jaki czas temu ogldaem sobie crackmes4u w poszukiwaniu jakiego reverseme, do ktrego napisabym tuta. Tego typu progw duo tam nie byo, a do wszystkich poza TeStON's ReverseMe #1 tutor by ju o dziwo napiasny. Nie miaem praktycznie adnego wyboru celu,chyba e zmienibym zdanie i wzi jakie crackme. Wczeniej jednak ustaliem, e bd pisa tuta do reverseme. Dlaczego? Powiem ci, e reversowanie jest czym znacznie ciekawszym ni amanie crackmesw i przynosi wicej satysfakcji. Tak przynajmniej mi si wydaje, a ty bdziesz mg to oceni, jeli dotrwasz do koca tego tekstu :).

-=[ Zapoznanie z reverseme ]=-

Mamy doczone readme, wic czytamy i widzimy "It's not very simple.." - zobaczymy :), a dalej mamy zasady: nie moemy patchowa ani uywa loaderw, bo mamy jakie magiczne wrota :> - no no, ciekawie si zapowiada :), a dalej lista rzeczy do zrobienia. Zakadam, e znasz englisha przynajmniej w takim stopniu, e rozumiesz co tam pisze. Jak nie, to sobie zobacz w sowniku albo lepiej - zacznij uczy si englisha, bo jeszcze nie raz ci si przyda :). Troch tego jest, ale pewnie jako sobie poradzimy :). Przysza pora na pierwsze uruchomienie i... widzimy naga :P - zreszt chyba ci to nie dziwi, skoro przeczytae readme (jak jeszcze tego nie zrobie, to najwysza pora :P). Dajemy mu OK i naszym oczom ukazuje si okienko SexyPorno Dialup hehe :). Zamykamy krzyykiem i... gwno - mj obecnie ledwo ywy win tego nie wytrzyma i si wiechn :P. Lepiej zamknij tego proga w bardziej drastyczny sposb ni ja :)

-=[ Szukamy magicznej bramy ]=-

Pierwszym celem, jaki mamy okrelony w readme jest usunicie naga. No to bana co nie? Ta, tylko nie moemy patchowa ani uywa loaderw. Pozostaje nam poszukanie tej magicznej bramy, o ktrej pisze w readme :). adujemy reverseme do IDA i patrzymy od samego pocztku co prog robi. Od pocztku DialogFunction wszystko jest standardowo, nie ma adnych mieci tylko po kolei obsuga rnych wiadomoci:

.text:00401064          mov     edx, [ebp+arg_4]
.text:00401067          cmp     edx, 10h        ; WM_CLOSE
.text:0040106A          jnz     short loc_40109A

Jak pewnie wiesz, IDA moe pozamienia te 10h i nastpne na tekst WM_CLOSE i inne. Wystarczy, e klikniesz na to 10h prawym, w menu dasz "Use standard symbolic constant" i wybierzesz to, co trzeba - w tym wypadku to, co zaczyna si na WM, czyli jest to WM_CLOSE.

WM_CLOSE jest oczywicie wywoywane po klikniciu krzyyka do zamykania okna, wic zwykle po tym komunikacie wywoujemy API EndDialog albo w przypadku takiego prostego programu z jednym dialogiem mona by tu zrobi po prostu ExitProcess. W tym progu mamy natomiast jakie dziwne miecie:

.text:0040106C          call    GetCurrentProcess
.text:00401071          push    80h             ; dwPriorityClass
.text:00401076          push    eax             ; hProcess
.text:00401077          call    SetPriorityClass
.text:0040107C 
.text:0040107C loc_40107C:                      ; CODE XREF: DialogFunc
.text:0040107C          push    offset ThreadId ; lpThreadId
.text:00401081          push    0               ; dwCreationFlags
.text:00401083          push    0               ; lpParameter
.text:00401085          push    offset StartAddress ; lpStartAddress
.text:0040108A          push    0               ; dwStackSize
.text:0040108C          push    0               ; lpThreadAttributes
.text:0040108E          call    CreateThread
.text:00401093          jmp     short loc_40107C

Jak wida po klikniciu na krzyyk wykonuje si jaka nieskoczona i na dodatek niepotrzebna nam ptla. Dlatego te prog wiesza si, gdy chcemy go zamkn.

Idziemy dalej i mamy tu obsug nastpnej wiadomoci:

.text:0040109A          cmp     edx, 110h       ; WM_INITDIALOG
.text:004010A0          jnz     loc_401231

W tym momencie wspomn, e jeli wczeniej (przy WM_CLOSE) uye "Use standard symbolic constant" i jeli teraz klikniesz na 110h prawym, to w menu, nad t opcj IDA sama dodaa WM_INITDIALOG, co uatwia i przyspiesza zamian tych numerw na tekst - Oh My gOd ida INTELIGENT ;)

Dobra ale teraz przyjrzyjmy si bliej temu, co jest w WM_INITDIALOG, bo ja tu widz co bardzo ciekawego :)

.text:004010B0          mov     hWnd, eax
.text:004010B5          push    offset aMagicgate_bin  ; interesujca nazwa
.text:004010BA          call    GetFileAttributesA
.text:004010BF          shl     eax, 8
.text:004010C2          shr     eax, 8
.text:004010C5          cmp     eax, 0FFFFFFh
.text:004010CA          jz      loc_401161
.text:004010D0          push    0               ; hTemplateFile
.text:004010D2          push    80h             ; dwFlagsAndAttributes
.text:004010D7          push    3               ; dwCreationDisposition
.text:004010D9          push    0               ; lpSecurityAttributes
.text:004010DB          push    0               ; dwShareMode
.text:004010DD          push    80000000h       ; dwDesiredAccess
.text:004010E2          push    offset aMagicgate_bin ; lpFileName
.text:004010E7          call    CreateFileA
.text:004010EC          mov     hFile, eax
.text:004010F1          push    0               ; lpFileSizeHigh
.text:004010F3          push    hFile           ; hFile
.text:004010F9          call    GetFileSize
.text:004010FE          mov     nNumberOfBytesToRead, eax
.text:00401103          cmp     eax, 100h
.text:00401108          jnb     short loc_401156
.text:0040110A          shl     eax, 1
.text:0040110C          push    eax             ; dwBytes
.text:0040110D          push    0               ; uFlags
.text:0040110F          call    GlobalAlloc
.text:00401114          mov     lpBuffer, eax
.text:00401119          push    0               ; lpOverlapped
.text:0040111B          push    offset NumberOfBytesRead ; lpNumberOfBytesRead
.text:00401120          push    nNumberOfBytesToRead ; nNumberOfBytesToRead
.text:00401126          push    lpBuffer        ; lpBuffer
.text:0040112C          push    hFile           ; hFile
.text:00401132          call    ReadFile
.text:00401137          mov     esi, lpBuffer
.text:0040113D          mov     eax, [esi]
.text:0040113F          cmp     eax, 54534554h
.text:00401144          jnz     short loc_40114B
.text:00401146          add     esi, 4
.text:00401149          call    esi
.text:0040114B 
.text:0040114B loc_40114B:                      ; CODE XREF: DialogFunc
.text:0040114B          push    lpBuffer        ; hMem
.text:00401151          call    GlobalFree
.text:00401156 
.text:00401156 loc_401156:                      ; CODE XREF: DialogFunc
.text:00401156          push    hFile           ; hObject
.text:0040115C          call    CloseHandle

Czaisz co tu si dzieje? :) Pewnie ta, ale to jest tutorial i moim obowizkiem jest wszystko wyjani :) (takie teksty to wiecznie w teleturniejach sysz ;)).

Najpierw mamy GetFileAttributesA, czyli prog sprawdza jakie s atrybuty pliku magicgate.bin :>. Potem obcina 8 pierwszych bitw z eax (do ktrego zwracane s flagi oznaczajce atrybuty pliku magicgate.bin) i jeli w eax jest 00FFFFFFh, to skacze dalej, omijajc troch kodu. Jeli skok nie zostanie wykonany, to prog otwiera do odczytu plik magicgate.bin (API CreateFileA). Dalej sprawdzane jest, czy rozmiar tego pliku nie przekracza 100h czyli 256. Jeli plik nie jest mniejszy ni 256 bajtw, to wykonuje si skok, ktry omija troch dalszego kodu. Potem mamy alokacje pamici, zczytanie tego co jest w pliku magicgate.bin i ustawienie esi na adres, w ktrym s zczytane z pliku dane. Pierwsze 4 zczytane bajty s przenoszone do eax i porwnywane z 54534554h. Jeli eax nie jest rwne tej liczbie, to ominity zostaje call esi. Co natomiast mamy w esi? No wasnie to, co byo w pliku magicgate.bin :>.

Czaisz co to znaczy? W pliku magicgate.bin moemy napisa taki kod asm jaki nam si tylko spodoba i to co w nim bdzie wykona si :D Czyli moemy zrobi po prostu wszystko z tym progiem bez patchowania ani uywania loaderw! Moesz zrobi, e po klikniciu na przycisk w tym progu zrobi si np. format c: :), moesz doda jakie nowe przyciski do proga, nowe funkcjie, moesz z tego proga zrobi nawet jak super giere jak Jedi2 ;D (teoretycznie of course hehe :D). No moe troch mnie ponioso :) ale chodzi o to, e moliwoci s poprostu nieograniczone - wszystko zaley tylko od twojej wyobrani, chci i umiejtnoci :).

Teraz pomylmy co musimy zrobi, eby prog nie omin naszej magicznej bramy, czyli call esi. Po pierwsz, w katalogu z reverseme musi istnie plik magicgate.bin, w ktrym umiecimy potem nasz kod. To czy plik istnieje sprawdzane jest skokiem z adresu 004010CAh. Eax bdzie rwne 00FFFFFFh, gdy GetFileAttributes zwrci FFFFFFFFh, a zwraca to wtedy, gdy plik nie istnieje. Po drugie jego rozmiar nie moe by wikszy od 255 bajtw (sprawdzane pod adresem 00401108h). Po trzecie pierwsze 4 bajty pliku magicgate.bin musz by takie: 54455354h (54534554h od tyu), czyli plik musi si zaczyna sowem "TEST".

Wiemy ju co mamy zrobi, wic tworzymy ten plik magicgate.bin w katalogu z reverseme i wpisujemy do niego sowo TEST. Jeli teraz by odpali proga, to powinien si on wiechn. Dzieje si tak dlatego, e jak wejdzie w tego call'a, to nie moe ju wrci, bo nie ma tam ret'a. Otwrz sobie to magicgate.bin HIEW'em i po TEST dopisz C3h, czyli po prostu opcode ret'a. Teraz reverseme powinno uruchamia si ju normalnie, ale nic nowego nie robi, bo jeszcze adnego kodu nie dodalimy (no i dalej wiesza si przy wyjciu :P)...

-=[ Koniec gldzenia i do roboty :) ]=-

Zaczniemy od prostych celw, gdzie wystarcz jakie drobne zmiany kodu, a potem przejdziemy do rzeczy bardziej skomplikowanych, gdzie bdziemy sami pisa nowy kod i dodawa go do reverseme.

-=[ Cel 1. - Remove NagScreen ]=-

Nasze pierwsze i najprostrze zadanie to usunicie naga, ktry pojawia si na starcie. Ustawiamy puapk na MessageBoxA w SICE i odpalamy nasze reverseme. Mamy taki kod:

015F:00401161  6A10                PUSH      10
015F:00401163  68BC314000          PUSH      004031BC
015F:00401168  68B0314000          PUSH      004031B0
015F:0040116D  FF7508              PUSH      DWORD PTR [EBP+08]
015F:00401170  E81B030000          CALL      USER32!MessageBoxA
015F:00401175  B81B040000          MOV       EAX,0000041B

Zanim zaczn robot, to powiem jeszcze, e pierwsze zadanie opisz moliwie jak najdokadniej, poniewa kolejne etapy bd rozwizywane w podobny sposb.

Jeli chcemy, eby nag si nie pokazywa, musimy wrzuci JMP 00401175 pod adres 00401161. Chcemy pozna opcody tej instrukcji, wic piszemy w SICE "a 401161", a potem piszemy "jmp 401175". Push zmienia si nam w nasz instrukcj jmp. Obok widzisz jej opcody, czyli EB12. Jeeli nie widzisz opcodw, to se napisz w SICE "code on".

Teraz kiedy wiemy gdzie ma by zmiana i wiemy jakie bajty mamy wstawi, otwieramy HIEW'em nasz plik magicgate.bin i ustawiamy widok na Decode (F4, a potem F3). Zmieniamy jeszcze widok kodu na 32 bitowy (ctrl+F1). Ustawiamy si na naszej ostatniej instrukcji (ret), dajemy F3 aby j zmieni, potem dajemy enter i piszemy now instrukcj. Ma to by co takiego: "mov word ptr [00401161], 012EBh". No dobra, ale nie moesz tego napisa tak, jak podaem, bo HIEW tego nie rozpozna. Musimy napisa co takiego: "mov w,[401161], 012EB". Po tym dajemy enter i piszemy jeszcze instrukcj ret, ktr wczeniej usunlimy. Mam nadziej, e rozumiesz dlaczego dalimy tu takie instrukcje, a nie inne. Bajty do wstawienia podajemy od koca, poniewa przy ich wstawianiu, s one odwracane. Zapisujemy nasz plik magicgate.bin (F9). W tej chwili twj plik powinien wyglda pod HIEW'em tak:

00000000: 54                     push    esp
00000001: 45                     inc     ebp
00000002: 53                     push    ebx
00000003: 54                     push    esp
00000004: 66C70561114000EB12     mov     w,[000401161],012EB
0000000D: C3                     retn

Najlepiej sprawd dokadnie, czy masz wszystkie opcody dokadnie takie same. Jak nie masz, to znaczy, e co le zrobie (moe np. pisae to jako kod 16 bitowy?) i musisz dokadnie sprawdi co le zrobie. Dalej ju nie bd si rozpisywa z takimi pierdoami, wic wane, eby teraz wszystko czai.

Wyjd z HIEW'a i odpal reverseme. Jeli wszystko dobrze zrobie, to nag si nie pokaza :). Moesz zamkn proga i jedziemy dalej :). Pamitaj, e dopki nie naprawimy buga z wyczaniem, lepiej wycza go przez ctrl+alt+del albo w inny brutalny sposb... :)

-=[ Cel 2. - There are a "bug ;>" when dialog are closing.. you must do it working ]=-

W IDA widzimy to:

.text:00401067          cmp     edx, WM_CLOSE
.text:0040106A          jnz     short loc_40109A
.text:0040106C          call    GetCurrentProcess
.text:00401071          push    80h             ; dwPriorityClass
.text:00401076          push    eax             ; hProcess
.text:00401077          call    SetPriorityClass
.text:0040107C 
.text:0040107C loc_40107C:                      ; CODE XREF: DialogFunc
.text:0040107C          push    offset ThreadId ; lpThreadId
.text:00401081          push    0               ; dwCreationFlags
.text:00401083          push    0               ; lpParameter
.text:00401085          push    offset StartAddress ; lpStartAddress
.text:0040108A          push    0               ; dwStackSize
.text:0040108C          push    0               ; lpThreadAttributes
.text:0040108E          call    CreateThread
.text:00401093          jmp     short loc_40107C

Mamy tu WM_CLOSE, po ktrym crackme wcale nie jest zamykane, tylko mamy ptelke w nieskoczono :P. Aby reverseme dobrze si wyczao, moemy pod adresem 0040106Ch zrobi skok do ExitProcess, ktry mamy tu:

.text:00401022          push    0               ; uExitCode
.text:00401024          call    ExitProcess

Czyli znowu otwieramy HIEW'em plik magicgate.bin i dodajemy nowy kod w ten sam sposb, jak robilimy to w przypadku usuwania naga. Nasza nowa linijka pod HIEW'em powinna wyglda tak: "mov w,[40106C], 0B4EB". Skd wiem, e ma by EBB4h? No co moesz to sprawdzi w SICE zmieniajc kod proga tak samo, jak przy nagu, albo moesz to wyliczy:

40106Ch - 401022h = 4Ah  ;rnica midzy dwoma adresami
FEh - 4Ah = B4h

Adres do ktrego skaczemy jest wczeniej, ni ten z ktrego skaczemy, wic musimy go odj od FEh czyli 100h-2h. Odejmujemy jeszcze te 2, bo instrukcja typu short jump zajmuje 2 bajty.

Zapisujemy magicgate.bin i odpalamy proga. Nie mamy naga i reverseme powinno si wycza prawidowo :).

-=[ Cel 3. - Make flat scrollbar of listview, and fullrow selection.. ]=-

Pora bliej przyjrze si temu, co pokazuje nam IDA. Zaraz po msgboxie mamy co takiego:

.text:00401175          mov     eax, 41Bh
.text:0040117A          push    eax             ; lParam
.text:0040117B          push    0               ; wParam
.text:0040117D          push    1036h           ; Msg
.text:00401182          push    hWnd            ; hWnd
.text:00401188          call    SendMessageA

1036h to LVM_SETEXTENDEDLISTVIEWSTYLE. Mona to znale przegldajc windows.inc, ale trzeba si troch wysili, bo tam jest to zapisane jako: LVM_SETEXTENDEDLISTVIEWSTYLE = LVM_FIRST + 54, take jak kto ma jaki lepszy spis, gdzie od razu mamy co w stylu LVM_SETEXTENDEDLISTVIEWSTYLE = 1036h, to niech mi zaraz le na maila, bo ja takiego nie posiadam a chtnie si zaopatrz :)

lParam, czyli 41Bh to kombinacja odpowiednich flag, odpowiedzialnych za wygld listy. My mamy zrobi "flat scrollbar" i "fullrow selection", wic szukamy sobie tego w windows.inc i mamy:

LVS_EX_FLATSB = 100h
LVS_EX_FULLROWSELECT = 20h

Teraz dodajemy to do 41Bh i mamy: 41Bh+100h+20h=53Bh. Pod adresem 00401175h musimy zmieni instrukcj "mov eax, 41Bh" na "mov eax, 53Bh", czyli musimy tam wrzuci bajty 3B05h. Znowu odpalamy magicgate.bin HIEW'em i analogicznie do poprzednich przykadw dodajemy now instrukcj: "mov w,[401176], 053B".

-=[ Cel 4. - All processes must be showed on listview ]=-

Moe nie zauwaye tego wczeniej, ale reverseme nie wywielta wszystkich uruchomionych procesw. Obojtnie ile progsw mamy odpalonych, zawsze na licie jest ich tylko 10. Pora przeanalizowa sobie dalszy kod. Nie bd tu wszystkiego wkleja, bo bym musia wklei poowe kodu, a nie widz w tym adnego sensu. IDA pokazuje nam 3 SendMessageA, a wysyana wiadomo to 101Bh, czyli LVM_INSERTCOLUMN. Ten kawaek po prostu tworzy 3 kolumny, ktre widzimy w progu ("Process", "ID" i "Path"). Dalej mamy calla do procki pod adresem 401252h. Ta caa procedura jest odpowiedzialna za to, co wida na licie. Na razie nie bdziemy si w to za bardzo wgbia.

Wiadomoci wysyane przez SendMessageA:
1007h - LVM_INSERTITEM
1006h - LVM_SETITEM

Skoro prog uywa tu takich funkcji, to mona si domyle, e wanie tu sprawdza jakie procesy s uruchomione w systemie i te tutaj dodaje te informacje do ListView. Pod koniec tej procedurki mamy takie co:

.text:004013CB          push    offset dword_403000
.text:004013D0          push    hObject
.text:004013D6          call    Process32Next
.text:004013DB          call    GetLastError
.text:004013E0          cmp     dword_403173, 0Ah
.text:004013E7          jnb     short locret_4013FD
.text:004013E9          cmp     eax, 12h
.text:004013EC          jnz     loc_4012ED
.text:004013F2 
.text:004013F2 loc_4013F2:                      ; CODE XREF: sub_401252
.text:004013F2          push    hObject         ; hObject
.text:004013F8          call    CloseHandle
.text:004013FD 
.text:004013FD locret_4013FD:                   ; CODE XREF: sub_401252
.text:004013FD                                  ; sub_401252
.text:004013FD          leave
.text:004013FE          retn

Pod adresem 004013E0h mamy porwnanie jakiego dworda z 0Ah=10d i jeli dword wikszy lub rwny, to nastpuje skok do reta i mamy koniec procki. Wczeniej ustalilimy, e reverseme pokazuje tylko 10 procesw no i ju wiemy dlaczego. Moemy si jeszcze upewni szukajc gdzie zmienia si ten dword i mamy:

.text:00401303          mov     ecx, dword_403173
.text:00401309          inc     ecx
.text:0040130A          mov     dword_403173, ecx

Ten kawaek wykonuje si przy dodawaniu nowego elementu do listy, czyli po prostu zlicza ile mamy ju wywietlonych wszystkich elementw. Wystarczy teraz pozby si tego porwania i skoku. Nie bdziemy nopowa, bo musielibymy wstawia wicej kodu. Zamiast nopw lepiej bdzie zrobi jumpa do adresu 4013E9h, czyli trzeba wrzuci bajty 07EBh pod adres 4031E0h. Tak samo jak w poprzednich przypadkach dodajemy now linijk kodu za pomoc HIEW'a. Bdzie ona wyglda tak: "mov w,[4013E0], 07EB".

-=[ Cel 5. - Make listing like this... ]=-

 ____________________________________________________ 
 | Process      |         ID | Path                 |
 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^|
 | FILE.EXE     | 0xFFFF67FA | C:\Program Files\... |
 | GG.EXE       | 0xFFFF67FC | C:\GG\               |
 | ...          | ...        | ...                  |
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

No dobra, do tej pory wszystko byo banalne. Wystarczyo tylko zmienia ze 2 bajty i ju kolejne cele byy zaatwione. Teraz jednak wyglda no to, e ju nie bdzie tak prosto. Obecnie reverseme pokazuje info o procesach mniej wicej tak:

 ____________________________________________________ 
 | Process      |         ID | Path                 |
 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^|
 | C:\GG\GG.EXE | 0xFFFF67FC |                      |
 | ...          | ...        | ...                  |
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Czyli w Process mamy i ciek i nazw samego procesu. Musimy to jako rozdziela na dwie kolumny. ID jest wywietlane tak jak powinno by, wic t kolumne mamy z gowy.

Pora dokadniej ogldn sobie kod procedurki z adresu 401252h pod SoftICE. W IDA wida, e na poczatku procki mamy wywoanie funkcji API GetModuleHandle, wic zakadamy sobie puapk na t API w SICE i odpalamy reverseme. Ponaciskaj sobie troch F11 a znajdziesz si w gwnym kodzie proga, pod adresem 401262h w naszej procedurce. Na pocztku nie mamy nic ciekawego. Jest tu tylko pobieranie adresw funkcji CreateToolhelp32Snapshot itp., wic idziemy sobie dalej po kodzie (F10). Jak ju dojdziemy do wywoania funkcji Process32First pod adresem 004012D8h, to zaczniemy sobie troszk analizowa :)

.text:004012CD          push    offset dword_403000
.text:004012D2          push    hObject
.text:004012D8          call    Process32First

Funkcja Process32First uzupenia nam struktur PROCESSENTRY32, ktra znajduje si pod adresem 00403000h. Struktura ta zawiera informacje takie jak cieka i nazwa procesu, jego ID itp.

.text:004012DD          xor     ecx, ecx
.text:004012DF          mov     dword_403173, ecx
.text:004012E5          or      eax, eax
.text:004012E7          jz      loc_4013F2
.text:004012ED 
.text:004012ED loc_4012ED:                      ; CODE XREF: sub_401252
.text:004012ED          mov     [ebp+lParam], 7
.text:004012F4          push    dword_403173
.text:004012FA          pop     [ebp+var_24]
.text:004012FD          push    dword_403173
.text:00401303          mov     ecx, dword_403173
.text:00401309          inc     ecx
.text:0040130A          mov     dword_403173, ecx

Wida tu licznik, o ktrym wspomniaem wczeniej. Natomiast niej zaczyna si wkadanie informacji do ListView. Cakiem prawdopodobne, e jeszcze tu do SoftICE powrcimy, wic piszemy sobie "bpx eip", eby potem od razu si tu zapa. Ale po zastawieniu wyczamy ten breakpoint, gdy narazie nie bdzie potrzebny, a SICE bdzie tylko niepotrzebnie przerywa. Wyczamy te puapk na GetModuleHandleA, ktra prawdopodobnie nie bdzie ju potrzebna.

.text:00401310          pop     [ebp+var_8]
.text:00401313          mov     [ebp+var_20], 0
.text:0040131A          mov     [ebp+var_14], offset unk_403024
.text:00401321          mov     [ebp+var_C], 0
.text:00401328          lea     eax, [ebp+lParam]
.text:0040132B          push    eax             ; lParam
.text:0040132C          push    0               ; wParam
.text:0040132E          push    1007h           ; Msg (LVM_INSERTITEM)
.text:00401333          push    hWnd            ; hWnd
.text:00401339          call    SendMessageA

lParam wskazuje tu na struktur LV_ITEM, w ktrej zawarte s informacje o elemencie jaki ma zosta dodany do listy. Struktura ta uzupeniana jest przed wywolaniem SendMessageA za pomoc tych wszystkich mov [ebp+...],... Warto by sobie zobaczy co tam do tej struktury jest wsadzane. Jestemy w SICE pod adresem 40131Ah i piszemy sobie "d 403024". Jak si pewnie domylasz (lub nie :)) pod tym adresem mamy stringa, ktry widzimy w reverseme, w kolumnie Process. Zmie go sobie w SICE i potem zobaczymy, czy rzeczywicie w reverseme bdzie wida to na co zmienilimy. Po zmianie idziemy dalej (F10).

.text:0040133E          mov     [ebp+lParam], 1
.text:00401345          inc     [ebp+var_20]
.text:00401348          mov     eax, dword_403008
.text:0040134D          push    eax
.text:0040134E          push    offset a0x08x   ; "0x%08X"
.text:00401353          push    offset unk_4031D2
.text:00401358          call    wsprintfA

Przerabianie dworda na string.

.text:0040135D          add     esp, 0Ch
.text:00401360          lea     eax, ds:4031D2h
.text:00401366          mov     [ebp+var_14], eax

Piszemy "d eax" i oczywicie widzimy stringa, ktrego w reverseme mamy w kolumnie ID.

.text:00401369          lea     eax, [ebp+lParam]
.text:0040136C          push    eax             ; lParam
.text:0040136D          push    0               ; wParam
.text:0040136F          push    1006h           ; Msg
.text:00401374          push    hWnd            ; hWnd
.text:0040137A          call    SendMessageA

Tu, przez SendMessageA ten string jest wstawiany do kolumny ID.

.text:0040137F          mov     [ebp+lParam], 1
.text:00401386          inc     [ebp+var_20]
.text:00401389          lea     edi, ds:4031D2h
.text:0040138F          xor     eax, eax
.text:00401391          mov     ecx, 0FFh
.text:00401396          rep stosb
.text:00401398          nop
;...tu jest ze 20 nopw - TeStON zostawi nam troch miejsca :)...
.text:004013AB          nop
.text:004013AC          lea     eax, ds:4031D2h
.text:004013B2          mov     [ebp+var_14], eax
.text:004013B5          lea     eax, [ebp+lParam]
.text:004013B8          push    eax             ; lParam
.text:004013B9          push    1               ; wParam
.text:004013BB          push    1006h           ; Msg
.text:004013C0          push    hWnd            ; hWnd
.text:004013C6          call    SendMessageA

Bardzo podobny fragment kodu do tego wczeniejszego, ktry wstawia string do kolumny z ID. Hmm... jak na moje oko, to bdzie wstawia tekst do kolumny Path. W 4031D2h nic nie ma, wic te nic nie widzimy w tej kolumnie. Przed wywoaniem SendMessageA napiszmy sobie co w SICE pod adres 4031D2h i zobaczymy co si stanie.

.text:004013CB          push    offset dword_403000
.text:004013D0          push    hObject
.text:004013D6          call    Process32Next
.text:004013DB          call    GetLastError
.text:004013E0          cmp     dword_403173, 0Ah
.text:004013E7          jnb     short locret_4013FD
.text:004013E9          cmp     eax, 12h
.text:004013EC          jnz     loc_4012ED

Cay ten kod wyej bdzie powtarzany tyle razy, eby obsuy wszystkie procesy aktywne w systemie i o wszystkich tych procesach umieci informacje w kolumnach listy. My nie bdziemy znowu tego samego kodu oglda, wic moemy waln F5 i pozwoli programowi normalnie si wykona.

.text:004013F2 
.text:004013F2 loc_4013F2:                      ; CODE XREF: sub_401252
.text:004013F2          push    hObject         ; hObject
.text:004013F8          call    CloseHandle
.text:004013FD 
.text:004013FD locret_4013FD:                   ; CODE XREF: sub_401252
.text:004013FD                                  ; sub_401252
.text:004013FD          leave
.text:004013FE          retn

Tak jak mona si byo domyli, prog pokaza nam w kolumnach Process i Path taki tekst, jaki wpisalimy w SICE pod adresami 403024h i 4031D2h. Pozostaje tylko napisa kod, ktry bdzie nam jako rozdziela cay ten string pod adresem 403024h wygldajcy np. tak: "C:\GG\GG.EXE" na dwa stringi wygldajce np. tak: "C:\GG\" - Path i "GG.EXE" - Process.

Zamykamy reverseme, w SICE wczamy zastawion wczeniej przez "bpx eip" puapk i spowrotem odpalamy proga. SoftICE oczywicie przerwa nam i jestemy w tych okolicach:

0177:004012FA  8F45DC              POP       DWORD PTR [EBP-24]
0177:004012FD  FF3573314000        PUSH      DWORD PTR [00403173]
0177:00401303  8B0D73314000        MOV       ECX,[00403173]
0177:00401309  41                  INC       ECX
0177:0040130A  890D73314000        MOV       [00403173],ECX
0177:00401310  8F45F8              POP       DWORD PTR [EBP-08]
0177:00401313  C745E000000000      MOV       DWORD PTR [EBP-20],00000000
0177:0040131A  C745EC24304000      MOV       DWORD PTR [EBP-14],00403024
0177:00401321  C745F400000000      MOV       DWORD PTR [EBP-0C],00000000
0177:00401328  8D45D8              LEA       EAX,[EBP-28]
0177:0040132B  50                  PUSH      EAX
0177:0040132C  6A00                PUSH      00
0177:0040132E  6807100000          PUSH      00001007
0177:00401333  FF356F314000        PUSH      DWORD PTR [0040316F]
0177:00401339  E858010000          CALL      USER32!SendMessageA

Kluczowym momentem jest instrukcja pod adresem 0040131Ah. To co zostanie woone do [ebp-14] bdzie wywietlone w kolumnie Process. Musimy tu co pozmienia. Trzeba jeszcze znale sobie troch miejsca na nasz nowy kod. Przewijamy w SICE okno z kodem i widzimy, e od adresu 4014AEh mamy sporo zer, czyli wolnego miejsca, w ktrym moemy doda kod. Majc w SICE podwietlon linijk pod adresem 40131Ah, piszemy komend "a", eby zmieni instrukcj mov... na inn. Musimy tu wstawi calla do tego pustego miejsca, czyli piszemy instrukcj: "call 4014AEh" i walimy enter. Widzimy, e kod reverseme si troch popieprzy, bo instrukcja call zajmuje mniej bajtw ni poprzednia instrukcja mov. Aby wszystko z kodem byo ok dodajemy jeszcze dwa nopy za callem. Teraz F8, eby do niego wej i zabieramy si za dodawanie kodu. Ma on znale miejsce w stringu typu "C:\GG\GG.EXE", w ktrym zaczyna si nazwa procesu, czyli "GG.EXE". Miejsce to moemy znale szukaj ostatniego "\" w stringu. Ja zrobiem do tego taki kod:

0177:004014AE  B824304000          MOV       EAX,00403024
0177:004014B3  40                  INC       EAX
0177:004014B4  803800              CMP       BYTE PTR [EAX],00
0177:004014B7  75FA                JNZ       004014B3
0177:004014B9  48                  DEC       EAX
0177:004014BA  80385C              CMP       BYTE PTR [EAX],5C
0177:004014BD  75FA                JNZ       004014B9
0177:004014BF  40                  INC       EAX
0177:004014C0  8945EC              MOV       [EBP-14],EAX
0177:004014C3  C3                  RET

Na pocztku wrzucamy adres ze stringiem typu "C:\GG\GG.EXE" do eax. Poniej zwikszamy eax a dojdziemy do koca stringa. Nastpnie zmniejszamy eax a znajdziemy znak "\". Po tym jeszcze inkrementujemy eax i kopiujemy adres z eax do struktury LV_ITEM. Aby SICE wstawi instrukcj "mov [ebp-14], eax" uywajc "a", musisz mu t instrukcj napisa tak: "mov dword ptr [ebp-14], eax". Jak nie napiszesz "dword ptr", to SICE zmieni ci eax na ax. Na kocu procki dajemy ret, aby wrci z calla. Tak teraz sobie myle, e warto by to znalezione eax gdzie zapisywa, bo potem ten adres bdzie potrzebny przy ustawianiu kolumny Path i nie musielibymy go na nowo szuka. Po wyjciu z nowo dodanej procedurki mamy 2 nopy, ktre przed chwil dodalimy aby kod si nie pieprzy. No wic zmieniamy komend "a" jednego nopa na push eax, aby szukany adres by zapisywany na stosie.

0177:0040131A  E88F010000          CALL      004014AE                           
0177:0040131F  50                  PUSH      EAX                                
0177:00401320  90                  NOP                                          

Naciskajc F10, wdrujemy sobie dalej po kodzie, a dojdziemy do miejsca, gdzie mamy ze 20 nopw. Po tych nopach uzupeniana jest znowu struktura LV_ITEM, ktra jest tu uywana do ustawiania kolumny Path. No to pora znowu dorzuci jaki kod od siebie :). Autor by tak miy, e zrobi nam tu troch miejsca, wic to wykorzystamy i zapenimy nopy. Potrzebny kod wyglda tak:

0177:004013A8  58                  POP       EAX
0177:004013A9  C60000              MOV       BYTE PTR [EAX],00
0177:004013AC  8D0524304000        LEA       EAX,[00403024]

Zdejmujemy zapisany wczeniej adres ze stosu i wrzucamy tam 0, aby ze stringu pod adresem 00403024h wyodrbni sam ciek do pliku. Nastpnie do eax wrzucamy adres stringa. Moemy wyczy wyszstkie breakpointy i puci proga wolno. Jak nic nie spieprzye, to lista powinna teraz wyglda tak, jak miaa wyglda :). Teraz musimy jeszcze odpowiednio wyedytowa plik magicgate.bin za pomoc HIEW'a. Czyli bdzie kilka nowych "mov d,[adres], bajty" :P. Troch zwalenie to robi w kko, zwaszcza teraz, kiedy dodalimy duo kodu. No ale trudno, zrobimy to jeszcze raz, ale ju ostatni, potem opracuj lepszy sposb :). Wszystkie instrukcje, ktre zmienialimy wypisywaem tu razem z opcodami, wic nie musisz znowu patrze do SICE co si zmieniao. No to HIEW w ap i dochodz nam instrukcje:

mov d,[40131A], 000018FE8
mov d,[40131E], 0C7905000
mov d,[4014AE], 0403024B8
mov d,[4014B2], 038804000
mov d,[4014B6], 048FA7500
mov d,[4014BA], 0755C3880
mov d,[4014BE], 0458940FA
mov w,[4014C2], 0C3EC
mov d,[401398], 00000C658
mov w,[4013AE], 03024

Jako e mam dobre serducho ;), to do tekstu doczam plik magicgate_po_cel5.bin, ktry zawiera w sobie wszystko, co do tej pory zrobilimy. Moesz go sobie przekopiowa do katalogu z reverseme i zmieni nazw na magicgate.bin, a bdziesz mia to przepisywanie z gowy.

Cel 5. za nami, ale teraz pojawia si pewien problem. Nasz plik magicgate.bin zajmuje ju 139 bajtw, a przecie mamy ograniczenie. Jeli plik magicgate.bin bdzie wikszy ni 255 bajtw, to reverseme bdzie si zachowywa tak, jakby tego pliku w ogle nie byo! Hmm... no to przesrane, bo te cele, ktre nam zostay wymagaj znacznie wikszej iloci kodu...

-=[ magiccode.bin, czyli rozwizujemy problem :) ]=-

No, moe po tytule ju domylasz si co chc zrobi :). Skoro nie moemy zmieci naszego kodu w magicgate.bin, to wrzucimy tam co podobnego do tego kodu, ktry wczytywa nam dane z pliku magicgate.bin. Tylko my bdziemy sobie wczytywa np. plik magiccode.bin i w tym pliku bdziemy rozwizywa kolejne zadania z reverseme.

Czyli za pomoc HIEW'a bdziemy pisa kod w magicgate.bin podobny do tego, ktry w reverseme zaczyna si pod adresem 004010D0h - pocztek wywoywania funkcji CreateFileA. Kod ten pokazywaem ju na pocztku tekstu przy okazji szukania magicznej bramy :). Zanim zabierzemy si za przepisywanie tego kodu (bo praktycznie to niewiele w tym zmienimy) do magicgate.bin musimy zastanowi si nad paroma drobnymi przeszkodami...

.text:004010E2          push    offset aMagicgate_bin ; lpFileName

Zamiast tego bdziemy musieli tu da offset do stringa z napisem np. magiccode.bin, a reverseme nie ma takiego stringa w sekcji .data. Ja wanie dlatego wybraem tak nazw pliku, gdy ten string bdzie nam atwo wrzuci do sekcji danych. Po prostu w stringu "magicgate.bin" zamienimy sobie litery "gate" na "code" - jedna instrukcja i po robocie :). Potrzebujemy jeszcze tylko adres pod ktrym ten string si znajduje. Sprawdzamy to w IDA i widzimy e jest tu:

.data:0040318B aMagicgate_bin  db 'magicgate.bin',0

Druga sprawa, to same wywoania funkcji API. Chyba jest oczywiste, e w HIEW'ie nie bdziemy sobie mogli napisa po prostu "call nazwa_funkcji_api". Aby wywoa funkcj API musimy zna adres tej funkcji. Adresy wida adnie pod IDA. Do naszego kodu potrzebujemy tych:

.text:00401406 ; [00000006 BYTES: COLLAPSED FUNCTION CreateFileA.
.text:00401442 ; [00000006 BYTES: COLLAPSED FUNCTION GlobalAlloc.
.text:00401460 ; [00000006 BYTES: COLLAPSED FUNCTION ReadFile.
.text:00401448 ; [00000006 BYTES: COLLAPSED FUNCTION GlobalFree.
.text:00401400 ; [00000006 BYTES: COLLAPSED FUNCTION CloseHandle.

Otwarcie pliku, alokowanie pamici, czytanie kodu z pliku, uwolnienie zaalokowanej pamici i zamknicie pliku. :) Bdziemy jeszcze potrzebowa jakiego miejsca dla zapisania jakich dwordw, np. hFile po wywoaniu CreateFileA, ale to ju nie bdzie wikszy problem i szybko sobie z tym poradzimy... ;)

No to odpalamy magicgate.bin HIEW'em i wedug tego kodu z reverseme piszemy nasz kod. Zaczynamy pod offsetem 08Ah.

push 0
push 00000080

Uwaga! HIEW normalnie wstawia tu "push 080", co ma inny opcod ni to co napisaem wyej. Opcode "push 00000080" to 6880000000h, a opcode "push 080" to 6A80h. Jeeli dalibymy tak jak proponuje HIEW, to okazaoby si, e potem nie bdzie to dziaa na win2k. Jeli mielibymy "push 080", to na stos w rzeczywistoci kadziona jest warto FFFFFF80h. Win98 jeszcze to toleruje i nie robi adnych problemw ale w win2k na stos musi i koniecznie 00000080h. Co ciekawe i najgorsze, okazuje si, e na win2k CreateFile wywouje si bez problemw gdy na stos idzie FFFFFF80h i poprawnie zwraca uchwyt do pliku, ale potem przy uywaniu ReadFile zwraca bd, przez co sugeruje, e problem znajduje si w ReadFile, a nie tak, jak to jest w rzeczywistoci w CreateFile. Mwic krtko - microshit znowu co spieprzy :P

push 3
push 0
push 0
push 80000000

Tu HIEW znowu odstawia mi jakie szopki i robi zamiast tego push 0 :P, ale jak napiszesz zamiast tego push 70000000, to HIEW wstawi to prawidowo i wtedy moesz to sobie rcznie po opcodach poprawi. Teraz ma by push offset nazwapliku. Najpierw musimy sobie zrobi string magiccode.bin:

mov d,[403190], 065646F63

Wczeniej sprawdzilimy w IDA, e string magicgate.bin znajduje si pod adresem 0040318Bh. Kawaek "magic" zostawiamy w spokoju, a zmieniamy tylko "gate", dlatego 40318Bh+5=403190h (5 liter). 065646F63h to "edoc". Przy wstawianiu do .data zostanie to odwrcone na "code". Mamy ju string "magiccode.bin", wic idziemy dalej.

push 40318B
mov eax, 401406 ; CreateFileA
call eax
cmp eax, -1
jne 0B5 ; skok za ret, 0B2+3 (0B2 to obecny offset)
ret

Teraz po ret ma by mov hFile, eax. Potrzebujemy jakiego miejsca, eby zapisa eax. Ja to zrobi tak:

mov [esi], eax

Ostatnio esi byo zapisywane po ReadFile :) i jest tam adres, gdzie zaczyna si kod magicgate.bin :D Hehe czyli bdziemy sobie zapisywa dane na kodzie. Przez to troch si nam ten kod popieprzy, aleeee: (1) jest on wykonywany tylko jeden raz, (2) tu gdzie jestemy, ten kod jest daleko za nami i by ju wykonany, (3) ten fragment kodu nie bdzie ju do niczego potrzebny, (4) niedugo cay ten kod zostanie zniszczony przez GlobalFree. Take nie mamy ani jednego powodu, eby przejmowa si tym naszym starym kodem i moemy go sobie troch poniszczy ;D.

No doba, idziemy dalej :)

push 800 ; 800h = 2048 - 2KB powinno stykn
push 0
mov eax, 401442 ; GlobalAlloc
call eax
mov [esi+4], eax ; znowu troch naszego kodu rozwalimy :)

push 0
push 403177 ; tu zapisujemy ilo odczytanych bajtw
push 800
push eax
push [esi]
mov eax, 401460 ; ReadFile
call eax

Skd wziem adres 00403177h? Ten sam adres jest uywany przy ReadFile do magicgate.bin, a ta warto na pewno nie bdzie ju do niczego potrzebna, wic moemy sobie tego uy.

mov eax, [esi+4]
call eax ; skok do kodu odczytanego z magiccode.bin

push [esi+4]
mov eax, 401448 ; GlobalFree
call eax
push [esi]
mov eax, 401400 ; CloseHandle
call eax
ret

No i koniec. Jeli chodzi o magicgate.bin, to ju wicej nie bdziemy tu niczego zmienia. Zapisz zmiany i moesz wyj z HIEW'a. Jak robie wszystko tak samo jak ja, to magicgate.bin zajmuje ci 250 bajtw. Dobrze, e zmiecilimy si w limicie :). Teraz jeszcze utwrz sobie plik magiccode.bin i wrzu tam ret'a, eby reverseme ci si nie wywalio przy uruchomieniu.

-=[ Cel 6. - Change dialog caption to "TeStON's ReverseMe #1" ]=-

Zrobilimy sobie obsug pliku magiccode.bin, w ktrym bdziemy pisa dalszy kod. Teraz jednak nie bdziemy si ju bawi pod HIEW'em, gdy na dusz met jest to do mczce, a poza tym kolejne cele s coraz trudniejsze i ciko by si je realizowao w hexedytorze. Skoro nie HIEW to... masm :). No tak :). Nie bdziemy mogli jednak pisa tak jak pisze si zwyke progi (co jest chyba oczywiste). Musimy przestrzega paru zasad. Na pewno nie moemy normalnie uywa funkcji API i nie moemy zrobi sobie sekcji .data itp. Mam nadziej, e jest to dla ciebie rwnie oczywiste jak dla mnie i rozumiesz dlaczego mamy takie ograniczenia.

Tworzymy sobie jaki plik abc.asm, w ktrym bdziemy teraz pisa kod. Na pocztek wrzucamy do niego to:

.486
.model flat, stdcall
option casemap:none

include \masm32\include\windows.inc

.code
start:

ret
end start

Szkietel mamy :). Potrzebujemy tylko windows.inc, eby mc korzysta ze staych tekstowych przy API, natomiast adnych innych includw nie potrzebujemy, gdy z samych API w normalny sposb korzysta nie moemy. Na kocu ret, eby wyj z call'a z magicgate.bin.

Najwysza pora zabra si za kolejny cel. Aby zmieni tytu okna wystarczy uy API SetWindowTextA. Potrzebne parametry to: uchwyt okna i adres stringu, ktry ma si pojawi na pasku tytuowym. Uchwyt okna jest zapisany w [ebp+8]. Mona si o tym przekona choby z tego kawaka kodu w IDA:

.text:0040105B hWnd     = dword ptr  8
...
.text:004010A6          push    65h             ; nIDDlgItem
.text:004010A8          push    [ebp+hWnd]      ; hDlg
.text:004010AB          call    GetDlgItem

Pozostaje jeszcze problem ze stringiem. Ale piszemy w MASM, a nie w HIEW, wic moemy to zaatwi cakiem atwo. Za kodem zrobimy sobie tak pseudo sekcje .data. Cao wyglda tak:

.486
.model flat, stdcall
option casemap:none

include \masm32\include\windows.inc

.code
start:

push esi ; w [esi] jest uchwyt pliku magiccode.bin, bdzie on potem potrzebny
; do zamknicia magiccode.bin za pomoc CloseHandle w kodzie z magicgate.bin

mov esi, eax ; w eax mamy offset start
add eax, sekcjadata ; w eax offset caption
push eax
push [ebp+8] ; hDlg
mov eax, 0040149Ch ; SetWindowTextA
call eax

; tu bdzie potem dalszy kod

pop esi ; musimy przywrci zmienione esi
ret
sekcjadata = $ - offset start ; sekcja data = dugo kodu
                              ; $ - oznacza obecny offset
caption db "TeStON's ReverseMe #1",0

end start

Adres SetWindowTextA adnie wida w IDA:

.text:0040149C ; [00000006 BYTES: COLLAPSED FUNCTION SetWindowTextA.

Adresy kolejnych funkcji API, ktrych bd uywa te mona zobaczy w IDA.

No chyba wszystko jasne :) Zapisujemy nasz abc.asm i kompilujemy. Dobra, teraz trzeba wycign kod i zapisa go do magiccode.bin. Ja to zrobiem przy uyciu Hex Workshop. Po prostu otwierasz abc.exe tym hex edytorem, szukasz ".text" i troch dalej masz kod. Zaczyna si od 56h, a koczy na 00h po 31h. Zaznaczasz ten fragment, kopiujesz, tworzysz nowy plik, wklejasz i zapisujesz jako magiccode.bin do katalogu z reverseme. Proste :). Tak samo bdziemy robi po rozwizaniu kolejnych zada.

-=[ Cel 7. - "Dump Full" button must be "Exit" button i odwrotnie ]=-

Przed chwil zmienilimy napis na pasku tytuu. Teraz mamy zmieni napis na buttonach. Czyli praktycznie to samo. Bdziemy musili tylko pobra uchwyt buttonw za pomoc GetDlgItem, a do tego potrzebne s ID przyciskw. Najatwiej sprawdzi je jakims resource edytorem. Mj pokazuje mi takie co:

PUSHBUTTON "Exit", 102, 0, 134, 81, 14, 0, WS_EX_STATICEDGE
PUSHBUTTON "Dump Full", 103, 83, 134, 81, 14, 0, WS_EX_STATICEDGE

Mamy ID, to teraz pozostaje tylko dopisa kod do abc.asm. Ale najpierw stringi do naszej pseudo sekcji data :) :

sekcjadata = $ - offset start ; sekcja data = dugo kodu
                              ; $ - oznacza obecny offset
caption db "TeStON's ReverseMe #1",0 ; 22 znaki
dumpfull db "&Dump Full",0 ; 11
exit db "&Exit",0 ; 6

Stringi mamy, to teraz pora na kod:

mov eax, esi
add eax, sekcjadata+22 ; "Dump Full"
push eax ; kadziemy na stos pierwszy parametr dla SetWindowTextA
push 102 ; Exit button ID
push [ebp+8] ; hDlg
mov eax, 0040148Ah ; GetDlgItem
call eax ; po tym dostajemy do eax uchwyt przycisku
push eax ; drugi parametr dla SetWindowTextA
mov eax, 0040149Ch ; SetWindowTextA
call eax

mov eax, esi
add eax, sekcjadata+22+11 ; "Exit"
push eax
push 103 ; DumpFull button ID
push [ebp+8]
mov eax, 0040148Ah
call eax
push eax
mov eax, 0040149Ch ; SetWindowTextA
call eax

Cao zapisujemy, kompilujemy i kopiujemy kod do magiccode.bin. Jak nic nie spieprzye, to napisy na przyciskach zmieniy si :).

-=[ Cel 8. - Make "Exit" button working.. ]=-

Aby button dziaa potrzebna jest obsuga WM_COMMAND, ktrej niestety w ogle nie ma w reverseme, wic musimy j sobie ca napisa sami. Do sporo niepotrzebnego miejsca znajduje si po obsudze WM_CLOSE. Jak pewnie pamietasz byo tam duo niepotrzebych mieci, ktre obecnie w ogle nie s wykonywane. No dobra, po odpaleniu progsa w okolicach WM_CLOSE mamy taki kod:

0177:00401064  8B550C              MOV       EDX,[EBP+0C] ; uMsg
0177:00401067  83FA10              CMP       EDX,10 ; WM_CLOSE
0177:0040106A  752E                JNZ       0040109A
0177:0040106C  EBB4                JMP       00401022 ; skok do ExitProcess
0177:0040106E  0300                ADD       EAX,[EAX] ; pierwszy smiec
0177:00401070  006880              ADD       [EAX-80],CH
0177:00401073  0000                ADD       [EAX],AL
0177:00401075  0050E8              ADD       [EAX-18],DL
0177:00401078  EA030000688731      JMP       3187:68000003
0177:0040107F  40                  INC       EAX
0177:00401080  006A00              ADD       [EDX+00],CH
0177:00401083  6A00                PUSH      00
0177:00401085  684C104000          PUSH      0040104C
0177:0040108A  6A00                PUSH      00
0177:0040108C  6A00                PUSH      00
0177:0040108E  E879030000          CALL      KERNEL32!CreateThread
0177:00401093  EBE7                JMP       0040107C
0177:00401095  E9AC010000          JMP       00401246 ; ostani smiec
0177:0040109A  81FA10010000        CMP       EDX,00000110 ; WM_INITDIALOG
0177:004010A0  0F858B010000        JNZ       00401231

Obsuge WM_COMMAND zaczniemy w miejscu, ktre oznaczyem jako pierwszy mie. Musimy zmieni skok "jnz 0040109A" na "jnz 0040106E". Czyli bdzie trzeba wstawi 02h pod adres 40106Bh. To chyba jasne, bo od razu wida, e mamy omin tylko 2 bajty. Pod adres 0040106Eh wrzucimy sobie cay kod obsugi WM_COMMAND. Ok, wiemy gdzie co mamy wrzuca, to teraz napiszemy sobie kod, ktry musimy wstawia w naszym pliku abc.asm. Zaczynamy of course za poprzednio dodanym kodem.

; obsluga WM_COMMAND
mov eax, 0040106Bh
mov byte ptr [eax], 02h
; kopiowanie obslugi do kodu
pusha
mov edi, 0040106Eh ; miejsce do ktorego kopiujemy kod
add esi, wmcommandproc ; miejsce z ktorego kopiujemy kod
mov ecx, wmcommandproclen ; ile bajtow kopiowac
rep movsb ; kopiuj
popa

Jak wida mamy tu inn, lepsz metod. Nie bdziemy ju robi wstawiania opcodw za pomoc mov'a tylko bdziemy sobie normalnie pisa wieksze iloci kodu i prosto je kopiowa :). No dobra, tylko jeszcze trzeba napisa to, co mamy skopiowa w podane miejsce. Musi to by mniej wicej co takiego:

cmp edx, 111h
jnz 0040109Ah
cmp dword ptr [ebp+10], 103
jz 00401022h
cmp dword ptr [ebp+10], 102
jz 00401022h ; narazie damy taki sam adres, zeby tylko zajac
; troch miejsca, jak napiszemy dump full proc, to go zmienimy
jmp 00401246h

Jednak mamy pewne ograniczenia, bo nie moemy uywa bezporednich adresw przy skokach. Dlatego nasz kod bdzie wyglda troch inaczej. W abc.asm piszemy go ju za retem wychodzcym z kodu abc.asm, czyli zaczynamy przed nasz pseudo sekcj data. Wyglda to tak:

wmcommandproc = $ - offset start
wmcommand proc

cmp edx, 111h ; sprawdzamy czy wiadomoscia jest WM_COMMAND
jz @F
push 0040109Ah ; pod tym adresem dalsza obsluga komunikatow
ret ; za pomoca reta skaczemy do podanego wyzej adresu
@@:
cmp dword ptr [ebp+10h], 103 ; 103 to ID obecnego Exit buttona
jnz @F ; [ebp+10h] to wParam gdzie jest ID kliknietego buttona
push 00401022h
ret ; jesli kliknieto exit to skacz do ExitProcess
@@:
cmp dword ptr [ebp+10h], 102 ; ID przycisku Dump Full
jnz @F
push 00401022h ; narazie damy se taki sam adres, zeby tylko zajac
ret        ; miejsce, jak napiszemu dum full proc, to go zmienimy
@@:
push 00401246h
ret ; koniec sprawdzania wiadomosci

wmcommand endp
wmcommandproclen = $ - offset wmcommand

Ten kod piszemy juz za retem, bo nie chcemy, eby on si wywoywa na starcie proga, tylko chcemy go skopiowa do gwnej czci kodu reverseme tak, eby mg si wywoywa wtedy, kiedy bdzie trzeba, czyli wtedy, kiedy zostanie wywoany komunikat WM_COMMAND. No mam nadzieje, e czaisz :).

"wmcommandproc = $ - offset start" dziaa na takiej samej zasadzie jak nasza pseudo sekcja data, wic chyba nie ma adnych pyta :P. Zapisujemy abc.asm, kompilujemy i podobnie jak poprzednio kopiujemy skompilowany kod do magiccode.bin. Hehe... nie wiem, czy zauwaye, ale po skompilowaniu nasza wmcommand proc zajmuje 44 bajty, czyli dokadnie tyle ile zajmoway mieci :) Jeden bajt wicej i dalszy kod by si nico spieprzy, ale fuks :D. No, a reverseme ju si wycza po klikniciu na exit button :)

-=[ Cel 9. - Selected process must be killed... ]=-

Teraz pora zrobi killowanie procesu po dwukrotnym klikniciu na niego mysz. Pierwsz rzecz jak musimy wiedzie, jest to, jak sprawdzi, czy dwukrotnie kliknito na ktry z procesw w licie. Do tego potrzebna jest nam wiadomo WM_NOTIFY, ktrej wystpowanie jest ju sprawdzane w kodzie:

.text:00401231          cmp     edx, WM_NOTIFY
.text:00401234          jnz     short loc_40123D
.text:00401236          nop
.text:00401237          nop
.text:00401238          nop
.text:00401239          nop
.text:0040123A          nop
.text:0040123B          jmp     short loc_401246

Autor zostawi nam nawet 5 nopw - idealnie, eby wrzuci tu jakiego call'a :). Tylko call'a do czego? No oczywicie call'a do miejsca, gdzie skopiujemy pniejszy kod obsugujcy WM_NOTIFY. Musimy znale sobie troch miejsca, gdzie bdziemy mogli ten kod spokojnie wrzuci. Cakiem sporo zer mamy zaczynajc od adresu 004014C4h. Troch wyej jest nasza procka uywana do ustawiania wygldu listy. Czyli pod adresem 00401236h zrobimy call 004014C4h, a tam ca obsug WM_NOTIFY i prock killujc :). Sprawdzamy sobie jeszcze opcody call'a w SICE. Debugger pokazuje nam: E889020000h. Oki, so lets open abc.asm. Za obslug WM_COMMAND, a przed retem wychodzcym z tamtego kodu dodajemy:

; call do obslugi WM_NOTIFY
mov eax, 00401236h ; wrzucamy call'a pod ten adres
mov dword ptr [eax], 000289E8h
add eax, 4
mov byte ptr [eax], 0
; kopiowanie obslugi do kodu
pusha
mov edi, 004014C4h ; miejsce do ktorego kopiujemy kod
add esi, wmnotifyproc ; miejsce z ktorego kopiujemy kod
mov ecx, wmnotifyproclen ; ile bajtow kopiowac
rep movsb ; kopiuj
popa

Natomiast przed pseudo sekcj .data dodamy ca obsug komunikatu i prock do zabijania procesw.

wmnotifyproc = $ - offset start
wmnotify proc

mov eax, [ebp+14h] ; [ebp+14h] to lParam ze wskanikiem do struktury NMHDR
mov eax, [eax] ; do eax idzie "hwndFrom" ze struktury NMHDR
mov ebx, 0040316Fh ; pod tym adresem jest zapisane hwnd listy
cmp eax, [ebx]
je @F ; jesli to samo hwnd to idziemy dalej
ret ; a jak nie to spadamy, bo inne kontrolki nas nie obchadza
@@:
mov eax, [ebp+14h] ; do eax spowrotem adres ze struktura NMHDR
add eax, 8 ; do eax idzie "code" ze struktury NMHDR
cmp dword ptr [eax], NM_DBLCLK ; czy wiadomoci jest podwjne kliknicie?
je @F ; jak tak to idziemy dalej
ret ; inne wiadomoci nas nie obchodz
@@:
wmnotify endp

Jak nie czaisz co z tego co jest wyej, to odpal sobie API helpa i przeczytaj co jest napisane na temat "WM_NOTIFY" i "NMHDR". Teraz trzeba si zastanowi jak zrobi zabijanie procesu. Pierwsze co mi przychodzi na myl to API TerminateProcess. Do niej z kolei potrzebny jest uchwyt procesu, ktry moemy otrzyma za pomoc API OpenPocess. Z kolei do niej potrzebujemy ID procesu, a ID jest przecie pobierane i wywietlane na licie w reverseme :). Do pobierania jakich kolwiek informacji o ktrym z elementw z listy bdziemy musieli uywa struktury LV_ITEM. Zamknlimy wmnotify proc i zaczniemy zabij proc. Moemy sobie w niej zrobi zmienn lokaln ze struktur LV_ITEM.

zabij proc
LOCAL lvi: LV_ITEM

Waciwie, to mona by si obej bez deklarowania tej zmiennej lokalnej, ale imho tak jest wygodniej :). Jeszcze jedna sprawa - pobieranie ID z listy. Moglibymy pobiera string z ID z listy i przerabia go na dword, ale jest lepszy sposb. Patrz:

typedef struct _LV_ITEM { 
    UINT   mask; 
    int    iItem; 
    int    iSubItem; 
    UINT   state; 
    UINT   stateMask; 
    LPTSTR  pszText; 
    int    cchTextMax; 
    int    iImage;       // index of the list view item's icon
    LPARAM lParam;       // 32-bit value to associate with item
} LV_ITEM; 

Widzisz lParam? Tam gdzie wkadane s kolejne elementy do listy moemy zadba o to, eby do lParam szo od razu ID w formie dworda, a potem bdziemy zczytywa lParam, wic nie bdziemy musili zczytywa stringa z ID i przerabia go na dword :). Zobaczmy to sobie w SICE.

0177:004012CD  6800304000          PUSH      00403000
0177:004012D2  FF3528334000        PUSH      DWORD PTR [00403328]
0177:004012D8  E877010000          CALL      KERNEL32!Process32First

; 00403000h jest wskanikiem do struktury PROCESSENTRY32, po wywolaniu
; powyzszej API, pod adresem 00403008h znajduje si ID danego procesu

0177:004012DD  33C9                XOR       ECX,ECX
0177:004012DF  890D73314000        MOV       [00403173],ECX
0177:004012E5  0BC0                OR        EAX,EAX
0177:004012E7  0F8405010000        JZ        004013F2
0177:004012ED  C745D807000000      MOV       DWORD PTR [EBP-28],00000007
0177:004012F4  FF3573314000        PUSH      DWORD PTR [00403173]
0177:004012FA  8F45DC              POP       DWORD PTR [EBP-24]
0177:004012FD  FF3573314000        PUSH      DWORD PTR [00403173]
0177:00401303  8B0D73314000        MOV       ECX,[00403173]
0177:00401309  41                  INC       ECX
0177:0040130A  890D73314000        MOV       [00403173],ECX
0177:00401310  8F45F8              POP       DWORD PTR [EBP-08]

; w ebp-8 znajduje sie lParam z struktury LV_ITEM,
; czyli tu bedziemy wrzucac ID w postaci dworda

0177:00401313  C745E000000000      MOV       DWORD PTR [EBP-20],00000000
0177:0040131A  E88F010000          CALL      004014AE
0177:0040131F  50                  PUSH      EAX
0177:00401320  90                  NOP
0177:00401321  C745F400000000      MOV       DWORD PTR [EBP-0C],00000000
0177:00401328  8D45D8              LEA       EAX,[EBP-28]
0177:0040132B  50                  PUSH      EAX
0177:0040132C  6A00                PUSH      00
0177:0040132E  6807100000          PUSH      00001007  ; LVM_INSERTITEM
0177:00401333  FF356F314000        PUSH      DWORD PTR [0040316F]
0177:00401339  E858010000          CALL      USER32!SendMessageA

Teraz, eby w lParam zapisywane byy ID kolejnych procesw wystarczy zmieni push'a spod adresu 004012FDh z "PUSH DWORD PTR [00403173]" na "PUSH DWORD PTR [00403008]". No to dodajemy do abc.asm przed ret'em takie co:

; zapisywanie do lParam ID procesu przy LVM_INSERTITEM
mov eax, 004012FFh
mov word ptr [eax], 03008h

Mamy ju wszystko co potrzebne, wic moemy pisa prock killujc :). Do zabij proc dopisujemy taki kod:

; pobieranie ID kliknietego elementu listy

push LVNI_SELECTED
push -1
push LVM_GETNEXTITEM
db 0FFh,35h,6Fh,31h,40h,00h ; push dword ptr [0040316F], tu jest hwnd listy
mov eax, 00401496h ; SendMessage
call eax ; po tym w eax numer zaznaczonego wiersza z listy (liczac od 0)
mov lvi.iItem, eax ; pobieramy atrybut z zaznaczonego wiersza
mov lvi.iSubItem, 0
mov lvi.imask, LVIF_PARAM ; atrybutem do pobrania jest lParam
lea eax, lvi
push eax
push 0
push LVM_GETITEM ; pobieramy info
db 0FFh,35h,6Fh,31h,40h,00h ; push dword ptr [0040316F] (uchwyt listy)
mov eax, 00401496h ; SendMessage
call eax
mov eax, lvi.lParam ; no i do eax wrzucamy pobrany ID kliknietego procesu
; egzekucja ;)
push eax
push TRUE
push PROCESS_TERMINATE ; chcemy miec mozliwosc zamordowania procesu :)
mov eax, 0040144Eh ; OpenProcess
call eax ; po tym w eax zwracany jest uchwyt procesu

Hmm... przy killowaniu ma si pojawia MessageBox czy proces zosta zabity, czy nie. Take tutaj trzeba zrobi sprawdzenie czy eax==0, a do msgbox'a potrzebujemy jakich odpowiednich stringw w stylu "Error" i "Done", ktrych w reverseme nie ma. Dopisujemy je na koniec naszej sekcji .data:

error db "Error!",0 ; 7
done db "Done!",0 ; 6

Natomist przed retem wychodzcym z kodu abc.asm dodajemy jeszcze kopiowanie tych danych do prawdziwej sekcji .data od reverseme:

; kopiowanie danych do sekcji .data
pusha
mov edi, 00403340h ; miejsce do ktorego kopiujemy dane
add esi, sekcjadata+22+11+6 ; miejsce z ktorego kopiujemy dane
mov ecx, 7+6 ; ile bajtow kopiowac
rep movsb ; kopiuj
popa

Adres, do ktrego moemy bezpiecznie kopiowa dane wida w IDA:

.data:0040333C dword_40333C    dd 0               ; DATA XREF: sub_401252
.data:00403340                 align 100h

Ostatnim adresem do danych uywanym przez progsa jest 0040333Ch, a dalej mamy troch miejsca, ktre na pewno nie jest do niczego uywane, wic moemy sobie tego uy do wasnych celw :). Oki, moemy kontynuowa pisanie procki killujcej.

test eax, eax
jz blad ; jesli otwarcie procesu nie powiodlo sie, to pokaz info o bledzie
push 0
push eax ; uchwyt procesu
mov eax, 00401472h ; TerminateProcess
call eax
test eax, eax
jz blad ; jesli TerminateProcess nie powiodlo sie, to info o bledzie
; egzekucja zakonczona powodzeniem
push 0
push 00403340h+7 ; string "Done!"
push 00403340h+7
push 0
mov eax, 00401490h ; MessageBox
call eax
ret
; nici z egzekucji :(
blad:
push 0
push 00403340h ; string "Error!"
push 00403340h
push 0
mov eax, 00401490h ; MessageBox
call eax
ret

zabij endp
wmnotifyproclen = $ - offset wmnotify

Cao kompilujemy i skompilowany kod kopiujemy do magiccode.bin. Odpalamy, sprawdzamy, wszystko dziaa :)

-=[ Cel 10. - Make "Dump Full" button working.. ]=-

Ostatnia rzecz jaka zostaa nam do zrobienia, to dump full procesu. Musimy zdumpowa, pokaza okienko GetSaveFileName i zapisa proces do wybranego w tym oknie pliku. Dla mnie ten cel to by waciwie jedyny wikszy problem, bo nie wiedziaem jak si robi dump full, ale miaem nadziej, e jak ju do tego celu dojd, to si skd dowiem jak to zrobi. No i tak te si stao :) - dostaem gotow prock dump full od Reverend'a z HTB Teamu (pozdo! i dziki :)), wic musiaem tylko dorobi zapisywanie dumpnitego procesu do pliku i troch przerobi prock tak, eby dziaaa po doczepieniu do reverseme. Oki, to jedziemy z tym koksem :)

Najpierw zrobimy jakie przekierowanie do procki dump po klikniciu na button Dump Full. Obsug WM_COMMAND robilimy przy okazji "naprawiania" buttona Exit. Zaczyna si ona pod adresem 0040106Eh, a troch dalej dalimy tam co takiego:

cmp dword ptr [ebp+10h], 102 ; ID przycisku Dump Full
jnz @F
push 00401022h ; narazie damy se taki sam adres, zeby tylko zajac
ret       ; miejsce, jak napiszemy dump full proc, to go zmienimy

Teraz wystarczy zmieni tu adres 00401022h na adres, do ktrego skopiujemy potem procke dump. Pod SICE wida, e kod, ktry do tej pory dodalimy koczy si pod 00401572h, czyli prock dump bdziemy kopiowa bajt dalej. Zatem zmieniamy w abc.asm ten adres 00401022h na 00401573h.

Teraz krtkie wyjanienie jak mona robi dumpowanie procesu na podstawie tego co dostaem od Reverend'a. Pami procesu odczytamy funkcj Toolhelp32ReadProcessMemory, do ktrej potrzebujemy ID dumpowanego procesu, adres podstawowy procesu, ktry zwracany jest w strukturze MODULEENTRY32 po odpowiednim wywoaniu Module32First i Next, jaki bufor do ktrego zapiszemy pami procesu oraz ilo bajtw jak naley odczyta. Aby wiedzie, czy informacje zwrcone w MODULEENTRY32 tycz si procesu, ktry chcemy zrzuca moemy porwnywa nazw pliku zawart w tej strukturze, w szModule do nazwy pliku zawartej w szExePath ze struktury PROCESSENTRY32, ktra jest uzupeniana przez API Process32First i Next. Z kolei do tych API potrzebujemy uchwytu od snapshota, ktry jest zwracany po wywoaniu CreateToolhelp32Snapshot.

No dobra, otwieramy abc.asm i zaczynamy za nasz prock zabij, a przed pseudo sekcj data. Podobnie do tego, jak to robilimy wczeniej zaczynamy tak:

dumpproc = $ - offset start
dump proc

Na pocztku zrobimy sobie okienko wyboru pliku, do ktrego chcemy zapisywa dumpowany proces, czyli funkcja GetSaveFileName. W helpie moemy zobaczy, e potrzebna jest struktura OPENFILENAME, wic robimy sobie odpowiedni zmienn lokaln na pocztku procki:

LOCAL ofn:OPENFILENAME

Zmienna zadeklarowana, moemy pisa kod. Jako e jest to zmienna lokalna, to musimy wypeni wszystkie pola, gdy jak pewnie wiesz z powodu metody jakiej tworzone s zmienne lokalne, na pocztku znajduj si w niej przypadkowe mieci. Moemy te zrobi sobie ma ptelk, ktra wyczyci nam t zmienn i potem nie bdziemy musili wypenia wszystkich pl. Waciwie jest ta nawet bardziej optymalne rozwizanie, ale eby byo bardziej przejrzycie, to ja u siebie bd po prostu wypenia po kolei wszystkie pola. Ty zrobisz sobie jak chcesz. No to uzupenmiamy wszystko wedug tego, co pisze w helpie.

mov ofn.lStructSize, SIZEOF ofn
mov ofn.hwndOwner, 0
mov ofn.hInstance, 0
mov ofn.lpstrFilter, 0
mov ofn.lpstrCustomFilter, 0
mov ofn.nMaxCustFilter, 0
mov ofn.nFilterIndex, 0
mov ofn.lpstrFile, 00403400h
mov ofn.nMaxFile, 256
mov ofn.lpstrFileTitle, 0
mov ofn.nMaxFileTitle, 0
mov ofn.lpstrInitialDir, 0
mov ofn.lpstrTitle, 0
mov ofn.Flags, 0
mov ofn.nFileOffset, 0
mov ofn.nFileExtension, 0
mov ofn.lpstrDefExt, 0
mov ofn.lCustData, 0
mov ofn.lpfnHook, 0
mov ofn.lpTemplateName, 0

Jak wida tak naprawd wane s tylko 3 pola, a reszta jest opcjonalna i mona je ola, chyba e chce si mie jakie filtry i inne bajery. Jak dla mnie jest to zbdne, bo tylko wicej roboty, a i tak za bardzo si nam nie przyda, wic nie ma po co sobie utrudnia ycia. Jak chcesz, to moesz sobie jakie filtry itp. sam dorobi. Jedyne co tu jeszcze chyba powinienem skomentowa to lpstrFile. To jest bufor na ciek do pliku jak sobie wybierzemy w oknie. Daem 00403400h, bo z tego co wida w SICE ten obszar nie jest ju do niczego uywany (widzimy, e cay czas le tam niepotrzebne zera). Jak mi nie wierzysz, to dla pewnoci moesz sobie ustawi puapk w SICE na odczyt i zapis z tego adresu i troch pouywa proga, eby zobaczy, czy rzeczywicie ten adres nie bdzie wykorzystywany :P. Struktura wypeniona, wic robimy samo wywoanie.

lea eax, ofn
push eax
mov eax, 004014A8h ; GetSaveFileName
call eax

Po tym wywoaniu, pod adresem 00403400h bdziemy mili ciek do pliku. Teraz musimy pobra ID zaznaczonego procesu. Robimy to w taki sam sposb, jak robilimy to w przypadku zabij proc. Of course dopisujemy jeszcze zmienn LOCAL lvi:LV_ITEM

; pobieranie ID zaznaczonego elementu listy
push LVNI_SELECTED
push -1
push LVM_GETNEXTITEM
db 0FFh,35h,6Fh,31h,40h,00h ; push dword ptr [0040316F], tu jest hwnd listy
mov eax, 00401496h ; SendMessage
call eax ; po tym w eax numer zaznaczonego wiersza z listy (liczac od 0)
mov lvi.iItem, eax ; pobieramy atrybut z zaznaczonego wiersza
mov lvi.iSubItem, 0
mov lvi.imask, LVIF_PARAM ; atrybutem do pobrania jest lParam
lea eax, lvi
push eax
push 0
push LVM_GETITEM ; pobieramy info
db 0FFh,35h,6Fh,31h,40h,00h ; push dword ptr [0040316F] (uchwyt listy)
mov eax, 00401496h ; SendMessage
call eax
mov eax, lvi.lParam ; no i do eax wrzucamy pobrany ID kliknietego procesu

Przydao by si gdzie to eax zachowa, bo zaraz bdziemy uywa innych api. Tworzymy sobie do tego celu zmienna lokalna, zaraz za zmienn ofn:

LOCAL dwPid:DWORD

Kopiujemy ID znajdujce si w eax do tej zmiennej:

mov dwPid, eax

Mamy ju wszystko co potrzebne do dumpowania i zapisania pliku, wic moemy przystpi do samego zrzucania procesu :).

push dwPid
push TH32CS_SNAPALL
mov eax, 00403334h
mov eax, [eax]
call eax ; CreateToolhelp32Snapshot

W eax zwracany jest uchwyt od snapshota procesu o ID znajdujcym si w dwPid. Musimy sobie ten uchwyt gdzie zapisa, wic dopisujemy do zmiennych lokalnych zmienn LOCAL Snapshot:DWORD.

mov Snapshot, eax ; zapisujemy zwrocony uchwyt

Teraz bdziemy wywoywa api Process32First i Process32Next, do ktrych potrzebujemy struktury PROCESSENTRY32, wic dopisujemy sobie odpowiedni zmienn na pocztku procki (LOCAL Process:PROCESSENTRY32). Teraz jednak nie bdziemy wypenia wszystkich pl, tylko zrobimy sobie to, o czym wspomniaem wczeniej - ptle czyszczc ca struktur PROCESSENTRY32.

lea ebx, Process
mov ecx, sizeof PROCESSENTRY32
@@:
mov byte ptr [ebx], 0
inc ebx
loop @B

Teraz nie musimy uzupenia wszystkich niepotrzebnych pl tak jak to robilimy przy OPENFILENAME, bo nie ma ju adnych mieci, tylko wszystkie pola s czyste. Jedyne pole struktury, ktre tym razem musimy wypeni to dwSize.

mov Process.dwSize, sizeof PROCESSENTRY32
lea ebx, Process
push ebx
push eax
mov eax, 00401454h ; Process32First
call eax
mov esi, dwPid
@@:
cmp Process.th32ProcessID, esi
jz processfound
push ebx
push Snapshot
mov eax, 0040145Ah ; Process32Next
call eax ; jesli jeszcze nie sprawdzono wszystkich procesow, to
dec eax  ; po wywolaniu API, w eax jest 1 i kontynujemy szukanie
jz @B
leave ; usuwamy rame stosu tworzona przy wchodzeniu do procki
mov eax, 00401246h ; i skoro nic nie znaleziono, to spadamy stad
jmp eax 
processfound:

Powyszy kawaek kodu pobiera kolejno ID wszystkich aktywnych procesw a do momentu, gdy pobrane ID zgadza si z tym, ktrego szukamy. Rama stosu jest tworzona przez to, e uywamy zmiennych lokalnych. Oki, teraz bdziemy uywa Module32First i Next, wic potrzebna jest nam taka zmienna: LOCAL Module:MODULEENTRY32. Hmm... ale prog nie ma tej API w tablicy importw, wic musimy pobra adres do tej API za pomoc GetProcAddress. Do tego z kolei potrzebny jest nam string "Module32First" i "Module32Next". Zatem dopisujemy na koniec naszej pseudo sekcji .data takie co:

sModule32First db "Module32First",0 ; 14
sModule32Next db "Module32Next",0 ; 13

Stringi te musimy skopiowa do sekcji data od reverseme. Nieco wyej w abc.asm mamy ju zrobione kopiowanie danych:

; kopiowanie danych do sekcji .data
pusha
mov edi, 00403340h ; miejsce do ktorego kopiujemy dane
add esi, sekcjadata+22+11+6 ; miejsce z ktorego kopiujemy dane
mov ecx, 7+6 ; ile bajtow kopiowac
rep movsb ; kopiuj
popa

Zmieniamy ilos kopiowanych bajtw na 7+6+14+13 i wracamy do pisania kodu.

lea ebx, Module
mov ecx, sizeof MODULEENTRY32
@@:
mov byte ptr [ebx], 0
inc ebx
loop @B ; czyscimy strukture MODULEENTRY32

mov Module.dwSize, sizeof MODULEENTRY32 ; znowu uzupelniamy tylko 1 pole

mov eax, 00403340h+7+6 ; pod tym adresem bedzie string "Module32First"
push eax
mov eax, 00403330h ; tu prog trzyma uchwyt od kernel32.dll
push dword ptr [eax]
mov eax, 0040143Ch ; GetProcAddress
call eax ; po tym w eax mamy adres do funkcji Module32First

lea ebx, Module
push ebx
push Snapshot
call eax ; Module32First

Po wywoaniu Module32First i Module32Next w Module.szModule mamy stringa z nazw moduu (np. "ble.dll" albo "cos.exe"). Musimy porwnywa t nazw tak dugo, a bdzie to nazwa uruchomionego proga, czyli np. "cos.exe", a nie "ble.dll". Nazwa pliku exe znajduje si w Process.szExeFile. Waciwie to mamy tu ca ciek do wybranego progsa (np. "C:\COS\cos.exe"). Hmm... nazw pliku ze ciek w szExeFile mamy w przypadku win98, natomiast w win2k mamy od razu tylko nazw pliku exe. Jako, e siedz teraz na win98, to jest troch wicej do roboty, bo musimy sobie oddzieli nazw pliku od cieki. Nie wiem po co w ogle mircoshit to zmienia. W moim api helpie pisze:

szExeFile
Path and filename of the executable file for the process.

Natomiast w msdn library online mamy podane:

szExeFile
Pointer to a null-terminated string that specifies the name of the executable file for the process

No i dupa. Raz pisz, e jest sama nazwa pliku exe, a drugi raz, e jest nazwa ze ciek, zamiast wyjani, e ze ciek jest w win98, a bez na nowszych os'ach. Potem takim ufaj :P. No to oddzielamy nazw pliku od cieki w szExeFile, a potem bdziemy porwna to z szModule.

checkfname:
lea eax,Module.szModule
lea edx,Process.szExeFile

xor ecx, ecx
; odzielanie nazwy pliku od sciezki
ab1:
cmp byte ptr [edx], 0
je ab2
inc edx
jmp ab1
ab2:
cmp byte ptr [edx], '\'
je ab3
dec edx
inc ecx
jmp ab2
ab3:
inc edx

; porownanie obu stringow
mov edi, eax
mov esi, edx
repe cmpsb
je modulefound

mov eax, 00403340h+7+6+14 ; pod tym adresem bedzie string "Module32Next"
push eax
mov eax, 00403330h ; tu prog trzyma uchwyt od kernel32.dll
push dword ptr [eax]
mov eax, 0040143Ch ; GetProcAddress
call eax ; po tym w eax mamy adres do funkcji Module32Next

lea ebx, Module
push ebx
push Snapshot
call eax ; Module32Next
dec eax
jz checkfname ; sprawdzaj nastepny modul, o ile jeszcze jakis inny istnieje
leave ; usuwamy rame stosu
mov eax, 00401246h ; i skoro nic nie znaleziono, to stad spadamy
jmp eax

modulefound:

Jak tu dojdziemy, to znaczy e znalelimy odpowiedni modu i w strukturze MODULEENTRY32 mamy zwrconych pare potrzebnych do dumpowania informacji...

; alokujemy tyle pamieci, ile zajmuje proces do dumpowania
mov ebx, Module.modBaseSize
push ebx
push GPTR
mov eax, 00401442h ; GlobalAlloc
call eax
mov edi, eax

Pami procesu odczytujemy funkcj Toolhelp32ReadProcessMemory. Mamy ju wszystko co potrzebne do jej wywoania :) Hmm... chocia nie, bo nie mamy jeszcze samego adresu do funkcji Toolhelp32ReadProcessMemory, ale pobierzemy go w taki sam sposb jak np. adres funkcji Module32First. Czyli potrzebujemy kolejnego stringa w sekcji danych. Dopisujemy go w abc.asm...

sToolhelp32ReadProcessMemory db "Toolhelp32ReadProcessMemory",0 ; 28

...i w miejscu, w ktrym kopiujemy dane, zwikszamy ilo kopiowanych bajtw o 28.

mov eax, 00403340h+7+6+14+13 ; string "Toolhelp32ReadProcessMemory"
push eax
mov eax, 00403330h
push dword ptr [eax]
mov eax, 0040143Ch ; GetProcAddress
call eax

mov esi, Module.modBaseAddr
push 0
push ebx
push edi
push esi
push dwPid
call eax ; Toolhelp32ReadProcessMemory

Po wywoaniu tego, w edi mamy cay proces. Teraz wystarczy to tylko zapisa na dysk, do pliku wybranego przez GetSaveFileName, do ktrego ciek pobralimy do adresu 00403400h :)

push 0
push FILE_ATTRIBUTE_ARCHIVE
push CREATE_ALWAYS
push 0
push FILE_SHARE_READ
push GENERIC_WRITE
push 00403400h
mov eax, 00401406h ; CreateFileA
call eax

Na zwrcony uchwyt robimy sobie jeszcze zmienn LOCAL hFile:DWORD na pocztku procki dump. Dalej robimy zapis do pliku przez WriteFile.

mov hFile, eax

push 0
push 00403600h ; jakies wolne miejsce w pamieci
push ebx ; w ebx jest ciagle ilosc zajmowanych przez proces bajtow
push edi ; w edi caly czas mamy adres pod ktorym jest pamiec procesu
push hFile

Nie mamy adresu do WriteFile, no ale to nie jest przecie wikszy problem. Znowu robimy to samo co przedtem, czyli dodajemy sobie string do naszej pseudo sekcji data.

sWriteFile db "WriteFile",0 ; 10

Tak jak poprzednio zwikszamy ilo kopiowanych bajtw o 10 i robimy GetProcAddress.

mov eax, 00403340h+7+6+14+13+28 ; string WriteFile
push eax
mov eax, 00403330h
push dword ptr [eax]
mov eax, 0040143Ch ; GetProcAddress
call eax

call eax ; WriteFile

; plik zapisany, jeszcze tylko adnie go zamykamy :)
push hFile
mov eax, 00401400h ; CloseHandle
call eax
; zwalniamy pamiec
push edi
mov eax, 00401448h ; GlobalFree
call eax
; i spadamy stad :)
leave
mov eax, 00401246h
jmp eax

dump endp
dumpproclen = $ - offset dump

Jeszcze tylko musimy zrobi kopiowanie tej procki do kodu reverseme pod ustalony wczeniej adres - 00401573h. Robimy to obok kopiowania sekcji data i w ten sam sposb:

; kopiowanie dump proc do kodu
pusha
mov edi, 00401573h ; miejsce do ktorego kopiujemy kod
add esi, dumpproc ; miejsce z ktorego kopiujemy kod
mov ecx, dumpproclen ; ile bajtow kopiowac
rep movsb ; kopiuj
popa

Kompilujemy abc.asm, skompilowany kod z abc.exe kopiujemy do magiccode.bin. Odpalamy, sprawdzamy, dziaa? No jasne, a jake by mogo nie dziaa :D

Uff nareszcie koniec :) Przed wakacjami postanowiem se, e na wakacjach w kocu skocz pisa tego tuta no i udao si... 'cos today is the last day of holiday :) Troch czasu mi zeszo na ten tekst, no ale w kocu jest i to si liczy :). Jeeli doczytae wszystko a do td to szczerze gratuluj :) Pewnie masz ju do ;), w kadym razie ja tak.

Wszystkie tworzone pliki, o ktrych bya mowa w tym tekcie powinny by do niego doczone. Jak czego nie zrozumiae i masz jakie pytania, to wal miao na mojego maila: finsss@wp.pl :)

--
Pozdro!
FiNS