***********************************************************
[ _TeStON_ ^ UnderPL - rozwiazanie do ReverseMe by MuSzyn ]
***********************************************************

[ Przypomne ze ten tutorial pisalem podczas lamania tego reverseme i nie jest on pisany poprawna polszczyzna ale powinienes (powinnas??) go zrozomiec ;) ]

 Potrzebne rzeczy:
  - IDA
  - HexEdytor
  - SoftIce
  - JumpGenerator
  - troche czasu i umiejetnosci ;))

1. Plik exe sie nie uruchamia, nie widac takze ikonki, objawy takie moga byc spowodowane zlym podaniem offsetu naglowka PE w naglowku DOS. Otwieramy "hot_reme.exe" w hexedytorze, ja uzywam HEDIT-a. Patrzymy gdzie zaczyna sie naglowek PE (Poznamy to po literach 'PE'),
jest to offset 80h. Teraz wracamy do naglowka DOS-u, i idziemy pod offset 3Ch, jest tam wartosc 20h, wiec juz widzimy ze wartosci 80h i 20h sie roznia, wiec zmieniamy 20h na 80h. Zapisujemy plik i wychodzimy z hexedytora. OK! pokazala sie ikonka programu, klikamy na nia i program sie pieknie uruchamia ;)
2. Patrzymy jeszcze raz pod hexedytoram na plik czy nie jest spakowany, i nie jest (lepiej dla nas ;))
3. Odpalamy IDE, i disasemblujemy program
Widzimy pare porownan w stylu:

seg000:00401710 loc_0_401710:                           ; CODE XREF: sub_0_401694+3Cj
seg000:00401710                 cmp     [ebp+wParam], 11h
seg000:00401714                 jnz     loc_0_401870
seg000:0040171A                 push    40h
seg000:0040171C                 push    offset aHotkey  ; "Hotkey!"
seg000:00401721                 push    offset aHotkeyIsAGoodThingCtrlWD ; "Hotkey is a good thing - CTRL-W ;-D"
seg000:00401726                 jmp     short loc_0_4017A4
seg000:00401728 ; 
seg000:00401728 
seg000:00401728 loc_0_401728:                           ; CODE XREF: sub_0_401694+33j
seg000:00401728                 cmp     [ebp+wParam], 41h
seg000:0040172C                 jz      short loc_0_401750
seg000:0040172E                 ja      short loc_0_401740
seg000:00401730                 cmp     [ebp+wParam], 1Bh      
seg000:00401734                 jz      short loc_0_4017B2
seg000:00401736                 jmp     loc_0_401870
seg000:00401736 ; 
seg000:0040173B                 align 8

4. Ok, wiemy juz co sie dzieje w kodzie, teraz pasuje znac dobre wartosci hotkeyow
Ja uruchomilem delphi i zrobilem tak:

procedure TForm1.FormKeyPress(Sender: TObject; var Key: Char);
begin
  Caption := IntToHex(Ord(Key), 0)+'h';
end;

Powyzsza procka pokazuje kod nacisnietych klawiszy na Captionie Formularza. I tak wyszlo mi ze:

"C"      - 63h
"CTRL-B" - 2h
"ESC"    - 1Bh

Czego tylko te 3? Poniewarz reszta hotkeyow dziala.

5. Zamiemy sie teraz hotkeyem ESC - 1Bh
Gdy w programie nacisniemy ESC pojawia na sie wygaszacz ekranu, wiec z tego wynika ze gdzies w programie musi bys porownanie z 1Bh i jest ;)

seg000:00401728 loc_0_401728:                           ; CODE XREF: sub_0_401694+33j
seg000:00401728                 cmp     [ebp+wParam], 41h
seg000:0040172C                 jz      short loc_0_401750
seg000:0040172E                 ja      short loc_0_401740
seg000:00401730                 cmp     [ebp+wParam], 1Bh       ;!!! TUTAJ !!!
seg000:00401734                 jz      short loc_0_4017B2
seg000:00401736                 jmp     loc_0_401870
seg000:00401736 ; 

Wiec pasuje zeby po porownaniu z 1Bh program skakal tam gdzie zamyka sie program, szukamy w programie odwolania do ExitProcess... jest:

seg000:004011CE                 push    ebx             ; uExitCode
seg000:004011CF                 call    ExitProcess

No to pasuje zmienic "jz short loc_0_4017B2" na "jz 4011CE", wchodzimy do hexedytora i otwieramy program. Trzeba teraz znalezc kod z pod adresu wirtualnego 401730h, w tym celu w IDZie klikamy na adres 401730h, z menu Edit wybieramy "Patch program -> Change byte" otworzylo sie okienko ze stringiem, sa to wartosci opkodow, kopiujemy je do schowka (Ctrl+C). Przelaczemy sie do hexedytora dajemy Find, w polu hen wklejamy string, klikamy Search. Znalazl te bajty pod adresem 0B30h, teraz trzeba zmienic te bajty, za skok odpowiedzialne sa "74 7C" ale zeby skoczyc pod 4011CEh trzeba miec opkod o dlugosci 6 bajtow ("0F8494FAFFFF" uzylem jumpgeneratora), wiec pomyslmy co mozna by wyrzucic:

seg000:00401728                 cmp     [ebp+wParam], 41h         ;!!! TO !!!
seg000:0040172C                 jz      short loc_0_401750        ;!!! TO !!!
seg000:0040172E                 ja      short loc_0_401740        ;!!! TO !!!
seg000:00401730                 cmp     [ebp+wParam], 1Bh         ;!!! TEGO NIE !!!
seg000:00401734                 jz      short loc_0_4017B2        ;!!! TO SIE ZMIENI !!! 
seg000:00401736                 jmp     loc_0_401870              ;!!! TEGO NIE !!!

czyli mozemy sobie pozmieniac bajty od 0B28h do 0B36h, wiec po przestawieniu otrzymamy:

           cmp [ebp+wParam], 1Bh
0040172C:  jz 004011CE
              xNOP
00401736:  jmp loc_0_401870

          opkod "jz 4011CE" = 0F84A2AFFFFF wynika to z tego ze
40172C - 4011CE = 55E - 1 = 55D
i teraz gdybysmy skakali do przodu to opkod bylby 0F840000055D ale ze skaczemy do tylu to wartosci 0000055D robimy NOT co daje FFFFFAA2 i odwracamy A2AFFFFF i z przody dodajemy 0F84
(84 - skacz gdy rowne "flaga zerowa Z = 1")
I tak zalatwilismy sprawe ESC, uruchamiamy program wciskamy ESC i program sie zamyka ;))

Aha... teraz sie skapnolem ze wywalilem porownanie z "A" - 41h, hmm pomyslmy, mozemy teraz zamiast tych nopow dac jumpa do procki ktora byla zamiast ESC (wlaczala wygaszacz ekranu).
Czyli musimy wstawic jumpa do adresu 004017B2, poprzednim razem byl skok z:
00401734:                 jz      short loc_0_4017B2 
i jego opkod wynisil 747C, jak widzimy miejsce 401734h jest wolne (nop), wiec mozna wstawic tam opkod EB7C  (EB - jmp, 74 - jz i zmieniamy z jz na jmp). I teraz naciskajac "A" zamiast infa mamy wlaczaony wygaszacz ekranu. wiec teraz zamiast procki pasuje dac porownanie czy Nacisnieto "A" jak tak to wywolaj info. Przechodzimy do IDY ladujemy od nowa program, idziemy do adresu 4017B2h
klikamy na niego, z menu Edit wybieramy "Patch program -> Change byte", kopiujemy string i wchodzimy do hexedytora, i szukamy zkopiowanego stringu. Wiec procka zaczyna sie od adresu 0BB2h a konczy na 0BC9h. Wiec zmieniamy bajty na 
83 7D 10 41 (cmp [ebp+wParam], 41h)
i teraz jezeli rowne to z pod adresu 004017B6h skaczemy do 00401750 czyli w tyl.

4017B6h - 401750h + 5h = 6Bh
not 65h = FFFFFF94, odwrocone 94FFFFFF i dodajemy 0F84 i mamy opkod 0F8494FFFFFF
Reszte bajtow nop-ujemy az do adresu 0BC9h
Ok, wszystko dziala.
Gdy nacisniemy "A" pokazuje sie info
Gdy nacisniemy "ESC" program wylacza sie.
Ale po nacisnieciu "O" nie otwiera sie cd-rom

seg000:00401728                 cmp     [ebp+wParam], 1Bh
seg000:0040172C                 jz      loc_0_4011D4
seg000:00401732                 nop
seg000:00401733                 nop
seg000:00401734                 jmp     short loc_0_4017B2
seg000:00401736 ; 
seg000:00401736                 jmp     loc_0_401870
seg000:00401736 ; 
seg000:0040173B                 align 8
seg000:00401740                 cmp     dword ptr [ebp+10h], 4Fh    ; to jest odp za cd-rom
seg000:00401744                 jz      short loc_0_401760
seg000:00401746                 jmp     loc_0_401870
ale tak logicznie myslac do porownania czy wczisnieto "O" nigdy nie dojdzie, ale my zrobimy tak ze po zrobieniu jupa do "short loc_0_4017B2" gdzie sprawdzane jest czy nacisnieto "A", program bedzie wracal pod adres 401740h

4017B2h - 401740h + 0Fh= 81h
i skaczemy do tylu
not 81h = 7EFFFFFF 
dodajemy  0F85 (85 - jnz) opkod = 0F857EFFFFFF

6. Zamykanie tacki cd-romu

W pliku nie ma stringu "set cdaudio door closed", wiec musimy poszukac jakiegos wolnego miejsca w programie, naszczescie autor zostawil nam 25 znakow w offsecie 6D6h. Wpisujemy tam brakujacy string. Na koncu wpisujemy 0. Teraz obliczamy pozycje stringu:

offset = 400C00h + 6D6h = 4012D6

Zamkniecie cd-romu musi nastapic po nacisnieciu klawisza "C" - 63h.

Ale w kodzie programu nie ma juz miejsca na takie bajery ;), hmm... pomyslmy moze jest jakis zbedny kod do wyrzucenia, przegladamy pod IDa na samym paczatku jakies dziwne funkcje hmm...
pozniej wywolywany jest "call 401990h" a pod tym adresem jest:

seg000:00401990                 push    ebp
seg000:00401991                 mov     ebp, esp
seg000:00401993                 sub     esp, 64h
seg000:00401996                 push    ebx
seg000:00401997                 call    sub_0_401AB0
seg000:0040199C                 call    GetCommandLineA
seg000:004019A1                 mov     ebx, eax
seg000:004019A3                 add     esp, 0FFFFFFF4h
seg000:004019A6                 lea     eax, [ebp+StartupInfo]

hmm... wiec tak jakby poczatek programu wiec po cholere tamte pierwsze funkcje? heh.. ano poto zebysmy mogli gdzie wstawic nasz kod ;). Ale najpierw musimy sprawdzic czy rzeczywiscie ten kod od 401000h jest zbedny.

Ja to zrobilem tak.. w JumpGeneratorze wpisalem "JMP" From "00401000" To "00401990" i wyliczyl opkod = E98B090000 wiec w hexedytorze ustawiamy sie na adresie 401000h - 400C00h czyli 400h
wstawiamy tam nasz opkod i zapisujemy. Utuchamiamy program i dziala :), wiec co? mamy kupe bajtow do wykorzystania do naszych celow :)))
Tak wiec otrzymalismy 0BAh (186) bajtow, wiec trzeba je rozplanowac.

Wiec najpierw nop-ujemy te bajty. Na samym poczatku (400h) wstawiamy "jmp 00401990" opkod = E98B090000

Zrobmy ze po sprawdzeniu czy wcisnieto "A", i jezeli nie to skacz do naszego nowego miejsca

seg000:004017B2                 cmp     [ebp+wParam], 41h
seg000:004017B6                 jz      loc_0_401750
seg000:004017BC                 jnz     loc_0_401005
seg000:004017C2                 nop
seg000:004017C3                 nop
seg000:004017C4                 nop


Tylko jest taki bajer ze to co napisalem w delphi (pokazuje kody nacisnietych klawiszy) nie dziala ;), tzn. klawisze hot-keyow maja inne kody, wiec z kad mamy wiedziec co nacisnal uzytkownik programu? pod adresem 405h wpiszmy wartosc CCh (int 3), w SoftIce ustawiamy na i3here on. I teraz po ebp+10h bedzie kod nasisnietego hotkeya. 

Oks, teraz wiemy ze zeby wywolac zamkniecie cd-romu musimy sprawdzic czy kod to 43h.

Teraz skopiujemy sobie procke wysuwajaca cd-rom i przerobimy tak aby go zamykala.
Procka ta zaczyna sie od 00401763 do 00401793 wiec w pliku od 0B63h do 0B93h

       00401763                 push    offset aWinmm_dll ; lpLibFileName
seg000:00401768                 call    LoadLibraryA
seg000:0040176D                 add     esp, 0FFFFFFF4h
seg000:00401770                 push    offset aMcisendstringa ; lpProcName
seg000:00401775                 push    eax             ; hModule
seg000:00401776                 call    GetProcAddress
seg000:0040177B                 mov     edx, eax
seg000:0040177D                 add     esp, 0FFFFFFF8h
seg000:00401780                 push    0
seg000:00401782                 push    0FFh
seg000:00401787                 lea     eax, [ebp+var_140]
seg000:0040178D                 push    eax
seg000:0040178E                 push    offset aSetCdaudioDoorOpen ; "set cdaudio door open"
seg000:00401793                 call    edx

68 40 16 40 00            ; push    offset aWinmm_dll
E8 8B 04 00 00            ; call    LoadLibraryA  (z pod adersu 00401768)
83 C4 F4                  ; add     esp, 0FFFFFFF4h   (niepotrzebne)
68 4A 16 40 00            ; push    offset aMcisendstringa ; lpProcName
50                        ; push    eax
E8 85-04 00 00            ; call    GetProcAddress (z pod adersu 00401776)
89 C2                     ; mov     edx, eax
83 C4 F8                  ; add     esp, 0FFFFFFF8h
6A 00                     ; push    0
68 FF 00 00 00            ; push    0FFh
8D 85 C0 FE FF FF         ; lea     eax, [ebp+var_140]
50                        ; push    eax
68 59 16 40 00            ; push    offset aSetCdaudioDoorOpen
FF D2                     ; call    edx

I jeszcze ja zoptymalizujemy do:

68 40 16 40 00            ; push    offset aWinmm_dll
E8 8B 04 00 00            ; call    LoadLibraryA  (z pod adersu 00401768)
68 4A 16 40 00            ; push    offset aMcisendstringa ; lpProcName
50                        ; push    eax
E8 85-04 00 00            ; call    GetProcAddress (z pod adersu 00401776)
89 C2                     ; mov     edx, eax
6A 00                     ; push    0
68 FF 00 00 00            ; push    0FFh
8D 85 C0 FE FF FF         ; lea     eax, [ebp+var_140]
50                        ; push    eax
68 59 16 40 00            ; push    offset aSetCdaudioDoorOpen
FF D2                     ; call    edx

(44 bajty)

Procke ta skopiujemy pod adres 48Ch, czyli mamy ja pod 0040108Ch.
I teraz musimy pozmieniac 2 call-e:

E8 8B 04 00 00            ; call    LoadLibraryA  (z pod adersu 00401768)
E8 85-04 00 00            ; call    GetProcAddress (z pod adersu 00401776)

Na takie zeby wywolywaly ta procedure z pod nowego adresu:

Wiedzac ze:

seg000:00401C00 GetProcAddress  proc near               ; CODE XREF: sub_0_401694+E2p
seg000:00401C00                 jmp     ds:__imp_GetProcAddress
seg000:00401C00 GetProcAddress  endp

i ze "call    GetProcAddress" jest pod adresem 49Ch (0040109C)

wiec 401C00 - 0040109C - 5 = B5Fh

wiec nowy opkod = E85F0B0000

seg000:00401BF8 LoadLibraryA    proc near               ; CODE XREF: sub_0_401694+D4p
seg000:00401BF8                 jmp     ds:__imp_LoadLibraryA
seg000:00401BF8 LoadLibraryA    endp

i ze "call    LoadLibraryA" jest pod adresem 491h (00401091)

wiec 00401BF8 - 00401091 - 5 = B62h

wiec nowy opkod = E8620B0000

Oraz musimy zmienic offset command-stringu z "set cdaudio door open" na wczesniej wpisany 
"set cdaudio door closed" ktory jest pod adresem 004012D6h

68 59 16 40 00            ; push    offset aSetCdaudioDoorOpen

i zmieniamy na:

68 D6 12 40 00            ; push    offset aSetCdaudioDoorClosed

na koncu procki (4B8h) dodajemy "jmp 00401870" (koniec procki)
wiec z adresu 004010B8h
 opkod = E9B3070000

Kasujemy (nopujemy) wartosc CCh z adresu 405h, i uruchamiamy proga, po nacisnieciu jakiegos klawisza oprocz "A" powinien sie przeladowac cd-rom. OK. Teraz zrobimy porownania:

cmp [ebp+10h], 43h  (klawisz "C")
jz 0040108Ch  (zamknij cd-rom)

Skopiujmy ta procke pod adres 405h

cmp [ebp+10h], 43h = 83 7D 10 43
i teraz jesli rowne to skok z adresu 409h (00401009) do 0040108C
opkod = 0F847D000000

I teraz uruchamiamy proga i wszystko powinno byc tak samo jak przed dodaniem porownania, OK.

Teraz damy porownanie z 30h (nacisnieto CTRL+B) i po tym ma wyswietlic sie MessageBox z info "You put CTRL+B"
hmm... pomyslmy MessageBox razem juz z Uchwytem okna jest pod adresem 004017A4h
wiec wystarczy podac :

seg000:00401798                 push    uType
seg000:0040179A                 push    offset lpCaption
seg000:0040179F                 push    offset lpText

i potem "jmp 004017A4h"

Teraz trzeba znalezc troche miejsca na stringa "You put CTRL+B",0 czyli 15 bajtow
Oks, zapiszby go pod adresem 47Dh (0040107D).

68 40 00 00 00            push    40h
68 CE 12 40 00            push    offset lpCaption ("Hotkey!")
68 7D 10 40 00            push    offset lpText ("You put CTRL+B")
                          jmp     004017A4h

Zeby zaoszczedzic miejsca musimy wpisywac od konca, wiec "jmp     004017A4h" jest skokiem tzw. dlugim wiec jego opkod bedize mial 5 bajtow, wiec odejmujemy je od 47Dh i otrzymujemy 478h
i teraz liczymy opkod dla jmp od 00401078 do 004017A4 

opkod = E927070000

ok teraz od konca wpisujemy opkody "push    offset lpText ("You put CTRL+B")" itd. az do "push 40h", i tak pod adresem 469h (00401069) mamy procke wyswietlajaca messagebox.

Teraz patrzymy z kad jest wywolywany inny hotkey (ctrl+w):

seg000:004016C0 loc_0_4016C0:                           ; CODE XREF: sub_0_401694+16j
seg000:004016C0                 cmp     [ebp+Msg], 100h
seg000:004016C7                 jz      short loc_0_401728
seg000:004016C9                 cmp     [ebp+Msg], 312h
seg000:004016D0                 jz      short loc_0_401710   ;<- skacze jak jest hotkey
seg000:004016D2                 jmp     loc_0_401859
   ...
seg000:00401710 loc_0_401710:                           ; CODE XREF: sub_0_401694+3Cj
seg000:00401710                 cmp     [ebp+wParam], 11h
seg000:00401714                 jnz     loc_0_401870        <- jezeli nie Ctrl+W to wyjdz z procki, my to zmienimy zeby robil "jnz 401014"
seg000:0040171A                 push    40h
seg000:0040171C                 push    offset aHotkey  ; "Hotkey!"
seg000:00401721                 push    offset aHotkeyIsAGoodThingCtrlWD ; "Hotkey is a good thing - CTRL-W ;-D"
seg000:00401726                 jmp     short loc_0_4017A4

"jnz 401014" - pod tym adresem bedzie sprawdzanie czy nacisnieto "ctrl+b" jak tak to wyswietl messagebox jak nie to skok do 00401870

Zmieniamy skok z adresu 00401714  do 00401014
opkod = 0F85FAF8FFFF

Adres = B14h

a pod adresem 414h (00401014) robimy porownanie:

  cmp [ebp+10h], 30h
  jz 00401069h
  jmp 00401870h

opkody:

83 7D 10 30
74 4F
E9 50 08 00 00


Ok, teraz musimy napisac procke rejestrujace nasz hotkey Ctrl+b, gdyz niestety rejestrowany jest tylko ctrl+w:

seg000:004016D7 loc_0_4016D7:                           ; CODE XREF: sub_0_401694+1Cj
seg000:004016D7                 push    57h             ; vk
seg000:004016D9                 push    2               ; fsModifiers
seg000:004016DB                 push    11h             ; id
seg000:004016DD                 mov     eax, [ebp+hWnd]
seg000:004016E0                 push    eax             ; hWnd
seg000:004016E1                 call    RegisterHotKey
seg000:004016E6                 jmp     loc_0_401870      ;<- to zmienimy na jmp 401020

Dlugosc procki to 10 bajtow wiec powinna sie zmiescic, zapiszemy ja w adresie 420h (00401020)

opkod =

6A 57
6A 02 
6A 11 
8B 45 08 
50 
E8 62 04 00 00

Musimy pozmieniac odpowiednie wartosci:
Przypomne :
  RegisterHotKey(Form1.Handle, $0001, MOD_CONTROL,  VK_F4);
  I tak na przyklad powyzsza procka rejestruje Ctrl+F4, a id = $0001 

6A 42        ; vk = 66 = 'B'
6A 02        ; ctrl 
6A 12        ; id = 12
8B 45 08     
50 
E8 62 04 00 00

oraz wywaoanie procedury RegisterHotKey, teraz z adresu 0040102A do 

seg000:00401B48 RegisterHotKey  proc near               ; CODE XREF: seg000:004016E1p
seg000:00401B48                 jmp     ds:__imp_RegisterHotKey
seg000:00401B48 RegisterHotKey  endp

00401B48 - 0040102A - 5 = B19h
opkod = E8 19 0B 00 00

Po tej funkcji dodajemy "jmp 00401870"
z 0040102F do 00401870
opkod = E93C080000

I jeszcze pod adresem 417h zmieniamy bajt na 12h (sprawdza czy nacisnieto Ctrl+B , id = 12h)

Teraz zmienimy jump:
seg000:004016E6                 jmp     loc_0_401870
 na 
seg000:004016E6                 jmp     loc_0_401020

opkod = E935F9FFFF

Ok, wszystkie hotkeye dzialaja :))), ao my to jeszcze mamy zrobic... aha program ma sie uruchamiac zminimalizowany. Pomyslmy... 

Program wywoluje funkcje ShowWindow ;), heh.. juz pewnie sami wiecie co dalej zrobimy ;))

seg000:00401933                 push    3               ; nCmdShow
seg000:00401935                 push    ebx             ; hWnd
seg000:00401936                 call    ShowWindow

jak widzimy jako nCmdShow podawana jest liczba 3 a, 3 = SW_MAXIMIZE i tak wlasnie uruchamia sie program zmaksymalizowany ;), my to zmienimy dajac SW_MINIMIZE = 6
idziemy do adresu 00401933 - 400C00 = D33 i zmieniamy 6A03 na 6A06

I TO WSZYSTKO !!! ReverseMe ZLAMANY ! ;)))

W zalaczniku rozwalony juz program (un_hot_reme.exe) i nie rozwalony (hot_reme.exe) (dla ciebie gdybys chcial sam sprobowac ;))

Pozdrawiam !

                 _TeStON_ ^ UnderPL

 Date: 04.05.2002
 mailto: teston@chesti.com
 http://www.pzone.of.pl/