|
VB
Reversing | ||
|
Data |
by "Winebag" |
|
|
18/03/2003 |
Published by Quequero | |
|
Sò diabbolico nell' amplesso, sprupurziunat' per quanto riguarda le dimensioni di sesso |
Grazie Wine |
...e se trovo la donna ggiusta me la ciuccio com' n'aracosta |
|
.... |
|
.... |
|
Difficoltà |
(X)NewBies ( )Intermedio ( )Avanzato ( )Master |
|
Oggi AndreaGeddon ci ha preparato un corso in cui ci divertiremo come bambini a reversare il Visual Basic!
|
Introduzione |
|
Tools usati |
|
URL o FTP del programma |
|
Notizie sul programma |
|
Essay |
mov dword ptr [ebp-4], 11h
mov ecx, length
call ds:__vbaI2I4<--trasforma una dword in word
mov lengthserial, ax
mov word ptr [ebp-0DCh], 1
mov word ptr counter, 1
jmp short entry1
Loop1:
mov cx, counter
add cx, [ebp-0DCh]<--questo valore è 1
jo Error
mov counter, cx
entry1:
mov dx, counter
cmp dx, lengthserial
jg exit1
mov dword ptr [ebp-4], 12h
mov dword ptr [ebp-58h], 1
mov dword ptr [ebp-60h], 2
lea eax, [ebp-2Ch]
mov [ebp-98h], eax
mov dword ptr [ebp-0A0h], 4008h
lea ecx, [ebp-60h]
push ecx
movsx edx, word ptr counter
push edx<---indice nella stringa
lea eax, [ebp-0A0h]
push eax
lea ecx, [ebp-70h]
push ecx
call ds:rtcMidCharVar
lea edx, [ebp-70h]
push edx
lea eax, [ebp-40h]
push eax
call ds:__vbaStrVarVal
push eax
call ds:rtcAnsiValueBstr
mov ecx, eax<--qui c'è il byte individuato dall'indice,
quindi dal contatore
call ds:__vbaUI1I2<--converte una word in un unsigned char
mov char, al<--qui salva questo valore in una variabile
locale
lea ecx, [ebp-40h]
call ds:__vbaFreeStr
lea ecx, [ebp-70h]
push ecx
lea edx, [ebp-60h]
push edx
push 2
call ds:__vbaFreeVarList
add esp, 0Ch
mov dword ptr [ebp-4], 13h
movzx ax, char
cmp ax, 30h<---
jge short OK3
jmp No
OK3:
mov dword ptr [ebp-4], 16h
movzx cx, char
cmp cx, 39h<---questi due cmp controllano che il
carattere sia numerico
jle short OK4
jmp No
OK4:
mov dword ptr [ebp-4], 19h
jmp Loop1
Starete pensando minchia che ciclo lungo, chissà quante cose riuscirà a fare questo ottimo VB! Invece no, non so se sia l'autore che volutamente per complicarci la vita abbia aggiunto codice inutile o se il compilatore si sia preso la libertà di farlo lui anche se mi sembra più plausibile la seconda ipotesi. Dunque cercherò di dare un'interpretazione alle sei funzioni chiamate dal programma, andando un po' a senso perché non credo siano documentate e ovviamente non me le sono reversate! La prima, rtcMidCharVar, salva in una qualche struttura l'indice inserito come parametro; __vbaStrVarVal restituisce un puntatore alla stringa considerata(in questo caso quella contenente il serial); rtcAnsiValueBstr restituisce il byte della stringa individuato dall'indice( ricordando che i byte sono numerati a partire da 1, quindi con indice 1 restituisce string[0], e che le stringhe sono in formato unicode); __vbaUI1I2 ha il compito di convertire il valore passatole in cx, in un byte; in questo caso mi sembra però sovrabbondante dato che la funzione precedente restituisce già un byte.__vbaFreeStr e __vbaFreeVarList dovrebbero servire a liberare la memoria precedentemente allocata,ma in ogni caso non ci interessa.Tutto questo loop come avevamo detto all'inizio è un banale controllo della "numericità" del serial,che in assembly ben scritto starebbe comodamente in una ventina di byte. Passiamo al secondo loop dove viene generata la dword[ebp-38h],rinominata Var1; ho tagliato qualche pezzo che si ripeteva uguale a sopra.
mov length, ax
mov word ptr [ebp-0E4h], 1
mov word ptr counter, 1
jmp short entry2
Loop2:
mov ax, counter
add ax, [ebp-0E4h]<--+1
jo error
mov counter, ax
entry2:
mov cx, counter
cmp cx, length
jg exit2
...<--qui in un modo non molto ortodosso viene messo
un carattere dell'UserName in al
movsx eax, ax
mov ecx, Var1<---alla Var1 del loop precedente
add ecx, eax<--viene aggiunto il carattere di questo
ciclo
jo error
mov Var1, ecx
...
jmp Loop2
exit2:
mov dword ptr [ebp-4], 1Fh
mov ecx, Var1
xor ecx, length<--xora la somma dei caratteri con la
lunghezza
mov Var1, ecx<-- e salva il risultato in Var1
Se togliamo il superfluo diventa ovvio capire come Var1,che all'inizio valeva 0, adesso contenga la sommatoria di tutti i caratteri xorata con la lunghezza. Passiamo ora ad analizzare il terzo loop:
mov word ptr [ebp-0F0h], 4
mov word ptr [ebp-0ECh], 1
mov word ptr counter, 1
jmp short entry3
Loop3:
mov dx, counter
add dx, [ebp-0ECh]<---+1
jo error
mov counter, dx
entry3:
mov ax, counter
cmp ax, [ebp-0F0h]<--Primi 4 char
jg exit3
mov dword ptr [ebp-4], 22h
mov dword ptr [ebp-58h], 1
mov dword ptr [ebp-60h], 2
lea ecx, [ebp-2Ch]
mov [ebp-98h], ecx
mov dword ptr [ebp-0A0h], 4008h
lea edx, [ebp-60h]
push edx
movsx eax, word ptr counter
push eax
lea ecx, [ebp-0A0h]
push ecx
lea edx, [ebp-70h]
push edx
call ds:rtcMidCharVar<-- di nuovo salva l'indice
rappresentato dal contatore
mov eax, Var2<-- prende il vecchio valore di Var2
push eax
call ds:__vbaStrI4<--lo trasforma in una stringa (tipo
itoa)
mov edx, eax
lea ecx, [ebp-44h]
call ds:__vbaStrMove<--copia
la stringa da un'altra parte
push eax
lea ecx, [ebp-70h]
push ecx
lea edx, [ebp-40h]
push edx
call ds:__vbaStrVarVal<--restituisce
il puntatore alla stringa
push eax
call ds:rtcAnsiValueBstr<--legge il valore del byte
sub ax, 30h<--legge il valore decimale rappresentato
jo error
push eax
call ds:__vbaStrI2<--lo riconverte in una stringa!
mov edx, eax
lea ecx, [ebp-48h]
call ds:__vbaStrMove<--copia la stringa tanto per sprecare
un po' di cicli
push eax
call ds:__vbaStrCat<--concatena le due stringhe
mov edx, eax
lea ecx, [ebp-4Ch]
call ds:__vbaStrMove<--sposta la stringa ottenuta,tanto
per cambiare
push eax
call ds:__vbaI4Str<--ritrasforma la stringa in intero
decimale(vedi atoi)
mov Var2, eax<--lo salva in Var2
...<--libera la memoria
jmp Loop3
exit3:
mov dword ptr [ebp-4], 24h
mov eax, Var2
xor eax, 29Ah<--xora il valore
ottenuto con 29Ah
mov Var2, eax
mov dword ptr [ebp-4], 25h
mov ecx, Var2
cmp ecx, Var1<--confronta i due valori
jz short OK5<--continua
jmp No<--esce
In sintesi, dimenticando tutto il commercio di stringhe che viene fatto, questo loop prende ciascuno dei primi 4 caratteri del serial e lo concatena ai precedenti in una stringa, che poi converte in un intero e salva in Var2; tutto ciò corrisponde ad un unico atoi, in Var2 ci sarà quindi il valore decimale dei primi 4 caratteri; questo valore viene xorato con 29Ah, e deve essere uguale al valore trovato sopra. Possiamo quindi avere un idea del serial: è di 8 caratteri, per ottenere i primi 4 sommo tutti i valori dell'UN, xoro prima con la sua lunghezza e poi con 29Ah. Andiamo al 4°loop.
mov dword ptr [ebp-4], 28h
mov dword ptr Var2, 0<---
mov dword ptr [ebp-4], 29h
mov dword ptr Var1, 0<--azzera le due variabili
mov dword ptr [ebp-4], 2Ah
mov ecx, length<--si riferisce
all'UN
call ds:__vbaI2I4
mov UNlength, ax
mov word ptr [ebp-0F4h], 1
mov word ptr counter, 1
jmp short entry4
loop4:
mov dx, counter
add dx, [ebp-0F4h]<--che brutto modo di scrivere inc dx :-((
jo error
mov counter, dx
entry4:
mov ax, counter
cmp ax, UNlength
jg exit4
mov dword ptr [ebp-4], 2Bh
mov dword ptr [ebp-58h], 1
mov dword ptr [ebp-60h], 2
lea ecx, [ebp-30h]
mov [ebp-98h], ecx
mov dword ptr [ebp-0A0h], 4008h
lea edx, [ebp-60h]
push edx
movsx eax, word ptr counter
push eax
lea ecx, [ebp-0A0h]
push ecx
lea edx, [ebp-70h]<--fate attenzione a questo indirizzo
push edx
call ds:rtcMidCharVar<--salva l'indice corrispondente al ciclo
mov dword ptr [ebp-78h], 1
mov dword ptr [ebp-80h], 2
lea eax, [ebp-30h]
mov [ebp-0B8h], eax
mov dword ptr [ebp-0C0h], 4008h
lea ecx, [ebp-80h]
push ecx
movsx edx, word ptr counter
mov eax, length
sub eax, edx<--qui eax=L-C
jo error
push eax<--fissa eax come indice per un secondo valore
lea ecx, [ebp-0C0h]
push ecx
lea edx, [ebp-90h]<--che mettera in una,credo, struttura a
quest'indirizzo
push edx
call ds:rtcMidCharVar
lea eax, [ebp-70h]<--questo si riferisce alla prima chiamata a
rtcMidCharVar
push eax
lea ecx, [ebp-40h]
push ecx
call ds:__vbaStrVarVal
push eax
call ds:rtcAnsiValueBstr<--questo sarà il carattere di
posizione C nella stringa col nostro UN
movsx edx, ax
mov esi, Var1
add esi, edx<--aggiunge a Var1 il carattere C
jo error
lea eax, [ebp-90h]<--questa variabile è stata usata dalla seconda
rtcMidCharVar
push eax
lea ecx, [ebp-44h]
push ecx
call ds:__vbaStrVarVal
push eax
call ds:rtcAnsiValueBstr<--quindi questo sarà il char di
posizione L-C
movsx edx, ax
xor esi, edx<--con cui xoriamo il risultato della somma precedente
mov Var1, esi<--che rimettiamo in Var1 per il prossimo ciclo
...
jmp loop4
Anche qui siamo alla fiera dell'overbloating,
e una banalissima routine viene espansa in righe e righe di codice Si
ma e' funzionale per annoiarci ;p NdQue.Vi ho messo quasi tutta la routine,
perché poteste vedere la differenza tra i due caratteri che vengono usati per
ogni ciclo : di posizione C e (L-C). Se però siete stati attenti noterete che
c'è un piccolo bug: infatti poiché i caratteri vengono contati a partire da
uno, la variabile C assumerà tutti i valori compresi tra 1 e L; l'indice dell'altro
carattere andrà quindi da (C-1) a (L-L)=0, quindi dal penultimo al "numero
zero"(come l'osteria:-))), che quindi non esiste. Strano a dirsi questo
fatto non fa crashare il programma,che anzi riprende da dove aveva lasciato
come se nulla fosse successo! Questo se vogliamo è una delle poche cose utili
del VB: anche se in questo caso c'è un errore, non si blocca,ma riprende da
dove aveva lasciato, anche se probabilmente in un linguaggio umano non sarebbe
neanche avvenuto l'errore, ma questo è un altro discorso. Ora a noi non interessa
se questo bug sia stato messo di proposito, a noi interessa sapere cosa succede
a Var1: ovviamente non viene modificata, quindi di fatto è come se il programma
facesse un ciclo in meno. Ricapitolando in pseudo-C:
for(i=0;i<strlen(un)-1;i++){Var1+=un[i]; Var1^=un[strlen(un)-i-2]
Adesso
dovremmo passare al quinto loop, che vi risparmio, tanto è uguale al terzo,
quindi un atoi, solo che per gli ultimi 4 char del serial; diamo uno sguardo
all' ultimo check, per vedere se ci sono altre operazioni:
mov word ptr [ebp-100h], 8<--
mov word ptr [ebp-0FCh], 1
mov word ptr counter, 5<---Notate solo che usa i caratteri da 5 a 8
...<---Var2=atol(&serial[4])
mov ecx, Var1
cmp ecx, Var2<--Niente, un semplice controllo
jz short OK6<--abbiamo finito
jmp No
Come avete potuto vedere la difficoltà più grossa è stata orientarsi nel codice mostruosamente lungo prodotto dal compilatore VB; l'algoritmo era piuttosto semplice, quindi possiamo scrivere un piccolo crackme, per dare un esempio in prima persona non ho usato il VB! Ho optato per il C, solo per la comodità delle funzioni di I-O, avrei anche potuto scriverlo in asm, per far risaltare chiaramente la differenza di lunghezza del compilato, ma non avevo voglia.
//----------------------------- Keygen.cpp-------------------------------------------
#include <stdio.h>
#include <string.h>
void main(){
char *name;
char s[9];
int a,l,h,b=0;
strcpy(s,"00000000");
gets(name);
l=strlen(name);
h=l^0x29A;
l--;
a=name[l];
for (int i=0;i<l;i++){
b+=name[i];
b^=name[l-i-1];
a+=name[i];}
a^=h;
b+=a*10000;
for (int i=7;i>=0;i--){
s[i]+=b%10;
b/=10;}
printf("%s",s);}
//---------------------------------------------------------------
Il codice ovviamente non è commentato,
ma se avete capito come funziona l'algo non dovreste avere problemi a capirlo;
l'unica cosa che ho aggiunto è l'ultimo ciclo, per formattare l'output, dato
che in printf non sapevo come ottenere l'equivalente di %08d.
Per oggi abbiamo
finito,ciao a tutti
Winebag
|
Note finali |
Allora saluterei gli autori di questo corso, Ntoskrnl e AndreaGeddon (con la gentile partecipazione dei suoi capelli), che mi hanno spinto a dare uno sguardo al VB, cosa che ho sempre tentato di evitare. Un ringraziamento va a tutta la UIC e a tutti quelli che si sbattono per mandarla avanti.
|
Disclaimer |
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.