Reverzujeme mshearts

Zdroj: SOOM.cz [ISSN 1804-7270]
Autor: ober
Datum: 13.3.2009
Hodnocení/Hlasovalo: 1.6/48

Budeme reverzovat M$ hearts (mshearts.exe) version 5.1, t.j. verze ktera je soucasti instalace WinXP. Ukolem bude pozmenit kod tak abychom videli vsechny karty obracene licem nahoru, tedy abychom videli i souperovy karty.

pouzite nastroje:
- OllyDbg
- MSVC 6.0
- Dependency Walker
- Process Explorer

reverzovany program:
- mshearts.exe ver. 5.1

Nejdrive musime najit kod, kde se jednotlive karty vykresluji.
Oteviram mshearts.exe ve VS abych se podival jestli neobsahuje v resources bitmapy jednotlivych karet (otevrit takto: File/Open, combo OpenAs nastavit na Resources, najit mshearts.exe a Open), k prohlednuti resources je mozno pouzit i jine sw.
V resources vidim ze tam zadne bitmapy nejsou, je tam par dialogu, ikona, string table ...
Jako dalsi vec se podivam, jake dll pouziva - presneji z jakych dalsich dll importuje.
Otevru mshearts.exe v DependendyWalker a vidim tam jen systemove dll a dll MFC a zadne jine podezrele dll ktere by mohlo vykreslovat bitmapy karet.
Zkusim to tedy jeste jinak, spustim mshearts a podivam se na neho v ProcessExploreru, jake dll ma naloadovane.
Hned jako ctvrta je cards.dll a to by melo byt to co hledam. Podivam se jake resources ma cards.dll ( je v \Windows\system32 ) a vidim ze tam jsou bitmapy vsech karet, ted jeste zjistit jak se vykresluji.
Podivam se jake funkce cards.dll exportuje (napr. DependencyWalkerem).
Nejzajimavejsi pro nas ucel se zdaji byt cdtDraw a cdtDrawExt.
Otevru mshearts.exe v Olly a protoze adresy cdtDraw funkci by mely byt ziskany volanim GetProcAddress, zkusim najit stringy "cdtDraw", "cdtDrawExt".
Na adrese 0x01001554 je "cdtDraw". Vyhledam mista kde se na tento string odkazuje "Find references/to selected address" nebo CTRL+R Odkaz je jenom na miste kde se vola GetProcAddress - 01002db9


tady vidim ze zjistena adresa funkce cdtDraw se ulozi na 0100d384, je to vlastne vysledek volani GetProcAddress ktery je v registru EAX.
Dam si breakpoint na 01002DD6 abych zjistil co bude v EAX, t.j. jaka je adresa cdtDraw funkce, spustim F9 a v mem pripade v EAX mam 6fc11813. Najedu na tu adresu (CTRL+G EAX) a nastavim breakpoint. Ted mam breakpoint nastaveny na zacatku funkce cdtDraw v cards.dll, pustim program dal F9,
(Pozn. pokud mate Olly zobrazeny na fullscreen tak nevidite co se deje v mshearts a program se na breakpointu nezastavil, prepnete se na mshearts a uvidite ze ceka na zadani jmena hrace, po zadani se uz zacnou vykreslovat karty, t.j. dojde na nas bp)
po zastaveni na breakpointu vidim neco takoveho, t.j. kod funkce cdtDraw v cards.dll:

ted potrebuju vedet odkud z mshearts.exe se to volalo.
Podivam se na CallStack (ALT+K) tam je jako posledni ulozena adresa, kam se program vrati po volani CALL CARDS.cdtDraw, nebo taky ve cloupci “Called from” je adresa kde je CALL (mshearts.01002FCF)
Mohu dat CTRL+G 01002FCF – t.j. goto na adresu, nebo F4 – execute to return nebo Show call a dostanu se na kod, odkud se z mshearts vola vykreslovani karty. Po chvili krokovani a sledovani co se vykresluje zjistim ze kod (viz nize) vykresli kartu licem nahoru

a kod (viz nize) vykresli kartu rubem nahoru

cdtDraw ma 6 parametru, a ted jeste vedet, co ktery znamena. Mohli bychom laborovat a zkouset ruzne moznosti a sledovat co se pri vykreslovani zmenilo nebo zkusim google a vida, je tam popis funci i parametru cards.dll (napr. zde: http://www.catch22.net/tuts/cards)

BOOL WINAPI cdtDraw (HDC hdc, int x, int y, int card, int type, DWORD color)

nas bude zajimat ctvrty parametr "card" ktery urcuje kod karty nebo kod pozadi (01002F95 PUSH ECX )
a paty parametr "type", ktery urcuje zda se zobrazi lic nebo rub (01002F92 PUSH DWORD PTR SS:[EBP+14] )
porovnanim obou casti kodu zjistime ze pri vykreslovani karty licem nahoru je "type" nula, zmenime tedy

01002F92 |. FF75 14 PUSH DWORD PTR SS:[EBP+14]


na

01002F92 6A 00 PUSH 0
01002F94 90    NOP


(pozn. NOP je tam pridane proto, abychom zachovali delku op. kodu, puvodni je 3 bajty dlouha FF 75 14 a my ji zmenime na push 0 ktera je 2 bajtova 6A 00 a proto zbyle bajty zmenime na NOP instrukce 90)

spustime a zjistime ze to jeste neni ono, protoze vsechny pozadi se vykreslily takto:

problem je v kodu karty, ten je totiz vzdy 36 - viz.

01002F8A 6A 36 PUSH 36
01002F8C 59    POP ECX
...
01002F95 51    PUSH ECX


porovnanim obou casti kodu pro vykreslovani karet a analyzou kodu zjistime, ze kod karty se uklada do registru ECX

01002F79 MOV ECX,DWORD PTR DS:[ECX]


je ale pote prepsan na hodnotu 36 (viz kod vyse) udelame jeste dalsi zmenu v kodu abychom zabranili prepsani registru ECX

01002F8A 90 NOP
01002F8B 90 NOP
01002F8C 90 NOP


(pozn. Prepisujeme tri bajty protoze push 63 je dvoubajtova 6A 36 a pop ecx je jednobajtova 59, takze celkem musime prepsat tri bajty)
spustime a meli bychom videt neco takoveho:



takze stacilo zmenit tri instrukce :-)