Lezione 8 per Newbies

Data

by tactus

 

29/1/2001

UIC's Home Page

Published by Quequero

...

Il tutorial è davvero esaustivo è preciso, ma fallo per me, la prossima volta non mi presentare il disassemblato in una sola riga, vai a capo ogni tanto ok?

...

....

Home page:
E-mail: tactus_2001@yahoo.com
Nick, UIN, canale IRC/EFnet frequentato:

....

Difficoltà

( X )NewBies ( )Intermedio ( )Avanzato ( )Master

 

Ottava fatica per un Newbie affrontata con il dead listing alla mano.


OTTAVO

Written by tactus

Introduzione

Ho cercato di essere chiaro anche se entrare nel dettagli di tutto (soprattutto dell'uso degli strumenti) avrebbe preso troppo spazio. Una analisi del disassemblato permette spesso di vedere cose che con SICE difficilmente si notano.

Tools usati

Tools usati
HIEW 6.15 non il migliore hexeditor ma insuperabile per il patch
IDA 3.80
Resource Hacker 3.1.0.24

URL o FTP del programma

http://quequero.cjb.net/

Notizie sul programma

8.

Essay


LIVELLO 1.

Io sono un fanatico di IDA, quindi non ho resistito ad un approccio 'dead listing' piuttosto che con Soft-Ice. Vediamo quindi come iniziare. C'è da abilitare un pulsante: all'atto della partenza il pulsante appare disabilitato, così abbiamo due possibilità: o viene disabilitato dalle risorse o da programma. Vediamo di chiarirci meglio. Le finestre che compaiono nei programmi, spesso sono create utilizzando un apposito editor, compilate separatamente ed inserite nel programma in una zona particolare (le Risorse). Questo rende molto facile, a chi usa il C++, sviluppare anche complessi dialoghi (sono chiamate così alcuni tipi di finestre) perchè l'editor dà una visione grafica di come apparirà.
Da buon cracker, dovete munirvi di uno strumento per andare a dare uno sguardo alle risorse di ogni programma. Io utilizzo Resource Hacker (attualmente alla versione 3.1.0.24) che ritengo il migliore ma può andare anche il Resource Workshop 4.5 di Borland.
L'utility ci dice che ci sono due dialoghi nell'applicazione. Ecco cosa riporta per il secondo:

102 DIALOGEX 0, 0, 182, 151 STYLE DS_SETFONT DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU EXSTYLE WS_EX_APPWINDOW CAPTION "Ottavo Corso Newbies - By AndreaGeddon" MENU 131 LANGUAGE LANG_ITALIAN, SUBLANG_ITALIAN FONT 8, "MS Sans Serif" { CONTROL "OK", 1, BUTTON, BS_DEFPUSHBUTTON | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 129, 135, 50, 14 CONTROL "Livello 1", 1000, BUTTON, BS_PUSHBUTTON | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 4, 50, 50, 14 CONTROL "Livello 2", 1001, BUTTON, BS_PUSHBUTTON | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 4, 70, 50, 14 CONTROL "Livello 3", 1002, BUTTON, BS_PUSHBUTTON | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 4, 90, 50, 14 CONTROL "About", 1003, BUTTON, BS_PUSHBUTTON | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 4, 135, 50, 14 CONTROL "UIC - Ottavo Corso Newbies", -1, STATIC, SS_LEFT | WS_CHILD | WS_VISIBLE | WS_GROUP, 45, 8, 94, 8 CONTROL "Written by: AndreaGeddon", -1, STATIC, SS_LEFT | WS_CHILD | WS_VISIBLE | WS_GROUP, 48, 19, 91, 8 CONTROL "", -1, BUTTON, BS_GROUPBOX | WS_CHILD | WS_VISIBLE, 39, 0, 105, 30 CONTROL "Volevate le funzioni disabilitate? Eccovele!", -1, STATIC, SS_LEFT | WS_CHILD | WS_VISIBLE | WS_GROUP, 26, 35, 140, 8 CONTROL "Istruzioni", 1004, BUTTON, BS_PUSHBUTTON | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 64, 135, 55, 14 CONTROL "", 1006, STATIC, SS_LEFT | WS_CHILD | WS_VISIBLE | WS_GROUP, 64, 53, 110, 8 CONTROL "", 1007, STATIC, SS_LEFT | WS_CHILD | WS_VISIBLE | WS_GROUP, 64, 73, 110, 8 CONTROL "", 1008, STATIC, SS_LEFT | WS_CHILD | WS_VISIBLE | WS_GROUP, 64, 93, 110, 8 CONTROL "", -1, STATIC, SS_BLACKFRAME | WS_CHILD | WS_VISIBLE, 5, 45, 174, 1 CONTROL "", -1, STATIC, SS_BLACKFRAME | WS_CHILD | WS_VISIBLE, 6, 130, 175, 1 CONTROL "Livello 4:", -1, STATIC, SS_LEFT | WS_CHILD | WS_VISIBLE | WS_GROUP, 14, 110, 40, 8 CONTROL "Livello 5", -1, STATIC, SS_LEFT | WS_CHILD | WS_VISIBLE | WS_GROUP, 14, 120, 40, 8 CONTROL "", 1009, STATIC, SS_LEFT | WS_CHILD | WS_VISIBLE | WS_GROUP, 64, 110, 110, 8 CONTROL "", 1010, STATIC, SS_LEFT | WS_CHILD | WS_VISIBLE | WS_GROUP, 64, 120, 110, 8 } L'ho riportato tutto perchè ci servirà molto durante il crack.
Notiamo subito che si tratta di una sorta di linguaggio speciale: viene descritto il dialogo ed i suoi componenti. Con il termine "CONTROL", si indica indifferentemente una label di testo o un pulsante. Vediamo in dettaglio il CONTROL con la scritta "Livello 1". Si tratta chiaramente del primo pulsante (compare "BUTTON" dopo la seconda virgola), fra virgolette la sua "Caption" (quello che deve esserci scritto sopra). Le sue proprietà sono elencate con le costanti tipiche (WS_ che sta per Window Style). Come si vede NON compare WS_DISABLED che avrebbe reso il pulsante disabilitato alla partenza; questo significa che inizialmente il bottone è attivo ma è il programma a disabiltarlo. Prendiamo nota del numero che compare appena prima di BUTTON: 1000 = 3E8h, questo numero è l'identificativo della risorsa nel programma: se qualcosa farà riferimento al pulsante, dovremo trovare questo numero lì intorno.
Ora è il momento di disassemblare il programma. Come al solito lanciamo IDA ed andiamo a farci un giro: il lavoro può durare parecchio. Al nostro ritorno cominciamo subito con il cercare nel sorgente il numero 3E8h: diamo Alt-T scriviamo il numero e diamo Enter.
Ecco cosa troviamo la prima volta:
.text:004013B9 add esi, 0E0h .text:004013BF push esi .text:004013C0 push 3E8h .text:004013C5 push edi .text:004013C6 call j_?DDX_Control@@YGXPAVCDataExchange@@HAAVCWnd@@@Z ; DDX_Control(CDataExchange *,int,CWnd &) Come si vede l'ID del pulsante è inserito nello stack appena prima della chiamata ad una funzione. In questo caso la funzione non ci dice molto; continuiamo a cercare. NON TROVIAMO PIU` NULLA! Questo indica che non possiamo agganciare il bottone direttamente ma possiamo tracciare la label vicino (i controlli STATIC), infatti la caption della label è vuoto (notate la stringa nulla appena dopo la parola CONTROL) e quindi qualcosa dovrà riempirla sia alla partenza sia quando ci registriamo.
La label ha ID 1006 = 3EEh: cerchiamola.
Ora va molto meglio: ecco cosa troviamo al primo stop:

.text:004014BA mov cl, 'd' .text:004014BC mov dl, 't' .text:004014BE mov al, 'r' .text:004014C0 mov Registered+9, cl .text:004014C6 mov Unregistered+0Bh, cl .text:004014CC push 0 ; Mettere a 1 per abilitare il primo bottone .text:004014CE lea ecx, [esi+0E0h] .text:004014D4 mov Registered, 'R' .text:004014DB mov Registered+1, bl .text:004014E1 mov Registered+2, 'g' .text:004014E8 mov Registered+3, 'i' .text:004014EF mov Registered+4, 's' .text:004014F6 mov Registered+5, dl .text:004014FC mov Registered+6, bl .text:00401502 mov Registered+7, al .text:00401507 mov Registered+8, bl .text:0040150D mov Registered+0Ah, 0 .text:00401514 mov Unregistered, 'U' .text:0040151B mov Unregistered+1, 'n' .text:00401522 mov Unregistered+2, al .text:00401527 mov Unregistered+3, bl .text:0040152D mov Unregistered+4, 'g' .text:00401534 mov Unregistered+5, 'i' .text:0040153B mov Unregistered+6, 's' .text:00401542 mov Unregistered+7, dl .text:00401548 mov Unregistered+8, bl .text:0040154E mov Unregistered+9, al .text:00401553 mov Unregistered+0Ah, bl .text:00401559 mov Unregistered+0Ch, 0 .text:00401560 call j_?EnableWindow@CWnd@@QAEHH@Z ; CWnd::EnableWindow(int) .text:00401565 push offset Unregistered .text:0040156A push 3EEh ; ID del primo static .text:0040156F mov ecx, esi .text:00401571 call j_?SetDlgItemTextA@CWnd@@QAEXHPBD@Z ; CWnd::SetDlgItemTextA(int,char const *) Il punto trovato è al fondo ma la parte sopra è importantissima. Qui IDA ci aiuta molto: nel suo ambiente interattivo ci permette di convertire facilmente una istruzione così:

.text:004014D4 mov byte_0_404208, 52h in una così:

.text:004014D4 mov Registered, 'R' che rende molto meglio il senso.
Come si vede il programma si dà in gran daffare per caricare la stringa REGISTERED e UNREGISTERED senza farla apparire direttamente. Grazie ad IDA alle locazioni 404208 e 4041F8 si possono creare due array di byte, dando i nomi che più ci aggrada. In questo modi risulta evidente quello che il programma fa: carica carattere per carattere le due stringhe. Finalmente al fondo inserisce nello stack l'offset della stringa UNREGISTERED e chiama SetDlgItemText che imposta il testo del controllo. Quindi qui siamo nel momento di inizializzazione e non molto distante deve anche esserci la disabilitazione del pulsante.
Infatti basta guardare appena sopra e si trova una chiamata a EnableWindow: il valore del suo unico parametro è pushato alla 4014CC, dove lo zero indica "disabilitato".
Quindi il primo è facile: basta eseguire la push di 1 piuttosto che zero.

LIVELLO 2.

Appena sotto la parte che abbiamo visto troviamo:

.text:00401576 push 0 ; attiva il secondo pulsante .text:00401578 lea ecx, [esi+0A0h] .text:0040157E call j_?EnableWindow@CWnd@@QAEHH@Z ; CWnd::EnableWindow(int) .text:00401583 push offset Unregistered .text:00401588 push 3EFh .text:0040158D mov ecx, esi .text:0040158F call j_?SetDlgItemTextA@CWnd@@QAEXHPBD@Z ; CWnd::SetDlgItemTextA(int,char const *) Guarda caso 3EFh è l'ID del secondo Static, quindi mettendo la push a 1 si abilita anche questo.
Sfortunetamente le cose non vanno così bene come prima e, appena premuto, il tasto torna disabilitato.
Dobbiamo fare ancora qualcosa. Sull'onda di prima cerchiamo 3EFh. La prima volta troviamo la parte che abbiamo visto ma alla seconda troviamo:

.text:004017F0 Livello_2 proc near .text:004017F0 .text:004017F0 var_14 = byte ptr -14h .text:004017F0 var_10 = dword ptr -10h .text:004017F0 var_C = dword ptr -0Ch .text:004017F0 var_8 = dword ptr -8 .text:004017F0 var_4 = byte ptr -4 .text:004017F0 .text:004017F0 sub esp, 10h .text:004017F3 mov eax, GrandeNumero_1 .text:004017F8 mov edx, dword_0_40405C .text:004017FE mov [esp+10h+var_10], eax .text:00401802 mov al, NumeroZero .text:00401807 push esi .text:00401808 mov esi, ecx .text:0040180A mov ecx, dword_0_404058 .text:00401810 mov [esp+14h+var_4], al .text:00401814 mov eax, dword_0_404020 .text:00401819 mov [esp+14h+var_C], ecx .text:0040181D cmp eax, 1E240h .text:00401822 mov [esp+14h+var_8], edx .text:00401826 jz short loc_0_401839 ; Salta sempre. .text:00401826 ; Se non salta registra il pulsante 2 .text:00401828 mov al, 20h .text:0040182A mov byte ptr [esp+14h+var_10+2], 52h .text:0040182F mov byte ptr [esp+14h+var_10], al .text:00401833 mov byte ptr [esp+14h+var_10+1], al .text:00401837 jmp short loc_0_401846 .text:00401839 ; --------------------------------------------------------------------------- .text:00401839 .text:00401839 loc_0_401839: ; CODE XREF: Livello_2+36j .text:00401839 push 0 .text:0040183B lea ecx, [esi+0A0h] .text:00401841 call j_?EnableWindow@CWnd@@QAEHH@Z ; CWnd::EnableWindow(int) .text:00401846 .text:00401846 loc_0_401846: ; CODE XREF: Livello_2+47j .text:00401846 lea ecx, [esp+18h+var_14] .text:0040184A push ecx .text:0040184B push 3EFh .text:00401850 mov ecx, esi .text:00401852 call j_?SetDlgItemTextA@CWnd@@QAEXHPBD@Z ; CWnd::SetDlgItemTextA(int,char const *) .text:00401857 pop esi .text:00401858 add esp, 10h .text:0040185B retn .text:0040185B Livello_2 endp ; sp = -0Ch .text:0040185B Come si vede siamo nel bel mezzo di una funzione che ho denominato Livello_2. Per il momento i campi GrandeNumero_1 e NumeroZero non ci interessano: gli useremo più avanti.
Dobbiamo concentrarci sul jz a 401826: il salto manda alla disabilitazione del tasto (stesso meccanismo di prima: richiama EnableWindow con 0) ma perchè salta? La risposta è nella cmp appena sopra; viene confrontato il numero 1E240h con il contenuto di eax che viene impostato poco più sopra dalla locazione dword_0_404020 che, guarda il caso, contiene proprio 1E240h.
Qui si può agire in diversi modi: per esempio cambiando uno dei dei valori numerici, ma io ho preferito modificare la jz facendola saltare comunque alla 00401828 (l'istruzione successiva).

LIVELLO 3.

Qui partiamo subito senza fare tante storie: cerchiamo 3F0h (l'ID del controllo STATIC per la terza label).
Lo troveremo ben tre volte:
  1. Nella parte relativa all'attivazione dei pulsanti, appena sotto i punti dove abbiamo già agito.
  2. Una funzione che potrebbe andare bene
  3. Una funzione che potrebbe pure andare bene

Al momento non sappiamo se la scelta 2 o 3 è quella giusta: un modo per scoprirlo è di modificale l'exe per attivare il pulsante e poi mettere un bpx da SoftICE nelle due parti; dove si verificherà il break, li è il gestore del tasto. Tuttavvia la funzione 2 appare più semplice ed è da quella che cominceremo. Eccola:

.text:00401860 Livello_3 proc near .text:00401860 .text:00401860 var_14 = byte ptr -14h .text:00401860 var_10 = dword ptr -10h .text:00401860 var_C = dword ptr -0Ch .text:00401860 var_8 = dword ptr -8 .text:00401860 var_4 = byte ptr -4 .text:00401860 .text:00401860 sub esp, 10h .text:00401863 mov eax, dword ptr GrandeNumero_1 ; "Unre" .text:00401868 mov edx, dword ptr GrandeNumero_1+8 ; "ered" .text:0040186E mov [esp+10h+var_10], eax .text:00401872 mov al, byte_0_404060 ; Questo byte vale zero .text:00401877 push esi .text:00401878 mov esi, ecx .text:0040187A mov ecx, dword ptr GrandeNumero_1+4 ; "gist" .text:00401880 mov [esp+14h+var_4], al .text:00401884 mov eax, DW_3DBh .text:00401889 mov [esp+14h+var_C], ecx .text:0040188D cmp eax, 3DBh .text:00401892 mov [esp+14h+var_8], edx .text:00401896 jz short Errore ; Salta Sempre .text:00401898 mov al, byte_0_404214 .text:0040189D test al, al .text:0040189F jnz short Buono .text:004018A1 cmp DW_29Ah, 29Ah .text:004018AB jz short Errore ; Salta Sempre .text:004018AD .text:004018AD Buono: ; CODE XREF: Livello_3+3Fj .text:004018AD mov ecx, dword ptr Registered .text:004018B3 mov edx, dword ptr Registered+4 .text:004018B9 mov ax, word ptr Registered+8 .text:004018BF mov [esp+14h+var_10], ecx .text:004018C3 mov cl, Registered+0Ah .text:004018C9 mov [esp+14h+var_C], edx .text:004018CD mov word ptr [esp+14h+var_8], ax .text:004018D2 mov byte ptr [esp+14h+var_8+2], cl .text:004018D6 jmp short loc_0_4018E2 .text:004018D8 ; --------------------------------------------------------------------------- .text:004018D8 .text:004018D8 Errore: ; CODE XREF: Livello_3+36j .text:004018D8 ; Livello_3+4Bj .text:004018D8 push 0 .text:004018DA lea ecx, [esi+60h] .text:004018DD call j_?EnableWindow@CWnd@@QAEHH@Z ; CWnd::EnableWindow(int) .text:004018E2 .text:004018E2 loc_0_4018E2: ; CODE XREF: Livello_3+76j .text:004018E2 lea edx, [esp+18h+var_14] .text:004018E6 mov ecx, esi .text:004018E8 push edx .text:004018E9 push 3F0h .text:004018EE call j_?SetDlgItemTextA@CWnd@@QAEXHPBD@Z ; CWnd::SetDlgItemTextA(int,char const *) .text:004018F3 pop esi .text:004018F4 add esp, 10h .text:004018F7 retn .text:004018F7 Livello_3 endp ; sp = -0Ch Anche qui IDA ci da una mano. La variabile GrandeNumero_1 appare subito così:

.data:00404054 GrandeNumero_1 dd 65726E55h ; DATA XREF: Livello_2+3r ma basta dire a IDA di farcelo vedere come se fosse una stringa ed otteniamo:

.data:00404054 GrandeNumero_1 db 'Unregistered' ; DATA XREF: Livello_2+3r Quindi ecco il primo trucco: la stringa viene caricata come se fosse un grosso numero, per questo viene inizialmente disassemblata con DD ma IDA ci permette di farne facilmente la traduzione, rendendo evidente il senso.
Le mov a 401863 e segg. hanno uno scopo ben preciso (oltre a fare confusione): costruiscono la stringa nelle variabili dinamiche allocate sullo stack; tutte le operazione sembrano manipolare numeri ed invece muovono pezzi di stringhe (che sono poi la stessa cosa!).
Vediamo ora la "protezione". Giocano un ruolo importante due variabili che riporto qui:

.data:00404024 DW_3DBh dd 3DBh ; DATA XREF: Livello_3+24r .data:00404028 DW_29Ah dd 29Ah ; DATA XREF: Livello_3+41r ho dato loro un nome che sia assolutamente esplicativo del contenuto. Come si vede sono variabili inizializzate.
A 40188D c'è il primo blocco: si confronta eax con 3DBh ma in eax era stato messa proprio la variabile DW_3DBh (alla 401884), quindi il confronto sarà sempre positivo e quindi a 401896 il jz salterà sempre.
Naturalmente ciò non basta: a 401898 si testa una locazione non inizializzata (ma al caricamento queste variabili vengono sempre inizializzate a zero dal sistema), se è zero ricadiamo in un confronto fra 29Ah e la variabile DW_29Ah. Riassumendo ci troviamo difronte a ben tre punti di salto che dobbiamo dribblare per giungere in porta.
Non c'è molto da pensare, possiamo utilizzare il primo salto (che viene fatto sempre) per saltare invece che a Errore, a Buono. Il patch è banale e con HIEW è possibile inserire direttamente l'indirizzo del salto.

LIVELLO 4.

Stessa storia di sopra, cerchiamo 3F1h che troviamo due volte. Ecco la prima:

.text:004015D7 call ds:GetMenu ; Get the handle of the menu assigned to the given window .text:004015DD mov ebx, ds:EnableMenuItem ; Enable/disable/grays .text:004015E3 mov edi, eax .text:004015E5 push 1 ; uEnable 1=MF_GRAYED .text:004015E7 push 32771 ; uIDEnableItem Abilitami! .text:004015EC push edi ; hMenu .text:004015ED call ebx .text:004015EF push offset Unregistered .text:004015F4 push 3F2h .text:004015F9 mov ecx, esi .text:004015FB call j_?SetDlgItemTextA@CWnd@@QAEXHPBD@Z ; CWnd::SetDlgItemTextA(int,char const *) .text:00401600 push 1 .text:00401602 push 32772 ; uIDEnableItem Livello4 .text:00401607 push edi .text:00401608 call ebx .text:0040160A push offset Unregistered .text:0040160F push 3F1h .text:00401614 mov ecx, esi .text:00401616 call j_?SetDlgItemTextA@CWnd@@QAEXHPBD@Z ; CWnd::SetDlgItemTextA(int,char const *) .text:0040161B call ds:GetTickCount ; Numero di millisecondi da quando .text:0040161B ; e' stato avviato Windows. Ovviamente .text:0040161B ; sempre maggiore di zero .text:00401621 lea ecx, [esp+98h+var_88] .text:00401625 mov WindowsMillisec, eax Ho riportato un pezzo un poco lungo ma c'è una ragione: poco prima della push di 3F1h, c'è una call ebx che possiamo capire solo vedendo la 4015DD: questa pratica è abbastanza frequente nei compilatori; si carica l'indirizzo di una funzione in un registro e poi la si chiama indirettamente con quello anche molte istruzioni dopo.
Per capire bene cosa sta succedendo, vediamo la parte delle risorse che riguarda il menù:

131 MENU LANGUAGE LANG_ITALIAN, SUBLANG_ITALIAN { MENUITEM "Livello 4", 32772 POPUP "Livello5" { MENUITEM "Abilitami!", 32771 } } Anche qui IDA interviene: inizialmente mostrava alla 401602 una push 8004h ma convertendo il valore in decimale ci mostra 32772, proprio l'ID del menù "Livello 4".
Punto della situazione: la call ebx richiama EnableMenuItem e questa lavorerà sul menù "Livello 4"; ci manda da capire cosa fa! La chiave sta in quel push 1 indicato dalla costante MF_GRAYED (Menu Format grigio cioè disabilitato).
Quindi la prima cosa da fare è cambiare l'1 della 401600 in zero.
Attenzione alla parte che segue: viene impostata una variabile che ho chiamato WindowsMillisec; ci servirà
Andiamo al secondo punto trovato cercando 3F1h:

.text:004019C0 Livello_4 proc near .text:004019C0 .text:004019C0 var_10 = dword ptr -10h .text:004019C0 var_C = dword ptr -0Ch .text:004019C0 var_8 = dword ptr -8 .text:004019C0 var_4 = byte ptr -4 .text:004019C0 .text:004019C0 sub esp, 10h .text:004019C3 mov eax, dword ptr GrandeNumero_1 .text:004019C8 push esi .text:004019C9 mov edx, dword ptr GrandeNumero_1+8 .text:004019CF mov esi, ecx .text:004019D1 mov ecx, dword ptr GrandeNumero_1+4 .text:004019D7 mov [esp+14h+var_10], eax .text:004019DB mov al, byte_0_404060 .text:004019E0 mov [esp+14h+var_C], ecx .text:004019E4 lea ecx, [esp+14h+var_10] .text:004019E8 mov [esp+14h+var_8], edx .text:004019EC push ecx .text:004019ED push 3F0h .text:004019F2 mov ecx, esi .text:004019F4 mov [esp+1Ch+var_4], al .text:004019F8 call j_?SetDlgItemTextA@CWnd@@QAEXHPBD@Z ; CWnd::SetDlgItemTextA(int,char const *) .text:004019FD cmp WindowsMillisec, 0Ah .text:00401A04 jge short loc_0_401A17 .text:00401A06 push offset Registered .text:00401A0B push 3F1h ; Quarto static .text:00401A10 mov ecx, esi .text:00401A12 call j_?SetDlgItemTextA@CWnd@@QAEXHPBD@Z ; CWnd::SetDlgItemTextA(int,char const *) .text:00401A17 .text:00401A17 loc_0_401A17: ; CODE XREF: Livello_4+44j .text:00401A17 pop esi .text:00401A18 add esp, 10h .text:00401A1B retn .text:00401A1B Livello_4 endp ; sp = -10h Prima di vedere questa parte, proviamo ad abilitare il menù e vediamo cosa succede: bene non solo non compare Registered al punto guisto ma il livello 3 ritorna Unregistered! Vediamo di dipanare questo mistero.
Osserviamo subito che la SetDlgItemTextA (a 4019F8) fa riferimento al controllo 3F0h (push in 4019ED) mentre il nostro è il 3F1h questo spiega la perdita della registrazione del livello 3. All'inizio c'è il solito pasticcio per non far vedere che si sta mettendo Unregistered. Alla 4019FD c'è la protezione: sicuramente saranno passati più di 10 millisecondi dalla partenza di Windows all'avvio del programma e quindi il test provoca sempre un salto.
In questo caso c'è una buona quantità di roba da buttare e quindi ci vuole una azione di forza: nella 4019EC mettiamo un jmps alla 401A06. In questo modo impediamo che si rovini la registrazione 3 e saltiamo il test di protezione.

LIVELLO 5.

Stesso procedimento per il Livello 4. Abilitiamo il sottomenù (la parte di codice da modificare l'ho riportata insieme a quella per il livello 4). Andiamo al sodo:

.text:00401980 Livello_5 proc near .text:00401980 .text:00401980 var_14 = byte ptr -14h .text:00401980 var_11 = byte ptr -11h .text:00401980 .text:00401980 sub esp, 14h .text:00401983 mov eax, ecx .text:00401985 mov edx, WindowsMillisec .text:0040198B mov ecx, 5 .text:00401990 push esi .text:00401991 push edi .text:00401992 mov esi, offset aSinarrivolostrainer .text:00401997 lea edi, [esp+1Ch+var_14] .text:0040199B repe movsd .text:0040199D movsx ecx, [esp+1Ch+var_11] .text:004019A2 cmp ecx, edx .text:004019A4 jle short loc_0_4019B7 ; Salta Sempre .text:004019A6 push offset Registered .text:004019AB push 3F2h .text:004019B0 mov ecx, eax .text:004019B2 call j_?SetDlgItemTextA@CWnd@@QAEXHPBD@Z ; CWnd::SetDlgItemTextA(int,char const *) .text:004019B7 .text:004019B7 loc_0_4019B7: ; CODE XREF: Livello_5+24j .text:004019B7 pop edi .text:004019B8 pop esi .text:004019B9 add esp, 14h .text:004019BC retn .text:004019BC Livello_5 endp ; sp = -8 Ancora la variabile WindowsMillisec che viene confrontata con 5 (la prima è caricata in edx alla 401895, il 5 è caricato in ecx alla 40198B, il confronto è a 4019A2). Qui è semplicissimo: basta eliminare il salto a 4019A4.
Voglio terminare con un dettaglio: appena sopra compare il riferimento alla stringa della Strainer, bene cambiamo l'offset della push a 4019A6 riportando lo stesso indirizzo che compare alla 401992.
Quindi da così

.00401992: BE0C414000 mov esi,00040410C ; .00401997: 8D7C2408 lea edi,[esp][00008] .0040199B: F3A5 repe movsd .0040199D: 0FBE4C240B movsx ecx,b,[esp][0000B] .004019A2: 3BCA cmp ecx,edx .004019A4: 7E11 jle .0004019B7 -------- (1) .004019A6: 6808424000 push 000404208 ; .004019AB: 68F2030000 push 0000003F2 ; .004019B0: 8BC8 mov ecx,eax .004019B2: E8BF020000 call .000401C76 -------- (2) a così:

.00401992: BE0C414000 mov esi,00040410C ; .00401997: 8D7C2408 lea edi,[esp][00008] .0040199B: F3A5 repe movsd .0040199D: 0FBE4C240B movsx ecx,b,[esp][0000B] .004019A2: 3BCA cmp ecx,edx .004019A4: 7E00 jle .0004019A6 -------- (1) .004019A6: 680C414000 push 00040410C ; .004019AB: 68F2030000 push 0000003F2 ; .004019B0: 8BC8 mov ecx,eax .004019B2: E8BF020000 call .000401C76 -------- (2) Notate il jle che comunque salta all'istruzione successiva (mettete 00 nel secondo byte) e la push di offset diverso a prima ma uguale alla mov in cima.
In questo modo, piuttosto che Registered comparirà la scritta "èInArrivoLoStrainer".

Note finali

Ho più volte letto e modificato questo tutorial: a volte mi sembrava di non aver detto tutto, altre volte toglievo intere parti per non appesantire ulteriormente la trattazione.
Sono certo che se qualcuno leggerà queste righe significa che ha avuto una pazienza non comune.

Disclaimer

Non assumo alcuna responsabilità per l'uso che può essere fatto di questo scritto o per le conseguenze dirette o indirette che possono derivare dall'utilizzo delle informazioni contenute.
Questo scritto ha l'unico scopo di studiare e valutare software ottenuto legalmente e non vuole suggerire alcuna attività illegale.