HTML

Hackstock

Hack the planet! Hackers unite!

Címkék

Címkefelhő

IDA for MacOSX akcióban

2008.01.13. 18:42 :: theshadow

Az IDA 5.2 for MacOSX elindításában két nehéz dolgot ismerek. Az első a beszerzése; nem egyszerű, mert nem kering minden csatornán. Ha az első problémát megoldottuk, akkor a mac_server és idal modulon a procmod-ot kell engedélyezni (chmod g+s vagy chgrp procmod).

Ezen túl a nyomkövetésben is némi eltérés mutatkozik. Egy terminálablakban el kell indítani a mac_server-t. Én ezt a következőképpen szoktam.

sudo ./mac_server -Pmypass

Itt most kétféleképpen járhatunk el. Van egy Windows-os számítógépen fejtetjük vissza a binárist vagy egy MacOSX-en. Azért lehet ez, mert mindkét esetben remote debuggolás fog történni. Helyben végezve az IDA-ban a Debug / Process options... menüpontban a következőképpen kell beállítani a paramétereket.

   

Ha eddig nincs probléma, akkor vessük rá magunkat első áldozatunkra, a Mah Jong Solitaire 2.21 for Mac OS X-et vettem kezelésbe (most találtam rá a 2.55-ös verzióra, sebaj ezért nem kezdek neki megint most).
A visszafejtés elkészülte után az első gondolatom az volt, hogyan találjam meg azt a funcionális részt, ahol az unlock kód ellenőrzése történik. Mivel itt is lokalizált erőforrások vannak, arra számítottam nem lesz könnyű dolgom de egy erőtlen próbálkozást megeresztettem. Szöveget kerestem a visszafejtett forrásban: "Register". Az első találat ez volt.

__text:00001F83                 call    ___keymgr_dwarf2_register_sections

Nem biztató, de tovább nyomkodtam a ctrl-t gombokat. Nem is olyan sokára érdekes dologra bukkantam.

__text:00023E3A __RegistrationController_registerOnline__ proc near

Online regisztráció? Vizsgáljuk meg közelebbről. Egy referencia látszik, amit követve adatszegmensben egy táblázatban találtam. Azt hittem, hogy ez probélma, de eszembe jutott, amit Windows-ban iTunes debuggolása közben láttam: objektumorientált struktúrák. Vessünk egy pillantást az egész táblázatra.

__inst_meth:00040360 dword_40360     dd 0         ; DATA XREF: __class:stru_3D420^o
__inst_meth:00040364                 dd 18h
__inst_meth:00040368                 dd offset aSaveprefsdata, offset a@12@04@8, offset __RegistrationController_savePrefsData__ ; "@12@0:4@8"
__inst_meth:00040374                 dd offset aShowentercodep, offset aV12@04@8, offset __RegistrationController_showEnterCodePanel__ ; "v12@0:4@8"
__inst_meth:00040380                 dd offset aFilloutregistr, offset a@8@04, offset __RegistrationController_fillOutRegistration_ ; "@8@0:4"
__inst_meth:0004038C                 dd offset aCodeentered, offset aV12@04@8, offset __RegistrationController_codeEntered__ ; "v12@0:4@8"
__inst_meth:00040398                 dd offset aRegistered, offset aC8@04, offset __RegistrationController_registered_ ; "c8@0:4"
__inst_meth:000403A4                 dd offset aGeneratechecks, offset a@12@04@8, offset __RegistrationController_generateChecksum__ ; "@12@0:4@8"
__inst_meth:000403B0                 dd offset aRegistered_0, offset aC12@04@8_0, offset __RegistrationController_registered__ ; "c12@0:4@8"
__inst_meth:000403BC                 dd offset aRemoveohs, offset aV12@048, offset __RegistrationController_removeOhs__ ; "v12@0:4*8"
__inst_meth:000403C8                 dd offset aGestaultcheck, offset aC12@04i8, offset __RegistrationController_gestaultCheck__ ; "c12@0:4i8"
__inst_meth:000403D4                 dd offset aShortversion, offset a@8@04, offset __RegistrationController_shortVersion_ ; "@8@0:4"
__inst_meth:000403E0                 dd offset aDaysowned, offset aI8@04, offset __RegistrationController_daysOwned_ ; "i8@0:4"
__inst_meth:000403EC                 dd offset aAddtogames, offset a@8@04, offset __RegistrationController_addToGames_ ; "@8@0:4"
__inst_meth:000403F8                 dd offset aValiditystring, offset a@12@04@8, offset __RegistrationController_validityString__ ; "@12@0:4@8"
__inst_meth:00040404                 dd offset aCapitalisestri, offset a@12@048, offset __RegistrationController_capitaliseString__ ; "@12@0:4*8"               
__inst_meth:00040410                 dd offset aShiftstring, offset a@16@048c12, offset __RegistrationController_shiftString___ ; "@16@0:4*8c12"
__inst_meth:0004041C                 dd offset aSetprefsdata, offset a@12@04@8, offset __RegistrationController_setPrefsData__ ; "@12@0:4@8"
__inst_meth:00040428                 dd offset aRegistrationst, offset a@8@04, offset __RegistrationController_registrationString_ ; "@8@0:4"
__inst_meth:00040434                 dd offset aRegisteronline, offset aV12@04@8, offset __RegistrationController_registerOnline__ ; "v12@0:4@8"
__inst_meth:00040440                 dd offset aUnlock, offset aV12@04@8, offset __RegistrationController_unlock__ ; "v12@0:4@8"
__inst_meth:0004044C                 dd offset aNotyet, offset aV12@04@8, offset __RegistrationController_notyet__ ; "v12@0:4@8"
__inst_meth:00040458                 dd offset aShowpanelbytim, offset a@12@04@8, offset __RegistrationController_showPanelByTimer__ ; "@12@0:4@8"
__inst_meth:00040464                 dd offset aShowlwygiyr, offset a@12@04@8, offset __RegistrationController_showLWYGIYR__ ; "@12@0:4@8"
__inst_meth:00040470                 dd offset aWindowshouldcl, offset aC12@04@8_0, offset __RegistrationController_windowShouldClose__ ; "c12@0:4@8"
__inst_meth:0004047C                 dd offset aShowaboutpanel, offset aV12@04@8, offset __RegistrationController_showAboutPanel__ ; "v12@0:4@8"

Ez bizony a RegistrationController objektum interface prototípusa, tehát itt vannak a pointerek a metódusok neveire, szignaturájára és metódusimplementációjára. Az érdekesség kedvéért nézzük meg az ő referenciáját is.

__class:0003D420 stru_3D420      __class_struct <offset stru_3DFE0, offset aNsobject, \
                       __class:0003D420   ; DATA XREF: __symbols:00043080vo
                       __class:0003D420    offset aRegistration_0, 0, 1, 6Ch, offset dword_42300,\ ;
                       __class:0003D420    offset dword_40360, 0, 0>

Nahát! Itt az első pointer az objektum ősosztályának ugyanilyen leíró blokkjára, majd az ősosztály neve. A következő mutató az aktuális objektum neve, az utolsó pedig a metódusleíró táblázat címe. Érdekes. Ezt azért mutattam meg, mert a későbbiekben nagyon hasznos lehet.
Most menjünk vissza és nézegessük a Registrationcontroller-t. Két metódusra figyeltem fel: aRegistered és aRegistered_0.

__text:0002453C __RegistrationController_registered_ proc near
__text:0002453C                                         ; DATA XREF: __inst_meth:00040398vo
__text:0002453C
__text:0002453C var_18          = dword ptr -18h
__text:0002453C var_14          = dword ptr -14h
__text:0002453C var_10          = dword ptr -10h
__text:0002453C arg_0           = dword ptr  8
__text:0002453C
__text:0002453C                 push    ebp
__text:0002453D                 mov     ebp, esp
__text:0002453F                 sub     esp, 18h
__text:00024542                 mov     edx, [ebp+arg_0]
__text:00024545                 mov     eax, [edx+54h]
__text:00024548                 mov     [esp+18h+var_10], eax
__text:0002454C                 mov     eax, ds:off_3CA64 ; registered:
__text:00024551                 mov     [esp+18h+var_14], eax
__text:00024555                 mov     [esp+18h+var_18], edx
__text:00024558                 call    _objc_msgSend
__text:0002455D                 leave
__text:0002455E                 retn
__text:0002455E __RegistrationController_registered_ endp

Azt úgy lehetne visszafordítani Objective-C-re:

[self registered: parameter]

. Ezek szerint a másik metódus lesz az érdekes, nosza nézzük meg azt is.
A __RegistrationController_registered__ metódus sokkal terjedelmesebb, ezért nem fogom mellékelni, de nézzük meg az értelmezését is.

param = [NSString stringWithCString: [self shiftString: [self capitaliseString: [self removeOhs: [param cString]]]: 'M']]

Ha nem is biztos, hogy pontosan ilyen volt, de értelmét tekintve ez a működés. Mivel már értelmeztem a saját eljárásokat, ezért gondolom, hogy ez a működés: a paraméterül kapott string-ből C-String-et készítünk, az O betüket nullára cseréljük benne és megkeressük az 'M' betüt, majd visszakonvertáljuk NSString-gé.
A következő lépés egy vizsgálat. A string 0. karaketere 'M', az első 'J', az ötödik 'X' és a hatodik 'S' karakter kell legyen. Ha ez nem így van, akkor EAX = 0 értékkel fejeződik be a rutin futása.

char* chksum = [[self generateChecksum: param] cString];
if (chksum[0] == param[12] && chksum[1] == param[13] && chksum[2] == param[13]){
    return 0;
}

A generateChecksum metódus az előbb előkészített string-et dolgozza fel, ami azt jelenti, hogy az első 11 karakterének a kódját számszerüleg összegzi, ezt XOR-olja 0xF95-tel és AND-olja 0xFFF-fel vagyis az alsó három hexadecimális számjegyet tartja meg. Ha ezek a számjegyek nem egyeznek meg a paraméter utolsó három karakterével, akkor nullás értékkel tér vissza.

int middle = _sscanf("%i","0x"+chksum[7]+chksum[8]+chksum[9]+chksum[10]+'\0');

Itt a 7-10 karakterből számértéket készítéttetük úgy, mintha azok hexadecimális jegyek lennének. A vizsgálata a következőképpen néz ki.

__text:000244AB                 cmp     eax, 5568h
__text:000244B0                 jz      short loc_244CE
__text:000244B2                 jg      short loc_244B9
__text:000244B4                 cmp     eax, 34h
__text:000244B7                 jmp     short loc_244C5
__text:000244B9 ; ---------------------------------------------------------------------------
__text:000244B9
__text:000244B9 loc_244B9: ; CODE XREF: __RegistrationController_registered__+140^j
__text:000244B9                 cmp     eax, 6789h
__text:000244BE                 jz      short loc_244CE
__text:000244C0                 cmp     eax, 7860h
__text:000244C5
__text:000244C5 loc_244C5: ; CODE XREF: __RegistrationController_registered__+145^j
__text:000244C5                 jz      short loc_244CE
__text:000244C7                 mov     eax, 1
__text:000244CC                 jmp     short loc_244D0
__text:000244CE ; ---------------------------------------------------------------------------
__text:000244CE
__text:000244CE loc_244CE: ; CODE XREF: __RegistrationController_registered__+10^j
__text:000244CE                                ; __RegistrationController_registered__+8D^j ...
__text:000244CE                 xor     eax, eax
__text:000244D0
__text:000244D0 loc_244D0: ; CODE XREF:__RegistrationController_registered__+15A^j

Tehát ha a kapott közbülső érték 0x5568, 0x6789, 0x7860 vagy 0x0034, akkor nulla értékkel lép ki.
Erre mit mondhatnék? Nem ez a legerősebb védelem, amit eddig láttam.
A teljesség igénye nélkül Java-ban a következő rutint állítottam össze ugyanennek az ellenőrzésnek a lebonyolítására.

    private boolean checkCode(byte[] code){
        boolean retval = false;
       
        if (code[0] == 'M' && code[1] == 'J' && code[5] == 'X' && code[6] == 'S'){
            int sum = 0;
            for (int i = 0; i < 0xb; ++i){
                sum += (code[i]&0xff);
            }
            sum = (sum ^ 0xf95) & 0xfff;
            String middle = new String(new byte[]{code[0x7],code[0x8],code[0x9],code[0xA]});
            retval = Integer.toHexString(sum).equalsIgnoreCase(new String(new byte[]{code[0xb],code[0xc],code[0xd]})) && !"5568".equalsIgnoreCase(middle) && !"6789".equalsIgnoreCase(middle) && !"7860".equalsIgnoreCase(middle);
            if (!retval){
                System.out.println("Checksum: "+Integer.toHexString(sum)+" ...or banned middle part (5568,6789,7860)");
            }
        }
       
        return retval;
    }

Tudom, hogy sok ellenőrzés hiányzik,de kísérletezni megteszi. Ha elsőre nem sikerülne eltalálnunk egy érvényes kódot, akkor a helyes checksum-ot megmutatja és a bannolt közteskódokat is.
Búcsúzóul álljon itt egy érvényes kód. Később talán áttekintem a következő verziót is, hátha ott rafináltabb az ellenőrzés.

MJ234XS7890D26

Szólj hozzá!

Címkék: macosx x86

A bejegyzés trackback címe:

https://hackstock.blog.hu/api/trackback/id/tr54295908

Kommentek:

A hozzászólások a vonatkozó jogszabályok  értelmében felhasználói tartalomnak minősülnek, értük a szolgáltatás technikai  üzemeltetője semmilyen felelősséget nem vállal, azokat nem ellenőrzi. Kifogás esetén forduljon a blog szerkesztőjéhez. Részletek a  Felhasználási feltételekben és az adatvédelmi tájékoztatóban.

Nincsenek hozzászólások.