PC-cillin 2003
Reversing the update client

Data

by "M@GiStR"

 

23/02/2003

UIC's Home Page

Published by Quequero

 
Bravo magi hai fatto proprio un bel tute per essere la tua prima volta, complimenti
 

....

irc.azzurranet.org / irc.tin.it      #crack-it

....

Difficoltà

(x)NewBies ( )Intermedio ( )Avanzato ( )Master

 

PC-cillin 2003
Reversing the update client

Written by M@GiStR.


Introduzione

Vedremo come eliminare il check della License Key dell'antivirus PC-cillin 2003 ogni volta che si effettua un update da programma. PC-cillin utilizza il proprio server per validare la licenza dell'utente che cerca di aggiornare il programma on-line. Se questo check dà esito negativo (sempre a meno che non abbiate pagato e siate registrati sul sito) il cillin non permette l'aggiornamento e fornisce una messagebox di errore..

Tools usati

Un disassembler qualsiasi, tipo win32dasm o IDA

Filemon

Un Hex-editor

URL o FTP del programma

www.trendmicro.com

Notizie sul programma

La prima cosa che ho fatto è stato cercare di capire come avvenisse questo scambio di dati con il server. Solitamente in questi tipi di programmi il server invia un file al client con dentro la risposta alla richiesta del client. Allora ho runnato filemon e mi sono accorto che all'atto dell'update viene utilizzato il processo "PCCClient" (il file è pccclient.exe). Che dite lo disassembliamo?? evvai! mano al dasm e via!

Essay

Come prima cosa un'occhiata alla string reference e subito mi balza all'occhio la stringa "RESPONSE". Potrebbe essere la risposta del server alla richiesta del client?? Per saperlo portiamoci sul codice e cosa vediamo? una call all'API GetPrivateProfileIntA. Questa si occupa di prelevare dati dai file .ini (in questo caso un intero).

Ecco la descrizione dell'API:

UINT GetPrivateProfileInt(

    LPCTSTR lpAppName,      // address of section name

    LPCTSTR lpKeyName,      // address of key name

    INT nDefault,          // return value if key name is not found

    LPCTSTR lpFileName        // address of initialization filename

   );

...e questo è il codice che vediamo:

:00408220 51                      push ecx         <--- pusha il nome del file

:00408221 6A00                    push 00000000    <--- pusha il valore di ritorno di default

* Possible Reference to Dialog

:00408223 68DC524400              push 004452DC    <--- pusha il nome della chiave da ricercare nel file

* Possible StringData Ref from Data Obj ->"RESPONSE"

:00408228 68E0524400              push 004452E0     <--- pusha il nome della sezione da ricercare nel file ([RESPONSE])

* Reference To: KERNEL32.GetPrivateProfileIntA, Ord:017Fh

:0040822D FF1510C34300            Call dword ptr [0043C310]   <--- invoca l'API  GetPrivateProfileIntA

:00408233 8945EC                  mov dword ptr [ebp-14], eax

:00408236 8D8DE4FEFFFF            lea ecx, dword ptr [ebp+FFFFFEE4]

:0040823C E88F6B0000              call 0040EDD0

:00408241 C745FC00000000          mov [ebp-04], 00000000

:00408248 8D4DF0                  lea ecx, dword ptr [ebp-10]

:0040824B E8806B0000              call 0040EDD0

:00408250 C645FC01                mov [ebp-04], 01

* Possible Reference to String Resource ID=57351: "Trend Micro PC-cillin"

:00408254 6807E00000              push 0000E007

:00408259 8D4DF0                  lea ecx, dword ptr [ebp-10]

:0040825C E82EAE0200              call 0043308F

:00408261 8B55EC                  mov edx, dword ptr [ebp-14]

:00408264 8995B8FEFFFF            mov dword ptr [ebp+FFFFFEB8], edx  <---- l'intero prelevato dal file ce lo troviamo qui

:0040826A 81BDB8FEFFFF9A010000    cmp dword ptr [ebp+FFFFFEB8], 0000019A <-- viene confrontato con 19Ah=410

:00408274 7F3A                    jg 004082B0               <-- se è > salta a 4082B0

:00408276 81BDB8FEFFFF9A010000    cmp dword ptr [ebp+FFFFFEB8], 0000019A <-- viene confrontato con 19Ah=410

:00408280 0F8463010000            je 004083E9                    <-- se è = salta a MessageBox("Expire DB connection error")

:00408286 83BDB8FEFFFF64          cmp dword ptr [ebp+FFFFFEB8], 00000064 <-- viene confrontato con 64h=100

:0040828D 7446                    je 004082D5                                       <-- se è = salta verso la fine della call

:0040828F 81BDB8FEFFFFD2000000    cmp dword ptr [ebp+FFFFFEB8], 000000D2 <-- viene confrontato con D2h=210

:00408299 7458                    je 004082F3                                         <-- se è = salta a MessageBox("Your license has expired")

:0040829B 81BDB8FEFFFF36010000    cmp dword ptr [ebp+FFFFFEB8], 00000136 <-- viene confrontato con 136h=310

:004082A5 0F84C3000000            je 0040836E                              <-- se è = salta a MessageBox("Your license key format is invalid")

:004082AB E9AA020000              jmp 0040855A                            <-- salta a MessageBox ("Unknown error")

* Referenced by a (U)nconditional or (C)onditional Jump at Address: 00408274(C)

:004082B0 81BDB8FEFFFFA4010000    cmp dword ptr [ebp+FFFFFEB8], 000001A4 <-- viene confrontato con 1A4h=420

:004082BA 0F84A4010000            je 00408464                                          <-- se è = salta a MessageBox ("No database error")

:004082C0 81BDB8FEFFFFAE010000    cmp dword ptr [ebp+FFFFFEB8], 000001AE <-- viene confrontato con 1AEh=430

:004082CA 0F840F020000            je 004084DF                                         <-- se è = salta a MessageBox ("Unknown error")

:004082D0 E985020000              jmp 0040855A                                         salta a MessageBox ("Unknown error")

Dunque adesso siamo sicuri che è proprio questo il check che ci interessa, infatti abbiamo visto che avviene prelevando la risposta da un file .ini inviato dal server. L'unica risposta che non fornisce un errore è all'indirizzo 40828D dove se l'intero ricercato è "100" salta verso la fine della call. Usciamo allora dalla call e ci ritroviamo all'indirizzo 408CF7. Si vede che lo stesso check sul file viene ripetuto altre 2 volte:

:00408CF2 E838F4FFFF              call 0040812F

:00408CF7 8985E4EAFFFF            mov dword ptr [ebp+FFFFEAE4], eax

:00408CFD 83BDE4EAFFFF64          cmp dword ptr [ebp+FFFFEAE4], 00000064  <--check

:00408D04 750B                    jne 00408D11

:00408D06 8B8D10F3FFFF            mov ecx, dword ptr [ebp+FFFFF310]

:00408D0C E8130E0000              call 00409B24

* Referenced by a (U)nconditional or (C)onditional Jump at Addresses: 00408C92(U), :00408CEA(C), :00408D04(C)

:00408D11 8B8DE4EAFFFF            mov ecx, dword ptr [ebp+FFFFEAE4]

:00408D17 51                      push ecx

* Possible Reference to Dialog: 

:00408D18 686C5A4400              push 00445A6C

:00408D1D 6A28                    push 00000028

:00408D1F 683C040000              push 0000043C

* Possible StringData Ref from Data Obj ->"D:\Pcc10\src\modules\PCCClient\MainFrm.cpp"

:00408D24 68A05A4400              push 00445AA0

:00408D29 E8EC670100              call 0041F51A

:00408D2E 83C414                  add esp, 00000014

:00408D31 83BDE4EAFFFF64          cmp dword ptr [ebp+FFFFEAE4], 00000064  <-- 3° check

:00408D38 7422                    je 00408D5C

La prima cosa che mi viene da fare è forzare i jump condizionali di tutti e tre i check con dei jump fissi in modo tale che il valore intero prelevato dal file sia sempre riconosciuto come "100", quindi:

check :0040828D 7446   je 004082D5                  -----> EB46 salto fisso

check :00408D04 750B   jne 00408D11                -----> 7500 nessun salto

check :00408D38 7422   je 00408D5C                 -----> EB22 salto fisso

Prima di salvare con il nostro bell'hex-editor terminiamo il processo "PCCClient" con il task manager, salviamo e facciamolo ripartire di nuovo. Adesso lanciamo l'updater e magicamente l'update viene fatto!!! Bene...potreste pensare che a questo punto abbiamo finito, ma invece NO! Mica vogliamo che il nostro bel seriale taroccato e magari qualche altra bella informazione venga inviata al server del Cillin??? ASSOLUTAMENTE NO!!!!!!!!Allora...scordatevi le modifiche che abbiamo fatto perchè non ci serviranno +. Tutto questo è servito per capire come funziona, ma ora passiamo al crackaggio vero e proprio.Vediamo se riusciamo a saltare tutta la procedura di check. Poco prima della call incriminata (quella a 408CF2) si notano altre 2 chiamate all'API: GetPrivateProfileStringA che è uguale alla precedente, eccetto per il fatto che restituisce una stringa invece di un intero. Soffermiamoci su quella all'indirizzo 408C71 e cerchiamo di capire cosa fa:

:00408C61 51                      push ecx                         <--- pusha il nome del file

* Possible Reference to Dialog: 

:00408C62 68FC2F4500              push 00452FFC                           <--- pusha il valore di ritorno di default

* Possible StringData Ref from Data Obj ->"LastCheckDate"

:00408C67 682C5A4400              push 00445A2C                          <--- pusha il nome della chiave da ricercare nel file

* Possible StringData Ref from Data Obj ->"UPDATE"

:00408C6C 683C5A4400              push 00445A3C                          <--- pusha il nome della sezione da ricercare nel file

* Reference To: KERNEL32.GetPrivateProfileStringA, Ord:0185h

:00408C71 FF1590C24300            Call dword ptr [0043C290]        <--- invoca l'API GetPrivateProfileStringA

:00408C77 C785E4EAFFFF64000000    mov dword ptr [ebp+FFFFEAE4], 00000064

:00408C81 8D95B0E0FFFF            lea edx, dword ptr [ebp+FFFFE0B0]

:00408C87 52                      push edx

:00408C88 E8B39A0100              call 00422740                              <--- questa call verifica se alla sezione UPDATE la chiave "LastCheckDate" è vuota o contiene una stringa (in questocaso è la data dell'ultimo check effettuato)

:00408C8D 83C404                  add esp, 00000004

:00408C90 85C0                    test eax, eax

:00408C92 747D                    je 00408D11    <--- se la stringa è vuota salta ben oltre la procedura di check e va direttamente alla procedura di update!!

:00408C94 8D8514F4FFFF            lea eax, dword ptr [ebp+FFFFF414]

:00408C9A 50                      push eax

:00408C9B 6804010000              push 00000104

:00408CA0 8D8DB0E0FFFF            lea ecx, dword ptr [ebp+FFFFE0B0]

:00408CA6 51                      push ecx

:00408CA7 6800304500              push 00453000

Beh! a questo punto tutto è chiaro! Il PC-Cillin fornisce un'unica possibilità di aggiornamento all'utente TRIAL. Una volta effettuata inserisce in pc-cillin.ini alla sezione UPDATE e alla voce "LastCheckDate" la data in cui è stato effettuato l'aggiornamento. Quindi quando questo campo è vuoto vuol dire che non abbiamo mai aggiornato il programma e quindi ce lo fa fare, viceversa quando trova una data inserita, vuol dire che abbiamo già aggiornato una volta e quindi lancia la procedura di check del serial e torniamo a tutto quello che abbiamo visto prima. Come risolviamo questo problema?? Beh...a questo punto anche un muflone saprebbe la risposta! Modifichiamo all'indirizzo 408C92 mettendo un jump fisso, quindi:

:00408C92 747D   je 00408D11        ---> EB7D

Note finali

Basta quindi modificare un solo byte per saltare tutta la procedura di check e aggiornare ogni volta che vogliamo!! Carino no?

Un saluto a...Quequero che ha pubblicato il mio primo tute per la UIC, _Blackdeath_, crazykiwi, DJK, Pincopall e tutti i membri della UIC!

byez e alla prossima!!

Disclaimer

Qui inserirete con questo carattere il vostro piccolo disclaimer, non è obbligatorio però è meglio per voi se c'è. Dovete scrivere qualcosa di simile a: vorrei ricordare che il software va comprato e  non rubato, dovete registrare il vostro prodotto dopo il periodo di valutazione. Non mi ritengo responsabile per eventuali danni causati al vostro computer determinati dall'uso improprio di questo tutorial. Questo documento è stato scritto per invogliare il consumatore a registrare legalmente i propri programmi, e non a fargli fare uso dei tantissimi file crack presenti in rete, infatti tale documento aiuta a comprendere lo sforzo immane che ogni singolo programmatore ha dovuto portare avanti per fornire ai rispettivi consumatori i migliori prodotti possibili.

Noi reversiamo al solo scopo informativo e di miglioramento del linguaggio Assembly.